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