Add CF_UNICODETEXT as primary text clipboard format.
[wine/wine64.git] / windows / x11drv / event.c
blob99364a6d76ee7c156aafbccae5ced81f22c70314
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
6 */
8 #include "config.h"
10 #include <X11/Xatom.h>
11 #include <X11/keysym.h>
13 #include "ts_xlib.h"
14 #include "ts_xresource.h"
15 #include "ts_xutil.h"
16 #ifdef HAVE_LIBXXSHM
17 #include "ts_xshm.h"
18 #endif
19 #ifdef HAVE_LIBXXF86DGA2
20 #include "ts_xf86dga2.h"
21 #endif
23 #include <assert.h>
24 #include <string.h>
25 #include "wine/winuser16.h"
26 #include "shlobj.h" /* DROPFILES */
28 #include "clipboard.h"
29 #include "dce.h"
30 #include "debugtools.h"
31 #include "heap.h"
32 #include "input.h"
33 #include "keyboard.h"
34 #include "message.h"
35 #include "mouse.h"
36 #include "options.h"
37 #include "queue.h"
38 #include "win.h"
39 #include "winpos.h"
40 #include "services.h"
41 #include "file.h"
42 #include "windef.h"
43 #include "x11drv.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 */
63 #define DndUnknown 0
64 #define DndRawData 1
65 #define DndFile 2
66 #define DndFiles 3
67 #define DndText 4
68 #define DndDir 5
69 #define DndLink 6
70 #define DndExe 7
72 #define DndEND 8
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);
97 /* Event handlers */
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 );
115 #ifdef HAVE_LIBXXSHM
116 static void EVENT_ShmCompletion( XShmCompletionEvent *event );
117 static int ShmAvailable, ShmCompletionType;
118 extern int XShmGetEventBase( Display * );/* Missing prototype for function in libXext. */
119 #endif
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 );
134 #endif
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 /***********************************************************************
151 * EVENT_Init
153 BOOL X11DRV_EVENT_Init(void)
155 #ifdef HAVE_LIBXXSHM
156 ShmAvailable = XShmQueryExtension( display );
157 if (ShmAvailable) {
158 ShmCompletionType = XShmGetEventBase( display ) + ShmCompletion;
160 #endif
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 );
170 else
171 SERVICE_AddTimer( 200, EVENT_Flush, 0 );
173 return TRUE;
176 /***********************************************************************
177 * EVENT_Flush
179 static void CALLBACK EVENT_Flush( ULONG_PTR arg )
181 TSXFlush( display );
184 /***********************************************************************
185 * EVENT_ProcessAllEvents
187 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
189 XEvent event;
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 /***********************************************************************
206 * X11DRV_Synchronize
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 /***********************************************************************
225 * EVENT_ProcessEvent
227 * Process an X event.
229 static void EVENT_ProcessEvent( XEvent *event )
231 HWND hWnd;
233 TRACE( "called.\n" );
235 switch (event->type)
237 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
238 FIXME("Got SelectionNotify - must not happen!\n");
239 /* fall through */
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
244 been deleted ... */
245 case CirculateNotify:
246 case CreateNotify:
247 case DestroyNotify:
248 case GravityNotify:
249 case ReparentNotify:
250 return;
253 #ifdef HAVE_LIBXXSHM
254 if (ShmAvailable && (event->type == ShmCompletionType)) {
255 EVENT_ShmCompletion( (XShmCompletionEvent*)event );
256 return;
258 #endif
260 #ifdef HAVE_LIBXXF86DGA2
261 if (DGAUsed) {
262 if (event->type == DGAMotionEventType) {
263 TRACE("DGAMotionEvent received.\n");
264 EVENT_DGAMotionEvent((XDGAMotionEvent *) event);
265 return;
267 if (event->type == DGAButtonPressEventType) {
268 TRACE("DGAButtonPressEvent received.\n");
269 EVENT_DGAButtonPressEvent((XDGAButtonEvent *) event);
270 return;
272 if (event->type == DGAButtonReleaseEventType) {
273 TRACE("DGAButtonReleaseEvent received.\n");
274 EVENT_DGAButtonReleaseEvent((XDGAButtonEvent *) event);
275 return;
277 if ((event->type == DGAKeyPressEventType) ||
278 (event->type == DGAKeyReleaseEventType)) {
279 /* Fill a XKeyEvent to send to EVENT_Key */
280 XKeyEvent ke;
281 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
283 TRACE("DGAKeyPress/ReleaseEvent received.\n");
285 if (evt->type == DGAKeyReleaseEventType)
286 ke.type = KeyRelease;
287 else
288 ke.type = KeyPress;
289 ke.serial = evt->serial;
290 ke.send_event = FALSE;
291 ke.display = evt->display;
292 ke.window = 0;
293 ke.root = 0;
294 ke.subwindow = 0;
295 ke.time = evt->time;
296 ke.x = PosX;
297 ke.y = PosY;
298 ke.x_root = -1;
299 ke.y_root = -1;
300 ke.state = evt->state;
301 ke.keycode = evt->keycode;
302 ke.same_screen = TRUE;
304 X11DRV_KEYBOARD_HandleEvent(NULL, &ke);
305 return;
308 #endif
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) */
314 Window root, child;
315 int root_x, root_y, child_x, child_y;
316 unsigned u;
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)
320 return;
321 } else {
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 );
331 else
332 TRACE("Got event %s for hwnd %04x\n",
333 event_names[event->type], hWnd );
335 switch(event->type)
337 case KeyPress:
338 case KeyRelease:
339 EVENT_Key( hWnd, (XKeyEvent*)event );
340 break;
342 case ButtonPress:
343 EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
344 break;
346 case ButtonRelease:
347 EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
348 break;
350 case MotionNotify:
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 );
365 break;
367 case FocusIn:
369 WND *pWndLastFocus = 0;
370 XWindowAttributes win_attr;
371 BOOL bIsDisabled;
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
381 * in a modal state.
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 );
393 EVENT_Synchronize();
394 break;
399 EVENT_FocusIn( hWnd, xfocChange );
400 break;
403 case FocusOut:
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 );
411 break;
414 case Expose:
415 if (bUserRepaintDisabled) return;
416 EVENT_Expose( hWnd, (XExposeEvent *)event );
417 break;
419 case GraphicsExpose:
420 if (bUserRepaintDisabled) return;
421 EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
422 break;
424 case ConfigureNotify:
425 if (!hWnd || bUserRepaintDisabled) return;
426 EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
427 break;
429 case SelectionRequest:
430 if (!hWnd || bUserRepaintDisabled) return;
431 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
432 break;
434 case SelectionClear:
435 if (!hWnd || bUserRepaintDisabled) return;
436 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
437 break;
439 case PropertyNotify:
440 EVENT_PropertyNotify( (XPropertyEvent *)event );
441 break;
443 case ClientMessage:
444 if (!hWnd || bUserRepaintDisabled) return;
445 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
446 break;
448 #if 0
449 case EnterNotify:
450 EVENT_EnterNotify( hWnd, (XCrossingEvent *) event );
451 break;
452 #endif
454 case NoExpose:
455 break;
457 case MapNotify:
458 if (!hWnd || bUserRepaintDisabled) return;
459 EVENT_MapNotify( hWnd, (XMapEvent *)event );
460 break;
462 case UnmapNotify:
463 if (!hWnd || bUserRepaintDisabled) return;
464 EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
465 break;
467 case MappingNotify:
468 EVENT_MappingNotify( (XMappingEvent *) event );
469 break;
471 default:
472 WARN("Unprocessed event %s for hwnd %04x\n",
473 event_names[event->type], hWnd );
474 break;
476 TRACE( "returns.\n" );
479 /***********************************************************************
480 * EVENT_QueryZOrder
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;
491 if( *pWndA )
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;
504 unsigned totalB;
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 );
514 if( A && B )
516 TSXQueryTree( display, A, &root, &B, children, total );
517 return A;
519 return 0 ;
522 static Window __get_top_decoration( Window w, Window ancestor )
524 Window* children, root, prev = w, parent = w;
525 unsigned total;
529 w = parent;
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 )
539 unsigned i;
540 for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
541 return i;
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),
567 &children, &total );
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 );
578 best = 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 )) )
588 continue;
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... */
594 best = pos;
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 )
617 int kstate = 0;
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;
624 return kstate;
627 /***********************************************************************
628 * EVENT_Expose
630 static void EVENT_Expose( HWND hWnd, XExposeEvent *event )
632 RECT rect;
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 )
663 RECT rect;
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 /***********************************************************************
687 * EVENT_Key
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 /***********************************************************************
701 * EVENT_MotionNotify
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);
715 } else {
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 /***********************************************************************
725 * EVENT_ButtonPress
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
749 * pressed is "down".
751 switch (buttonNum)
753 case 0:
754 keystate |= MK_LBUTTON;
755 break;
756 case 1:
757 keystate |= MK_MBUTTON;
758 break;
759 case 2:
760 keystate |= MK_RBUTTON;
761 break;
762 case 3:
763 wData = WHEEL_DELTA;
764 break;
765 case 4:
766 wData = -WHEEL_DELTA;
767 break;
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;
788 WORD keystate;
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
801 * released is "up".
803 switch (buttonNum)
805 case 0:
806 keystate &= ~MK_LBUTTON;
807 break;
808 case 1:
809 keystate &= ~MK_MBUTTON;
810 break;
811 case 2:
812 keystate &= ~MK_RBUTTON;
813 break;
814 default:
815 return;
818 X11DRV_SendEvent( statusCodes[buttonNum],
819 xOffset + event->x, yOffset + event->y,
820 keystate, event->time - X11DRV_server_startticks, hWnd);
824 /**********************************************************************
825 * EVENT_FocusIn
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 /**********************************************************************
839 * EVENT_FocusOut
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 /**********************************************************************
867 * X11DRV_CheckFocus
869 BOOL X11DRV_CheckFocus(void)
871 HWND hWnd;
872 Window xW;
873 int state;
875 TSXGetInputFocus(display, &xW, &state);
876 if( xW == None ||
877 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
878 return FALSE;
879 return TRUE;
882 /**********************************************************************
883 * EVENT_GetGeometry
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 )
891 Window root, top;
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,
898 &border, &depth );
900 /* Translate the window origin to root coordinates */
901 XTranslateCoordinates( display, win, root, 0, 0, &x, &y, &top );
903 LeaveCriticalSection( &X11DRV_CritSection );
905 *px = x;
906 *py = y;
907 *pwidth = width;
908 *pheight = height;
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 )
919 RECT rectWindow;
920 int x, y, flags = 0;
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;
935 for (;;)
937 oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
938 if (!oldInsertAfter)
940 oldInsertAfter = HWND_TOP;
941 break;
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 )
950 flags |= SWP_NOMOVE;
951 else
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 )
957 flags |= SWP_NOSIZE;
958 else
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;
965 else
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);
984 Atom* targets;
985 Atom prop;
986 UINT wFormat;
987 unsigned long cTargets;
988 BOOL bHavePixmap;
989 int xRc;
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) )
999 cTargets++;
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 */
1013 int i;
1014 BOOL bExists;
1015 for (i = 0, bExists = FALSE; i < cTargets; i++)
1017 if (targets[i] == prop)
1019 bExists = TRUE;
1020 break;
1023 if (!bExists)
1025 targets[cTargets++] = prop;
1027 /* Add PIXMAP prop for bitmaps additionally */
1028 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
1029 && !bHavePixmap )
1031 targets[cTargets++] = XA_PIXMAP;
1032 bHavePixmap = TRUE;
1038 if (TRACE_ON(event))
1040 int i;
1041 for ( i = 0; i < cTargets; i++)
1043 if (targets[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 );
1064 return rprop;
1068 /***********************************************************************
1069 * EVENT_SelectionRequest_STRING
1070 * Service a STRING selection request event
1072 static Atom EVENT_SelectionRequest_STRING( Window requestor, Atom target, Atom rprop )
1074 static UINT text_cp = (UINT)-1;
1075 HANDLE hUnicodeText;
1076 LPWSTR uni_text;
1077 LPSTR text;
1078 int size,i,j;
1079 char* lpstr = 0;
1080 char *itemFmtName;
1081 int xRc;
1083 if(text_cp == (UINT)-1)
1084 text_cp = PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP);
1087 * Map the requested X selection property type atom name to a
1088 * windows clipboard format ID.
1090 itemFmtName = TSXGetAtomName(display, target);
1091 TRACE("Request for %s (wFormat=%x %s)\n",
1092 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT));
1093 TSXFree(itemFmtName);
1095 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
1096 if(!hUnicodeText)
1097 return None;
1098 uni_text = GlobalLock(hUnicodeText);
1099 if(!uni_text)
1100 return None;
1102 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
1103 text = HeapAlloc(GetProcessHeap(), 0, size);
1104 if (!text)
1105 return None;
1106 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
1108 /* remove carriage returns */
1110 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
1111 if(lpstr == NULL) return None;
1112 for(i=0,j=0; i < size && text[i]; i++ )
1114 if( text[i] == '\r' &&
1115 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1116 lpstr[j++] = text[i];
1118 lpstr[j]='\0';
1120 /* Update the X property */
1121 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
1122 xRc = TSXChangeProperty(display, requestor, rprop,
1123 XA_STRING, 8, PropModeReplace,
1124 lpstr, j);
1125 TRACE("(Rc=%d)\n", xRc);
1127 GlobalUnlock(hUnicodeText);
1128 HeapFree(GetProcessHeap(), 0, text);
1129 HeapFree( GetProcessHeap(), 0, lpstr );
1131 return rprop;
1134 /***********************************************************************
1135 * EVENT_SelectionRequest_PIXMAP
1136 * Service a PIXMAP selection request event
1138 static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
1140 HANDLE hClipData = 0;
1141 Pixmap pixmap = 0;
1142 UINT wFormat;
1143 char * itemFmtName;
1144 int xRc;
1145 #if(0)
1146 XSetWindowAttributes win_attr;
1147 XWindowAttributes win_attr_src;
1148 #endif
1151 * Map the requested X selection property type atom name to a
1152 * windows clipboard format ID.
1154 itemFmtName = TSXGetAtomName(display, target);
1155 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1156 TRACE("Request for %s (wFormat=%x %s)\n",
1157 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1158 TSXFree(itemFmtName);
1160 hClipData = GetClipboardData(wFormat);
1161 if ( !hClipData )
1163 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
1164 rprop = None; /* Fail the request */
1165 goto END;
1168 if (wFormat == CF_DIB)
1170 HWND hwnd = GetOpenClipboardWindow();
1171 HDC hdc = GetDC(hwnd);
1173 /* For convert from packed DIB to Pixmap */
1174 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
1176 ReleaseDC(hdc, hwnd);
1178 else if (wFormat == CF_BITMAP)
1180 HWND hwnd = GetOpenClipboardWindow();
1181 HDC hdc = GetDC(hwnd);
1183 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
1185 ReleaseDC(hdc, hwnd);
1187 else
1189 FIXME("%s to PIXMAP conversion not yet implemented!\n",
1190 CLIPBOARD_GetFormatName(wFormat));
1191 rprop = None;
1192 goto END;
1195 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
1196 TSXGetAtomName(display, rprop), (long)requestor,
1197 TSXGetAtomName(display, target), pixmap);
1199 /* Store the Pixmap handle in the property */
1200 xRc = TSXChangeProperty(display, requestor, rprop, target,
1201 32, PropModeReplace,
1202 (unsigned char *)&pixmap, 1);
1203 TRACE("(Rc=%d)\n", xRc);
1205 /* Enable the code below if you want to handle destroying Pixmap resources
1206 * in response to property notify events. Clients like XPaint don't
1207 * appear to be duplicating Pixmaps so they don't like us deleting,
1208 * the resource in response to the property being deleted.
1210 #if(0)
1211 /* Express interest in property notify events so that we can delete the
1212 * pixmap when the client deletes the property atom.
1214 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
1215 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
1216 (long)requestor);
1217 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
1218 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
1220 /* Register the Pixmap we created with the request property Atom.
1221 * When this property is destroyed we also destroy the Pixmap in
1222 * response to the PropertyNotify event.
1224 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
1225 #endif
1227 END:
1228 return rprop;
1232 /***********************************************************************
1233 * EVENT_SelectionRequest_WCF
1234 * Service a Wine Clipboard Format selection request event.
1235 * For <WCF>* data types we simply copy the data to X without conversion.
1237 static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
1239 HANDLE hClipData = 0;
1240 void* lpClipData;
1241 UINT wFormat;
1242 char * itemFmtName;
1243 int cBytes;
1244 int xRc;
1247 * Map the requested X selection property type atom name to a
1248 * windows clipboard format ID.
1250 itemFmtName = TSXGetAtomName(display, target);
1251 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1252 TRACE("Request for %s (wFormat=%x %s)\n",
1253 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1254 TSXFree(itemFmtName);
1256 hClipData = GetClipboardData16(wFormat);
1258 if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
1260 cBytes = GlobalSize16(hClipData);
1262 TRACE("\tUpdating property %s, %d bytes...\n",
1263 TSXGetAtomName(display, rprop), cBytes);
1265 xRc = TSXChangeProperty(display, requestor, rprop,
1266 target, 8, PropModeReplace,
1267 (unsigned char *)lpClipData, cBytes);
1268 TRACE("(Rc=%d)\n", xRc);
1270 GlobalUnlock16(hClipData);
1272 else
1274 TRACE("\tCould not retrieve native format!\n");
1275 rprop = None; /* Fail the request */
1278 return rprop;
1282 /***********************************************************************
1283 * EVENT_SelectionRequest_MULTIPLE
1284 * Service a MULTIPLE selection request event
1285 * rprop contains a list of (target,property) atom pairs.
1286 * The first atom names a target and the second names a property.
1287 * The effect is as if we have received a sequence of SelectionRequest events
1288 * (one for each atom pair) except that:
1289 * 1. We reply with a SelectionNotify only when all the requested conversions
1290 * have been performed.
1291 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1292 * we replace the atom in the property by None.
1294 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
1296 Atom rprop;
1297 Atom atype=AnyPropertyType;
1298 int aformat;
1299 unsigned long remain;
1300 Atom* targetPropList=NULL;
1301 unsigned long cTargetPropList = 0;
1302 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1304 /* If the specified property is None the requestor is an obsolete client.
1305 * We support these by using the specified target atom as the reply property.
1307 rprop = pevent->property;
1308 if( rprop == None )
1309 rprop = pevent->target;
1310 if (!rprop)
1311 goto END;
1313 /* Read the MULTIPLE property contents. This should contain a list of
1314 * (target,property) atom pairs.
1316 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
1317 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
1318 &cTargetPropList, &remain,
1319 (unsigned char**)&targetPropList) != Success)
1320 TRACE("\tCouldn't read MULTIPLE property\n");
1321 else
1323 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1324 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
1327 * Make sure we got what we expect.
1328 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1329 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1330 * However some X apps(such as XPaint) are not compliant with this and return
1331 * a user defined atom in atype when XGetWindowProperty is called.
1332 * The data *is* an atom pair but is not denoted as such.
1334 if(aformat == 32 /* atype == xAtomPair */ )
1336 int i;
1338 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1339 * for each (target,property) pair */
1341 for (i = 0; i < cTargetPropList; i+=2)
1343 char *targetName = TSXGetAtomName(display, targetPropList[i]);
1344 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
1345 XSelectionRequestEvent event;
1347 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
1348 i/2, targetName, propName);
1349 TSXFree(targetName);
1350 TSXFree(propName);
1352 /* We must have a non "None" property to service a MULTIPLE target atom */
1353 if ( !targetPropList[i+1] )
1355 TRACE("\tMULTIPLE(%d): Skipping target with empty property!", i);
1356 continue;
1359 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1360 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
1361 event.target = targetPropList[i];
1362 event.property = targetPropList[i+1];
1364 /* Fire a SelectionRequest, informing the handler that we are processing
1365 * a MULTIPLE selection request event.
1367 EVENT_SelectionRequest( hWnd, &event, TRUE );
1371 /* Free the list of targets/properties */
1372 TSXFree(targetPropList);
1375 END:
1376 return rprop;
1380 /***********************************************************************
1381 * EVENT_SelectionRequest
1382 * Process an event selection request event.
1383 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1384 * recursively while servicing a "MULTIPLE" selection target.
1386 * Note: We only receive this event when WINE owns the X selection
1388 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1390 XSelectionEvent result;
1391 Atom rprop = None;
1392 Window request = event->requestor;
1393 BOOL couldOpen = FALSE;
1394 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1395 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
1396 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1399 * We can only handle the selection request if :
1400 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1401 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1402 * since this has been already done.
1404 if ( !bIsMultiple )
1406 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1407 || !(couldOpen = OpenClipboard(hWnd)) )
1408 goto END;
1411 /* If the specified property is None the requestor is an obsolete client.
1412 * We support these by using the specified target atom as the reply property.
1414 rprop = event->property;
1415 if( rprop == None )
1416 rprop = event->target;
1418 if(event->target == xaTargets) /* Return a list of all supported targets */
1420 /* TARGETS selection request */
1421 rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
1423 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1425 /* MULTIPLE selection request */
1426 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1428 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1430 /* XA_STRING selection request */
1431 rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
1433 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1435 /* XA_PIXMAP selection request */
1436 rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
1438 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1440 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1441 rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
1443 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1445 /* All <WCF> selection requests */
1446 rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
1448 else
1449 rprop = None; /* Don't support this format */
1451 END:
1452 /* close clipboard only if we opened before */
1453 if(couldOpen) CloseClipboard();
1455 if( rprop == None)
1456 TRACE("\tRequest ignored\n");
1458 /* reply to sender
1459 * SelectionNotify should be sent only at the end of a MULTIPLE request
1461 if ( !bIsMultiple )
1463 result.type = SelectionNotify;
1464 result.display = display;
1465 result.requestor = request;
1466 result.selection = event->selection;
1467 result.property = rprop;
1468 result.target = event->target;
1469 result.time = event->time;
1470 TRACE("Sending SelectionNotify event...\n");
1471 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1475 /***********************************************************************
1476 * EVENT_SelectionClear
1478 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1480 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1482 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1483 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1486 /***********************************************************************
1487 * EVENT_PropertyNotify
1488 * We use this to release resources like Pixmaps when a selection
1489 * client no longer needs them.
1491 static void EVENT_PropertyNotify( XPropertyEvent *event )
1493 /* Check if we have any resources to free */
1494 TRACE("Received PropertyNotify event: ");
1496 switch(event->state)
1498 case PropertyDelete:
1500 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1501 TSXGetAtomName(event->display, event->atom), (long)event->window);
1503 if (X11DRV_IsSelectionOwner())
1504 X11DRV_CLIPBOARD_FreeResources( event->atom );
1505 break;
1508 case PropertyNewValue:
1510 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1511 TSXGetAtomName(event->display, event->atom), (long)event->window);
1512 break;
1515 default:
1516 break;
1520 /**********************************************************************
1521 * EVENT_DropFromOffix
1523 * don't know if it still works (last Changlog is from 96/11/04)
1525 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1527 unsigned long data_length;
1528 unsigned long aux_long;
1529 unsigned char* p_data = NULL;
1530 union {
1531 Atom atom_aux;
1532 struct {
1533 int x;
1534 int y;
1535 } pt_aux;
1536 int i;
1537 } u;
1538 int x, y;
1539 BOOL16 bAccept;
1540 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO16));
1541 LPDRAGINFO16 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
1542 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1543 Window w_aux_root, w_aux_child;
1544 WND* pDropWnd;
1545 WND* pWnd;
1547 if( !lpDragInfo || !spDragInfo ) return;
1549 pWnd = WIN_FindWndPtr(hWnd);
1551 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
1552 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1553 (unsigned int*)&aux_long);
1555 lpDragInfo->hScope = hWnd;
1556 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1558 /* find out drop point and drop window */
1559 if( x < 0 || y < 0 ||
1560 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1561 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1562 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1563 else
1565 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1566 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1568 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1569 WIN_ReleaseWndPtr(pWnd);
1571 GlobalFree16( hDragInfo );
1573 if( bAccept )
1575 TSXGetWindowProperty( display, DefaultRootWindow(display),
1576 dndSelection, 0, 65535, FALSE,
1577 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1578 &data_length, &aux_long, &p_data);
1580 if( !aux_long && p_data) /* don't bother if > 64K */
1582 char *p = (char*) p_data;
1583 char *p_drop;
1585 aux_long = 0;
1586 while( *p ) /* calculate buffer size */
1588 p_drop = p;
1589 if((u.i = *p) != -1 )
1591 INT len = GetShortPathNameA( p, NULL, 0 );
1592 if (len) aux_long += len + 1;
1593 else *p = -1;
1595 p += strlen(p) + 1;
1597 if( aux_long && aux_long < 65535 )
1599 HDROP hDrop;
1600 DROPFILES *lpDrop;
1602 aux_long += sizeof(DROPFILES) + 1;
1603 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1604 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1606 if( lpDrop )
1608 lpDrop->pFiles = sizeof(DROPFILES);
1609 lpDrop->pt.x = x;
1610 lpDrop->pt.y = y;
1611 lpDrop->fNC =
1612 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1613 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1614 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1615 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1616 lpDrop->fWide = FALSE;
1617 p_drop = (char *)(lpDrop + 1);
1618 p = p_data;
1619 while(*p)
1621 if( *p != -1 ) /* use only "good" entries */
1623 GetShortPathNameA( p, p_drop, 65535 );
1624 p_drop += strlen( p_drop ) + 1;
1626 p += strlen(p) + 1;
1628 *p_drop = '\0';
1629 PostMessageA( hWnd, WM_DROPFILES, hDrop, 0L );
1633 if( p_data ) TSXFree(p_data);
1635 } /* WS_EX_ACCEPTFILES */
1637 WIN_ReleaseWndPtr(pDropWnd);
1640 /**********************************************************************
1641 * EVENT_DropURLs
1643 * drop items are separated by \n
1644 * each item is prefixed by its mime type
1646 * event->data.l[3], event->data.l[4] contains drop x,y position
1648 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1650 WND *pDropWnd;
1651 WND *pWnd;
1652 unsigned long data_length;
1653 unsigned long aux_long, drop_len = 0;
1654 unsigned char *p_data = NULL; /* property data */
1655 char *p_drop = NULL;
1656 char *p, *next;
1657 int x, y;
1658 DROPFILES *lpDrop;
1659 HDROP hDrop;
1660 union {
1661 Atom atom_aux;
1662 int i;
1663 Window w_aux;
1664 } u; /* unused */
1666 pWnd = WIN_FindWndPtr(hWnd);
1668 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1670 WIN_ReleaseWndPtr(pWnd);
1671 return;
1673 WIN_ReleaseWndPtr(pWnd);
1675 TSXGetWindowProperty( display, DefaultRootWindow(display),
1676 dndSelection, 0, 65535, FALSE,
1677 AnyPropertyType, &u.atom_aux, &u.i,
1678 &data_length, &aux_long, &p_data);
1679 if (aux_long)
1680 WARN("property too large, truncated!\n");
1681 TRACE("urls=%s\n", p_data);
1683 if( !aux_long && p_data) { /* don't bother if > 64K */
1684 /* calculate length */
1685 p = p_data;
1686 next = strchr(p, '\n');
1687 while (p) {
1688 if (next) *next=0;
1689 if (strncmp(p,"file:",5) == 0 ) {
1690 INT len = GetShortPathNameA( p+5, NULL, 0 );
1691 if (len) drop_len += len + 1;
1693 if (next) {
1694 *next = '\n';
1695 p = next + 1;
1696 next = strchr(p, '\n');
1697 } else {
1698 p = NULL;
1702 if( drop_len && drop_len < 65535 ) {
1703 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
1704 &x, &y, &u.i, &u.i, &u.i);
1706 pDropWnd = WIN_FindWndPtr( hWnd );
1708 drop_len += sizeof(DROPFILES) + 1;
1709 hDrop = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
1710 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1712 if( lpDrop ) {
1713 lpDrop->pFiles = sizeof(DROPFILES);
1714 lpDrop->pt.x = (INT)x;
1715 lpDrop->pt.y = (INT)y;
1716 lpDrop->fNC =
1717 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1718 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1719 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1720 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1721 lpDrop->fWide = FALSE;
1722 p_drop = (char*)(lpDrop + 1);
1725 /* create message content */
1726 if (p_drop) {
1727 p = p_data;
1728 next = strchr(p, '\n');
1729 while (p) {
1730 if (next) *next=0;
1731 if (strncmp(p,"file:",5) == 0 ) {
1732 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1733 if (len) {
1734 TRACE("drop file %s as %s\n", p+5, p_drop);
1735 p_drop += len+1;
1736 } else {
1737 WARN("can't convert file %s to dos name \n", p+5);
1739 } else {
1740 WARN("unknown mime type %s\n", p);
1742 if (next) {
1743 *next = '\n';
1744 p = next + 1;
1745 next = strchr(p, '\n');
1746 } else {
1747 p = NULL;
1749 *p_drop = '\0';
1752 GlobalUnlock(hDrop);
1753 PostMessageA( hWnd, WM_DROPFILES, hDrop, 0L );
1755 WIN_ReleaseWndPtr(pDropWnd);
1757 if( p_data ) TSXFree(p_data);
1761 /**********************************************************************
1762 * EVENT_ClientMessage
1764 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1766 if (event->message_type != None && event->format == 32) {
1767 if ((event->message_type == wmProtocols) &&
1768 (((Atom) event->data.l[0]) == wmDeleteWindow))
1770 /* Ignore the delete window request if the window has been disabled
1771 * and we are in managed mode. This is to disallow applications from
1772 * being closed by the window manager while in a modal state.
1774 BOOL bIsDisabled;
1775 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
1777 if ( !Options.managed || !bIsDisabled )
1778 PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1780 else if ( event->message_type == dndProtocol &&
1781 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1782 EVENT_DropFromOffiX(hWnd, event);
1783 else if ( event->message_type == dndProtocol &&
1784 event->data.l[0] == DndURL )
1785 EVENT_DropURLs(hWnd, event);
1786 else {
1787 #if 0
1788 /* enable this if you want to see the message */
1789 unsigned char* p_data = NULL;
1790 union {
1791 unsigned long l;
1792 int i;
1793 Atom atom;
1794 } u; /* unused */
1795 TSXGetWindowProperty( display, DefaultRootWindow(display),
1796 dndSelection, 0, 65535, FALSE,
1797 AnyPropertyType, &u.atom, &u.i,
1798 &u.l, &u.l, &p_data);
1799 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1800 event->message_type, event->data.l[0], event->data.l[1],
1801 event->data.l[2], event->data.l[3], event->data.l[4],
1802 p_data);
1803 #endif
1804 TRACE("unrecognized ClientMessage\n" );
1809 /**********************************************************************
1810 * EVENT_EnterNotify
1812 * Install colormap when Wine window is focused in
1813 * self-managed mode with private colormap
1815 #if 0
1816 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
1818 if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1819 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1820 TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
1822 #endif
1824 /**********************************************************************
1825 * EVENT_MapNotify
1827 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1829 HWND hwndFocus = GetFocus();
1830 WND *wndFocus = WIN_FindWndPtr(hwndFocus);
1831 WND *pWnd = WIN_FindWndPtr(hWnd);
1832 if (pWnd && (pWnd->dwExStyle & WS_EX_MANAGED))
1834 DCE_InvalidateDCE( pWnd, &pWnd->rectWindow );
1835 pWnd->dwStyle &= ~WS_MINIMIZE;
1836 pWnd->dwStyle |= WS_VISIBLE;
1837 WIN_InternalShowOwnedPopups(hWnd,TRUE,TRUE);
1839 WIN_ReleaseWndPtr(pWnd);
1841 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1842 X11DRV_WND_SetFocus(wndFocus);
1844 WIN_ReleaseWndPtr(wndFocus);
1846 return;
1850 /**********************************************************************
1851 * EVENT_UnmapNotify
1853 void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
1855 WND *pWnd = WIN_FindWndPtr(hWnd);
1856 if (pWnd && (pWnd->dwExStyle & WS_EX_MANAGED))
1858 EndMenu();
1859 if( pWnd->dwStyle & WS_VISIBLE )
1861 pWnd->dwStyle |= WS_MINIMIZE;
1862 pWnd->dwStyle &= ~WS_VISIBLE;
1863 WIN_InternalShowOwnedPopups(hWnd,FALSE,TRUE);
1866 WIN_ReleaseWndPtr(pWnd);
1869 /***********************************************************************
1870 * EVENT_MappingNotify
1872 static void EVENT_MappingNotify( XMappingEvent *event )
1874 TSXRefreshKeyboardMapping(event);
1876 /* reinitialize Wine-X11 driver keyboard table */
1877 X11DRV_InitKeyboard();
1881 /**********************************************************************
1882 * X11DRV_EVENT_SetInputMethod
1884 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1886 INPUT_TYPE prev = current_input_type;
1888 /* Flag not used yet */
1889 in_transition = FALSE;
1890 current_input_type = type;
1892 return prev;
1895 #ifdef HAVE_LIBXXF86DGA2
1896 /**********************************************************************
1897 * X11DRV_EVENT_SetDGAStatus
1899 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1901 if (event_base < 0) {
1902 DGAUsed = FALSE;
1903 DGAhwnd = 0;
1904 } else {
1905 DGAUsed = TRUE;
1906 DGAhwnd = hwnd;
1907 DGAMotionEventType = event_base + MotionNotify;
1908 DGAButtonPressEventType = event_base + ButtonPress;
1909 DGAButtonReleaseEventType = event_base + ButtonRelease;
1910 DGAKeyPressEventType = event_base + KeyPress;
1911 DGAKeyReleaseEventType = event_base + KeyRelease;
1915 /* DGA2 event handlers */
1916 static void EVENT_DGAMotionEvent( XDGAMotionEvent *event )
1918 X11DRV_SendEvent( MOUSEEVENTF_MOVE,
1919 event->dx, event->dy,
1920 X11DRV_EVENT_XStateToKeyState( event->state ),
1921 event->time - X11DRV_server_startticks, DGAhwnd );
1924 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent *event )
1926 static WORD statusCodes[NB_BUTTONS] =
1927 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
1928 int buttonNum = event->button - 1;
1930 WORD keystate;
1932 if (buttonNum >= NB_BUTTONS) return;
1934 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1936 switch (buttonNum)
1938 case 0:
1939 keystate |= MK_LBUTTON;
1940 break;
1941 case 1:
1942 keystate |= MK_MBUTTON;
1943 break;
1944 case 2:
1945 keystate |= MK_RBUTTON;
1946 break;
1949 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time - X11DRV_server_startticks, DGAhwnd );
1952 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent *event )
1954 static WORD statusCodes[NB_BUTTONS] =
1955 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
1956 int buttonNum = event->button - 1;
1958 WORD keystate;
1960 if (buttonNum >= NB_BUTTONS) return;
1962 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1964 switch (buttonNum)
1966 case 0:
1967 keystate &= ~MK_LBUTTON;
1968 break;
1969 case 1:
1970 keystate &= ~MK_MBUTTON;
1971 break;
1972 case 2:
1973 keystate &= ~MK_RBUTTON;
1974 break;
1977 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time - X11DRV_server_startticks, DGAhwnd );
1980 #endif
1982 #ifdef HAVE_LIBXXSHM
1985 Normal XShm operation:
1987 X11 service thread app thread
1988 ------------- ----------------- ------------------------
1989 (idle) ddraw calls XShmPutImage
1990 (copies data) (waiting for shm_event)
1991 ShmCompletion -> (waiting for shm_event)
1992 (idle) signal shm_event ->
1993 (idle) returns to app
1995 However, this situation can occur for some reason:
1997 X11 service thread app thread
1998 ------------- ----------------- ------------------------
1999 Expose ->
2000 WM_ERASEBKGND? ->
2001 (waiting for app) ddraw calls XShmPutImage
2002 (copies data) (waiting for app) (waiting for shm_event)
2003 ShmCompletion (waiting for app) (waiting for shm_event)
2004 (idle) DEADLOCK DEADLOCK
2006 which is why I also wait for shm_read and do XCheckTypedEvent()
2007 calls in the wait loop. This results in:
2009 X11 service thread app thread
2010 ------------- ----------------- ------------------------
2011 ShmCompletion (waiting for app) waking up on shm_read
2012 (idle) (waiting for app) XCheckTypedEvent() -> signal shm_event
2013 (waiting for app) returns
2014 (idle)
2017 typedef struct {
2018 Drawable draw;
2019 LONG state, waiter;
2020 HANDLE sema;
2021 } shm_qs;
2023 /* FIXME: this is not pretty */
2024 static HANDLE shm_read = 0;
2026 #define SHM_MAX_Q 4
2027 static volatile shm_qs shm_q[SHM_MAX_Q];
2029 static void EVENT_ShmCompletion( XShmCompletionEvent *event )
2031 int n;
2033 TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event->drawable, GetTickCount() );
2035 for (n=0; n<SHM_MAX_Q; n++)
2036 if ((shm_q[n].draw == event->drawable) && (shm_q[n].state == 0)) {
2037 HANDLE sema = shm_q[n].sema;
2038 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].state, (PVOID)1, (PVOID)0)) {
2039 ReleaseSemaphore(sema, 1, NULL);
2040 TRACE("Signaling ShmCompletion (#%d) (semaphore %x)\n", n, sema);
2042 return;
2045 ERR("Got ShmCompletion for unknown drawable %ld\n", event->drawable );
2048 int X11DRV_EVENT_PrepareShmCompletion( Drawable dw )
2050 int n;
2052 if (!shm_read)
2053 shm_read = FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE );
2055 for (n=0; n<SHM_MAX_Q; n++)
2056 if (!shm_q[n].draw)
2057 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].draw, (PVOID)dw, (PVOID)0))
2058 break;
2060 if (n>=SHM_MAX_Q) {
2061 ERR("Maximum number of outstanding ShmCompletions exceeded!\n");
2062 return 0;
2065 shm_q[n].state = 0;
2066 if (!shm_q[n].sema) {
2067 shm_q[n].sema = CreateSemaphoreA( NULL, 0, 256, NULL );
2068 TRACE("Allocated ShmCompletion slots have been increased to %d, new semaphore is %x\n", n+1, shm_q[n].sema);
2071 TRACE("Prepared ShmCompletion (#%d) wait for drawable %ld (thread %lx) (time %ld)\n", n, dw, GetCurrentThreadId(), GetTickCount() );
2072 return n+1;
2075 static void X11DRV_EVENT_WaitReplaceShmCompletionInternal( int *compl, Drawable dw, int creat )
2077 int n = *compl;
2078 LONG nn, st;
2079 HANDLE sema;
2081 if ((!n) || (creat && (!shm_q[n-1].draw))) {
2082 nn = X11DRV_EVENT_PrepareShmCompletion(dw);
2083 if (!(n=(LONG)InterlockedCompareExchange((PVOID*)compl, (PVOID)nn, (PVOID)n)))
2084 return;
2085 /* race for compl lost, clear slot */
2086 shm_q[nn-1].draw = 0;
2087 return;
2090 if (dw && (shm_q[n-1].draw != dw)) {
2091 /* this shouldn't happen with the current ddraw implementation */
2092 FIXME("ShmCompletion replace with different drawable!\n");
2093 return;
2096 sema = shm_q[n-1].sema;
2097 if (!sema) {
2098 /* nothing to wait on (PrepareShmCompletion not done yet?), so probably nothing to wait for */
2099 return;
2102 nn = InterlockedExchangeAdd((PLONG)&shm_q[n-1].waiter, 1);
2103 if ((!shm_q[n-1].draw) || (shm_q[n-1].state == 2)) {
2104 /* too late, the wait was just cleared (wait complete) */
2105 TRACE("Wait skip for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2106 } else {
2107 TRACE("Waiting for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2108 if (nn) {
2109 /* another thread is already waiting, let the primary waiter do the dirty work
2110 * (to avoid TSX critical section contention - that could get really slow) */
2111 WaitForSingleObject( sema, INFINITE );
2112 } else
2113 /* we're primary waiter - first check if it's already triggered */
2114 if ( WaitForSingleObject( sema, 0 ) != WAIT_OBJECT_0 ) {
2115 /* nope, may need to poll X event queue, in case the service thread is blocked */
2116 XEvent event;
2117 HANDLE hnd[2];
2119 hnd[0] = sema;
2120 hnd[1] = shm_read;
2121 do {
2122 /* check X event queue */
2123 if (TSXCheckTypedEvent( display, ShmCompletionType, &event)) {
2124 EVENT_ProcessEvent( &event );
2126 } while ( WaitForMultipleObjects(2, hnd, FALSE, INFINITE) > WAIT_OBJECT_0 );
2128 TRACE("Wait complete (thread %lx) (time %ld)\n", GetCurrentThreadId(), GetTickCount() );
2130 /* clear wait */
2131 st = InterlockedExchange((LPLONG)&shm_q[n-1].state, 2);
2132 if (st != 2) {
2133 /* first waiter to return, release all other waiters */
2134 nn = shm_q[n-1].waiter;
2135 TRACE("Signaling %ld additional ShmCompletion (#%d) waiter(s), semaphore %x\n", nn-1, n-1, sema);
2136 ReleaseSemaphore(sema, nn-1, NULL);
2139 nn = InterlockedDecrement((LPLONG)&shm_q[n-1].waiter);
2140 if (!nn) {
2141 /* last waiter to return, replace drawable and prepare new wait */
2142 shm_q[n-1].draw = dw;
2143 shm_q[n-1].state = 0;
2147 void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw )
2149 X11DRV_EVENT_WaitReplaceShmCompletionInternal( compl, dw, 1 );
2152 void X11DRV_EVENT_WaitShmCompletion( int compl )
2154 if (!compl) return;
2155 X11DRV_EVENT_WaitReplaceShmCompletionInternal( &compl, 0, 0 );
2158 void X11DRV_EVENT_WaitShmCompletions( Drawable dw )
2160 int n;
2162 for (n=0; n<SHM_MAX_Q; n++)
2163 if (shm_q[n].draw == dw)
2164 X11DRV_EVENT_WaitShmCompletion( n+1 );
2167 #endif /* defined(HAVE_LIBXXSHM) */