4 * Copyright 1993 Alexandre Julliard
10 #ifndef X_DISPLAY_MISSING
12 #include <X11/Xatom.h>
13 #include <X11/keysym.h>
15 #include "ts_xresource.h"
21 #ifdef HAVE_LIBXXF86DGA2
22 #include "ts_xf86dga2.h"
28 #include "clipboard.h"
30 #include "debugtools.h"
47 DEFAULT_DEBUG_CHANNEL(event
);
48 DECLARE_DEBUG_CHANNEL(win
);
50 /* X context to associate a hwnd to an X window */
51 extern XContext winContext
;
53 extern Atom wmProtocols
;
54 extern Atom wmDeleteWindow
;
55 extern Atom dndProtocol
;
56 extern Atom dndSelection
;
58 extern void X11DRV_KEYBOARD_UpdateState(void);
59 extern void X11DRV_KEYBOARD_HandleEvent(WND
*pWnd
, XKeyEvent
*event
);
61 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
63 #define DndNotDnd -1 /* OffiX drag&drop */
75 #define DndURL 128 /* KDE drag&drop */
77 /* The last X window which had the focus */
78 static Window glastXFocusWin
= 0;
80 static const char * const event_names
[] =
82 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
83 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
84 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
85 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
86 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
87 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
88 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
89 "ClientMessage", "MappingNotify"
93 static void CALLBACK
EVENT_Flush( ULONG_PTR arg
);
94 static void CALLBACK
EVENT_ProcessAllEvents( ULONG_PTR arg
);
95 static void EVENT_ProcessEvent( XEvent
*event
);
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
);
115 static void EVENT_ShmCompletion( XShmCompletionEvent
*event
);
116 static int ShmAvailable
, ShmCompletionType
;
117 extern int XShmGetEventBase( Display
* );/* Missing prototype for function in libXext. */
120 #ifdef HAVE_LIBXXF86DGA2
121 static int DGAMotionEventType
;
122 static int DGAButtonPressEventType
;
123 static int DGAButtonReleaseEventType
;
124 static int DGAKeyPressEventType
;
125 static int DGAKeyReleaseEventType
;
127 static BOOL DGAUsed
= FALSE
;
128 static HWND DGAhwnd
= 0;
130 static void EVENT_DGAMotionEvent( XDGAMotionEvent
*event
);
131 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent
*event
);
132 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent
*event
);
135 /* Usable only with OLVWM - compile option perhaps?
136 static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
139 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
140 unsigned int *pwidth
, unsigned int *pheight
);
143 static BOOL bUserRepaintDisabled
= TRUE
;
145 /* Static used for the current input method */
146 static INPUT_TYPE current_input_type
= X11DRV_INPUT_ABSOLUTE
;
147 static BOOL in_transition
= FALSE
; /* This is not used as for today */
149 /***********************************************************************
152 BOOL
X11DRV_EVENT_Init(void)
155 ShmAvailable
= XShmQueryExtension( display
);
157 ShmCompletionType
= XShmGetEventBase( display
) + ShmCompletion
;
161 /* Install the X event processing callback */
162 SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display
),
163 GENERIC_READ
| SYNCHRONIZE
),
164 EVENT_ProcessAllEvents
, 0 );
166 /* Install the XFlush timer callback */
167 if ( Options
.synchronous
)
168 TSXSynchronize( display
, True
);
170 SERVICE_AddTimer( 200000L, EVENT_Flush
, 0 );
175 /***********************************************************************
178 static void CALLBACK
EVENT_Flush( ULONG_PTR arg
)
183 /***********************************************************************
184 * EVENT_ProcessAllEvents
186 static void CALLBACK
EVENT_ProcessAllEvents( ULONG_PTR arg
)
190 TRACE( "called (thread %lx).\n", GetCurrentThreadId() );
192 EnterCriticalSection( &X11DRV_CritSection
);
193 while ( XPending( display
) )
195 XNextEvent( display
, &event
);
197 LeaveCriticalSection( &X11DRV_CritSection
);
198 EVENT_ProcessEvent( &event
);
199 EnterCriticalSection( &X11DRV_CritSection
);
201 LeaveCriticalSection( &X11DRV_CritSection
);
204 /***********************************************************************
207 * Synchronize with the X server. Should not be used too often.
209 void X11DRV_EVENT_Synchronize( void )
211 TSXSync( display
, False
);
212 EVENT_ProcessAllEvents( 0 );
215 /***********************************************************************
216 * EVENT_UserRepaintDisable
218 void X11DRV_EVENT_UserRepaintDisable( BOOL bDisabled
)
220 bUserRepaintDisabled
= bDisabled
;
223 /***********************************************************************
226 * Process an X event.
228 static void EVENT_ProcessEvent( XEvent
*event
)
232 TRACE( "called.\n" );
236 case SelectionNotify
: /* all of these should be caught by XCheckTypedWindowEvent() */
237 FIXME("Got SelectionNotify - must not happen!\n");
240 /* We get all these because of StructureNotifyMask.
241 This check is placed here to avoid getting error messages below,
242 as X might send some of these even for windows that have already
244 case CirculateNotify
:
253 if (ShmAvailable
&& (event
->type
== ShmCompletionType
)) {
254 EVENT_ShmCompletion( (XShmCompletionEvent
*)event
);
259 #ifdef HAVE_LIBXXF86DGA2
261 if (event
->type
== DGAMotionEventType
) {
262 TRACE("DGAMotionEvent received.\n");
263 EVENT_DGAMotionEvent((XDGAMotionEvent
*) event
);
266 if (event
->type
== DGAButtonPressEventType
) {
267 TRACE("DGAButtonPressEvent received.\n");
268 EVENT_DGAButtonPressEvent((XDGAButtonEvent
*) event
);
271 if (event
->type
== DGAButtonReleaseEventType
) {
272 TRACE("DGAButtonReleaseEvent received.\n");
273 EVENT_DGAButtonReleaseEvent((XDGAButtonEvent
*) event
);
276 if ((event
->type
== DGAKeyPressEventType
) ||
277 (event
->type
== DGAKeyReleaseEventType
)) {
278 /* Fill a XKeyEvent to send to EVENT_Key */
280 XDGAKeyEvent
*evt
= (XDGAKeyEvent
*) event
;
282 TRACE("DGAKeyPress/ReleaseEvent received.\n");
284 if (evt
->type
== DGAKeyReleaseEventType
)
285 ke
.type
= KeyRelease
;
288 ke
.serial
= evt
->serial
;
289 ke
.send_event
= FALSE
;
290 ke
.display
= evt
->display
;
299 ke
.state
= evt
->state
;
300 ke
.keycode
= evt
->keycode
;
301 ke
.same_screen
= TRUE
;
303 X11DRV_KEYBOARD_HandleEvent(NULL
, &ke
);
309 if ( TSXFindContext( display
, event
->xany
.window
, winContext
,
310 (char **)&hWnd
) != 0) {
311 if ( event
->type
== ClientMessage
) {
312 /* query window (drag&drop event contains only drag window) */
314 int root_x
, root_y
, child_x
, child_y
;
316 TSXQueryPointer( display
, X11DRV_GetXRootWindow(), &root
, &child
,
317 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
318 if (TSXFindContext( display
, child
, winContext
, (char **)&hWnd
) != 0)
321 hWnd
= 0; /* Not for a registered window */
325 if ( !hWnd
&& event
->xany
.window
!= X11DRV_GetXRootWindow()
326 && event
->type
!= PropertyNotify
)
327 ERR("Got event %s for unknown Window %08lx\n",
328 event_names
[event
->type
], event
->xany
.window
);
330 TRACE("Got event %s for hwnd %04x\n",
331 event_names
[event
->type
], hWnd
);
337 EVENT_Key( hWnd
, (XKeyEvent
*)event
);
341 EVENT_ButtonPress( hWnd
, (XButtonEvent
*)event
);
345 EVENT_ButtonRelease( hWnd
, (XButtonEvent
*)event
);
349 /* Wine between two fast machines across the overloaded campus
350 ethernet gets very boged down in MotionEvents. The following
351 simply finds the last motion event in the queue and drops
352 the rest. On a good link events are servered before they build
353 up so this doesn't take place. On a slow link this may cause
354 problems if the event order is important. I'm not yet seen
355 of any problems. Jon 7/6/96.
357 if ((current_input_type
== X11DRV_INPUT_ABSOLUTE
) &&
358 (in_transition
== FALSE
))
359 /* Only cumulate events if in absolute mode */
360 while (TSXCheckTypedWindowEvent(display
,((XAnyEvent
*)event
)->window
,
361 MotionNotify
, event
));
362 EVENT_MotionNotify( hWnd
, (XMotionEvent
*)event
);
367 WND
*pWndLastFocus
= 0;
368 XWindowAttributes win_attr
;
370 XFocusChangeEvent
*xfocChange
= (XFocusChangeEvent
*)event
;
372 if (!hWnd
|| bUserRepaintDisabled
) return;
374 bIsDisabled
= GetWindowLongA( hWnd
, GWL_STYLE
) & WS_DISABLED
;
376 /* If the window has been disabled and we are in managed mode,
377 * revert the X focus back to the last focus window. This is to disallow
378 * the window manager from switching focus away while the app is
381 if ( Options
.managed
&& bIsDisabled
&& glastXFocusWin
)
383 /* Change focus only if saved focus window is registered and viewable */
384 if ( TSXFindContext( xfocChange
->display
, glastXFocusWin
, winContext
,
385 (char **)&pWndLastFocus
) == 0 )
387 if ( TSXGetWindowAttributes( display
, glastXFocusWin
, &win_attr
) &&
388 (win_attr
.map_state
== IsViewable
) )
390 TSXSetInputFocus( xfocChange
->display
, glastXFocusWin
, RevertToParent
, CurrentTime
);
397 EVENT_FocusIn( hWnd
, xfocChange
);
403 /* Save the last window which had the focus */
404 XFocusChangeEvent
*xfocChange
= (XFocusChangeEvent
*)event
;
405 glastXFocusWin
= xfocChange
->window
;
406 if (!hWnd
|| bUserRepaintDisabled
) return;
407 if (GetWindowLongA( hWnd
, GWL_STYLE
) & WS_DISABLED
) glastXFocusWin
= 0;
408 EVENT_FocusOut( hWnd
, (XFocusChangeEvent
*)event
);
413 if (bUserRepaintDisabled
) return;
414 EVENT_Expose( hWnd
, (XExposeEvent
*)event
);
418 if (bUserRepaintDisabled
) return;
419 EVENT_GraphicsExpose( hWnd
, (XGraphicsExposeEvent
*)event
);
422 case ConfigureNotify
:
423 if (!hWnd
|| bUserRepaintDisabled
) return;
424 EVENT_ConfigureNotify( hWnd
, (XConfigureEvent
*)event
);
427 case SelectionRequest
:
428 if (!hWnd
|| bUserRepaintDisabled
) return;
429 EVENT_SelectionRequest( hWnd
, (XSelectionRequestEvent
*)event
, FALSE
);
433 if (!hWnd
|| bUserRepaintDisabled
) return;
434 EVENT_SelectionClear( hWnd
, (XSelectionClearEvent
*) event
);
438 EVENT_PropertyNotify( (XPropertyEvent
*)event
);
442 if (!hWnd
|| bUserRepaintDisabled
) return;
443 EVENT_ClientMessage( hWnd
, (XClientMessageEvent
*) event
);
448 EVENT_EnterNotify( hWnd
, (XCrossingEvent
*) event
);
456 if (!hWnd
|| bUserRepaintDisabled
) return;
457 EVENT_MapNotify( hWnd
, (XMapEvent
*)event
);
461 if (!hWnd
|| bUserRepaintDisabled
) return;
462 EVENT_UnmapNotify( hWnd
, (XUnmapEvent
*)event
);
466 WARN("Unprocessed event %s for hwnd %04x\n",
467 event_names
[event
->type
], hWnd
);
470 TRACE( "returns.\n" );
473 /***********************************************************************
476 * Synchronize internal z-order with the window manager's.
478 static BOOL
__check_query_condition( WND
** pWndA
, WND
** pWndB
)
480 /* return TRUE if we have at least two managed windows */
482 for( *pWndB
= NULL
; *pWndA
; *pWndA
= (*pWndA
)->next
)
483 if( (*pWndA
)->flags
& WIN_MANAGED
&&
484 (*pWndA
)->dwStyle
& WS_VISIBLE
) break;
486 for( *pWndB
= (*pWndA
)->next
; *pWndB
; *pWndB
= (*pWndB
)->next
)
487 if( (*pWndB
)->flags
& WIN_MANAGED
&&
488 (*pWndB
)->dwStyle
& WS_VISIBLE
) break;
489 return ((*pWndB
) != NULL
);
492 static Window
__get_common_ancestor( Window A
, Window B
,
493 Window
** children
, unsigned* total
)
495 /* find the real root window */
497 Window root
, *childrenB
;
502 TSXQueryTree( display
, A
, &root
, &A
, children
, total
);
503 TSXQueryTree( display
, B
, &root
, &B
, &childrenB
, &totalB
);
504 if( childrenB
) TSXFree( childrenB
);
505 if( *children
) TSXFree( *children
), *children
= NULL
;
506 } while( A
!= B
&& A
&& B
);
510 TSXQueryTree( display
, A
, &root
, &B
, children
, total
);
516 static Window
__get_top_decoration( Window w
, Window ancestor
)
518 Window
* children
, root
, prev
= w
, parent
= w
;
524 TSXQueryTree( display
, w
, &root
, &parent
, &children
, &total
);
525 if( children
) TSXFree( children
);
526 } while( parent
&& parent
!= ancestor
);
527 TRACE("\t%08x -> %08x\n", (unsigned)prev
, (unsigned)w
);
528 return ( parent
) ? w
: 0 ;
531 static unsigned __td_lookup( Window w
, Window
* list
, unsigned max
)
534 for( i
= max
- 1; i
>= 0; i
-- ) if( list
[i
] == w
) break;
538 static HWND
EVENT_QueryZOrder( HWND hWndCheck
)
540 HWND hwndInsertAfter
= HWND_TOP
;
541 WND
*pWndCheck
= WIN_FindWndPtr(hWndCheck
);
542 WND
*pDesktop
= WIN_GetDesktop();
543 WND
*pWnd
, *pWndZ
= WIN_LockWndPtr(pDesktop
->child
);
544 Window w
, parent
, *children
= NULL
;
545 unsigned total
, check
, pos
, best
;
547 if( !__check_query_condition(&pWndZ
, &pWnd
) )
549 WIN_ReleaseWndPtr(pWndCheck
);
550 WIN_ReleaseWndPtr(pDesktop
->child
);
551 WIN_ReleaseDesktop();
552 return hwndInsertAfter
;
554 WIN_LockWndPtr(pWndZ
);
555 WIN_LockWndPtr(pWnd
);
556 WIN_ReleaseWndPtr(pDesktop
->child
);
557 WIN_ReleaseDesktop();
559 parent
= __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ
),
560 X11DRV_WND_GetXWindow(pWnd
),
562 if( parent
&& children
)
564 /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
566 w
= __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck
), parent
);
568 if( w
!= children
[total
-1] ) /* check if at the top */
570 /* X child at index 0 is at the bottom, at index total-1 is at the top */
571 check
= __td_lookup( w
, children
, total
);
574 for( WIN_UpdateWndPtr(&pWnd
,pWndZ
); pWnd
;WIN_UpdateWndPtr(&pWnd
,pWnd
->next
))
576 /* go through all windows in Wine z-order... */
578 if( pWnd
!= pWndCheck
)
580 if( !(pWnd
->flags
& WIN_MANAGED
) ||
581 !(w
= __get_top_decoration( X11DRV_WND_GetXWindow(pWnd
), parent
)) )
583 pos
= __td_lookup( w
, children
, total
);
584 if( pos
< best
&& pos
> check
)
586 /* find a nearest Wine window precedes
587 * pWndCheck in the real z-order... */
589 hwndInsertAfter
= pWnd
->hwndSelf
;
591 if( best
- check
== 1 ) break;
596 if( children
) TSXFree( children
);
597 WIN_ReleaseWndPtr(pWnd
);
598 WIN_ReleaseWndPtr(pWndZ
);
599 WIN_ReleaseWndPtr(pWndCheck
);
600 return hwndInsertAfter
;
603 /***********************************************************************
604 * X11DRV_EVENT_XStateToKeyState
606 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
607 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
609 WORD
X11DRV_EVENT_XStateToKeyState( int state
)
613 if (state
& Button1Mask
) kstate
|= MK_LBUTTON
;
614 if (state
& Button2Mask
) kstate
|= MK_MBUTTON
;
615 if (state
& Button3Mask
) kstate
|= MK_RBUTTON
;
616 if (state
& ShiftMask
) kstate
|= MK_SHIFT
;
617 if (state
& ControlMask
) kstate
|= MK_CONTROL
;
621 /***********************************************************************
624 static void EVENT_Expose( HWND hWnd
, XExposeEvent
*event
)
628 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
629 /* Make position relative to client area instead of window */
630 rect
.left
= event
->x
- (pWnd
? (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
) : 0);
631 rect
.top
= event
->y
- (pWnd
? (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
) : 0);
632 rect
.right
= rect
.left
+ event
->width
;
633 rect
.bottom
= rect
.top
+ event
->height
;
634 WIN_ReleaseWndPtr(pWnd
);
636 Callout
.RedrawWindow( hWnd
, &rect
, 0,
637 RDW_INVALIDATE
| RDW_FRAME
| RDW_ALLCHILDREN
| RDW_ERASE
|
638 (event
->count
? 0 : RDW_ERASENOW
) );
642 /***********************************************************************
643 * EVENT_GraphicsExpose
645 * This is needed when scrolling area is partially obscured
646 * by non-Wine X window.
648 static void EVENT_GraphicsExpose( HWND hWnd
, XGraphicsExposeEvent
*event
)
651 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
653 /* Make position relative to client area instead of window */
654 rect
.left
= event
->x
- (pWnd
? (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
) : 0);
655 rect
.top
= event
->y
- (pWnd
? (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
) : 0);
656 rect
.right
= rect
.left
+ event
->width
;
657 rect
.bottom
= rect
.top
+ event
->height
;
659 WIN_ReleaseWndPtr(pWnd
);
661 Callout
.RedrawWindow( hWnd
, &rect
, 0,
662 RDW_INVALIDATE
| RDW_ALLCHILDREN
| RDW_ERASE
|
663 (event
->count
? 0 : RDW_ERASENOW
) );
667 /***********************************************************************
670 * Handle a X key event
672 static void EVENT_Key( HWND hWnd
, XKeyEvent
*event
)
674 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
675 X11DRV_KEYBOARD_HandleEvent( pWnd
, event
);
676 WIN_ReleaseWndPtr(pWnd
);
681 /***********************************************************************
684 static void EVENT_MotionNotify( HWND hWnd
, XMotionEvent
*event
)
686 if (current_input_type
== X11DRV_INPUT_ABSOLUTE
) {
687 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
688 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
689 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
690 WIN_ReleaseWndPtr(pWnd
);
692 MOUSE_SendEvent( MOUSEEVENTF_MOVE
| MOUSEEVENTF_ABSOLUTE
,
693 xOffset
+ event
->x
, yOffset
+ event
->y
,
694 X11DRV_EVENT_XStateToKeyState( event
->state
),
695 event
->time
- MSG_WineStartTicks
,
698 MOUSE_SendEvent( MOUSEEVENTF_MOVE
,
699 event
->x_root
, event
->y_root
,
700 X11DRV_EVENT_XStateToKeyState( event
->state
),
701 event
->time
- MSG_WineStartTicks
,
707 /***********************************************************************
710 static void EVENT_ButtonPress( HWND hWnd
, XButtonEvent
*event
)
712 static WORD statusCodes
[NB_BUTTONS
] =
713 { MOUSEEVENTF_LEFTDOWN
, MOUSEEVENTF_MIDDLEDOWN
, MOUSEEVENTF_RIGHTDOWN
};
714 int buttonNum
= event
->button
- 1;
716 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
717 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
718 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
721 WIN_ReleaseWndPtr(pWnd
);
723 if (buttonNum
>= NB_BUTTONS
) return;
726 * Get the compatible keystate
728 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
731 * Make sure that the state of the button that was just
737 keystate
|= MK_LBUTTON
;
740 keystate
|= MK_MBUTTON
;
743 keystate
|= MK_RBUTTON
;
747 MOUSE_SendEvent( statusCodes
[buttonNum
],
748 xOffset
+ event
->x
, yOffset
+ event
->y
,
750 event
->time
- MSG_WineStartTicks
,
755 /***********************************************************************
756 * EVENT_ButtonRelease
758 static void EVENT_ButtonRelease( HWND hWnd
, XButtonEvent
*event
)
760 static WORD statusCodes
[NB_BUTTONS
] =
761 { MOUSEEVENTF_LEFTUP
, MOUSEEVENTF_MIDDLEUP
, MOUSEEVENTF_RIGHTUP
};
762 int buttonNum
= event
->button
- 1;
763 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
764 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
765 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
768 WIN_ReleaseWndPtr(pWnd
);
770 if (buttonNum
>= NB_BUTTONS
) return;
773 * Get the compatible keystate
775 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
778 * Make sure that the state of the button that was just
784 keystate
&= ~MK_LBUTTON
;
787 keystate
&= ~MK_MBUTTON
;
790 keystate
&= ~MK_RBUTTON
;
794 MOUSE_SendEvent( statusCodes
[buttonNum
],
795 xOffset
+ event
->x
, yOffset
+ event
->y
,
797 event
->time
- MSG_WineStartTicks
,
802 /**********************************************************************
805 static void EVENT_FocusIn( HWND hWnd
, XFocusChangeEvent
*event
)
807 if (event
->detail
!= NotifyPointer
)
808 if (hWnd
!= GetForegroundWindow())
810 SetForegroundWindow( hWnd
);
811 X11DRV_KEYBOARD_UpdateState();
816 /**********************************************************************
819 * Note: only top-level override-redirect windows get FocusOut events.
821 static void EVENT_FocusOut( HWND hWnd
, XFocusChangeEvent
*event
)
823 if (event
->detail
!= NotifyPointer
)
824 if (hWnd
== GetForegroundWindow())
826 SendMessageA( hWnd
, WM_CANCELMODE
, 0, 0 );
828 /* Abey : 6-Oct-99. Check again if the focus out window is the
829 Foreground window, because in most cases the messages sent
830 above must have already changed the foreground window, in which
831 case we don't have to change the foreground window to 0 */
833 if (hWnd
== GetForegroundWindow())
834 SetForegroundWindow( 0 );
838 /**********************************************************************
839 * X11DRV_EVENT_CheckFocus
841 BOOL
X11DRV_EVENT_CheckFocus(void)
847 TSXGetInputFocus(display
, &xW
, &state
);
849 TSXFindContext(display
, xW
, winContext
, (char **)&hWnd
) )
854 /**********************************************************************
857 * Helper function for ConfigureNotify handling.
858 * Get the new geometry of a window relative to the root window.
860 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
861 unsigned int *pwidth
, unsigned int *pheight
)
864 int x
, y
, width
, height
, border
, depth
;
866 EnterCriticalSection( &X11DRV_CritSection
);
868 /* Get the geometry of the window */
869 XGetGeometry( display
, win
, &root
, &x
, &y
, &width
, &height
,
872 /* Translate the window origin to root coordinates */
873 XTranslateCoordinates( display
, win
, root
, 0, 0, &x
, &y
, &top
);
875 LeaveCriticalSection( &X11DRV_CritSection
);
883 /**********************************************************************
884 * EVENT_ConfigureNotify
886 * The ConfigureNotify event is only selected on top-level windows
887 * when the -managed flag is used.
889 static void EVENT_ConfigureNotify( HWND hWnd
, XConfigureEvent
*event
)
893 unsigned int width
, height
;
894 HWND newInsertAfter
, oldInsertAfter
;
896 /* Get geometry and Z-order according to X */
898 EVENT_GetGeometry( event
->window
, &x
, &y
, &width
, &height
);
899 newInsertAfter
= EVENT_QueryZOrder( hWnd
);
901 /* Get geometry and Z-order according to Wine */
904 * Needs to find the first Visible Window above the current one
906 oldInsertAfter
= hWnd
;
909 oldInsertAfter
= GetWindow( oldInsertAfter
, GW_HWNDPREV
);
912 oldInsertAfter
= HWND_TOP
;
915 if (GetWindowLongA( oldInsertAfter
, GWL_STYLE
) & WS_VISIBLE
) break;
918 /* Compare what has changed */
920 GetWindowRect( hWnd
, &rectWindow
);
921 if ( rectWindow
.left
== x
&& rectWindow
.top
== y
)
924 TRACE_(win
)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd
,
925 rectWindow
.left
, rectWindow
.top
, x
, y
);
927 if ( rectWindow
.right
- rectWindow
.left
== width
928 && rectWindow
.bottom
- rectWindow
.top
== height
)
931 TRACE_(win
)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd
,
932 rectWindow
.right
- rectWindow
.left
,
933 rectWindow
.bottom
- rectWindow
.top
, width
, height
);
935 if ( newInsertAfter
== oldInsertAfter
)
936 flags
|= SWP_NOZORDER
;
938 TRACE_(win
)( "%04x restacking from after %04x to after %04x\n", hWnd
,
939 oldInsertAfter
, newInsertAfter
);
941 /* If anything changed, call SetWindowPos */
943 if ( flags
!= (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
) )
944 SetWindowPos( hWnd
, newInsertAfter
, x
, y
, width
, height
,
945 flags
| SWP_NOACTIVATE
| SWP_WINE_NOHOSTMOVE
);
949 /***********************************************************************
950 * EVENT_SelectionRequest_TARGETS
951 * Service a TARGETS selection request event
953 static Atom
EVENT_SelectionRequest_TARGETS( Window requestor
, Atom target
, Atom rprop
)
955 Atom xaTargets
= TSXInternAtom(display
, "TARGETS", False
);
959 unsigned long cTargets
;
963 TRACE("Request for %s\n", TSXGetAtomName(display
, target
));
966 * Count the number of items we wish to expose as selection targets.
967 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
969 cTargets
= CountClipboardFormats() + 1;
970 if ( CLIPBOARD_IsPresent(CF_DIB
) || CLIPBOARD_IsPresent(CF_BITMAP
) )
973 /* Allocate temp buffer */
974 targets
= (Atom
*)HEAP_xalloc( GetProcessHeap(), 0, cTargets
* sizeof(Atom
));
976 /* Create TARGETS property list (First item in list is TARGETS itself) */
978 for ( targets
[0] = xaTargets
, cTargets
= 1, wFormat
= 0, bHavePixmap
= FALSE
;
979 (wFormat
= EnumClipboardFormats( wFormat
)); )
981 if ( (prop
= X11DRV_CLIPBOARD_MapFormatToProperty(wFormat
)) != None
)
983 /* Scan through what we have so far to avoid duplicates */
986 for (i
= 0, bExists
= FALSE
; i
< cTargets
; i
++)
988 if (targets
[i
] == prop
)
996 targets
[cTargets
++] = prop
;
998 /* Add PIXMAP prop for bitmaps additionally */
999 if ( (wFormat
== CF_DIB
|| wFormat
== CF_BITMAP
)
1002 targets
[cTargets
++] = XA_PIXMAP
;
1009 if (TRACE_ON(event
))
1012 for ( i
= 0; i
< cTargets
; i
++)
1016 char *itemFmtName
= TSXGetAtomName(display
, targets
[i
]);
1017 TRACE("\tAtom# %d: Type %s\n", i
, itemFmtName
);
1018 TSXFree(itemFmtName
);
1023 /* Update the X property */
1024 TRACE("\tUpdating property %s...", TSXGetAtomName(display
, rprop
));
1026 /* We may want to consider setting the type to xaTargets instead,
1027 * in case some apps expect this instead of XA_ATOM */
1028 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
1029 XA_ATOM
, 32, PropModeReplace
,
1030 (unsigned char *)targets
, cTargets
);
1031 TRACE("(Rc=%d)\n", xRc
);
1033 HeapFree( GetProcessHeap(), 0, targets
);
1039 /***********************************************************************
1040 * EVENT_SelectionRequest_STRING
1041 * Service a STRING selection request event
1043 static Atom
EVENT_SelectionRequest_STRING( Window requestor
, Atom target
, Atom rprop
)
1053 * Map the requested X selection property type atom name to a
1054 * windows clipboard format ID.
1056 itemFmtName
= TSXGetAtomName(display
, target
);
1057 TRACE("Request for %s (wFormat=%x %s)\n",
1058 itemFmtName
, CF_TEXT
, CLIPBOARD_GetFormatName(CF_TEXT
));
1059 TSXFree(itemFmtName
);
1061 hText
= GetClipboardData16(CF_TEXT
);
1064 text
= GlobalLock16(hText
);
1067 size
= GlobalSize16(hText
);
1068 /* remove carriage returns */
1070 lpstr
= (char*)HEAP_xalloc( GetProcessHeap(), 0, size
-- );
1071 for(i
=0,j
=0; i
< size
&& text
[i
]; i
++ )
1073 if( text
[i
] == '\r' &&
1074 (text
[i
+1] == '\n' || text
[i
+1] == '\0') ) continue;
1075 lpstr
[j
++] = text
[i
];
1079 /* Update the X property */
1080 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display
, rprop
));
1081 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
1082 XA_STRING
, 8, PropModeReplace
,
1084 TRACE("(Rc=%d)\n", xRc
);
1086 GlobalUnlock16(hText
);
1087 HeapFree( GetProcessHeap(), 0, lpstr
);
1092 /***********************************************************************
1093 * EVENT_SelectionRequest_PIXMAP
1094 * Service a PIXMAP selection request event
1096 static Atom
EVENT_SelectionRequest_PIXMAP( Window requestor
, Atom target
, Atom rprop
)
1098 HANDLE hClipData
= 0;
1104 XSetWindowAttributes win_attr
;
1105 XWindowAttributes win_attr_src
;
1109 * Map the requested X selection property type atom name to a
1110 * windows clipboard format ID.
1112 itemFmtName
= TSXGetAtomName(display
, target
);
1113 wFormat
= X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName
);
1114 TRACE("Request for %s (wFormat=%x %s)\n",
1115 itemFmtName
, wFormat
, CLIPBOARD_GetFormatName( wFormat
));
1116 TSXFree(itemFmtName
);
1118 hClipData
= GetClipboardData(wFormat
);
1121 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
1122 rprop
= None
; /* Fail the request */
1126 if (wFormat
== CF_DIB
)
1128 HWND hwnd
= GetOpenClipboardWindow();
1129 HDC hdc
= GetDC(hwnd
);
1131 /* For convert from packed DIB to Pixmap */
1132 pixmap
= X11DRV_DIB_CreatePixmapFromDIB(hClipData
, hdc
);
1134 ReleaseDC(hdc
, hwnd
);
1136 else if (wFormat
== CF_BITMAP
)
1138 HWND hwnd
= GetOpenClipboardWindow();
1139 HDC hdc
= GetDC(hwnd
);
1141 pixmap
= X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData
, hdc
);
1143 ReleaseDC(hdc
, hwnd
);
1147 FIXME("%s to PIXMAP conversion not yet implemented!\n",
1148 CLIPBOARD_GetFormatName(wFormat
));
1153 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
1154 TSXGetAtomName(display
, rprop
), (long)requestor
,
1155 TSXGetAtomName(display
, target
), pixmap
);
1157 /* Store the Pixmap handle in the property */
1158 xRc
= TSXChangeProperty(display
, requestor
, rprop
, target
,
1159 32, PropModeReplace
,
1160 (unsigned char *)&pixmap
, 1);
1161 TRACE("(Rc=%d)\n", xRc
);
1163 /* Enable the code below if you want to handle destroying Pixmap resources
1164 * in response to property notify events. Clients like XPaint don't
1165 * appear to be duplicating Pixmaps so they don't like us deleting,
1166 * the resource in response to the property being deleted.
1169 /* Express interest in property notify events so that we can delete the
1170 * pixmap when the client deletes the property atom.
1172 xRc
= TSXGetWindowAttributes(display
, requestor
, &win_attr_src
);
1173 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
1175 win_attr
.event_mask
= win_attr_src
.your_event_mask
| PropertyChangeMask
;
1176 TSXChangeWindowAttributes(display
, requestor
, CWEventMask
, &win_attr
);
1178 /* Register the Pixmap we created with the request property Atom.
1179 * When this property is destroyed we also destroy the Pixmap in
1180 * response to the PropertyNotify event.
1182 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop
, pixmap
);
1190 /***********************************************************************
1191 * EVENT_SelectionRequest_WCF
1192 * Service a Wine Clipboard Format selection request event.
1193 * For <WCF>* data types we simply copy the data to X without conversion.
1195 static Atom
EVENT_SelectionRequest_WCF( Window requestor
, Atom target
, Atom rprop
)
1197 HANDLE hClipData
= 0;
1205 * Map the requested X selection property type atom name to a
1206 * windows clipboard format ID.
1208 itemFmtName
= TSXGetAtomName(display
, target
);
1209 wFormat
= X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName
);
1210 TRACE("Request for %s (wFormat=%x %s)\n",
1211 itemFmtName
, wFormat
, CLIPBOARD_GetFormatName( wFormat
));
1212 TSXFree(itemFmtName
);
1214 hClipData
= GetClipboardData16(wFormat
);
1216 if( hClipData
&& (lpClipData
= GlobalLock16(hClipData
)) )
1218 cBytes
= GlobalSize16(hClipData
);
1220 TRACE("\tUpdating property %s, %d bytes...\n",
1221 TSXGetAtomName(display
, rprop
), cBytes
);
1223 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
1224 target
, 8, PropModeReplace
,
1225 (unsigned char *)lpClipData
, cBytes
);
1226 TRACE("(Rc=%d)\n", xRc
);
1228 GlobalUnlock16(hClipData
);
1232 TRACE("\tCould not retrieve native format!\n");
1233 rprop
= None
; /* Fail the request */
1240 /***********************************************************************
1241 * EVENT_SelectionRequest_MULTIPLE
1242 * Service a MULTIPLE selection request event
1243 * rprop contains a list of (target,property) atom pairs.
1244 * The first atom names a target and the second names a property.
1245 * The effect is as if we have received a sequence of SelectionRequest events
1246 * (one for each atom pair) except that:
1247 * 1. We reply with a SelectionNotify only when all the requested conversions
1248 * have been performed.
1249 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1250 * we replace the atom in the property by None.
1252 static Atom
EVENT_SelectionRequest_MULTIPLE( HWND hWnd
, XSelectionRequestEvent
*pevent
)
1255 Atom atype
=AnyPropertyType
;
1257 unsigned long remain
;
1258 Atom
* targetPropList
=NULL
;
1259 unsigned long cTargetPropList
= 0;
1260 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1262 /* If the specified property is None the requestor is an obsolete client.
1263 * We support these by using the specified target atom as the reply property.
1265 rprop
= pevent
->property
;
1267 rprop
= pevent
->target
;
1271 /* Read the MULTIPLE property contents. This should contain a list of
1272 * (target,property) atom pairs.
1274 if(TSXGetWindowProperty(display
, pevent
->requestor
, rprop
,
1275 0, 0x3FFF, False
, AnyPropertyType
, &atype
,&aformat
,
1276 &cTargetPropList
, &remain
,
1277 (unsigned char**)&targetPropList
) != Success
)
1278 TRACE("\tCouldn't read MULTIPLE property\n");
1281 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1282 TSXGetAtomName(display
, atype
), aformat
, cTargetPropList
, remain
);
1285 * Make sure we got what we expect.
1286 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1287 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1288 * However some X apps(such as XPaint) are not compliant with this and return
1289 * a user defined atom in atype when XGetWindowProperty is called.
1290 * The data *is* an atom pair but is not denoted as such.
1292 if(aformat
== 32 /* atype == xAtomPair */ )
1296 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1297 * for each (target,property) pair */
1299 for (i
= 0; i
< cTargetPropList
; i
+=2)
1301 char *targetName
= TSXGetAtomName(display
, targetPropList
[i
]);
1302 char *propName
= TSXGetAtomName(display
, targetPropList
[i
+1]);
1303 XSelectionRequestEvent event
;
1305 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
1306 i
/2, targetName
, propName
);
1307 TSXFree(targetName
);
1310 /* We must have a non "None" property to service a MULTIPLE target atom */
1311 if ( !targetPropList
[i
+1] )
1313 TRACE("\tMULTIPLE(%d): Skipping target with empty property!", i
);
1317 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1318 memcpy( &event
, pevent
, sizeof(XSelectionRequestEvent
) );
1319 event
.target
= targetPropList
[i
];
1320 event
.property
= targetPropList
[i
+1];
1322 /* Fire a SelectionRequest, informing the handler that we are processing
1323 * a MULTIPLE selection request event.
1325 EVENT_SelectionRequest( hWnd
, &event
, TRUE
);
1329 /* Free the list of targets/properties */
1330 TSXFree(targetPropList
);
1338 /***********************************************************************
1339 * EVENT_SelectionRequest
1340 * Process an event selection request event.
1341 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1342 * recursively while servicing a "MULTIPLE" selection target.
1344 * Note: We only receive this event when WINE owns the X selection
1346 static void EVENT_SelectionRequest( HWND hWnd
, XSelectionRequestEvent
*event
, BOOL bIsMultiple
)
1348 XSelectionEvent result
;
1350 Window request
= event
->requestor
;
1351 BOOL couldOpen
= FALSE
;
1352 Atom xaClipboard
= TSXInternAtom(display
, "CLIPBOARD", False
);
1353 Atom xaTargets
= TSXInternAtom(display
, "TARGETS", False
);
1354 Atom xaMultiple
= TSXInternAtom(display
, "MULTIPLE", False
);
1357 * We can only handle the selection request if :
1358 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1359 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1360 * since this has been already done.
1364 if ( ( (event
->selection
!= XA_PRIMARY
) && (event
->selection
!= xaClipboard
) )
1365 || !(couldOpen
= OpenClipboard(hWnd
)) )
1369 /* If the specified property is None the requestor is an obsolete client.
1370 * We support these by using the specified target atom as the reply property.
1372 rprop
= event
->property
;
1374 rprop
= event
->target
;
1376 if(event
->target
== xaTargets
) /* Return a list of all supported targets */
1378 /* TARGETS selection request */
1379 rprop
= EVENT_SelectionRequest_TARGETS( request
, event
->target
, rprop
);
1381 else if(event
->target
== xaMultiple
) /* rprop contains a list of (target, property) atom pairs */
1383 /* MULTIPLE selection request */
1384 rprop
= EVENT_SelectionRequest_MULTIPLE( hWnd
, event
);
1386 else if(event
->target
== XA_STRING
) /* treat CF_TEXT as Unix text */
1388 /* XA_STRING selection request */
1389 rprop
= EVENT_SelectionRequest_STRING( request
, event
->target
, rprop
);
1391 else if(event
->target
== XA_PIXMAP
) /* Convert DIB's to Pixmaps */
1393 /* XA_PIXMAP selection request */
1394 rprop
= EVENT_SelectionRequest_PIXMAP( request
, event
->target
, rprop
);
1396 else if(event
->target
== XA_BITMAP
) /* Convert DIB's to 1-bit Pixmaps */
1398 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1399 rprop
= EVENT_SelectionRequest_PIXMAP( request
, XA_PIXMAP
, rprop
);
1401 else if(X11DRV_CLIPBOARD_IsNativeProperty(event
->target
)) /* <WCF>* */
1403 /* All <WCF> selection requests */
1404 rprop
= EVENT_SelectionRequest_WCF( request
, event
->target
, rprop
);
1407 rprop
= None
; /* Don't support this format */
1410 /* close clipboard only if we opened before */
1411 if(couldOpen
) CloseClipboard();
1414 TRACE("\tRequest ignored\n");
1417 * SelectionNotify should be sent only at the end of a MULTIPLE request
1421 result
.type
= SelectionNotify
;
1422 result
.display
= display
;
1423 result
.requestor
= request
;
1424 result
.selection
= event
->selection
;
1425 result
.property
= rprop
;
1426 result
.target
= event
->target
;
1427 result
.time
= event
->time
;
1428 TRACE("Sending SelectionNotify event...\n");
1429 TSXSendEvent(display
,event
->requestor
,False
,NoEventMask
,(XEvent
*)&result
);
1433 /***********************************************************************
1434 * EVENT_SelectionClear
1436 static void EVENT_SelectionClear( HWND hWnd
, XSelectionClearEvent
*event
)
1438 Atom xaClipboard
= TSXInternAtom(display
, "CLIPBOARD", False
);
1440 if (event
->selection
== XA_PRIMARY
|| event
->selection
== xaClipboard
)
1441 X11DRV_CLIPBOARD_ReleaseSelection( event
->selection
, event
->window
, hWnd
);
1444 /***********************************************************************
1445 * EVENT_PropertyNotify
1446 * We use this to release resources like Pixmaps when a selection
1447 * client no longer needs them.
1449 static void EVENT_PropertyNotify( XPropertyEvent
*event
)
1451 /* Check if we have any resources to free */
1452 TRACE("Received PropertyNotify event: ");
1454 switch(event
->state
)
1456 case PropertyDelete
:
1458 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1459 TSXGetAtomName(event
->display
, event
->atom
), (long)event
->window
);
1461 if (X11DRV_CLIPBOARD_IsSelectionowner())
1462 X11DRV_CLIPBOARD_FreeResources( event
->atom
);
1466 case PropertyNewValue
:
1468 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1469 TSXGetAtomName(event
->display
, event
->atom
), (long)event
->window
);
1478 /**********************************************************************
1479 * EVENT_DropFromOffix
1481 * don't know if it still works (last Changlog is from 96/11/04)
1483 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1485 unsigned long data_length
;
1486 unsigned long aux_long
;
1487 unsigned char* p_data
= NULL
;
1498 HGLOBAL16 hDragInfo
= GlobalAlloc16( GMEM_SHARE
| GMEM_ZEROINIT
, sizeof(DRAGINFO
));
1499 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) GlobalLock16(hDragInfo
);
1500 SEGPTR spDragInfo
= (SEGPTR
) WIN16_GlobalLock16(hDragInfo
);
1501 Window w_aux_root
, w_aux_child
;
1505 if( !lpDragInfo
|| !spDragInfo
) return;
1507 pWnd
= WIN_FindWndPtr(hWnd
);
1509 TSXQueryPointer( display
, X11DRV_WND_GetXWindow(pWnd
), &w_aux_root
, &w_aux_child
,
1510 &x
, &y
, (int *) &u
.pt_aux
.x
, (int *) &u
.pt_aux
.y
,
1511 (unsigned int*)&aux_long
);
1513 lpDragInfo
->hScope
= hWnd
;
1514 lpDragInfo
->pt
.x
= (INT16
)x
; lpDragInfo
->pt
.y
= (INT16
)y
;
1516 /* find out drop point and drop window */
1517 if( x
< 0 || y
< 0 ||
1518 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
1519 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
1520 { bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
; x
= y
= 0; }
1523 bAccept
= DRAG_QueryUpdate( hWnd
, spDragInfo
, TRUE
);
1524 x
= lpDragInfo
->pt
.x
; y
= lpDragInfo
->pt
.y
;
1526 pDropWnd
= WIN_FindWndPtr( lpDragInfo
->hScope
);
1527 WIN_ReleaseWndPtr(pWnd
);
1529 GlobalFree16( hDragInfo
);
1533 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1534 dndSelection
, 0, 65535, FALSE
,
1535 AnyPropertyType
, &u
.atom_aux
, (int *) &u
.pt_aux
.y
,
1536 &data_length
, &aux_long
, &p_data
);
1538 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1540 char *p
= (char*) p_data
;
1544 while( *p
) /* calculate buffer size */
1547 if((u
.i
= *p
) != -1 )
1548 u
.i
= DRIVE_FindDriveRoot( (const char **)&p_drop
);
1549 if( u
.i
== -1 ) *p
= -1; /* mark as "bad" */
1552 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1553 if (len
) aux_long
+= len
+ 1;
1558 if( aux_long
&& aux_long
< 65535 )
1561 LPDROPFILESTRUCT16 lpDrop
;
1563 aux_long
+= sizeof(DROPFILESTRUCT16
) + 1;
1564 hDrop
= (HDROP16
)GlobalAlloc16( GMEM_SHARE
, aux_long
);
1565 lpDrop
= (LPDROPFILESTRUCT16
) GlobalLock16( hDrop
);
1569 lpDrop
->wSize
= sizeof(DROPFILESTRUCT16
);
1570 lpDrop
->ptMousePos
.x
= (INT16
)x
;
1571 lpDrop
->ptMousePos
.y
= (INT16
)y
;
1572 lpDrop
->fInNonClientArea
= (BOOL16
)
1573 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1574 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1575 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1576 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1577 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT16
);
1581 if( *p
!= -1 ) /* use only "good" entries */
1583 GetShortPathNameA( p
, p_drop
, 65535 );
1584 p_drop
+= strlen( p_drop
) + 1;
1589 PostMessage16( hWnd
, WM_DROPFILES
,
1590 (WPARAM16
)hDrop
, 0L );
1594 if( p_data
) TSXFree(p_data
);
1596 } /* WS_EX_ACCEPTFILES */
1598 WIN_ReleaseWndPtr(pDropWnd
);
1601 /**********************************************************************
1604 * drop items are separated by \n
1605 * each item is prefixed by its mime type
1607 * event->data.l[3], event->data.l[4] contains drop x,y position
1609 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1613 unsigned long data_length
;
1614 unsigned long aux_long
, drop_len
= 0;
1615 unsigned char *p_data
= NULL
; /* property data */
1616 char *p_drop
= NULL
;
1618 int x
, y
, drop32
= FALSE
;
1629 pWnd
= WIN_FindWndPtr(hWnd
);
1630 drop32
= pWnd
->flags
& WIN_ISWIN32
;
1632 if (!(pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
))
1634 WIN_ReleaseWndPtr(pWnd
);
1637 WIN_ReleaseWndPtr(pWnd
);
1639 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1640 dndSelection
, 0, 65535, FALSE
,
1641 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1642 &data_length
, &aux_long
, &p_data
);
1644 WARN("property too large, truncated!\n");
1645 TRACE("urls=%s\n", p_data
);
1647 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1648 /* calculate length */
1650 next
= strchr(p
, '\n');
1653 if (strncmp(p
,"file:",5) == 0 ) {
1654 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1655 if (len
) drop_len
+= len
+ 1;
1660 next
= strchr(p
, '\n');
1666 if( drop_len
&& drop_len
< 65535 ) {
1667 TSXQueryPointer( display
, X11DRV_GetXRootWindow(), &u
.w_aux
, &u
.w_aux
,
1668 &x
, &y
, &u
.i
, &u
.i
, &u
.i
);
1670 pDropWnd
= WIN_FindWndPtr( hWnd
);
1673 LPDROPFILESTRUCT lpDrop
;
1674 drop_len
+= sizeof(DROPFILESTRUCT
) + 1;
1675 hDrop
.h32
= (HDROP
)GlobalAlloc( GMEM_SHARE
, drop_len
);
1676 lpDrop
= (LPDROPFILESTRUCT
) GlobalLock( hDrop
.h32
);
1679 lpDrop
->lSize
= sizeof(DROPFILESTRUCT
);
1680 lpDrop
->ptMousePos
.x
= (INT
)x
;
1681 lpDrop
->ptMousePos
.y
= (INT
)y
;
1682 lpDrop
->fInNonClientArea
= (BOOL
)
1683 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1684 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1685 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1686 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1687 lpDrop
->fWideChar
= FALSE
;
1688 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT
);
1691 LPDROPFILESTRUCT16 lpDrop
;
1692 drop_len
+= sizeof(DROPFILESTRUCT16
) + 1;
1693 hDrop
.h16
= (HDROP16
)GlobalAlloc16( GMEM_SHARE
, drop_len
);
1694 lpDrop
= (LPDROPFILESTRUCT16
) GlobalLock16( hDrop
.h16
);
1697 lpDrop
->wSize
= sizeof(DROPFILESTRUCT16
);
1698 lpDrop
->ptMousePos
.x
= (INT16
)x
;
1699 lpDrop
->ptMousePos
.y
= (INT16
)y
;
1700 lpDrop
->fInNonClientArea
= (BOOL16
)
1701 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1702 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1703 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1704 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1705 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT16
);
1709 /* create message content */
1712 next
= strchr(p
, '\n');
1715 if (strncmp(p
,"file:",5) == 0 ) {
1716 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1718 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1721 WARN("can't convert file %s to dos name \n", p
+5);
1724 WARN("unknown mime type %s\n", p
);
1729 next
= strchr(p
, '\n');
1737 /* can not use PostMessage32A because it is currently based on
1738 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1740 GlobalUnlock(hDrop
.h32
);
1741 SendMessageA( hWnd
, WM_DROPFILES
,
1742 (WPARAM
)hDrop
.h32
, 0L );
1744 GlobalUnlock16(hDrop
.h16
);
1745 PostMessage16( hWnd
, WM_DROPFILES
,
1746 (WPARAM16
)hDrop
.h16
, 0L );
1749 WIN_ReleaseWndPtr(pDropWnd
);
1751 if( p_data
) TSXFree(p_data
);
1755 /**********************************************************************
1756 * EVENT_ClientMessage
1758 static void EVENT_ClientMessage( HWND hWnd
, XClientMessageEvent
*event
)
1760 if (event
->message_type
!= None
&& event
->format
== 32) {
1761 if ((event
->message_type
== wmProtocols
) &&
1762 (((Atom
) event
->data
.l
[0]) == wmDeleteWindow
))
1764 /* Ignore the delete window request if the window has been disabled
1765 * and we are in managed mode. This is to disallow applications from
1766 * being closed by the window manager while in a modal state.
1769 bIsDisabled
= GetWindowLongA( hWnd
, GWL_STYLE
) & WS_DISABLED
;
1771 if ( !Options
.managed
|| !bIsDisabled
)
1772 PostMessage16( hWnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1774 else if ( event
->message_type
== dndProtocol
&&
1775 (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
) )
1776 EVENT_DropFromOffiX(hWnd
, event
);
1777 else if ( event
->message_type
== dndProtocol
&&
1778 event
->data
.l
[0] == DndURL
)
1779 EVENT_DropURLs(hWnd
, event
);
1782 /* enable this if you want to see the message */
1783 unsigned char* p_data
= NULL
;
1789 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1790 dndSelection
, 0, 65535, FALSE
,
1791 AnyPropertyType
, &u
.atom
, &u
.i
,
1792 &u
.l
, &u
.l
, &p_data
);
1793 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1794 event
->message_type
, event
->data
.l
[0], event
->data
.l
[1],
1795 event
->data
.l
[2], event
->data
.l
[3], event
->data
.l
[4],
1798 TRACE("unrecognized ClientMessage\n" );
1803 /**********************************************************************
1806 * Install colormap when Wine window is focused in
1807 * self-managed mode with private colormap
1810 void EVENT_EnterNotify( HWND hWnd
, XCrossingEvent
*event
)
1812 if( !Options
.managed
&& X11DRV_GetXRootWindow() == DefaultRootWindow(display
) &&
1813 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE
) && GetFocus() )
1814 TSXInstallColormap( display
, X11DRV_PALETTE_GetColormap() );
1818 /**********************************************************************
1821 void EVENT_MapNotify( HWND hWnd
, XMapEvent
*event
)
1823 HWND hwndFocus
= GetFocus();
1824 WND
*wndFocus
= WIN_FindWndPtr(hwndFocus
);
1825 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
1826 if (pWnd
->flags
& WIN_MANAGED
)
1828 DCE_InvalidateDCE( pWnd
, &pWnd
->rectWindow
);
1829 pWnd
->dwStyle
&= ~WS_MINIMIZE
;
1830 pWnd
->dwStyle
|= WS_VISIBLE
;
1831 ShowOwnedPopups(hWnd
,TRUE
);
1833 WIN_ReleaseWndPtr(pWnd
);
1835 if (hwndFocus
&& IsChild( hWnd
, hwndFocus
))
1836 X11DRV_WND_SetFocus(wndFocus
);
1838 WIN_ReleaseWndPtr(wndFocus
);
1844 /**********************************************************************
1847 void EVENT_UnmapNotify( HWND hWnd
, XUnmapEvent
*event
)
1849 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
1850 if (pWnd
->flags
& WIN_MANAGED
)
1853 if( pWnd
->dwStyle
& WS_VISIBLE
)
1855 pWnd
->dwStyle
|= WS_MINIMIZE
;
1856 pWnd
->dwStyle
&= ~WS_VISIBLE
;
1857 ShowOwnedPopups(hWnd
,FALSE
);
1860 WIN_ReleaseWndPtr(pWnd
);
1863 /**********************************************************************
1864 * X11DRV_EVENT_SetInputMehod
1866 INPUT_TYPE
X11DRV_EVENT_SetInputMehod(INPUT_TYPE type
)
1868 INPUT_TYPE prev
= current_input_type
;
1870 /* Flag not used yet */
1871 in_transition
= FALSE
;
1872 current_input_type
= type
;
1877 #ifdef HAVE_LIBXXF86DGA2
1878 /**********************************************************************
1879 * X11DRV_EVENT_SetDGAStatus
1881 void X11DRV_EVENT_SetDGAStatus(HWND hwnd
, int event_base
)
1883 if (event_base
< 0) {
1889 DGAMotionEventType
= event_base
+ MotionNotify
;
1890 DGAButtonPressEventType
= event_base
+ ButtonPress
;
1891 DGAButtonReleaseEventType
= event_base
+ ButtonRelease
;
1892 DGAKeyPressEventType
= event_base
+ KeyPress
;
1893 DGAKeyReleaseEventType
= event_base
+ KeyRelease
;
1897 /* DGA2 event handlers */
1898 static void EVENT_DGAMotionEvent( XDGAMotionEvent
*event
)
1900 MOUSE_SendEvent( MOUSEEVENTF_MOVE
,
1901 event
->dx
, event
->dy
,
1902 X11DRV_EVENT_XStateToKeyState( event
->state
),
1903 event
->time
- MSG_WineStartTicks
,
1907 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent
*event
)
1909 static WORD statusCodes
[NB_BUTTONS
] =
1910 { MOUSEEVENTF_LEFTDOWN
, MOUSEEVENTF_MIDDLEDOWN
, MOUSEEVENTF_RIGHTDOWN
};
1911 int buttonNum
= event
->button
- 1;
1915 if (buttonNum
>= NB_BUTTONS
) return;
1917 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
1922 keystate
|= MK_LBUTTON
;
1925 keystate
|= MK_MBUTTON
;
1928 keystate
|= MK_RBUTTON
;
1932 MOUSE_SendEvent( statusCodes
[buttonNum
],
1935 event
->time
- MSG_WineStartTicks
,
1939 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent
*event
)
1941 static WORD statusCodes
[NB_BUTTONS
] =
1942 { MOUSEEVENTF_LEFTUP
, MOUSEEVENTF_MIDDLEUP
, MOUSEEVENTF_RIGHTUP
};
1943 int buttonNum
= event
->button
- 1;
1947 if (buttonNum
>= NB_BUTTONS
) return;
1949 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
1954 keystate
&= ~MK_LBUTTON
;
1957 keystate
&= ~MK_MBUTTON
;
1960 keystate
&= ~MK_RBUTTON
;
1964 MOUSE_SendEvent( statusCodes
[buttonNum
],
1967 event
->time
- MSG_WineStartTicks
,
1973 #ifdef HAVE_LIBXXSHM
1976 Normal XShm operation:
1978 X11 service thread app thread
1979 ------------- ----------------- ------------------------
1980 (idle) ddraw calls XShmPutImage
1981 (copies data) (waiting for shm_event)
1982 ShmCompletion -> (waiting for shm_event)
1983 (idle) signal shm_event ->
1984 (idle) returns to app
1986 However, this situation can occur for some reason:
1988 X11 service thread app thread
1989 ------------- ----------------- ------------------------
1992 (waiting for app) ddraw calls XShmPutImage
1993 (copies data) (waiting for app) (waiting for shm_event)
1994 ShmCompletion (waiting for app) (waiting for shm_event)
1995 (idle) DEADLOCK DEADLOCK
1997 which is why I also wait for shm_read and do XCheckTypedEvent()
1998 calls in the wait loop. This results in:
2000 X11 service thread app thread
2001 ------------- ----------------- ------------------------
2002 ShmCompletion (waiting for app) waking up on shm_read
2003 (idle) (waiting for app) XCheckTypedEvent() -> signal shm_event
2004 (waiting for app) returns
2014 /* FIXME: this is not pretty */
2015 static HANDLE shm_read
= 0;
2018 static volatile shm_qs shm_q
[SHM_MAX_Q
];
2020 static void EVENT_ShmCompletion( XShmCompletionEvent
*event
)
2024 TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event
->drawable
, GetTickCount() );
2026 for (n
=0; n
<SHM_MAX_Q
; n
++)
2027 if ((shm_q
[n
].draw
== event
->drawable
) && (shm_q
[n
].state
== 0)) {
2028 HANDLE sema
= shm_q
[n
].sema
;
2029 if (!InterlockedCompareExchange((PVOID
*)&shm_q
[n
].state
, (PVOID
)1, (PVOID
)0)) {
2030 ReleaseSemaphore(sema
, 1, NULL
);
2031 TRACE("Signaling ShmCompletion (#%d) (semaphore %x)\n", n
, sema
);
2036 ERR("Got ShmCompletion for unknown drawable %ld\n", event
->drawable
);
2039 int X11DRV_EVENT_PrepareShmCompletion( Drawable dw
)
2044 shm_read
= ConvertToGlobalHandle( FILE_DupUnixHandle( ConnectionNumber(display
), GENERIC_READ
| SYNCHRONIZE
) );
2046 for (n
=0; n
<SHM_MAX_Q
; n
++)
2048 if (!InterlockedCompareExchange((PVOID
*)&shm_q
[n
].draw
, (PVOID
)dw
, (PVOID
)0))
2052 ERR("Maximum number of outstanding ShmCompletions exceeded!\n");
2057 if (!shm_q
[n
].sema
) {
2058 shm_q
[n
].sema
= ConvertToGlobalHandle( CreateSemaphoreA( NULL
, 0, 256, NULL
) );
2059 TRACE("Allocated ShmCompletion slots have been increased to %d, new semaphore is %x\n", n
+1, shm_q
[n
].sema
);
2062 TRACE("Prepared ShmCompletion (#%d) wait for drawable %ld (thread %lx) (time %ld)\n", n
, dw
, GetCurrentThreadId(), GetTickCount() );
2066 static void X11DRV_EVENT_WaitReplaceShmCompletionInternal( int *compl, Drawable dw
, int creat
)
2072 if ((!n
) || (creat
&& (!shm_q
[n
-1].draw
))) {
2073 nn
= X11DRV_EVENT_PrepareShmCompletion(dw
);
2074 if (!(n
=(LONG
)InterlockedCompareExchange((PVOID
*)compl, (PVOID
)nn
, (PVOID
)n
)))
2076 /* race for compl lost, clear slot */
2077 shm_q
[nn
-1].draw
= 0;
2081 if (dw
&& (shm_q
[n
-1].draw
!= dw
)) {
2082 /* this shouldn't happen with the current ddraw implementation */
2083 FIXME("ShmCompletion replace with different drawable!\n");
2087 sema
= shm_q
[n
-1].sema
;
2089 /* nothing to wait on (PrepareShmCompletion not done yet?), so probably nothing to wait for */
2093 nn
= InterlockedExchangeAdd((PLONG
)&shm_q
[n
-1].waiter
, 1);
2094 if ((!shm_q
[n
-1].draw
) || (shm_q
[n
-1].state
== 2)) {
2095 /* too late, the wait was just cleared (wait complete) */
2096 TRACE("Wait skip for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n
-1, GetCurrentThreadId(), GetTickCount(), sema
);
2098 TRACE("Waiting for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n
-1, GetCurrentThreadId(), GetTickCount(), sema
);
2100 /* another thread is already waiting, let the primary waiter do the dirty work
2101 * (to avoid TSX critical section contention - that could get really slow) */
2102 WaitForSingleObject( sema
, INFINITE
);
2104 /* we're primary waiter - first check if it's already triggered */
2105 if ( WaitForSingleObject( sema
, 0 ) != WAIT_OBJECT_0
) {
2106 /* nope, may need to poll X event queue, in case the service thread is blocked */
2113 /* check X event queue */
2114 if (TSXCheckTypedEvent( display
, ShmCompletionType
, &event
)) {
2115 EVENT_ProcessEvent( &event
);
2117 } while ( WaitForMultipleObjects(2, hnd
, FALSE
, INFINITE
) > WAIT_OBJECT_0
);
2119 TRACE("Wait complete (thread %lx) (time %ld)\n", GetCurrentThreadId(), GetTickCount() );
2122 st
= InterlockedExchange((LPLONG
)&shm_q
[n
-1].state
, 2);
2124 /* first waiter to return, release all other waiters */
2125 nn
= shm_q
[n
-1].waiter
;
2126 TRACE("Signaling %ld additional ShmCompletion (#%d) waiter(s), semaphore %x\n", nn
-1, n
-1, sema
);
2127 ReleaseSemaphore(sema
, nn
-1, NULL
);
2130 nn
= InterlockedDecrement((LPLONG
)&shm_q
[n
-1].waiter
);
2132 /* last waiter to return, replace drawable and prepare new wait */
2133 shm_q
[n
-1].draw
= dw
;
2134 shm_q
[n
-1].state
= 0;
2138 void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw
)
2140 X11DRV_EVENT_WaitReplaceShmCompletionInternal( compl, dw
, 1 );
2143 void X11DRV_EVENT_WaitShmCompletion( int compl )
2146 X11DRV_EVENT_WaitReplaceShmCompletionInternal( &compl, 0, 0 );
2149 void X11DRV_EVENT_WaitShmCompletions( Drawable dw
)
2153 for (n
=0; n
<SHM_MAX_Q
; n
++)
2154 if (shm_q
[n
].draw
== dw
)
2155 X11DRV_EVENT_WaitShmCompletion( n
+1 );
2158 #endif /* defined(HAVE_LIBXXSHM) */
2160 #endif /* !defined(X_DISPLAY_MISSING) */