Moved most builtin controls structures into their respective C file.
[wine/testsucceed.git] / windows / x11drv / event.c
blob519ab377a0c15f42091c769e5d3faed85b1d9ef5
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 HANDLE16 hText;
1075 LPSTR text;
1076 int size,i,j;
1077 char* lpstr = 0;
1078 char *itemFmtName;
1079 int xRc;
1082 * Map the requested X selection property type atom name to a
1083 * windows clipboard format ID.
1085 itemFmtName = TSXGetAtomName(display, target);
1086 TRACE("Request for %s (wFormat=%x %s)\n",
1087 itemFmtName, CF_TEXT, CLIPBOARD_GetFormatName(CF_TEXT));
1088 TSXFree(itemFmtName);
1090 hText = GetClipboardData16(CF_TEXT);
1091 if ( !hText )
1092 return None;
1093 text = GlobalLock16(hText);
1094 if (!text)
1095 return None;
1096 size = GlobalSize16(hText);
1097 /* remove carriage returns */
1099 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
1100 if(lpstr == NULL) return None;
1101 for(i=0,j=0; i < size && text[i]; i++ )
1103 if( text[i] == '\r' &&
1104 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1105 lpstr[j++] = text[i];
1107 lpstr[j]='\0';
1109 /* Update the X property */
1110 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
1111 xRc = TSXChangeProperty(display, requestor, rprop,
1112 XA_STRING, 8, PropModeReplace,
1113 lpstr, j);
1114 TRACE("(Rc=%d)\n", xRc);
1116 GlobalUnlock16(hText);
1117 HeapFree( GetProcessHeap(), 0, lpstr );
1119 return rprop;
1122 /***********************************************************************
1123 * EVENT_SelectionRequest_PIXMAP
1124 * Service a PIXMAP selection request event
1126 static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
1128 HANDLE hClipData = 0;
1129 Pixmap pixmap = 0;
1130 UINT wFormat;
1131 char * itemFmtName;
1132 int xRc;
1133 #if(0)
1134 XSetWindowAttributes win_attr;
1135 XWindowAttributes win_attr_src;
1136 #endif
1139 * Map the requested X selection property type atom name to a
1140 * windows clipboard format ID.
1142 itemFmtName = TSXGetAtomName(display, target);
1143 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1144 TRACE("Request for %s (wFormat=%x %s)\n",
1145 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1146 TSXFree(itemFmtName);
1148 hClipData = GetClipboardData(wFormat);
1149 if ( !hClipData )
1151 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
1152 rprop = None; /* Fail the request */
1153 goto END;
1156 if (wFormat == CF_DIB)
1158 HWND hwnd = GetOpenClipboardWindow();
1159 HDC hdc = GetDC(hwnd);
1161 /* For convert from packed DIB to Pixmap */
1162 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
1164 ReleaseDC(hdc, hwnd);
1166 else if (wFormat == CF_BITMAP)
1168 HWND hwnd = GetOpenClipboardWindow();
1169 HDC hdc = GetDC(hwnd);
1171 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
1173 ReleaseDC(hdc, hwnd);
1175 else
1177 FIXME("%s to PIXMAP conversion not yet implemented!\n",
1178 CLIPBOARD_GetFormatName(wFormat));
1179 rprop = None;
1180 goto END;
1183 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
1184 TSXGetAtomName(display, rprop), (long)requestor,
1185 TSXGetAtomName(display, target), pixmap);
1187 /* Store the Pixmap handle in the property */
1188 xRc = TSXChangeProperty(display, requestor, rprop, target,
1189 32, PropModeReplace,
1190 (unsigned char *)&pixmap, 1);
1191 TRACE("(Rc=%d)\n", xRc);
1193 /* Enable the code below if you want to handle destroying Pixmap resources
1194 * in response to property notify events. Clients like XPaint don't
1195 * appear to be duplicating Pixmaps so they don't like us deleting,
1196 * the resource in response to the property being deleted.
1198 #if(0)
1199 /* Express interest in property notify events so that we can delete the
1200 * pixmap when the client deletes the property atom.
1202 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
1203 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
1204 (long)requestor);
1205 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
1206 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
1208 /* Register the Pixmap we created with the request property Atom.
1209 * When this property is destroyed we also destroy the Pixmap in
1210 * response to the PropertyNotify event.
1212 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
1213 #endif
1215 END:
1216 return rprop;
1220 /***********************************************************************
1221 * EVENT_SelectionRequest_WCF
1222 * Service a Wine Clipboard Format selection request event.
1223 * For <WCF>* data types we simply copy the data to X without conversion.
1225 static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
1227 HANDLE hClipData = 0;
1228 void* lpClipData;
1229 UINT wFormat;
1230 char * itemFmtName;
1231 int cBytes;
1232 int xRc;
1235 * Map the requested X selection property type atom name to a
1236 * windows clipboard format ID.
1238 itemFmtName = TSXGetAtomName(display, target);
1239 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1240 TRACE("Request for %s (wFormat=%x %s)\n",
1241 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1242 TSXFree(itemFmtName);
1244 hClipData = GetClipboardData16(wFormat);
1246 if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
1248 cBytes = GlobalSize16(hClipData);
1250 TRACE("\tUpdating property %s, %d bytes...\n",
1251 TSXGetAtomName(display, rprop), cBytes);
1253 xRc = TSXChangeProperty(display, requestor, rprop,
1254 target, 8, PropModeReplace,
1255 (unsigned char *)lpClipData, cBytes);
1256 TRACE("(Rc=%d)\n", xRc);
1258 GlobalUnlock16(hClipData);
1260 else
1262 TRACE("\tCould not retrieve native format!\n");
1263 rprop = None; /* Fail the request */
1266 return rprop;
1270 /***********************************************************************
1271 * EVENT_SelectionRequest_MULTIPLE
1272 * Service a MULTIPLE selection request event
1273 * rprop contains a list of (target,property) atom pairs.
1274 * The first atom names a target and the second names a property.
1275 * The effect is as if we have received a sequence of SelectionRequest events
1276 * (one for each atom pair) except that:
1277 * 1. We reply with a SelectionNotify only when all the requested conversions
1278 * have been performed.
1279 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1280 * we replace the atom in the property by None.
1282 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
1284 Atom rprop;
1285 Atom atype=AnyPropertyType;
1286 int aformat;
1287 unsigned long remain;
1288 Atom* targetPropList=NULL;
1289 unsigned long cTargetPropList = 0;
1290 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1292 /* If the specified property is None the requestor is an obsolete client.
1293 * We support these by using the specified target atom as the reply property.
1295 rprop = pevent->property;
1296 if( rprop == None )
1297 rprop = pevent->target;
1298 if (!rprop)
1299 goto END;
1301 /* Read the MULTIPLE property contents. This should contain a list of
1302 * (target,property) atom pairs.
1304 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
1305 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
1306 &cTargetPropList, &remain,
1307 (unsigned char**)&targetPropList) != Success)
1308 TRACE("\tCouldn't read MULTIPLE property\n");
1309 else
1311 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1312 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
1315 * Make sure we got what we expect.
1316 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1317 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1318 * However some X apps(such as XPaint) are not compliant with this and return
1319 * a user defined atom in atype when XGetWindowProperty is called.
1320 * The data *is* an atom pair but is not denoted as such.
1322 if(aformat == 32 /* atype == xAtomPair */ )
1324 int i;
1326 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1327 * for each (target,property) pair */
1329 for (i = 0; i < cTargetPropList; i+=2)
1331 char *targetName = TSXGetAtomName(display, targetPropList[i]);
1332 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
1333 XSelectionRequestEvent event;
1335 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
1336 i/2, targetName, propName);
1337 TSXFree(targetName);
1338 TSXFree(propName);
1340 /* We must have a non "None" property to service a MULTIPLE target atom */
1341 if ( !targetPropList[i+1] )
1343 TRACE("\tMULTIPLE(%d): Skipping target with empty property!", i);
1344 continue;
1347 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1348 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
1349 event.target = targetPropList[i];
1350 event.property = targetPropList[i+1];
1352 /* Fire a SelectionRequest, informing the handler that we are processing
1353 * a MULTIPLE selection request event.
1355 EVENT_SelectionRequest( hWnd, &event, TRUE );
1359 /* Free the list of targets/properties */
1360 TSXFree(targetPropList);
1363 END:
1364 return rprop;
1368 /***********************************************************************
1369 * EVENT_SelectionRequest
1370 * Process an event selection request event.
1371 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1372 * recursively while servicing a "MULTIPLE" selection target.
1374 * Note: We only receive this event when WINE owns the X selection
1376 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1378 XSelectionEvent result;
1379 Atom rprop = None;
1380 Window request = event->requestor;
1381 BOOL couldOpen = FALSE;
1382 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1383 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
1384 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1387 * We can only handle the selection request if :
1388 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1389 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1390 * since this has been already done.
1392 if ( !bIsMultiple )
1394 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1395 || !(couldOpen = OpenClipboard(hWnd)) )
1396 goto END;
1399 /* If the specified property is None the requestor is an obsolete client.
1400 * We support these by using the specified target atom as the reply property.
1402 rprop = event->property;
1403 if( rprop == None )
1404 rprop = event->target;
1406 if(event->target == xaTargets) /* Return a list of all supported targets */
1408 /* TARGETS selection request */
1409 rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
1411 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1413 /* MULTIPLE selection request */
1414 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1416 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1418 /* XA_STRING selection request */
1419 rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
1421 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1423 /* XA_PIXMAP selection request */
1424 rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
1426 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1428 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1429 rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
1431 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1433 /* All <WCF> selection requests */
1434 rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
1436 else
1437 rprop = None; /* Don't support this format */
1439 END:
1440 /* close clipboard only if we opened before */
1441 if(couldOpen) CloseClipboard();
1443 if( rprop == None)
1444 TRACE("\tRequest ignored\n");
1446 /* reply to sender
1447 * SelectionNotify should be sent only at the end of a MULTIPLE request
1449 if ( !bIsMultiple )
1451 result.type = SelectionNotify;
1452 result.display = display;
1453 result.requestor = request;
1454 result.selection = event->selection;
1455 result.property = rprop;
1456 result.target = event->target;
1457 result.time = event->time;
1458 TRACE("Sending SelectionNotify event...\n");
1459 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1463 /***********************************************************************
1464 * EVENT_SelectionClear
1466 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1468 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1470 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1471 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1474 /***********************************************************************
1475 * EVENT_PropertyNotify
1476 * We use this to release resources like Pixmaps when a selection
1477 * client no longer needs them.
1479 static void EVENT_PropertyNotify( XPropertyEvent *event )
1481 /* Check if we have any resources to free */
1482 TRACE("Received PropertyNotify event: ");
1484 switch(event->state)
1486 case PropertyDelete:
1488 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1489 TSXGetAtomName(event->display, event->atom), (long)event->window);
1491 if (X11DRV_IsSelectionOwner())
1492 X11DRV_CLIPBOARD_FreeResources( event->atom );
1493 break;
1496 case PropertyNewValue:
1498 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1499 TSXGetAtomName(event->display, event->atom), (long)event->window);
1500 break;
1503 default:
1504 break;
1508 /**********************************************************************
1509 * EVENT_DropFromOffix
1511 * don't know if it still works (last Changlog is from 96/11/04)
1513 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1515 unsigned long data_length;
1516 unsigned long aux_long;
1517 unsigned char* p_data = NULL;
1518 union {
1519 Atom atom_aux;
1520 struct {
1521 int x;
1522 int y;
1523 } pt_aux;
1524 int i;
1525 } u;
1526 int x, y;
1527 BOOL16 bAccept;
1528 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO16));
1529 LPDRAGINFO16 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
1530 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1531 Window w_aux_root, w_aux_child;
1532 WND* pDropWnd;
1533 WND* pWnd;
1535 if( !lpDragInfo || !spDragInfo ) return;
1537 pWnd = WIN_FindWndPtr(hWnd);
1539 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
1540 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1541 (unsigned int*)&aux_long);
1543 lpDragInfo->hScope = hWnd;
1544 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1546 /* find out drop point and drop window */
1547 if( x < 0 || y < 0 ||
1548 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1549 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1550 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1551 else
1553 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1554 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1556 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1557 WIN_ReleaseWndPtr(pWnd);
1559 GlobalFree16( hDragInfo );
1561 if( bAccept )
1563 TSXGetWindowProperty( display, DefaultRootWindow(display),
1564 dndSelection, 0, 65535, FALSE,
1565 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1566 &data_length, &aux_long, &p_data);
1568 if( !aux_long && p_data) /* don't bother if > 64K */
1570 char *p = (char*) p_data;
1571 char *p_drop;
1573 aux_long = 0;
1574 while( *p ) /* calculate buffer size */
1576 p_drop = p;
1577 if((u.i = *p) != -1 )
1579 INT len = GetShortPathNameA( p, NULL, 0 );
1580 if (len) aux_long += len + 1;
1581 else *p = -1;
1583 p += strlen(p) + 1;
1585 if( aux_long && aux_long < 65535 )
1587 HDROP hDrop;
1588 DROPFILES *lpDrop;
1590 aux_long += sizeof(DROPFILES) + 1;
1591 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1592 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1594 if( lpDrop )
1596 lpDrop->pFiles = sizeof(DROPFILES);
1597 lpDrop->pt.x = x;
1598 lpDrop->pt.y = y;
1599 lpDrop->fNC =
1600 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1601 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1602 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1603 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1604 lpDrop->fWide = FALSE;
1605 p_drop = (char *)(lpDrop + 1);
1606 p = p_data;
1607 while(*p)
1609 if( *p != -1 ) /* use only "good" entries */
1611 GetShortPathNameA( p, p_drop, 65535 );
1612 p_drop += strlen( p_drop ) + 1;
1614 p += strlen(p) + 1;
1616 *p_drop = '\0';
1617 PostMessageA( hWnd, WM_DROPFILES, hDrop, 0L );
1621 if( p_data ) TSXFree(p_data);
1623 } /* WS_EX_ACCEPTFILES */
1625 WIN_ReleaseWndPtr(pDropWnd);
1628 /**********************************************************************
1629 * EVENT_DropURLs
1631 * drop items are separated by \n
1632 * each item is prefixed by its mime type
1634 * event->data.l[3], event->data.l[4] contains drop x,y position
1636 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1638 WND *pDropWnd;
1639 WND *pWnd;
1640 unsigned long data_length;
1641 unsigned long aux_long, drop_len = 0;
1642 unsigned char *p_data = NULL; /* property data */
1643 char *p_drop = NULL;
1644 char *p, *next;
1645 int x, y;
1646 DROPFILES *lpDrop;
1647 HDROP hDrop;
1648 union {
1649 Atom atom_aux;
1650 int i;
1651 Window w_aux;
1652 } u; /* unused */
1654 pWnd = WIN_FindWndPtr(hWnd);
1656 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1658 WIN_ReleaseWndPtr(pWnd);
1659 return;
1661 WIN_ReleaseWndPtr(pWnd);
1663 TSXGetWindowProperty( display, DefaultRootWindow(display),
1664 dndSelection, 0, 65535, FALSE,
1665 AnyPropertyType, &u.atom_aux, &u.i,
1666 &data_length, &aux_long, &p_data);
1667 if (aux_long)
1668 WARN("property too large, truncated!\n");
1669 TRACE("urls=%s\n", p_data);
1671 if( !aux_long && p_data) { /* don't bother if > 64K */
1672 /* calculate length */
1673 p = p_data;
1674 next = strchr(p, '\n');
1675 while (p) {
1676 if (next) *next=0;
1677 if (strncmp(p,"file:",5) == 0 ) {
1678 INT len = GetShortPathNameA( p+5, NULL, 0 );
1679 if (len) drop_len += len + 1;
1681 if (next) {
1682 *next = '\n';
1683 p = next + 1;
1684 next = strchr(p, '\n');
1685 } else {
1686 p = NULL;
1690 if( drop_len && drop_len < 65535 ) {
1691 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
1692 &x, &y, &u.i, &u.i, &u.i);
1694 pDropWnd = WIN_FindWndPtr( hWnd );
1696 drop_len += sizeof(DROPFILES) + 1;
1697 hDrop = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
1698 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1700 if( lpDrop ) {
1701 lpDrop->pFiles = sizeof(DROPFILES);
1702 lpDrop->pt.x = (INT)x;
1703 lpDrop->pt.y = (INT)y;
1704 lpDrop->fNC =
1705 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1706 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1707 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1708 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1709 lpDrop->fWide = FALSE;
1710 p_drop = (char*)(lpDrop + 1);
1713 /* create message content */
1714 if (p_drop) {
1715 p = p_data;
1716 next = strchr(p, '\n');
1717 while (p) {
1718 if (next) *next=0;
1719 if (strncmp(p,"file:",5) == 0 ) {
1720 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1721 if (len) {
1722 TRACE("drop file %s as %s\n", p+5, p_drop);
1723 p_drop += len+1;
1724 } else {
1725 WARN("can't convert file %s to dos name \n", p+5);
1727 } else {
1728 WARN("unknown mime type %s\n", p);
1730 if (next) {
1731 *next = '\n';
1732 p = next + 1;
1733 next = strchr(p, '\n');
1734 } else {
1735 p = NULL;
1737 *p_drop = '\0';
1740 GlobalUnlock(hDrop);
1741 PostMessageA( hWnd, WM_DROPFILES, hDrop, 0L );
1743 WIN_ReleaseWndPtr(pDropWnd);
1745 if( p_data ) TSXFree(p_data);
1749 /**********************************************************************
1750 * EVENT_ClientMessage
1752 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1754 if (event->message_type != None && event->format == 32) {
1755 if ((event->message_type == wmProtocols) &&
1756 (((Atom) event->data.l[0]) == wmDeleteWindow))
1758 /* Ignore the delete window request if the window has been disabled
1759 * and we are in managed mode. This is to disallow applications from
1760 * being closed by the window manager while in a modal state.
1762 BOOL bIsDisabled;
1763 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
1765 if ( !Options.managed || !bIsDisabled )
1766 PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1768 else if ( event->message_type == dndProtocol &&
1769 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1770 EVENT_DropFromOffiX(hWnd, event);
1771 else if ( event->message_type == dndProtocol &&
1772 event->data.l[0] == DndURL )
1773 EVENT_DropURLs(hWnd, event);
1774 else {
1775 #if 0
1776 /* enable this if you want to see the message */
1777 unsigned char* p_data = NULL;
1778 union {
1779 unsigned long l;
1780 int i;
1781 Atom atom;
1782 } u; /* unused */
1783 TSXGetWindowProperty( display, DefaultRootWindow(display),
1784 dndSelection, 0, 65535, FALSE,
1785 AnyPropertyType, &u.atom, &u.i,
1786 &u.l, &u.l, &p_data);
1787 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1788 event->message_type, event->data.l[0], event->data.l[1],
1789 event->data.l[2], event->data.l[3], event->data.l[4],
1790 p_data);
1791 #endif
1792 TRACE("unrecognized ClientMessage\n" );
1797 /**********************************************************************
1798 * EVENT_EnterNotify
1800 * Install colormap when Wine window is focused in
1801 * self-managed mode with private colormap
1803 #if 0
1804 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
1806 if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1807 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1808 TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
1810 #endif
1812 /**********************************************************************
1813 * EVENT_MapNotify
1815 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1817 HWND hwndFocus = GetFocus();
1818 WND *wndFocus = WIN_FindWndPtr(hwndFocus);
1819 WND *pWnd = WIN_FindWndPtr(hWnd);
1820 if (pWnd && (pWnd->dwExStyle & WS_EX_MANAGED))
1822 DCE_InvalidateDCE( pWnd, &pWnd->rectWindow );
1823 pWnd->dwStyle &= ~WS_MINIMIZE;
1824 pWnd->dwStyle |= WS_VISIBLE;
1825 WIN_InternalShowOwnedPopups(hWnd,TRUE,TRUE);
1827 WIN_ReleaseWndPtr(pWnd);
1829 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1830 X11DRV_WND_SetFocus(wndFocus);
1832 WIN_ReleaseWndPtr(wndFocus);
1834 return;
1838 /**********************************************************************
1839 * EVENT_UnmapNotify
1841 void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
1843 WND *pWnd = WIN_FindWndPtr(hWnd);
1844 if (pWnd && (pWnd->dwExStyle & WS_EX_MANAGED))
1846 EndMenu();
1847 if( pWnd->dwStyle & WS_VISIBLE )
1849 pWnd->dwStyle |= WS_MINIMIZE;
1850 pWnd->dwStyle &= ~WS_VISIBLE;
1851 WIN_InternalShowOwnedPopups(hWnd,FALSE,TRUE);
1854 WIN_ReleaseWndPtr(pWnd);
1857 /***********************************************************************
1858 * EVENT_MappingNotify
1860 static void EVENT_MappingNotify( XMappingEvent *event )
1862 TSXRefreshKeyboardMapping(event);
1864 /* reinitialize Wine-X11 driver keyboard table */
1865 X11DRV_InitKeyboard();
1869 /**********************************************************************
1870 * X11DRV_EVENT_SetInputMethod
1872 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1874 INPUT_TYPE prev = current_input_type;
1876 /* Flag not used yet */
1877 in_transition = FALSE;
1878 current_input_type = type;
1880 return prev;
1883 #ifdef HAVE_LIBXXF86DGA2
1884 /**********************************************************************
1885 * X11DRV_EVENT_SetDGAStatus
1887 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1889 if (event_base < 0) {
1890 DGAUsed = FALSE;
1891 DGAhwnd = 0;
1892 } else {
1893 DGAUsed = TRUE;
1894 DGAhwnd = hwnd;
1895 DGAMotionEventType = event_base + MotionNotify;
1896 DGAButtonPressEventType = event_base + ButtonPress;
1897 DGAButtonReleaseEventType = event_base + ButtonRelease;
1898 DGAKeyPressEventType = event_base + KeyPress;
1899 DGAKeyReleaseEventType = event_base + KeyRelease;
1903 /* DGA2 event handlers */
1904 static void EVENT_DGAMotionEvent( XDGAMotionEvent *event )
1906 X11DRV_SendEvent( MOUSEEVENTF_MOVE,
1907 event->dx, event->dy,
1908 X11DRV_EVENT_XStateToKeyState( event->state ),
1909 event->time - X11DRV_server_startticks, DGAhwnd );
1912 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent *event )
1914 static WORD statusCodes[NB_BUTTONS] =
1915 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
1916 int buttonNum = event->button - 1;
1918 WORD keystate;
1920 if (buttonNum >= NB_BUTTONS) return;
1922 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1924 switch (buttonNum)
1926 case 0:
1927 keystate |= MK_LBUTTON;
1928 break;
1929 case 1:
1930 keystate |= MK_MBUTTON;
1931 break;
1932 case 2:
1933 keystate |= MK_RBUTTON;
1934 break;
1937 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time - X11DRV_server_startticks, DGAhwnd );
1940 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent *event )
1942 static WORD statusCodes[NB_BUTTONS] =
1943 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
1944 int buttonNum = event->button - 1;
1946 WORD keystate;
1948 if (buttonNum >= NB_BUTTONS) return;
1950 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1952 switch (buttonNum)
1954 case 0:
1955 keystate &= ~MK_LBUTTON;
1956 break;
1957 case 1:
1958 keystate &= ~MK_MBUTTON;
1959 break;
1960 case 2:
1961 keystate &= ~MK_RBUTTON;
1962 break;
1965 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time - X11DRV_server_startticks, DGAhwnd );
1968 #endif
1970 #ifdef HAVE_LIBXXSHM
1973 Normal XShm operation:
1975 X11 service thread app thread
1976 ------------- ----------------- ------------------------
1977 (idle) ddraw calls XShmPutImage
1978 (copies data) (waiting for shm_event)
1979 ShmCompletion -> (waiting for shm_event)
1980 (idle) signal shm_event ->
1981 (idle) returns to app
1983 However, this situation can occur for some reason:
1985 X11 service thread app thread
1986 ------------- ----------------- ------------------------
1987 Expose ->
1988 WM_ERASEBKGND? ->
1989 (waiting for app) ddraw calls XShmPutImage
1990 (copies data) (waiting for app) (waiting for shm_event)
1991 ShmCompletion (waiting for app) (waiting for shm_event)
1992 (idle) DEADLOCK DEADLOCK
1994 which is why I also wait for shm_read and do XCheckTypedEvent()
1995 calls in the wait loop. This results in:
1997 X11 service thread app thread
1998 ------------- ----------------- ------------------------
1999 ShmCompletion (waiting for app) waking up on shm_read
2000 (idle) (waiting for app) XCheckTypedEvent() -> signal shm_event
2001 (waiting for app) returns
2002 (idle)
2005 typedef struct {
2006 Drawable draw;
2007 LONG state, waiter;
2008 HANDLE sema;
2009 } shm_qs;
2011 /* FIXME: this is not pretty */
2012 static HANDLE shm_read = 0;
2014 #define SHM_MAX_Q 4
2015 static volatile shm_qs shm_q[SHM_MAX_Q];
2017 static void EVENT_ShmCompletion( XShmCompletionEvent *event )
2019 int n;
2021 TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event->drawable, GetTickCount() );
2023 for (n=0; n<SHM_MAX_Q; n++)
2024 if ((shm_q[n].draw == event->drawable) && (shm_q[n].state == 0)) {
2025 HANDLE sema = shm_q[n].sema;
2026 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].state, (PVOID)1, (PVOID)0)) {
2027 ReleaseSemaphore(sema, 1, NULL);
2028 TRACE("Signaling ShmCompletion (#%d) (semaphore %x)\n", n, sema);
2030 return;
2033 ERR("Got ShmCompletion for unknown drawable %ld\n", event->drawable );
2036 int X11DRV_EVENT_PrepareShmCompletion( Drawable dw )
2038 int n;
2040 if (!shm_read)
2041 shm_read = FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE );
2043 for (n=0; n<SHM_MAX_Q; n++)
2044 if (!shm_q[n].draw)
2045 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].draw, (PVOID)dw, (PVOID)0))
2046 break;
2048 if (n>=SHM_MAX_Q) {
2049 ERR("Maximum number of outstanding ShmCompletions exceeded!\n");
2050 return 0;
2053 shm_q[n].state = 0;
2054 if (!shm_q[n].sema) {
2055 shm_q[n].sema = CreateSemaphoreA( NULL, 0, 256, NULL );
2056 TRACE("Allocated ShmCompletion slots have been increased to %d, new semaphore is %x\n", n+1, shm_q[n].sema);
2059 TRACE("Prepared ShmCompletion (#%d) wait for drawable %ld (thread %lx) (time %ld)\n", n, dw, GetCurrentThreadId(), GetTickCount() );
2060 return n+1;
2063 static void X11DRV_EVENT_WaitReplaceShmCompletionInternal( int *compl, Drawable dw, int creat )
2065 int n = *compl;
2066 LONG nn, st;
2067 HANDLE sema;
2069 if ((!n) || (creat && (!shm_q[n-1].draw))) {
2070 nn = X11DRV_EVENT_PrepareShmCompletion(dw);
2071 if (!(n=(LONG)InterlockedCompareExchange((PVOID*)compl, (PVOID)nn, (PVOID)n)))
2072 return;
2073 /* race for compl lost, clear slot */
2074 shm_q[nn-1].draw = 0;
2075 return;
2078 if (dw && (shm_q[n-1].draw != dw)) {
2079 /* this shouldn't happen with the current ddraw implementation */
2080 FIXME("ShmCompletion replace with different drawable!\n");
2081 return;
2084 sema = shm_q[n-1].sema;
2085 if (!sema) {
2086 /* nothing to wait on (PrepareShmCompletion not done yet?), so probably nothing to wait for */
2087 return;
2090 nn = InterlockedExchangeAdd((PLONG)&shm_q[n-1].waiter, 1);
2091 if ((!shm_q[n-1].draw) || (shm_q[n-1].state == 2)) {
2092 /* too late, the wait was just cleared (wait complete) */
2093 TRACE("Wait skip for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2094 } else {
2095 TRACE("Waiting for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2096 if (nn) {
2097 /* another thread is already waiting, let the primary waiter do the dirty work
2098 * (to avoid TSX critical section contention - that could get really slow) */
2099 WaitForSingleObject( sema, INFINITE );
2100 } else
2101 /* we're primary waiter - first check if it's already triggered */
2102 if ( WaitForSingleObject( sema, 0 ) != WAIT_OBJECT_0 ) {
2103 /* nope, may need to poll X event queue, in case the service thread is blocked */
2104 XEvent event;
2105 HANDLE hnd[2];
2107 hnd[0] = sema;
2108 hnd[1] = shm_read;
2109 do {
2110 /* check X event queue */
2111 if (TSXCheckTypedEvent( display, ShmCompletionType, &event)) {
2112 EVENT_ProcessEvent( &event );
2114 } while ( WaitForMultipleObjects(2, hnd, FALSE, INFINITE) > WAIT_OBJECT_0 );
2116 TRACE("Wait complete (thread %lx) (time %ld)\n", GetCurrentThreadId(), GetTickCount() );
2118 /* clear wait */
2119 st = InterlockedExchange((LPLONG)&shm_q[n-1].state, 2);
2120 if (st != 2) {
2121 /* first waiter to return, release all other waiters */
2122 nn = shm_q[n-1].waiter;
2123 TRACE("Signaling %ld additional ShmCompletion (#%d) waiter(s), semaphore %x\n", nn-1, n-1, sema);
2124 ReleaseSemaphore(sema, nn-1, NULL);
2127 nn = InterlockedDecrement((LPLONG)&shm_q[n-1].waiter);
2128 if (!nn) {
2129 /* last waiter to return, replace drawable and prepare new wait */
2130 shm_q[n-1].draw = dw;
2131 shm_q[n-1].state = 0;
2135 void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw )
2137 X11DRV_EVENT_WaitReplaceShmCompletionInternal( compl, dw, 1 );
2140 void X11DRV_EVENT_WaitShmCompletion( int compl )
2142 if (!compl) return;
2143 X11DRV_EVENT_WaitReplaceShmCompletionInternal( &compl, 0, 0 );
2146 void X11DRV_EVENT_WaitShmCompletions( Drawable dw )
2148 int n;
2150 for (n=0; n<SHM_MAX_Q; n++)
2151 if (shm_q[n].draw == dw)
2152 X11DRV_EVENT_WaitShmCompletion( n+1 );
2155 #endif /* defined(HAVE_LIBXXSHM) */