4 * Copyright 1993 Alexandre Julliard
10 #include <X11/Xatom.h>
11 #include <X11/keysym.h>
14 #include "ts_xresource.h"
19 #ifdef HAVE_LIBXXF86DGA2
20 #include "ts_xf86dga2.h"
25 #include "wine/winuser16.h"
26 #include "shlobj.h" /* DROPFILES */
28 #include "clipboard.h"
30 #include "debugtools.h"
45 DEFAULT_DEBUG_CHANNEL(event
);
46 DECLARE_DEBUG_CHANNEL(win
);
48 /* X context to associate a hwnd to an X window */
49 extern XContext winContext
;
51 extern Atom wmProtocols
;
52 extern Atom wmDeleteWindow
;
53 extern Atom dndProtocol
;
54 extern Atom dndSelection
;
56 extern void X11DRV_KEYBOARD_UpdateState(void);
57 extern void X11DRV_KEYBOARD_HandleEvent(WND
*pWnd
, XKeyEvent
*event
);
59 #define NB_BUTTONS 5 /* Windows can handle 3 buttons and the wheel too */
62 #define DndNotDnd -1 /* OffiX drag&drop */
74 #define DndURL 128 /* KDE drag&drop */
76 /* The last X window which had the focus */
77 static Window glastXFocusWin
= 0;
79 static const char * const event_names
[] =
81 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
82 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
83 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
84 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
85 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
86 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
87 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
88 "ClientMessage", "MappingNotify"
92 static void CALLBACK
EVENT_Flush( ULONG_PTR arg
);
93 static void CALLBACK
EVENT_ProcessAllEvents( ULONG_PTR arg
);
94 static void EVENT_ProcessEvent( XEvent
*event
);
95 BOOL
X11DRV_CheckFocus(void);
98 static void EVENT_Key( HWND hWnd
, XKeyEvent
*event
);
99 static void EVENT_ButtonPress( HWND hWnd
, XButtonEvent
*event
);
100 static void EVENT_ButtonRelease( HWND hWnd
, XButtonEvent
*event
);
101 static void EVENT_MotionNotify( HWND hWnd
, XMotionEvent
*event
);
102 static void EVENT_FocusIn( HWND hWnd
, XFocusChangeEvent
*event
);
103 static void EVENT_FocusOut( HWND hWnd
, XFocusChangeEvent
*event
);
104 static void EVENT_Expose( HWND hWnd
, XExposeEvent
*event
);
105 static void EVENT_GraphicsExpose( HWND hWnd
, XGraphicsExposeEvent
*event
);
106 static void EVENT_ConfigureNotify( HWND hWnd
, XConfigureEvent
*event
);
107 static void EVENT_SelectionRequest( HWND hWnd
, XSelectionRequestEvent
*event
, BOOL bIsMultiple
);
108 static void EVENT_SelectionClear( HWND hWnd
, XSelectionClearEvent
*event
);
109 static void EVENT_PropertyNotify( XPropertyEvent
*event
);
110 static void EVENT_ClientMessage( HWND hWnd
, XClientMessageEvent
*event
);
111 static void EVENT_MapNotify( HWND pWnd
, XMapEvent
*event
);
112 static void EVENT_UnmapNotify( HWND pWnd
, XUnmapEvent
*event
);
113 static void EVENT_MappingNotify( XMappingEvent
*event
);
116 static void EVENT_ShmCompletion( XShmCompletionEvent
*event
);
117 static int ShmAvailable
, ShmCompletionType
;
118 extern int XShmGetEventBase( Display
* );/* Missing prototype for function in libXext. */
121 #ifdef HAVE_LIBXXF86DGA2
122 static int DGAMotionEventType
;
123 static int DGAButtonPressEventType
;
124 static int DGAButtonReleaseEventType
;
125 static int DGAKeyPressEventType
;
126 static int DGAKeyReleaseEventType
;
128 static BOOL DGAUsed
= FALSE
;
129 static HWND DGAhwnd
= 0;
131 static void EVENT_DGAMotionEvent( XDGAMotionEvent
*event
);
132 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent
*event
);
133 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent
*event
);
136 /* Usable only with OLVWM - compile option perhaps?
137 static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
140 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
141 unsigned int *pwidth
, unsigned int *pheight
);
144 static BOOL bUserRepaintDisabled
= TRUE
;
146 /* Static used for the current input method */
147 static INPUT_TYPE current_input_type
= X11DRV_INPUT_ABSOLUTE
;
148 static BOOL in_transition
= FALSE
; /* This is not used as for today */
150 /***********************************************************************
153 BOOL
X11DRV_EVENT_Init(void)
156 ShmAvailable
= XShmQueryExtension( display
);
158 ShmCompletionType
= XShmGetEventBase( display
) + ShmCompletion
;
162 /* Install the X event processing callback */
163 SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display
),
164 GENERIC_READ
| SYNCHRONIZE
),
165 EVENT_ProcessAllEvents
, 0 );
167 /* Install the XFlush timer callback */
168 if ( Options
.synchronous
)
169 TSXSynchronize( display
, True
);
171 SERVICE_AddTimer( 200, EVENT_Flush
, 0 );
176 /***********************************************************************
179 static void CALLBACK
EVENT_Flush( ULONG_PTR arg
)
184 /***********************************************************************
185 * EVENT_ProcessAllEvents
187 static void CALLBACK
EVENT_ProcessAllEvents( ULONG_PTR arg
)
191 TRACE( "called (thread %lx).\n", GetCurrentThreadId() );
193 EnterCriticalSection( &X11DRV_CritSection
);
194 while ( XPending( display
) )
196 XNextEvent( display
, &event
);
198 LeaveCriticalSection( &X11DRV_CritSection
);
199 EVENT_ProcessEvent( &event
);
200 EnterCriticalSection( &X11DRV_CritSection
);
202 LeaveCriticalSection( &X11DRV_CritSection
);
205 /***********************************************************************
208 * Synchronize with the X server. Should not be used too often.
210 void X11DRV_Synchronize( void )
212 TSXSync( display
, False
);
213 EVENT_ProcessAllEvents( 0 );
216 /***********************************************************************
217 * X11DRV_UserRepaintDisable
219 void X11DRV_UserRepaintDisable( BOOL bDisabled
)
221 bUserRepaintDisabled
= bDisabled
;
224 /***********************************************************************
227 * Process an X event.
229 static void EVENT_ProcessEvent( XEvent
*event
)
233 TRACE( "called.\n" );
237 case SelectionNotify
: /* all of these should be caught by XCheckTypedWindowEvent() */
238 FIXME("Got SelectionNotify - must not happen!\n");
241 /* We get all these because of StructureNotifyMask.
242 This check is placed here to avoid getting error messages below,
243 as X might send some of these even for windows that have already
245 case CirculateNotify
:
254 if (ShmAvailable
&& (event
->type
== ShmCompletionType
)) {
255 EVENT_ShmCompletion( (XShmCompletionEvent
*)event
);
260 #ifdef HAVE_LIBXXF86DGA2
262 if (event
->type
== DGAMotionEventType
) {
263 TRACE("DGAMotionEvent received.\n");
264 EVENT_DGAMotionEvent((XDGAMotionEvent
*) event
);
267 if (event
->type
== DGAButtonPressEventType
) {
268 TRACE("DGAButtonPressEvent received.\n");
269 EVENT_DGAButtonPressEvent((XDGAButtonEvent
*) event
);
272 if (event
->type
== DGAButtonReleaseEventType
) {
273 TRACE("DGAButtonReleaseEvent received.\n");
274 EVENT_DGAButtonReleaseEvent((XDGAButtonEvent
*) event
);
277 if ((event
->type
== DGAKeyPressEventType
) ||
278 (event
->type
== DGAKeyReleaseEventType
)) {
279 /* Fill a XKeyEvent to send to EVENT_Key */
281 XDGAKeyEvent
*evt
= (XDGAKeyEvent
*) event
;
283 TRACE("DGAKeyPress/ReleaseEvent received.\n");
285 if (evt
->type
== DGAKeyReleaseEventType
)
286 ke
.type
= KeyRelease
;
289 ke
.serial
= evt
->serial
;
290 ke
.send_event
= FALSE
;
291 ke
.display
= evt
->display
;
300 ke
.state
= evt
->state
;
301 ke
.keycode
= evt
->keycode
;
302 ke
.same_screen
= TRUE
;
304 X11DRV_KEYBOARD_HandleEvent(NULL
, &ke
);
310 if ( TSXFindContext( display
, event
->xany
.window
, winContext
,
311 (char **)&hWnd
) != 0) {
312 if ( event
->type
== ClientMessage
) {
313 /* query window (drag&drop event contains only drag window) */
315 int root_x
, root_y
, child_x
, child_y
;
317 TSXQueryPointer( display
, X11DRV_GetXRootWindow(), &root
, &child
,
318 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
319 if (TSXFindContext( display
, child
, winContext
, (char **)&hWnd
) != 0)
322 hWnd
= 0; /* Not for a registered window */
326 if ( !hWnd
&& event
->xany
.window
!= X11DRV_GetXRootWindow()
327 && event
->type
!= PropertyNotify
328 && event
->type
!= MappingNotify
)
329 ERR("Got event %s for unknown Window %08lx\n",
330 event_names
[event
->type
], event
->xany
.window
);
332 TRACE("Got event %s for hwnd %04x\n",
333 event_names
[event
->type
], hWnd
);
339 EVENT_Key( hWnd
, (XKeyEvent
*)event
);
343 EVENT_ButtonPress( hWnd
, (XButtonEvent
*)event
);
347 EVENT_ButtonRelease( hWnd
, (XButtonEvent
*)event
);
351 /* Wine between two fast machines across the overloaded campus
352 ethernet gets very boged down in MotionEvents. The following
353 simply finds the last motion event in the queue and drops
354 the rest. On a good link events are servered before they build
355 up so this doesn't take place. On a slow link this may cause
356 problems if the event order is important. I'm not yet seen
357 of any problems. Jon 7/6/96.
359 if ((current_input_type
== X11DRV_INPUT_ABSOLUTE
) &&
360 (in_transition
== FALSE
))
361 /* Only cumulate events if in absolute mode */
362 while (TSXCheckTypedWindowEvent(display
,((XAnyEvent
*)event
)->window
,
363 MotionNotify
, event
));
364 EVENT_MotionNotify( hWnd
, (XMotionEvent
*)event
);
369 WND
*pWndLastFocus
= 0;
370 XWindowAttributes win_attr
;
372 XFocusChangeEvent
*xfocChange
= (XFocusChangeEvent
*)event
;
374 if (!hWnd
|| bUserRepaintDisabled
) return;
376 bIsDisabled
= GetWindowLongA( hWnd
, GWL_STYLE
) & WS_DISABLED
;
378 /* If the window has been disabled and we are in managed mode,
379 * revert the X focus back to the last focus window. This is to disallow
380 * the window manager from switching focus away while the app is
383 if ( Options
.managed
&& bIsDisabled
&& glastXFocusWin
)
385 /* Change focus only if saved focus window is registered and viewable */
386 if ( TSXFindContext( xfocChange
->display
, glastXFocusWin
, winContext
,
387 (char **)&pWndLastFocus
) == 0 )
389 if ( TSXGetWindowAttributes( display
, glastXFocusWin
, &win_attr
) &&
390 (win_attr
.map_state
== IsViewable
) )
392 TSXSetInputFocus( xfocChange
->display
, glastXFocusWin
, RevertToParent
, CurrentTime
);
399 EVENT_FocusIn( hWnd
, xfocChange
);
405 /* Save the last window which had the focus */
406 XFocusChangeEvent
*xfocChange
= (XFocusChangeEvent
*)event
;
407 glastXFocusWin
= xfocChange
->window
;
408 if (!hWnd
|| bUserRepaintDisabled
) return;
409 if (GetWindowLongA( hWnd
, GWL_STYLE
) & WS_DISABLED
) glastXFocusWin
= 0;
410 EVENT_FocusOut( hWnd
, (XFocusChangeEvent
*)event
);
415 if (bUserRepaintDisabled
) return;
416 EVENT_Expose( hWnd
, (XExposeEvent
*)event
);
420 if (bUserRepaintDisabled
) return;
421 EVENT_GraphicsExpose( hWnd
, (XGraphicsExposeEvent
*)event
);
424 case ConfigureNotify
:
425 if (!hWnd
|| bUserRepaintDisabled
) return;
426 EVENT_ConfigureNotify( hWnd
, (XConfigureEvent
*)event
);
429 case SelectionRequest
:
430 if (!hWnd
|| bUserRepaintDisabled
) return;
431 EVENT_SelectionRequest( hWnd
, (XSelectionRequestEvent
*)event
, FALSE
);
435 if (!hWnd
|| bUserRepaintDisabled
) return;
436 EVENT_SelectionClear( hWnd
, (XSelectionClearEvent
*) event
);
440 EVENT_PropertyNotify( (XPropertyEvent
*)event
);
444 if (!hWnd
|| bUserRepaintDisabled
) return;
445 EVENT_ClientMessage( hWnd
, (XClientMessageEvent
*) event
);
450 EVENT_EnterNotify( hWnd
, (XCrossingEvent
*) event
);
458 if (!hWnd
|| bUserRepaintDisabled
) return;
459 EVENT_MapNotify( hWnd
, (XMapEvent
*)event
);
463 if (!hWnd
|| bUserRepaintDisabled
) return;
464 EVENT_UnmapNotify( hWnd
, (XUnmapEvent
*)event
);
468 EVENT_MappingNotify( (XMappingEvent
*) event
);
472 WARN("Unprocessed event %s for hwnd %04x\n",
473 event_names
[event
->type
], hWnd
);
476 TRACE( "returns.\n" );
479 /***********************************************************************
482 * Synchronize internal z-order with the window manager's.
484 static BOOL
__check_query_condition( WND
** pWndA
, WND
** pWndB
)
486 /* return TRUE if we have at least two managed windows */
488 for( *pWndB
= NULL
; *pWndA
; *pWndA
= (*pWndA
)->next
)
489 if( ((*pWndA
)->dwExStyle
& WS_EX_MANAGED
) &&
490 ((*pWndA
)->dwStyle
& WS_VISIBLE
)) break;
492 for( *pWndB
= (*pWndA
)->next
; *pWndB
; *pWndB
= (*pWndB
)->next
)
493 if( ((*pWndB
)->dwExStyle
& WS_EX_MANAGED
) &&
494 ((*pWndB
)->dwStyle
& WS_VISIBLE
)) break;
495 return ((*pWndB
) != NULL
);
498 static Window
__get_common_ancestor( Window A
, Window B
,
499 Window
** children
, unsigned* total
)
501 /* find the real root window */
503 Window root
, *childrenB
;
508 TSXQueryTree( display
, A
, &root
, &A
, children
, total
);
509 TSXQueryTree( display
, B
, &root
, &B
, &childrenB
, &totalB
);
510 if( childrenB
) TSXFree( childrenB
);
511 if( *children
) TSXFree( *children
), *children
= NULL
;
512 } while( A
!= B
&& A
&& B
);
516 TSXQueryTree( display
, A
, &root
, &B
, children
, total
);
522 static Window
__get_top_decoration( Window w
, Window ancestor
)
524 Window
* children
, root
, prev
= w
, parent
= w
;
530 TSXQueryTree( display
, w
, &root
, &parent
, &children
, &total
);
531 if( children
) TSXFree( children
);
532 } while( parent
&& parent
!= ancestor
);
533 TRACE("\t%08x -> %08x\n", (unsigned)prev
, (unsigned)w
);
534 return ( parent
) ? w
: 0 ;
537 static unsigned __td_lookup( Window w
, Window
* list
, unsigned max
)
540 for( i
= max
- 1; i
>= 0; i
-- ) if( list
[i
] == w
) break;
544 static HWND
EVENT_QueryZOrder( HWND hWndCheck
)
546 HWND hwndInsertAfter
= HWND_TOP
;
547 WND
*pWndCheck
= WIN_FindWndPtr(hWndCheck
);
548 WND
*pDesktop
= WIN_GetDesktop();
549 WND
*pWnd
, *pWndZ
= WIN_LockWndPtr(pDesktop
->child
);
550 Window w
, parent
, *children
= NULL
;
551 unsigned total
, check
, pos
, best
;
553 if( !__check_query_condition(&pWndZ
, &pWnd
) )
555 WIN_ReleaseWndPtr(pWndCheck
);
556 WIN_ReleaseWndPtr(pDesktop
->child
);
557 WIN_ReleaseDesktop();
558 return hwndInsertAfter
;
560 WIN_LockWndPtr(pWndZ
);
561 WIN_LockWndPtr(pWnd
);
562 WIN_ReleaseWndPtr(pDesktop
->child
);
563 WIN_ReleaseDesktop();
565 parent
= __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ
),
566 X11DRV_WND_GetXWindow(pWnd
),
568 if( parent
&& children
)
570 /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
572 w
= __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck
), parent
);
574 if( w
!= children
[total
-1] ) /* check if at the top */
576 /* X child at index 0 is at the bottom, at index total-1 is at the top */
577 check
= __td_lookup( w
, children
, total
);
580 for( WIN_UpdateWndPtr(&pWnd
,pWndZ
); pWnd
;WIN_UpdateWndPtr(&pWnd
,pWnd
->next
))
582 /* go through all windows in Wine z-order... */
584 if( pWnd
!= pWndCheck
)
586 if( !(pWnd
->dwExStyle
& WS_EX_MANAGED
) ||
587 !(w
= __get_top_decoration( X11DRV_WND_GetXWindow(pWnd
), parent
)) )
589 pos
= __td_lookup( w
, children
, total
);
590 if( pos
< best
&& pos
> check
)
592 /* find a nearest Wine window precedes
593 * pWndCheck in the real z-order... */
595 hwndInsertAfter
= pWnd
->hwndSelf
;
597 if( best
- check
== 1 ) break;
602 if( children
) TSXFree( children
);
603 WIN_ReleaseWndPtr(pWnd
);
604 WIN_ReleaseWndPtr(pWndZ
);
605 WIN_ReleaseWndPtr(pWndCheck
);
606 return hwndInsertAfter
;
609 /***********************************************************************
610 * X11DRV_EVENT_XStateToKeyState
612 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
613 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
615 WORD
X11DRV_EVENT_XStateToKeyState( int state
)
619 if (state
& Button1Mask
) kstate
|= MK_LBUTTON
;
620 if (state
& Button2Mask
) kstate
|= MK_MBUTTON
;
621 if (state
& Button3Mask
) kstate
|= MK_RBUTTON
;
622 if (state
& ShiftMask
) kstate
|= MK_SHIFT
;
623 if (state
& ControlMask
) kstate
|= MK_CONTROL
;
627 /***********************************************************************
630 static void EVENT_Expose( HWND hWnd
, XExposeEvent
*event
)
633 int offx
= 0,offy
= 0;
635 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
636 /* Make position relative to client area instead of window */
637 offx
= (pWnd
? (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
) : 0);
638 offy
= (pWnd
? (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
) : 0);
640 rect
.left
= event
->x
- offx
;
641 rect
.top
= event
->y
- offy
;
643 rect
.right
= rect
.left
+ event
->width
;
644 rect
.bottom
= rect
.top
+ event
->height
;
646 WIN_ReleaseWndPtr(pWnd
);
648 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
| RDW_FRAME
| RDW_ALLCHILDREN
| RDW_ERASE
);
650 if (event
->count
== 0)
651 SendNotifyMessageA(hWnd
,WM_SYNCPAINT
, 0, 0);
655 /***********************************************************************
656 * EVENT_GraphicsExpose
658 * This is needed when scrolling area is partially obscured
659 * by non-Wine X window.
661 static void EVENT_GraphicsExpose( HWND hWnd
, XGraphicsExposeEvent
*event
)
664 int offx
= 0,offy
= 0;
666 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
667 /* Make position relative to client area instead of window */
668 offx
= (pWnd
? (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
) : 0);
669 offy
= (pWnd
? (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
) : 0);
671 rect
.left
= event
->x
- offx
;
672 rect
.top
= event
->y
- offy
;
674 rect
.right
= rect
.left
+ event
->width
;
675 rect
.bottom
= rect
.top
+ event
->height
;
677 WIN_ReleaseWndPtr(pWnd
);
679 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
| RDW_ALLCHILDREN
| RDW_ERASE
);
681 if (event
->count
== 0)
682 SendNotifyMessageA(hWnd
,WM_SYNCPAINT
, 0, 0);
686 /***********************************************************************
689 * Handle a X key event
691 static void EVENT_Key( HWND hWnd
, XKeyEvent
*event
)
693 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
694 X11DRV_KEYBOARD_HandleEvent( pWnd
, event
);
695 WIN_ReleaseWndPtr(pWnd
);
700 /***********************************************************************
703 static void EVENT_MotionNotify( HWND hWnd
, XMotionEvent
*event
)
705 if (current_input_type
== X11DRV_INPUT_ABSOLUTE
) {
706 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
707 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
708 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
709 WIN_ReleaseWndPtr(pWnd
);
711 X11DRV_SendEvent( MOUSEEVENTF_MOVE
| MOUSEEVENTF_ABSOLUTE
,
712 xOffset
+ event
->x
, yOffset
+ event
->y
,
713 X11DRV_EVENT_XStateToKeyState( event
->state
),
714 event
->time
- X11DRV_server_startticks
, hWnd
);
716 X11DRV_SendEvent( MOUSEEVENTF_MOVE
,
717 event
->x_root
, event
->y_root
,
718 X11DRV_EVENT_XStateToKeyState( event
->state
),
719 event
->time
- X11DRV_server_startticks
, hWnd
);
724 /***********************************************************************
727 static void EVENT_ButtonPress( HWND hWnd
, XButtonEvent
*event
)
729 static WORD statusCodes
[NB_BUTTONS
] =
730 { MOUSEEVENTF_LEFTDOWN
, MOUSEEVENTF_MIDDLEDOWN
, MOUSEEVENTF_RIGHTDOWN
, MOUSEEVENTF_WHEEL
, MOUSEEVENTF_WHEEL
};
731 int buttonNum
= event
->button
- 1;
733 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
734 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
735 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
736 WORD keystate
,wData
= 0;
738 WIN_ReleaseWndPtr(pWnd
);
740 if (buttonNum
>= NB_BUTTONS
) return;
743 * Get the compatible keystate
745 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
748 * Make sure that the state of the button that was just
754 keystate
|= MK_LBUTTON
;
757 keystate
|= MK_MBUTTON
;
760 keystate
|= MK_RBUTTON
;
766 wData
= -WHEEL_DELTA
;
770 X11DRV_SendEvent( statusCodes
[buttonNum
],
771 xOffset
+ event
->x
, yOffset
+ event
->y
,
772 MAKEWPARAM(keystate
,wData
),
773 event
->time
- X11DRV_server_startticks
, hWnd
);
777 /***********************************************************************
778 * EVENT_ButtonRelease
780 static void EVENT_ButtonRelease( HWND hWnd
, XButtonEvent
*event
)
782 static WORD statusCodes
[NB_BUTTONS
] =
783 { MOUSEEVENTF_LEFTUP
, MOUSEEVENTF_MIDDLEUP
, MOUSEEVENTF_RIGHTUP
};
784 int buttonNum
= event
->button
- 1;
785 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
786 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
787 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
790 WIN_ReleaseWndPtr(pWnd
);
792 if (buttonNum
>= NB_BUTTONS
) return;
795 * Get the compatible keystate
797 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
800 * Make sure that the state of the button that was just
806 keystate
&= ~MK_LBUTTON
;
809 keystate
&= ~MK_MBUTTON
;
812 keystate
&= ~MK_RBUTTON
;
818 X11DRV_SendEvent( statusCodes
[buttonNum
],
819 xOffset
+ event
->x
, yOffset
+ event
->y
,
820 keystate
, event
->time
- X11DRV_server_startticks
, hWnd
);
824 /**********************************************************************
827 static void EVENT_FocusIn( HWND hWnd
, XFocusChangeEvent
*event
)
829 if (event
->detail
!= NotifyPointer
)
830 if (hWnd
!= GetForegroundWindow())
832 SetForegroundWindow( hWnd
);
833 X11DRV_KEYBOARD_UpdateState();
838 /**********************************************************************
841 * Note: only top-level override-redirect windows get FocusOut events.
843 static void EVENT_FocusOut( HWND hWnd
, XFocusChangeEvent
*event
)
845 if (event
->detail
!= NotifyPointer
)
846 if (hWnd
== GetForegroundWindow())
848 SendMessageA( hWnd
, WM_CANCELMODE
, 0, 0 );
851 /* don't reset the foreground window, if the window who's
852 getting the focus is a Wine window */
853 if (!X11DRV_CheckFocus())
855 /* Abey : 6-Oct-99. Check again if the focus out window is the
856 Foreground window, because in most cases the messages sent
857 above must have already changed the foreground window, in which
858 case we don't have to change the foreground window to 0 */
860 if (hWnd
== GetForegroundWindow())
861 SetForegroundWindow( 0 );
866 /**********************************************************************
869 BOOL
X11DRV_CheckFocus(void)
875 TSXGetInputFocus(display
, &xW
, &state
);
877 TSXFindContext(display
, xW
, winContext
, (char **)&hWnd
) )
882 /**********************************************************************
885 * Helper function for ConfigureNotify handling.
886 * Get the new geometry of a window relative to the root window.
888 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
889 unsigned int *pwidth
, unsigned int *pheight
)
892 int x
, y
, width
, height
, border
, depth
;
894 EnterCriticalSection( &X11DRV_CritSection
);
896 /* Get the geometry of the window */
897 XGetGeometry( display
, win
, &root
, &x
, &y
, &width
, &height
,
900 /* Translate the window origin to root coordinates */
901 XTranslateCoordinates( display
, win
, root
, 0, 0, &x
, &y
, &top
);
903 LeaveCriticalSection( &X11DRV_CritSection
);
911 /**********************************************************************
912 * EVENT_ConfigureNotify
914 * The ConfigureNotify event is only selected on top-level windows
915 * when the -managed flag is used.
917 static void EVENT_ConfigureNotify( HWND hWnd
, XConfigureEvent
*event
)
921 unsigned int width
, height
;
922 HWND newInsertAfter
, oldInsertAfter
;
924 /* Get geometry and Z-order according to X */
926 EVENT_GetGeometry( event
->window
, &x
, &y
, &width
, &height
);
927 newInsertAfter
= EVENT_QueryZOrder( hWnd
);
929 /* Get geometry and Z-order according to Wine */
932 * Needs to find the first Visible Window above the current one
934 oldInsertAfter
= hWnd
;
937 oldInsertAfter
= GetWindow( oldInsertAfter
, GW_HWNDPREV
);
940 oldInsertAfter
= HWND_TOP
;
943 if (GetWindowLongA( oldInsertAfter
, GWL_STYLE
) & WS_VISIBLE
) break;
946 /* Compare what has changed */
948 GetWindowRect( hWnd
, &rectWindow
);
949 if ( rectWindow
.left
== x
&& rectWindow
.top
== y
)
952 TRACE_(win
)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd
,
953 rectWindow
.left
, rectWindow
.top
, x
, y
);
955 if ( rectWindow
.right
- rectWindow
.left
== width
956 && rectWindow
.bottom
- rectWindow
.top
== height
)
959 TRACE_(win
)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd
,
960 rectWindow
.right
- rectWindow
.left
,
961 rectWindow
.bottom
- rectWindow
.top
, width
, height
);
963 if ( newInsertAfter
== oldInsertAfter
)
964 flags
|= SWP_NOZORDER
;
966 TRACE_(win
)( "%04x restacking from after %04x to after %04x\n", hWnd
,
967 oldInsertAfter
, newInsertAfter
);
969 /* If anything changed, call SetWindowPos */
971 if ( flags
!= (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
) )
972 SetWindowPos( hWnd
, newInsertAfter
, x
, y
, width
, height
,
973 flags
| SWP_NOACTIVATE
| SWP_WINE_NOHOSTMOVE
);
977 /***********************************************************************
978 * EVENT_SelectionRequest_TARGETS
979 * Service a TARGETS selection request event
981 static Atom
EVENT_SelectionRequest_TARGETS( Window requestor
, Atom target
, Atom rprop
)
983 Atom xaTargets
= TSXInternAtom(display
, "TARGETS", False
);
987 unsigned long cTargets
;
991 TRACE("Request for %s\n", TSXGetAtomName(display
, target
));
994 * Count the number of items we wish to expose as selection targets.
995 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
997 cTargets
= CountClipboardFormats() + 1;
998 if ( CLIPBOARD_IsPresent(CF_DIB
) || CLIPBOARD_IsPresent(CF_BITMAP
) )
1001 /* Allocate temp buffer */
1002 targets
= (Atom
*)HeapAlloc( GetProcessHeap(), 0, cTargets
* sizeof(Atom
));
1003 if(targets
== NULL
) return None
;
1005 /* Create TARGETS property list (First item in list is TARGETS itself) */
1007 for ( targets
[0] = xaTargets
, cTargets
= 1, wFormat
= 0, bHavePixmap
= FALSE
;
1008 (wFormat
= EnumClipboardFormats( wFormat
)); )
1010 if ( (prop
= X11DRV_CLIPBOARD_MapFormatToProperty(wFormat
)) != None
)
1012 /* Scan through what we have so far to avoid duplicates */
1015 for (i
= 0, bExists
= FALSE
; i
< cTargets
; i
++)
1017 if (targets
[i
] == prop
)
1025 targets
[cTargets
++] = prop
;
1027 /* Add PIXMAP prop for bitmaps additionally */
1028 if ( (wFormat
== CF_DIB
|| wFormat
== CF_BITMAP
)
1031 targets
[cTargets
++] = XA_PIXMAP
;
1038 if (TRACE_ON(event
))
1041 for ( i
= 0; i
< cTargets
; i
++)
1045 char *itemFmtName
= TSXGetAtomName(display
, targets
[i
]);
1046 TRACE("\tAtom# %d: Type %s\n", i
, itemFmtName
);
1047 TSXFree(itemFmtName
);
1052 /* Update the X property */
1053 TRACE("\tUpdating property %s...", TSXGetAtomName(display
, rprop
));
1055 /* We may want to consider setting the type to xaTargets instead,
1056 * in case some apps expect this instead of XA_ATOM */
1057 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
1058 XA_ATOM
, 32, PropModeReplace
,
1059 (unsigned char *)targets
, cTargets
);
1060 TRACE("(Rc=%d)\n", xRc
);
1062 HeapFree( GetProcessHeap(), 0, targets
);
1068 /***********************************************************************
1069 * EVENT_SelectionRequest_STRING
1070 * Service a STRING selection request event
1072 static Atom
EVENT_SelectionRequest_STRING( Window requestor
, Atom target
, Atom rprop
)
1082 * Map the requested X selection property type atom name to a
1083 * windows clipboard format ID.
1085 itemFmtName
= TSXGetAtomName(display
, target
);
1086 TRACE("Request for %s (wFormat=%x %s)\n",
1087 itemFmtName
, CF_TEXT
, CLIPBOARD_GetFormatName(CF_TEXT
));
1088 TSXFree(itemFmtName
);
1090 hText
= GetClipboardData16(CF_TEXT
);
1093 text
= GlobalLock16(hText
);
1096 size
= GlobalSize16(hText
);
1097 /* remove carriage returns */
1099 lpstr
= (char*)HeapAlloc( GetProcessHeap(), 0, size
-- );
1100 if(lpstr
== NULL
) return None
;
1101 for(i
=0,j
=0; i
< size
&& text
[i
]; i
++ )
1103 if( text
[i
] == '\r' &&
1104 (text
[i
+1] == '\n' || text
[i
+1] == '\0') ) continue;
1105 lpstr
[j
++] = text
[i
];
1109 /* Update the X property */
1110 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display
, rprop
));
1111 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
1112 XA_STRING
, 8, PropModeReplace
,
1114 TRACE("(Rc=%d)\n", xRc
);
1116 GlobalUnlock16(hText
);
1117 HeapFree( GetProcessHeap(), 0, lpstr
);
1122 /***********************************************************************
1123 * EVENT_SelectionRequest_PIXMAP
1124 * Service a PIXMAP selection request event
1126 static Atom
EVENT_SelectionRequest_PIXMAP( Window requestor
, Atom target
, Atom rprop
)
1128 HANDLE hClipData
= 0;
1134 XSetWindowAttributes win_attr
;
1135 XWindowAttributes win_attr_src
;
1139 * Map the requested X selection property type atom name to a
1140 * windows clipboard format ID.
1142 itemFmtName
= TSXGetAtomName(display
, target
);
1143 wFormat
= X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName
);
1144 TRACE("Request for %s (wFormat=%x %s)\n",
1145 itemFmtName
, wFormat
, CLIPBOARD_GetFormatName( wFormat
));
1146 TSXFree(itemFmtName
);
1148 hClipData
= GetClipboardData(wFormat
);
1151 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
1152 rprop
= None
; /* Fail the request */
1156 if (wFormat
== CF_DIB
)
1158 HWND hwnd
= GetOpenClipboardWindow();
1159 HDC hdc
= GetDC(hwnd
);
1161 /* For convert from packed DIB to Pixmap */
1162 pixmap
= X11DRV_DIB_CreatePixmapFromDIB(hClipData
, hdc
);
1164 ReleaseDC(hdc
, hwnd
);
1166 else if (wFormat
== CF_BITMAP
)
1168 HWND hwnd
= GetOpenClipboardWindow();
1169 HDC hdc
= GetDC(hwnd
);
1171 pixmap
= X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData
, hdc
);
1173 ReleaseDC(hdc
, hwnd
);
1177 FIXME("%s to PIXMAP conversion not yet implemented!\n",
1178 CLIPBOARD_GetFormatName(wFormat
));
1183 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
1184 TSXGetAtomName(display
, rprop
), (long)requestor
,
1185 TSXGetAtomName(display
, target
), pixmap
);
1187 /* Store the Pixmap handle in the property */
1188 xRc
= TSXChangeProperty(display
, requestor
, rprop
, target
,
1189 32, PropModeReplace
,
1190 (unsigned char *)&pixmap
, 1);
1191 TRACE("(Rc=%d)\n", xRc
);
1193 /* Enable the code below if you want to handle destroying Pixmap resources
1194 * in response to property notify events. Clients like XPaint don't
1195 * appear to be duplicating Pixmaps so they don't like us deleting,
1196 * the resource in response to the property being deleted.
1199 /* Express interest in property notify events so that we can delete the
1200 * pixmap when the client deletes the property atom.
1202 xRc
= TSXGetWindowAttributes(display
, requestor
, &win_attr_src
);
1203 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
1205 win_attr
.event_mask
= win_attr_src
.your_event_mask
| PropertyChangeMask
;
1206 TSXChangeWindowAttributes(display
, requestor
, CWEventMask
, &win_attr
);
1208 /* Register the Pixmap we created with the request property Atom.
1209 * When this property is destroyed we also destroy the Pixmap in
1210 * response to the PropertyNotify event.
1212 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop
, pixmap
);
1220 /***********************************************************************
1221 * EVENT_SelectionRequest_WCF
1222 * Service a Wine Clipboard Format selection request event.
1223 * For <WCF>* data types we simply copy the data to X without conversion.
1225 static Atom
EVENT_SelectionRequest_WCF( Window requestor
, Atom target
, Atom rprop
)
1227 HANDLE hClipData
= 0;
1235 * Map the requested X selection property type atom name to a
1236 * windows clipboard format ID.
1238 itemFmtName
= TSXGetAtomName(display
, target
);
1239 wFormat
= X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName
);
1240 TRACE("Request for %s (wFormat=%x %s)\n",
1241 itemFmtName
, wFormat
, CLIPBOARD_GetFormatName( wFormat
));
1242 TSXFree(itemFmtName
);
1244 hClipData
= GetClipboardData16(wFormat
);
1246 if( hClipData
&& (lpClipData
= GlobalLock16(hClipData
)) )
1248 cBytes
= GlobalSize16(hClipData
);
1250 TRACE("\tUpdating property %s, %d bytes...\n",
1251 TSXGetAtomName(display
, rprop
), cBytes
);
1253 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
1254 target
, 8, PropModeReplace
,
1255 (unsigned char *)lpClipData
, cBytes
);
1256 TRACE("(Rc=%d)\n", xRc
);
1258 GlobalUnlock16(hClipData
);
1262 TRACE("\tCould not retrieve native format!\n");
1263 rprop
= None
; /* Fail the request */
1270 /***********************************************************************
1271 * EVENT_SelectionRequest_MULTIPLE
1272 * Service a MULTIPLE selection request event
1273 * rprop contains a list of (target,property) atom pairs.
1274 * The first atom names a target and the second names a property.
1275 * The effect is as if we have received a sequence of SelectionRequest events
1276 * (one for each atom pair) except that:
1277 * 1. We reply with a SelectionNotify only when all the requested conversions
1278 * have been performed.
1279 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1280 * we replace the atom in the property by None.
1282 static Atom
EVENT_SelectionRequest_MULTIPLE( HWND hWnd
, XSelectionRequestEvent
*pevent
)
1285 Atom atype
=AnyPropertyType
;
1287 unsigned long remain
;
1288 Atom
* targetPropList
=NULL
;
1289 unsigned long cTargetPropList
= 0;
1290 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1292 /* If the specified property is None the requestor is an obsolete client.
1293 * We support these by using the specified target atom as the reply property.
1295 rprop
= pevent
->property
;
1297 rprop
= pevent
->target
;
1301 /* Read the MULTIPLE property contents. This should contain a list of
1302 * (target,property) atom pairs.
1304 if(TSXGetWindowProperty(display
, pevent
->requestor
, rprop
,
1305 0, 0x3FFF, False
, AnyPropertyType
, &atype
,&aformat
,
1306 &cTargetPropList
, &remain
,
1307 (unsigned char**)&targetPropList
) != Success
)
1308 TRACE("\tCouldn't read MULTIPLE property\n");
1311 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1312 TSXGetAtomName(display
, atype
), aformat
, cTargetPropList
, remain
);
1315 * Make sure we got what we expect.
1316 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1317 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1318 * However some X apps(such as XPaint) are not compliant with this and return
1319 * a user defined atom in atype when XGetWindowProperty is called.
1320 * The data *is* an atom pair but is not denoted as such.
1322 if(aformat
== 32 /* atype == xAtomPair */ )
1326 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1327 * for each (target,property) pair */
1329 for (i
= 0; i
< cTargetPropList
; i
+=2)
1331 char *targetName
= TSXGetAtomName(display
, targetPropList
[i
]);
1332 char *propName
= TSXGetAtomName(display
, targetPropList
[i
+1]);
1333 XSelectionRequestEvent event
;
1335 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
1336 i
/2, targetName
, propName
);
1337 TSXFree(targetName
);
1340 /* We must have a non "None" property to service a MULTIPLE target atom */
1341 if ( !targetPropList
[i
+1] )
1343 TRACE("\tMULTIPLE(%d): Skipping target with empty property!", i
);
1347 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1348 memcpy( &event
, pevent
, sizeof(XSelectionRequestEvent
) );
1349 event
.target
= targetPropList
[i
];
1350 event
.property
= targetPropList
[i
+1];
1352 /* Fire a SelectionRequest, informing the handler that we are processing
1353 * a MULTIPLE selection request event.
1355 EVENT_SelectionRequest( hWnd
, &event
, TRUE
);
1359 /* Free the list of targets/properties */
1360 TSXFree(targetPropList
);
1368 /***********************************************************************
1369 * EVENT_SelectionRequest
1370 * Process an event selection request event.
1371 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1372 * recursively while servicing a "MULTIPLE" selection target.
1374 * Note: We only receive this event when WINE owns the X selection
1376 static void EVENT_SelectionRequest( HWND hWnd
, XSelectionRequestEvent
*event
, BOOL bIsMultiple
)
1378 XSelectionEvent result
;
1380 Window request
= event
->requestor
;
1381 BOOL couldOpen
= FALSE
;
1382 Atom xaClipboard
= TSXInternAtom(display
, "CLIPBOARD", False
);
1383 Atom xaTargets
= TSXInternAtom(display
, "TARGETS", False
);
1384 Atom xaMultiple
= TSXInternAtom(display
, "MULTIPLE", False
);
1387 * We can only handle the selection request if :
1388 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1389 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1390 * since this has been already done.
1394 if ( ( (event
->selection
!= XA_PRIMARY
) && (event
->selection
!= xaClipboard
) )
1395 || !(couldOpen
= OpenClipboard(hWnd
)) )
1399 /* If the specified property is None the requestor is an obsolete client.
1400 * We support these by using the specified target atom as the reply property.
1402 rprop
= event
->property
;
1404 rprop
= event
->target
;
1406 if(event
->target
== xaTargets
) /* Return a list of all supported targets */
1408 /* TARGETS selection request */
1409 rprop
= EVENT_SelectionRequest_TARGETS( request
, event
->target
, rprop
);
1411 else if(event
->target
== xaMultiple
) /* rprop contains a list of (target, property) atom pairs */
1413 /* MULTIPLE selection request */
1414 rprop
= EVENT_SelectionRequest_MULTIPLE( hWnd
, event
);
1416 else if(event
->target
== XA_STRING
) /* treat CF_TEXT as Unix text */
1418 /* XA_STRING selection request */
1419 rprop
= EVENT_SelectionRequest_STRING( request
, event
->target
, rprop
);
1421 else if(event
->target
== XA_PIXMAP
) /* Convert DIB's to Pixmaps */
1423 /* XA_PIXMAP selection request */
1424 rprop
= EVENT_SelectionRequest_PIXMAP( request
, event
->target
, rprop
);
1426 else if(event
->target
== XA_BITMAP
) /* Convert DIB's to 1-bit Pixmaps */
1428 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1429 rprop
= EVENT_SelectionRequest_PIXMAP( request
, XA_PIXMAP
, rprop
);
1431 else if(X11DRV_CLIPBOARD_IsNativeProperty(event
->target
)) /* <WCF>* */
1433 /* All <WCF> selection requests */
1434 rprop
= EVENT_SelectionRequest_WCF( request
, event
->target
, rprop
);
1437 rprop
= None
; /* Don't support this format */
1440 /* close clipboard only if we opened before */
1441 if(couldOpen
) CloseClipboard();
1444 TRACE("\tRequest ignored\n");
1447 * SelectionNotify should be sent only at the end of a MULTIPLE request
1451 result
.type
= SelectionNotify
;
1452 result
.display
= display
;
1453 result
.requestor
= request
;
1454 result
.selection
= event
->selection
;
1455 result
.property
= rprop
;
1456 result
.target
= event
->target
;
1457 result
.time
= event
->time
;
1458 TRACE("Sending SelectionNotify event...\n");
1459 TSXSendEvent(display
,event
->requestor
,False
,NoEventMask
,(XEvent
*)&result
);
1463 /***********************************************************************
1464 * EVENT_SelectionClear
1466 static void EVENT_SelectionClear( HWND hWnd
, XSelectionClearEvent
*event
)
1468 Atom xaClipboard
= TSXInternAtom(display
, "CLIPBOARD", False
);
1470 if (event
->selection
== XA_PRIMARY
|| event
->selection
== xaClipboard
)
1471 X11DRV_CLIPBOARD_ReleaseSelection( event
->selection
, event
->window
, hWnd
);
1474 /***********************************************************************
1475 * EVENT_PropertyNotify
1476 * We use this to release resources like Pixmaps when a selection
1477 * client no longer needs them.
1479 static void EVENT_PropertyNotify( XPropertyEvent
*event
)
1481 /* Check if we have any resources to free */
1482 TRACE("Received PropertyNotify event: ");
1484 switch(event
->state
)
1486 case PropertyDelete
:
1488 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1489 TSXGetAtomName(event
->display
, event
->atom
), (long)event
->window
);
1491 if (X11DRV_IsSelectionOwner())
1492 X11DRV_CLIPBOARD_FreeResources( event
->atom
);
1496 case PropertyNewValue
:
1498 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1499 TSXGetAtomName(event
->display
, event
->atom
), (long)event
->window
);
1508 /**********************************************************************
1509 * EVENT_DropFromOffix
1511 * don't know if it still works (last Changlog is from 96/11/04)
1513 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1515 unsigned long data_length
;
1516 unsigned long aux_long
;
1517 unsigned char* p_data
= NULL
;
1528 HGLOBAL16 hDragInfo
= GlobalAlloc16( GMEM_SHARE
| GMEM_ZEROINIT
, sizeof(DRAGINFO16
));
1529 LPDRAGINFO16 lpDragInfo
= (LPDRAGINFO16
) GlobalLock16(hDragInfo
);
1530 SEGPTR spDragInfo
= (SEGPTR
) WIN16_GlobalLock16(hDragInfo
);
1531 Window w_aux_root
, w_aux_child
;
1535 if( !lpDragInfo
|| !spDragInfo
) return;
1537 pWnd
= WIN_FindWndPtr(hWnd
);
1539 TSXQueryPointer( display
, X11DRV_WND_GetXWindow(pWnd
), &w_aux_root
, &w_aux_child
,
1540 &x
, &y
, (int *) &u
.pt_aux
.x
, (int *) &u
.pt_aux
.y
,
1541 (unsigned int*)&aux_long
);
1543 lpDragInfo
->hScope
= hWnd
;
1544 lpDragInfo
->pt
.x
= (INT16
)x
; lpDragInfo
->pt
.y
= (INT16
)y
;
1546 /* find out drop point and drop window */
1547 if( x
< 0 || y
< 0 ||
1548 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
1549 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
1550 { bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
; x
= y
= 0; }
1553 bAccept
= DRAG_QueryUpdate( hWnd
, spDragInfo
, TRUE
);
1554 x
= lpDragInfo
->pt
.x
; y
= lpDragInfo
->pt
.y
;
1556 pDropWnd
= WIN_FindWndPtr( lpDragInfo
->hScope
);
1557 WIN_ReleaseWndPtr(pWnd
);
1559 GlobalFree16( hDragInfo
);
1563 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1564 dndSelection
, 0, 65535, FALSE
,
1565 AnyPropertyType
, &u
.atom_aux
, (int *) &u
.pt_aux
.y
,
1566 &data_length
, &aux_long
, &p_data
);
1568 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1570 char *p
= (char*) p_data
;
1574 while( *p
) /* calculate buffer size */
1577 if((u
.i
= *p
) != -1 )
1579 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1580 if (len
) aux_long
+= len
+ 1;
1585 if( aux_long
&& aux_long
< 65535 )
1590 aux_long
+= sizeof(DROPFILES
) + 1;
1591 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1592 lpDrop
= (DROPFILES
*)GlobalLock( hDrop
);
1596 lpDrop
->pFiles
= sizeof(DROPFILES
);
1600 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1601 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1602 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1603 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1604 lpDrop
->fWide
= FALSE
;
1605 p_drop
= (char *)(lpDrop
+ 1);
1609 if( *p
!= -1 ) /* use only "good" entries */
1611 GetShortPathNameA( p
, p_drop
, 65535 );
1612 p_drop
+= strlen( p_drop
) + 1;
1617 PostMessageA( hWnd
, WM_DROPFILES
, hDrop
, 0L );
1621 if( p_data
) TSXFree(p_data
);
1623 } /* WS_EX_ACCEPTFILES */
1625 WIN_ReleaseWndPtr(pDropWnd
);
1628 /**********************************************************************
1631 * drop items are separated by \n
1632 * each item is prefixed by its mime type
1634 * event->data.l[3], event->data.l[4] contains drop x,y position
1636 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1640 unsigned long data_length
;
1641 unsigned long aux_long
, drop_len
= 0;
1642 unsigned char *p_data
= NULL
; /* property data */
1643 char *p_drop
= NULL
;
1654 pWnd
= WIN_FindWndPtr(hWnd
);
1656 if (!(pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
))
1658 WIN_ReleaseWndPtr(pWnd
);
1661 WIN_ReleaseWndPtr(pWnd
);
1663 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1664 dndSelection
, 0, 65535, FALSE
,
1665 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1666 &data_length
, &aux_long
, &p_data
);
1668 WARN("property too large, truncated!\n");
1669 TRACE("urls=%s\n", p_data
);
1671 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1672 /* calculate length */
1674 next
= strchr(p
, '\n');
1677 if (strncmp(p
,"file:",5) == 0 ) {
1678 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1679 if (len
) drop_len
+= len
+ 1;
1684 next
= strchr(p
, '\n');
1690 if( drop_len
&& drop_len
< 65535 ) {
1691 TSXQueryPointer( display
, X11DRV_GetXRootWindow(), &u
.w_aux
, &u
.w_aux
,
1692 &x
, &y
, &u
.i
, &u
.i
, &u
.i
);
1694 pDropWnd
= WIN_FindWndPtr( hWnd
);
1696 drop_len
+= sizeof(DROPFILES
) + 1;
1697 hDrop
= (HDROP
)GlobalAlloc( GMEM_SHARE
, drop_len
);
1698 lpDrop
= (DROPFILES
*) GlobalLock( hDrop
);
1701 lpDrop
->pFiles
= sizeof(DROPFILES
);
1702 lpDrop
->pt
.x
= (INT
)x
;
1703 lpDrop
->pt
.y
= (INT
)y
;
1705 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1706 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1707 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1708 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1709 lpDrop
->fWide
= FALSE
;
1710 p_drop
= (char*)(lpDrop
+ 1);
1713 /* create message content */
1716 next
= strchr(p
, '\n');
1719 if (strncmp(p
,"file:",5) == 0 ) {
1720 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1722 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1725 WARN("can't convert file %s to dos name \n", p
+5);
1728 WARN("unknown mime type %s\n", p
);
1733 next
= strchr(p
, '\n');
1740 GlobalUnlock(hDrop
);
1741 PostMessageA( hWnd
, WM_DROPFILES
, hDrop
, 0L );
1743 WIN_ReleaseWndPtr(pDropWnd
);
1745 if( p_data
) TSXFree(p_data
);
1749 /**********************************************************************
1750 * EVENT_ClientMessage
1752 static void EVENT_ClientMessage( HWND hWnd
, XClientMessageEvent
*event
)
1754 if (event
->message_type
!= None
&& event
->format
== 32) {
1755 if ((event
->message_type
== wmProtocols
) &&
1756 (((Atom
) event
->data
.l
[0]) == wmDeleteWindow
))
1758 /* Ignore the delete window request if the window has been disabled
1759 * and we are in managed mode. This is to disallow applications from
1760 * being closed by the window manager while in a modal state.
1763 bIsDisabled
= GetWindowLongA( hWnd
, GWL_STYLE
) & WS_DISABLED
;
1765 if ( !Options
.managed
|| !bIsDisabled
)
1766 PostMessage16( hWnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1768 else if ( event
->message_type
== dndProtocol
&&
1769 (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
) )
1770 EVENT_DropFromOffiX(hWnd
, event
);
1771 else if ( event
->message_type
== dndProtocol
&&
1772 event
->data
.l
[0] == DndURL
)
1773 EVENT_DropURLs(hWnd
, event
);
1776 /* enable this if you want to see the message */
1777 unsigned char* p_data
= NULL
;
1783 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1784 dndSelection
, 0, 65535, FALSE
,
1785 AnyPropertyType
, &u
.atom
, &u
.i
,
1786 &u
.l
, &u
.l
, &p_data
);
1787 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1788 event
->message_type
, event
->data
.l
[0], event
->data
.l
[1],
1789 event
->data
.l
[2], event
->data
.l
[3], event
->data
.l
[4],
1792 TRACE("unrecognized ClientMessage\n" );
1797 /**********************************************************************
1800 * Install colormap when Wine window is focused in
1801 * self-managed mode with private colormap
1804 void EVENT_EnterNotify( HWND hWnd
, XCrossingEvent
*event
)
1806 if( !Options
.managed
&& X11DRV_GetXRootWindow() == DefaultRootWindow(display
) &&
1807 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE
) && GetFocus() )
1808 TSXInstallColormap( display
, X11DRV_PALETTE_GetColormap() );
1812 /**********************************************************************
1815 void EVENT_MapNotify( HWND hWnd
, XMapEvent
*event
)
1817 HWND hwndFocus
= GetFocus();
1818 WND
*wndFocus
= WIN_FindWndPtr(hwndFocus
);
1819 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
1820 if (pWnd
&& (pWnd
->dwExStyle
& WS_EX_MANAGED
))
1822 DCE_InvalidateDCE( pWnd
, &pWnd
->rectWindow
);
1823 pWnd
->dwStyle
&= ~WS_MINIMIZE
;
1824 pWnd
->dwStyle
|= WS_VISIBLE
;
1825 WIN_InternalShowOwnedPopups(hWnd
,TRUE
,TRUE
);
1827 WIN_ReleaseWndPtr(pWnd
);
1829 if (hwndFocus
&& IsChild( hWnd
, hwndFocus
))
1830 X11DRV_WND_SetFocus(wndFocus
);
1832 WIN_ReleaseWndPtr(wndFocus
);
1838 /**********************************************************************
1841 void EVENT_UnmapNotify( HWND hWnd
, XUnmapEvent
*event
)
1843 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
1844 if (pWnd
&& (pWnd
->dwExStyle
& WS_EX_MANAGED
))
1847 if( pWnd
->dwStyle
& WS_VISIBLE
)
1849 pWnd
->dwStyle
|= WS_MINIMIZE
;
1850 pWnd
->dwStyle
&= ~WS_VISIBLE
;
1851 WIN_InternalShowOwnedPopups(hWnd
,FALSE
,TRUE
);
1854 WIN_ReleaseWndPtr(pWnd
);
1857 /***********************************************************************
1858 * EVENT_MappingNotify
1860 static void EVENT_MappingNotify( XMappingEvent
*event
)
1862 TSXRefreshKeyboardMapping(event
);
1864 /* reinitialize Wine-X11 driver keyboard table */
1865 X11DRV_InitKeyboard();
1869 /**********************************************************************
1870 * X11DRV_EVENT_SetInputMethod
1872 INPUT_TYPE
X11DRV_EVENT_SetInputMethod(INPUT_TYPE type
)
1874 INPUT_TYPE prev
= current_input_type
;
1876 /* Flag not used yet */
1877 in_transition
= FALSE
;
1878 current_input_type
= type
;
1883 #ifdef HAVE_LIBXXF86DGA2
1884 /**********************************************************************
1885 * X11DRV_EVENT_SetDGAStatus
1887 void X11DRV_EVENT_SetDGAStatus(HWND hwnd
, int event_base
)
1889 if (event_base
< 0) {
1895 DGAMotionEventType
= event_base
+ MotionNotify
;
1896 DGAButtonPressEventType
= event_base
+ ButtonPress
;
1897 DGAButtonReleaseEventType
= event_base
+ ButtonRelease
;
1898 DGAKeyPressEventType
= event_base
+ KeyPress
;
1899 DGAKeyReleaseEventType
= event_base
+ KeyRelease
;
1903 /* DGA2 event handlers */
1904 static void EVENT_DGAMotionEvent( XDGAMotionEvent
*event
)
1906 X11DRV_SendEvent( MOUSEEVENTF_MOVE
,
1907 event
->dx
, event
->dy
,
1908 X11DRV_EVENT_XStateToKeyState( event
->state
),
1909 event
->time
- X11DRV_server_startticks
, DGAhwnd
);
1912 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent
*event
)
1914 static WORD statusCodes
[NB_BUTTONS
] =
1915 { MOUSEEVENTF_LEFTDOWN
, MOUSEEVENTF_MIDDLEDOWN
, MOUSEEVENTF_RIGHTDOWN
};
1916 int buttonNum
= event
->button
- 1;
1920 if (buttonNum
>= NB_BUTTONS
) return;
1922 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
1927 keystate
|= MK_LBUTTON
;
1930 keystate
|= MK_MBUTTON
;
1933 keystate
|= MK_RBUTTON
;
1937 X11DRV_SendEvent( statusCodes
[buttonNum
], 0, 0, keystate
, event
->time
- X11DRV_server_startticks
, DGAhwnd
);
1940 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent
*event
)
1942 static WORD statusCodes
[NB_BUTTONS
] =
1943 { MOUSEEVENTF_LEFTUP
, MOUSEEVENTF_MIDDLEUP
, MOUSEEVENTF_RIGHTUP
};
1944 int buttonNum
= event
->button
- 1;
1948 if (buttonNum
>= NB_BUTTONS
) return;
1950 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
1955 keystate
&= ~MK_LBUTTON
;
1958 keystate
&= ~MK_MBUTTON
;
1961 keystate
&= ~MK_RBUTTON
;
1965 X11DRV_SendEvent( statusCodes
[buttonNum
], 0, 0, keystate
, event
->time
- X11DRV_server_startticks
, DGAhwnd
);
1970 #ifdef HAVE_LIBXXSHM
1973 Normal XShm operation:
1975 X11 service thread app thread
1976 ------------- ----------------- ------------------------
1977 (idle) ddraw calls XShmPutImage
1978 (copies data) (waiting for shm_event)
1979 ShmCompletion -> (waiting for shm_event)
1980 (idle) signal shm_event ->
1981 (idle) returns to app
1983 However, this situation can occur for some reason:
1985 X11 service thread app thread
1986 ------------- ----------------- ------------------------
1989 (waiting for app) ddraw calls XShmPutImage
1990 (copies data) (waiting for app) (waiting for shm_event)
1991 ShmCompletion (waiting for app) (waiting for shm_event)
1992 (idle) DEADLOCK DEADLOCK
1994 which is why I also wait for shm_read and do XCheckTypedEvent()
1995 calls in the wait loop. This results in:
1997 X11 service thread app thread
1998 ------------- ----------------- ------------------------
1999 ShmCompletion (waiting for app) waking up on shm_read
2000 (idle) (waiting for app) XCheckTypedEvent() -> signal shm_event
2001 (waiting for app) returns
2011 /* FIXME: this is not pretty */
2012 static HANDLE shm_read
= 0;
2015 static volatile shm_qs shm_q
[SHM_MAX_Q
];
2017 static void EVENT_ShmCompletion( XShmCompletionEvent
*event
)
2021 TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event
->drawable
, GetTickCount() );
2023 for (n
=0; n
<SHM_MAX_Q
; n
++)
2024 if ((shm_q
[n
].draw
== event
->drawable
) && (shm_q
[n
].state
== 0)) {
2025 HANDLE sema
= shm_q
[n
].sema
;
2026 if (!InterlockedCompareExchange((PVOID
*)&shm_q
[n
].state
, (PVOID
)1, (PVOID
)0)) {
2027 ReleaseSemaphore(sema
, 1, NULL
);
2028 TRACE("Signaling ShmCompletion (#%d) (semaphore %x)\n", n
, sema
);
2033 ERR("Got ShmCompletion for unknown drawable %ld\n", event
->drawable
);
2036 int X11DRV_EVENT_PrepareShmCompletion( Drawable dw
)
2041 shm_read
= FILE_DupUnixHandle( ConnectionNumber(display
), GENERIC_READ
| SYNCHRONIZE
);
2043 for (n
=0; n
<SHM_MAX_Q
; n
++)
2045 if (!InterlockedCompareExchange((PVOID
*)&shm_q
[n
].draw
, (PVOID
)dw
, (PVOID
)0))
2049 ERR("Maximum number of outstanding ShmCompletions exceeded!\n");
2054 if (!shm_q
[n
].sema
) {
2055 shm_q
[n
].sema
= CreateSemaphoreA( NULL
, 0, 256, NULL
);
2056 TRACE("Allocated ShmCompletion slots have been increased to %d, new semaphore is %x\n", n
+1, shm_q
[n
].sema
);
2059 TRACE("Prepared ShmCompletion (#%d) wait for drawable %ld (thread %lx) (time %ld)\n", n
, dw
, GetCurrentThreadId(), GetTickCount() );
2063 static void X11DRV_EVENT_WaitReplaceShmCompletionInternal( int *compl, Drawable dw
, int creat
)
2069 if ((!n
) || (creat
&& (!shm_q
[n
-1].draw
))) {
2070 nn
= X11DRV_EVENT_PrepareShmCompletion(dw
);
2071 if (!(n
=(LONG
)InterlockedCompareExchange((PVOID
*)compl, (PVOID
)nn
, (PVOID
)n
)))
2073 /* race for compl lost, clear slot */
2074 shm_q
[nn
-1].draw
= 0;
2078 if (dw
&& (shm_q
[n
-1].draw
!= dw
)) {
2079 /* this shouldn't happen with the current ddraw implementation */
2080 FIXME("ShmCompletion replace with different drawable!\n");
2084 sema
= shm_q
[n
-1].sema
;
2086 /* nothing to wait on (PrepareShmCompletion not done yet?), so probably nothing to wait for */
2090 nn
= InterlockedExchangeAdd((PLONG
)&shm_q
[n
-1].waiter
, 1);
2091 if ((!shm_q
[n
-1].draw
) || (shm_q
[n
-1].state
== 2)) {
2092 /* too late, the wait was just cleared (wait complete) */
2093 TRACE("Wait skip for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n
-1, GetCurrentThreadId(), GetTickCount(), sema
);
2095 TRACE("Waiting for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n
-1, GetCurrentThreadId(), GetTickCount(), sema
);
2097 /* another thread is already waiting, let the primary waiter do the dirty work
2098 * (to avoid TSX critical section contention - that could get really slow) */
2099 WaitForSingleObject( sema
, INFINITE
);
2101 /* we're primary waiter - first check if it's already triggered */
2102 if ( WaitForSingleObject( sema
, 0 ) != WAIT_OBJECT_0
) {
2103 /* nope, may need to poll X event queue, in case the service thread is blocked */
2110 /* check X event queue */
2111 if (TSXCheckTypedEvent( display
, ShmCompletionType
, &event
)) {
2112 EVENT_ProcessEvent( &event
);
2114 } while ( WaitForMultipleObjects(2, hnd
, FALSE
, INFINITE
) > WAIT_OBJECT_0
);
2116 TRACE("Wait complete (thread %lx) (time %ld)\n", GetCurrentThreadId(), GetTickCount() );
2119 st
= InterlockedExchange((LPLONG
)&shm_q
[n
-1].state
, 2);
2121 /* first waiter to return, release all other waiters */
2122 nn
= shm_q
[n
-1].waiter
;
2123 TRACE("Signaling %ld additional ShmCompletion (#%d) waiter(s), semaphore %x\n", nn
-1, n
-1, sema
);
2124 ReleaseSemaphore(sema
, nn
-1, NULL
);
2127 nn
= InterlockedDecrement((LPLONG
)&shm_q
[n
-1].waiter
);
2129 /* last waiter to return, replace drawable and prepare new wait */
2130 shm_q
[n
-1].draw
= dw
;
2131 shm_q
[n
-1].state
= 0;
2135 void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw
)
2137 X11DRV_EVENT_WaitReplaceShmCompletionInternal( compl, dw
, 1 );
2140 void X11DRV_EVENT_WaitShmCompletion( int compl )
2143 X11DRV_EVENT_WaitReplaceShmCompletionInternal( &compl, 0, 0 );
2146 void X11DRV_EVENT_WaitShmCompletions( Drawable dw
)
2150 for (n
=0; n
<SHM_MAX_Q
; n
++)
2151 if (shm_q
[n
].draw
== dw
)
2152 X11DRV_EVENT_WaitShmCompletion( n
+1 );
2155 #endif /* defined(HAVE_LIBXXSHM) */