With some apps a fault was possible in ExtractAssociatedIcon.
[wine.git] / windows / x11drv / event.c
blob9377bb30303ec4fe0d87bf490db733e5adfd9260
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 "callback.h"
26 #include "clipboard.h"
27 #include "dce.h"
28 #include "debugtools.h"
29 #include "drive.h"
30 #include "heap.h"
31 #include "input.h"
32 #include "keyboard.h"
33 #include "message.h"
34 #include "mouse.h"
35 #include "options.h"
36 #include "queue.h"
37 #include "shell.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 );
96 /* Event handlers */
97 static void EVENT_Key( HWND hWnd, XKeyEvent *event );
98 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event );
99 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event );
100 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event );
101 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
102 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
103 static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
104 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event );
105 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event );
106 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
107 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
108 static void EVENT_PropertyNotify( XPropertyEvent *event );
109 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
110 static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
111 static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
112 static void EVENT_MappingNotify( XMappingEvent *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( 200, 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 && event->type != MappingNotify)
328 ERR("Got event %s for unknown Window %08lx\n",
329 event_names[event->type], event->xany.window );
330 else
331 TRACE("Got event %s for hwnd %04x\n",
332 event_names[event->type], hWnd );
334 switch(event->type)
336 case KeyPress:
337 case KeyRelease:
338 EVENT_Key( hWnd, (XKeyEvent*)event );
339 break;
341 case ButtonPress:
342 EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
343 break;
345 case ButtonRelease:
346 EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
347 break;
349 case MotionNotify:
350 /* Wine between two fast machines across the overloaded campus
351 ethernet gets very boged down in MotionEvents. The following
352 simply finds the last motion event in the queue and drops
353 the rest. On a good link events are servered before they build
354 up so this doesn't take place. On a slow link this may cause
355 problems if the event order is important. I'm not yet seen
356 of any problems. Jon 7/6/96.
358 if ((current_input_type == X11DRV_INPUT_ABSOLUTE) &&
359 (in_transition == FALSE))
360 /* Only cumulate events if in absolute mode */
361 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
362 MotionNotify, event));
363 EVENT_MotionNotify( hWnd, (XMotionEvent*)event );
364 break;
366 case FocusIn:
368 WND *pWndLastFocus = 0;
369 XWindowAttributes win_attr;
370 BOOL bIsDisabled;
371 XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
373 if (!hWnd || bUserRepaintDisabled) return;
375 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
377 /* If the window has been disabled and we are in managed mode,
378 * revert the X focus back to the last focus window. This is to disallow
379 * the window manager from switching focus away while the app is
380 * in a modal state.
382 if ( Options.managed && bIsDisabled && glastXFocusWin)
384 /* Change focus only if saved focus window is registered and viewable */
385 if ( TSXFindContext( xfocChange->display, glastXFocusWin, winContext,
386 (char **)&pWndLastFocus ) == 0 )
388 if ( TSXGetWindowAttributes( display, glastXFocusWin, &win_attr ) &&
389 (win_attr.map_state == IsViewable) )
391 TSXSetInputFocus( xfocChange->display, glastXFocusWin, RevertToParent, CurrentTime );
392 EVENT_Synchronize();
393 break;
398 EVENT_FocusIn( hWnd, xfocChange );
399 break;
402 case FocusOut:
404 /* Save the last window which had the focus */
405 XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
406 glastXFocusWin = xfocChange->window;
407 if (!hWnd || bUserRepaintDisabled) return;
408 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
409 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
410 break;
413 case Expose:
414 if (bUserRepaintDisabled) return;
415 EVENT_Expose( hWnd, (XExposeEvent *)event );
416 break;
418 case GraphicsExpose:
419 if (bUserRepaintDisabled) return;
420 EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
421 break;
423 case ConfigureNotify:
424 if (!hWnd || bUserRepaintDisabled) return;
425 EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
426 break;
428 case SelectionRequest:
429 if (!hWnd || bUserRepaintDisabled) return;
430 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
431 break;
433 case SelectionClear:
434 if (!hWnd || bUserRepaintDisabled) return;
435 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
436 break;
438 case PropertyNotify:
439 EVENT_PropertyNotify( (XPropertyEvent *)event );
440 break;
442 case ClientMessage:
443 if (!hWnd || bUserRepaintDisabled) return;
444 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
445 break;
447 #if 0
448 case EnterNotify:
449 EVENT_EnterNotify( hWnd, (XCrossingEvent *) event );
450 break;
451 #endif
453 case NoExpose:
454 break;
456 case MapNotify:
457 if (!hWnd || bUserRepaintDisabled) return;
458 EVENT_MapNotify( hWnd, (XMapEvent *)event );
459 break;
461 case UnmapNotify:
462 if (!hWnd || bUserRepaintDisabled) return;
463 EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
464 break;
466 case MappingNotify:
467 EVENT_MappingNotify( (XMappingEvent *) event );
468 break;
470 default:
471 WARN("Unprocessed event %s for hwnd %04x\n",
472 event_names[event->type], hWnd );
473 break;
475 TRACE( "returns.\n" );
478 /***********************************************************************
479 * EVENT_QueryZOrder
481 * Synchronize internal z-order with the window manager's.
483 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
485 /* return TRUE if we have at least two managed windows */
487 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
488 if( (*pWndA)->flags & WIN_MANAGED &&
489 (*pWndA)->dwStyle & WS_VISIBLE ) break;
490 if( *pWndA )
491 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
492 if( (*pWndB)->flags & WIN_MANAGED &&
493 (*pWndB)->dwStyle & WS_VISIBLE ) break;
494 return ((*pWndB) != NULL);
497 static Window __get_common_ancestor( Window A, Window B,
498 Window** children, unsigned* total )
500 /* find the real root window */
502 Window root, *childrenB;
503 unsigned totalB;
507 TSXQueryTree( display, A, &root, &A, children, total );
508 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
509 if( childrenB ) TSXFree( childrenB );
510 if( *children ) TSXFree( *children ), *children = NULL;
511 } while( A != B && A && B );
513 if( A && B )
515 TSXQueryTree( display, A, &root, &B, children, total );
516 return A;
518 return 0 ;
521 static Window __get_top_decoration( Window w, Window ancestor )
523 Window* children, root, prev = w, parent = w;
524 unsigned total;
528 w = parent;
529 TSXQueryTree( display, w, &root, &parent, &children, &total );
530 if( children ) TSXFree( children );
531 } while( parent && parent != ancestor );
532 TRACE("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
533 return ( parent ) ? w : 0 ;
536 static unsigned __td_lookup( Window w, Window* list, unsigned max )
538 unsigned i;
539 for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
540 return i;
543 static HWND EVENT_QueryZOrder( HWND hWndCheck)
545 HWND hwndInsertAfter = HWND_TOP;
546 WND *pWndCheck = WIN_FindWndPtr(hWndCheck);
547 WND *pDesktop = WIN_GetDesktop();
548 WND *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
549 Window w, parent, *children = NULL;
550 unsigned total, check, pos, best;
552 if( !__check_query_condition(&pWndZ, &pWnd) )
554 WIN_ReleaseWndPtr(pWndCheck);
555 WIN_ReleaseWndPtr(pDesktop->child);
556 WIN_ReleaseDesktop();
557 return hwndInsertAfter;
559 WIN_LockWndPtr(pWndZ);
560 WIN_LockWndPtr(pWnd);
561 WIN_ReleaseWndPtr(pDesktop->child);
562 WIN_ReleaseDesktop();
564 parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ),
565 X11DRV_WND_GetXWindow(pWnd),
566 &children, &total );
567 if( parent && children )
569 /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
571 w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
573 if( w != children[total-1] ) /* check if at the top */
575 /* X child at index 0 is at the bottom, at index total-1 is at the top */
576 check = __td_lookup( w, children, total );
577 best = total;
579 for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
581 /* go through all windows in Wine z-order... */
583 if( pWnd != pWndCheck )
585 if( !(pWnd->flags & WIN_MANAGED) ||
586 !(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
587 continue;
588 pos = __td_lookup( w, children, total );
589 if( pos < best && pos > check )
591 /* find a nearest Wine window precedes
592 * pWndCheck in the real z-order... */
593 best = pos;
594 hwndInsertAfter = pWnd->hwndSelf;
596 if( best - check == 1 ) break;
601 if( children ) TSXFree( children );
602 WIN_ReleaseWndPtr(pWnd);
603 WIN_ReleaseWndPtr(pWndZ);
604 WIN_ReleaseWndPtr(pWndCheck);
605 return hwndInsertAfter;
608 /***********************************************************************
609 * X11DRV_EVENT_XStateToKeyState
611 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
612 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
614 WORD X11DRV_EVENT_XStateToKeyState( int state )
616 int kstate = 0;
618 if (state & Button1Mask) kstate |= MK_LBUTTON;
619 if (state & Button2Mask) kstate |= MK_MBUTTON;
620 if (state & Button3Mask) kstate |= MK_RBUTTON;
621 if (state & ShiftMask) kstate |= MK_SHIFT;
622 if (state & ControlMask) kstate |= MK_CONTROL;
623 return kstate;
626 /***********************************************************************
627 * EVENT_Expose
629 static void EVENT_Expose( HWND hWnd, XExposeEvent *event )
631 RECT rect;
633 WND *pWnd = WIN_FindWndPtr(hWnd);
634 /* Make position relative to client area instead of window */
635 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
636 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
637 rect.right = rect.left + event->width;
638 rect.bottom = rect.top + event->height;
639 WIN_ReleaseWndPtr(pWnd);
641 Callout.RedrawWindow( hWnd, &rect, 0,
642 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
643 (event->count ? 0 : RDW_ERASENOW) );
647 /***********************************************************************
648 * EVENT_GraphicsExpose
650 * This is needed when scrolling area is partially obscured
651 * by non-Wine X window.
653 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event )
655 RECT rect;
656 WND *pWnd = WIN_FindWndPtr(hWnd);
658 /* Make position relative to client area instead of window */
659 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
660 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
661 rect.right = rect.left + event->width;
662 rect.bottom = rect.top + event->height;
664 WIN_ReleaseWndPtr(pWnd);
666 Callout.RedrawWindow( hWnd, &rect, 0,
667 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
668 (event->count ? 0 : RDW_ERASENOW) );
672 /***********************************************************************
673 * EVENT_Key
675 * Handle a X key event
677 static void EVENT_Key( HWND hWnd, XKeyEvent *event )
679 WND *pWnd = WIN_FindWndPtr(hWnd);
680 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
681 WIN_ReleaseWndPtr(pWnd);
686 /***********************************************************************
687 * EVENT_MotionNotify
689 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event )
691 if (current_input_type == X11DRV_INPUT_ABSOLUTE) {
692 WND *pWnd = WIN_FindWndPtr(hWnd);
693 int xOffset = pWnd? pWnd->rectWindow.left : 0;
694 int yOffset = pWnd? pWnd->rectWindow.top : 0;
695 WIN_ReleaseWndPtr(pWnd);
697 X11DRV_MOUSE_SendEvent( MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
698 xOffset + event->x, yOffset + event->y,
699 X11DRV_EVENT_XStateToKeyState( event->state ),
700 event->time, hWnd);
701 } else {
702 X11DRV_MOUSE_SendEvent( MOUSEEVENTF_MOVE,
703 event->x_root, event->y_root,
704 X11DRV_EVENT_XStateToKeyState( event->state ),
705 event->time, hWnd);
710 /***********************************************************************
711 * EVENT_ButtonPress
713 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event )
715 static WORD statusCodes[NB_BUTTONS] =
716 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL};
717 int buttonNum = event->button - 1;
719 WND *pWnd = WIN_FindWndPtr(hWnd);
720 int xOffset = pWnd? pWnd->rectWindow.left : 0;
721 int yOffset = pWnd? pWnd->rectWindow.top : 0;
722 WORD keystate,wData = 0;
724 WIN_ReleaseWndPtr(pWnd);
726 if (buttonNum >= NB_BUTTONS) return;
729 * Get the compatible keystate
731 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
734 * Make sure that the state of the button that was just
735 * pressed is "down".
737 switch (buttonNum)
739 case 0:
740 keystate |= MK_LBUTTON;
741 break;
742 case 1:
743 keystate |= MK_MBUTTON;
744 break;
745 case 2:
746 keystate |= MK_RBUTTON;
747 break;
748 case 3:
749 wData = WHEEL_DELTA;
750 break;
751 case 4:
752 wData = -WHEEL_DELTA;
753 break;
756 X11DRV_MOUSE_SendEvent( statusCodes[buttonNum],
757 xOffset + event->x, yOffset + event->y,
758 MAKEWPARAM(keystate,wData),
759 event->time, hWnd);
763 /***********************************************************************
764 * EVENT_ButtonRelease
766 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event )
768 static WORD statusCodes[NB_BUTTONS] =
769 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
770 int buttonNum = event->button - 1;
771 WND *pWnd = WIN_FindWndPtr(hWnd);
772 int xOffset = pWnd? pWnd->rectWindow.left : 0;
773 int yOffset = pWnd? pWnd->rectWindow.top : 0;
774 WORD keystate;
776 WIN_ReleaseWndPtr(pWnd);
778 if (buttonNum >= NB_BUTTONS) return;
781 * Get the compatible keystate
783 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
786 * Make sure that the state of the button that was just
787 * released is "up".
789 switch (buttonNum)
791 case 0:
792 keystate &= ~MK_LBUTTON;
793 break;
794 case 1:
795 keystate &= ~MK_MBUTTON;
796 break;
797 case 2:
798 keystate &= ~MK_RBUTTON;
799 break;
800 default:
801 return;
804 X11DRV_MOUSE_SendEvent( statusCodes[buttonNum],
805 xOffset + event->x, yOffset + event->y,
806 keystate, event->time, hWnd);
810 /**********************************************************************
811 * EVENT_FocusIn
813 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
815 if (event->detail != NotifyPointer)
816 if (hWnd != GetForegroundWindow())
818 SetForegroundWindow( hWnd );
819 X11DRV_KEYBOARD_UpdateState();
824 /**********************************************************************
825 * EVENT_FocusOut
827 * Note: only top-level override-redirect windows get FocusOut events.
829 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
831 if (event->detail != NotifyPointer)
832 if (hWnd == GetForegroundWindow())
834 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
836 /* Abey : 6-Oct-99. Check again if the focus out window is the
837 Foreground window, because in most cases the messages sent
838 above must have already changed the foreground window, in which
839 case we don't have to change the foreground window to 0 */
841 if (hWnd == GetForegroundWindow())
842 SetForegroundWindow( 0 );
846 /**********************************************************************
847 * X11DRV_EVENT_CheckFocus
849 BOOL X11DRV_EVENT_CheckFocus(void)
851 HWND hWnd;
852 Window xW;
853 int state;
855 TSXGetInputFocus(display, &xW, &state);
856 if( xW == None ||
857 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
858 return FALSE;
859 return TRUE;
862 /**********************************************************************
863 * EVENT_GetGeometry
865 * Helper function for ConfigureNotify handling.
866 * Get the new geometry of a window relative to the root window.
868 static void EVENT_GetGeometry( Window win, int *px, int *py,
869 unsigned int *pwidth, unsigned int *pheight )
871 Window root, top;
872 int x, y, width, height, border, depth;
874 EnterCriticalSection( &X11DRV_CritSection );
876 /* Get the geometry of the window */
877 XGetGeometry( display, win, &root, &x, &y, &width, &height,
878 &border, &depth );
880 /* Translate the window origin to root coordinates */
881 XTranslateCoordinates( display, win, root, 0, 0, &x, &y, &top );
883 LeaveCriticalSection( &X11DRV_CritSection );
885 *px = x;
886 *py = y;
887 *pwidth = width;
888 *pheight = height;
891 /**********************************************************************
892 * EVENT_ConfigureNotify
894 * The ConfigureNotify event is only selected on top-level windows
895 * when the -managed flag is used.
897 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event )
899 RECT rectWindow;
900 int x, y, flags = 0;
901 unsigned int width, height;
902 HWND newInsertAfter, oldInsertAfter;
904 /* Get geometry and Z-order according to X */
906 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
907 newInsertAfter = EVENT_QueryZOrder( hWnd );
909 /* Get geometry and Z-order according to Wine */
912 * Needs to find the first Visible Window above the current one
914 oldInsertAfter = hWnd;
915 for (;;)
917 oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
918 if (!oldInsertAfter)
920 oldInsertAfter = HWND_TOP;
921 break;
923 if (GetWindowLongA( oldInsertAfter, GWL_STYLE ) & WS_VISIBLE) break;
926 /* Compare what has changed */
928 GetWindowRect( hWnd, &rectWindow );
929 if ( rectWindow.left == x && rectWindow.top == y )
930 flags |= SWP_NOMOVE;
931 else
932 TRACE_(win)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd,
933 rectWindow.left, rectWindow.top, x, y );
935 if ( rectWindow.right - rectWindow.left == width
936 && rectWindow.bottom - rectWindow.top == height )
937 flags |= SWP_NOSIZE;
938 else
939 TRACE_(win)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd,
940 rectWindow.right - rectWindow.left,
941 rectWindow.bottom - rectWindow.top, width, height );
943 if ( newInsertAfter == oldInsertAfter )
944 flags |= SWP_NOZORDER;
945 else
946 TRACE_(win)( "%04x restacking from after %04x to after %04x\n", hWnd,
947 oldInsertAfter, newInsertAfter );
949 /* If anything changed, call SetWindowPos */
951 if ( flags != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) )
952 SetWindowPos( hWnd, newInsertAfter, x, y, width, height,
953 flags | SWP_NOACTIVATE | SWP_WINE_NOHOSTMOVE );
957 /***********************************************************************
958 * EVENT_SelectionRequest_TARGETS
959 * Service a TARGETS selection request event
961 static Atom EVENT_SelectionRequest_TARGETS( Window requestor, Atom target, Atom rprop )
963 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
964 Atom* targets;
965 Atom prop;
966 UINT wFormat;
967 unsigned long cTargets;
968 BOOL bHavePixmap;
969 int xRc;
971 TRACE("Request for %s\n", TSXGetAtomName(display, target));
974 * Count the number of items we wish to expose as selection targets.
975 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
977 cTargets = CountClipboardFormats() + 1;
978 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
979 cTargets++;
981 /* Allocate temp buffer */
982 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
983 if(targets == NULL) return None;
985 /* Create TARGETS property list (First item in list is TARGETS itself) */
987 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
988 (wFormat = EnumClipboardFormats( wFormat )); )
990 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
992 /* Scan through what we have so far to avoid duplicates */
993 int i;
994 BOOL bExists;
995 for (i = 0, bExists = FALSE; i < cTargets; i++)
997 if (targets[i] == prop)
999 bExists = TRUE;
1000 break;
1003 if (!bExists)
1005 targets[cTargets++] = prop;
1007 /* Add PIXMAP prop for bitmaps additionally */
1008 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
1009 && !bHavePixmap )
1011 targets[cTargets++] = XA_PIXMAP;
1012 bHavePixmap = TRUE;
1018 if (TRACE_ON(event))
1020 int i;
1021 for ( i = 0; i < cTargets; i++)
1023 if (targets[i])
1025 char *itemFmtName = TSXGetAtomName(display, targets[i]);
1026 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
1027 TSXFree(itemFmtName);
1032 /* Update the X property */
1033 TRACE("\tUpdating property %s...", TSXGetAtomName(display, rprop));
1035 /* We may want to consider setting the type to xaTargets instead,
1036 * in case some apps expect this instead of XA_ATOM */
1037 xRc = TSXChangeProperty(display, requestor, rprop,
1038 XA_ATOM, 32, PropModeReplace,
1039 (unsigned char *)targets, cTargets);
1040 TRACE("(Rc=%d)\n", xRc);
1042 HeapFree( GetProcessHeap(), 0, targets );
1044 return rprop;
1048 /***********************************************************************
1049 * EVENT_SelectionRequest_STRING
1050 * Service a STRING selection request event
1052 static Atom EVENT_SelectionRequest_STRING( Window requestor, Atom target, Atom rprop )
1054 HANDLE16 hText;
1055 LPSTR text;
1056 int size,i,j;
1057 char* lpstr = 0;
1058 char *itemFmtName;
1059 int xRc;
1062 * Map the requested X selection property type atom name to a
1063 * windows clipboard format ID.
1065 itemFmtName = TSXGetAtomName(display, target);
1066 TRACE("Request for %s (wFormat=%x %s)\n",
1067 itemFmtName, CF_TEXT, CLIPBOARD_GetFormatName(CF_TEXT));
1068 TSXFree(itemFmtName);
1070 hText = GetClipboardData16(CF_TEXT);
1071 if ( !hText )
1072 return None;
1073 text = GlobalLock16(hText);
1074 if (!text)
1075 return None;
1076 size = GlobalSize16(hText);
1077 /* remove carriage returns */
1079 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
1080 if(lpstr == NULL) return None;
1081 for(i=0,j=0; i < size && text[i]; i++ )
1083 if( text[i] == '\r' &&
1084 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1085 lpstr[j++] = text[i];
1087 lpstr[j]='\0';
1089 /* Update the X property */
1090 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
1091 xRc = TSXChangeProperty(display, requestor, rprop,
1092 XA_STRING, 8, PropModeReplace,
1093 lpstr, j);
1094 TRACE("(Rc=%d)\n", xRc);
1096 GlobalUnlock16(hText);
1097 HeapFree( GetProcessHeap(), 0, lpstr );
1099 return rprop;
1102 /***********************************************************************
1103 * EVENT_SelectionRequest_PIXMAP
1104 * Service a PIXMAP selection request event
1106 static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
1108 HANDLE hClipData = 0;
1109 Pixmap pixmap = 0;
1110 UINT wFormat;
1111 char * itemFmtName;
1112 int xRc;
1113 #if(0)
1114 XSetWindowAttributes win_attr;
1115 XWindowAttributes win_attr_src;
1116 #endif
1119 * Map the requested X selection property type atom name to a
1120 * windows clipboard format ID.
1122 itemFmtName = TSXGetAtomName(display, target);
1123 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1124 TRACE("Request for %s (wFormat=%x %s)\n",
1125 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1126 TSXFree(itemFmtName);
1128 hClipData = GetClipboardData(wFormat);
1129 if ( !hClipData )
1131 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
1132 rprop = None; /* Fail the request */
1133 goto END;
1136 if (wFormat == CF_DIB)
1138 HWND hwnd = GetOpenClipboardWindow();
1139 HDC hdc = GetDC(hwnd);
1141 /* For convert from packed DIB to Pixmap */
1142 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
1144 ReleaseDC(hdc, hwnd);
1146 else if (wFormat == CF_BITMAP)
1148 HWND hwnd = GetOpenClipboardWindow();
1149 HDC hdc = GetDC(hwnd);
1151 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
1153 ReleaseDC(hdc, hwnd);
1155 else
1157 FIXME("%s to PIXMAP conversion not yet implemented!\n",
1158 CLIPBOARD_GetFormatName(wFormat));
1159 rprop = None;
1160 goto END;
1163 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
1164 TSXGetAtomName(display, rprop), (long)requestor,
1165 TSXGetAtomName(display, target), pixmap);
1167 /* Store the Pixmap handle in the property */
1168 xRc = TSXChangeProperty(display, requestor, rprop, target,
1169 32, PropModeReplace,
1170 (unsigned char *)&pixmap, 1);
1171 TRACE("(Rc=%d)\n", xRc);
1173 /* Enable the code below if you want to handle destroying Pixmap resources
1174 * in response to property notify events. Clients like XPaint don't
1175 * appear to be duplicating Pixmaps so they don't like us deleting,
1176 * the resource in response to the property being deleted.
1178 #if(0)
1179 /* Express interest in property notify events so that we can delete the
1180 * pixmap when the client deletes the property atom.
1182 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
1183 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
1184 (long)requestor);
1185 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
1186 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
1188 /* Register the Pixmap we created with the request property Atom.
1189 * When this property is destroyed we also destroy the Pixmap in
1190 * response to the PropertyNotify event.
1192 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
1193 #endif
1195 END:
1196 return rprop;
1200 /***********************************************************************
1201 * EVENT_SelectionRequest_WCF
1202 * Service a Wine Clipboard Format selection request event.
1203 * For <WCF>* data types we simply copy the data to X without conversion.
1205 static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
1207 HANDLE hClipData = 0;
1208 void* lpClipData;
1209 UINT wFormat;
1210 char * itemFmtName;
1211 int cBytes;
1212 int xRc;
1215 * Map the requested X selection property type atom name to a
1216 * windows clipboard format ID.
1218 itemFmtName = TSXGetAtomName(display, target);
1219 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1220 TRACE("Request for %s (wFormat=%x %s)\n",
1221 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1222 TSXFree(itemFmtName);
1224 hClipData = GetClipboardData16(wFormat);
1226 if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
1228 cBytes = GlobalSize16(hClipData);
1230 TRACE("\tUpdating property %s, %d bytes...\n",
1231 TSXGetAtomName(display, rprop), cBytes);
1233 xRc = TSXChangeProperty(display, requestor, rprop,
1234 target, 8, PropModeReplace,
1235 (unsigned char *)lpClipData, cBytes);
1236 TRACE("(Rc=%d)\n", xRc);
1238 GlobalUnlock16(hClipData);
1240 else
1242 TRACE("\tCould not retrieve native format!\n");
1243 rprop = None; /* Fail the request */
1246 return rprop;
1250 /***********************************************************************
1251 * EVENT_SelectionRequest_MULTIPLE
1252 * Service a MULTIPLE selection request event
1253 * rprop contains a list of (target,property) atom pairs.
1254 * The first atom names a target and the second names a property.
1255 * The effect is as if we have received a sequence of SelectionRequest events
1256 * (one for each atom pair) except that:
1257 * 1. We reply with a SelectionNotify only when all the requested conversions
1258 * have been performed.
1259 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1260 * we replace the atom in the property by None.
1262 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
1264 Atom rprop;
1265 Atom atype=AnyPropertyType;
1266 int aformat;
1267 unsigned long remain;
1268 Atom* targetPropList=NULL;
1269 unsigned long cTargetPropList = 0;
1270 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1272 /* If the specified property is None the requestor is an obsolete client.
1273 * We support these by using the specified target atom as the reply property.
1275 rprop = pevent->property;
1276 if( rprop == None )
1277 rprop = pevent->target;
1278 if (!rprop)
1279 goto END;
1281 /* Read the MULTIPLE property contents. This should contain a list of
1282 * (target,property) atom pairs.
1284 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
1285 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
1286 &cTargetPropList, &remain,
1287 (unsigned char**)&targetPropList) != Success)
1288 TRACE("\tCouldn't read MULTIPLE property\n");
1289 else
1291 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1292 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
1295 * Make sure we got what we expect.
1296 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1297 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1298 * However some X apps(such as XPaint) are not compliant with this and return
1299 * a user defined atom in atype when XGetWindowProperty is called.
1300 * The data *is* an atom pair but is not denoted as such.
1302 if(aformat == 32 /* atype == xAtomPair */ )
1304 int i;
1306 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1307 * for each (target,property) pair */
1309 for (i = 0; i < cTargetPropList; i+=2)
1311 char *targetName = TSXGetAtomName(display, targetPropList[i]);
1312 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
1313 XSelectionRequestEvent event;
1315 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
1316 i/2, targetName, propName);
1317 TSXFree(targetName);
1318 TSXFree(propName);
1320 /* We must have a non "None" property to service a MULTIPLE target atom */
1321 if ( !targetPropList[i+1] )
1323 TRACE("\tMULTIPLE(%d): Skipping target with empty property!", i);
1324 continue;
1327 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1328 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
1329 event.target = targetPropList[i];
1330 event.property = targetPropList[i+1];
1332 /* Fire a SelectionRequest, informing the handler that we are processing
1333 * a MULTIPLE selection request event.
1335 EVENT_SelectionRequest( hWnd, &event, TRUE );
1339 /* Free the list of targets/properties */
1340 TSXFree(targetPropList);
1343 END:
1344 return rprop;
1348 /***********************************************************************
1349 * EVENT_SelectionRequest
1350 * Process an event selection request event.
1351 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1352 * recursively while servicing a "MULTIPLE" selection target.
1354 * Note: We only receive this event when WINE owns the X selection
1356 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1358 XSelectionEvent result;
1359 Atom rprop = None;
1360 Window request = event->requestor;
1361 BOOL couldOpen = FALSE;
1362 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1363 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
1364 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1367 * We can only handle the selection request if :
1368 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1369 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1370 * since this has been already done.
1372 if ( !bIsMultiple )
1374 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1375 || !(couldOpen = OpenClipboard(hWnd)) )
1376 goto END;
1379 /* If the specified property is None the requestor is an obsolete client.
1380 * We support these by using the specified target atom as the reply property.
1382 rprop = event->property;
1383 if( rprop == None )
1384 rprop = event->target;
1386 if(event->target == xaTargets) /* Return a list of all supported targets */
1388 /* TARGETS selection request */
1389 rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
1391 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1393 /* MULTIPLE selection request */
1394 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1396 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1398 /* XA_STRING selection request */
1399 rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
1401 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1403 /* XA_PIXMAP selection request */
1404 rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
1406 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1408 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1409 rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
1411 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1413 /* All <WCF> selection requests */
1414 rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
1416 else
1417 rprop = None; /* Don't support this format */
1419 END:
1420 /* close clipboard only if we opened before */
1421 if(couldOpen) CloseClipboard();
1423 if( rprop == None)
1424 TRACE("\tRequest ignored\n");
1426 /* reply to sender
1427 * SelectionNotify should be sent only at the end of a MULTIPLE request
1429 if ( !bIsMultiple )
1431 result.type = SelectionNotify;
1432 result.display = display;
1433 result.requestor = request;
1434 result.selection = event->selection;
1435 result.property = rprop;
1436 result.target = event->target;
1437 result.time = event->time;
1438 TRACE("Sending SelectionNotify event...\n");
1439 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1443 /***********************************************************************
1444 * EVENT_SelectionClear
1446 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1448 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1450 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1451 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1454 /***********************************************************************
1455 * EVENT_PropertyNotify
1456 * We use this to release resources like Pixmaps when a selection
1457 * client no longer needs them.
1459 static void EVENT_PropertyNotify( XPropertyEvent *event )
1461 /* Check if we have any resources to free */
1462 TRACE("Received PropertyNotify event: ");
1464 switch(event->state)
1466 case PropertyDelete:
1468 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1469 TSXGetAtomName(event->display, event->atom), (long)event->window);
1471 if (X11DRV_CLIPBOARD_IsSelectionowner())
1472 X11DRV_CLIPBOARD_FreeResources( event->atom );
1473 break;
1476 case PropertyNewValue:
1478 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1479 TSXGetAtomName(event->display, event->atom), (long)event->window);
1480 break;
1483 default:
1484 break;
1488 /**********************************************************************
1489 * EVENT_DropFromOffix
1491 * don't know if it still works (last Changlog is from 96/11/04)
1493 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1495 unsigned long data_length;
1496 unsigned long aux_long;
1497 unsigned char* p_data = NULL;
1498 union {
1499 Atom atom_aux;
1500 struct {
1501 int x;
1502 int y;
1503 } pt_aux;
1504 int i;
1505 } u;
1506 int x, y;
1507 BOOL16 bAccept;
1508 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1509 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1510 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1511 Window w_aux_root, w_aux_child;
1512 WND* pDropWnd;
1513 WND* pWnd;
1515 if( !lpDragInfo || !spDragInfo ) return;
1517 pWnd = WIN_FindWndPtr(hWnd);
1519 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
1520 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1521 (unsigned int*)&aux_long);
1523 lpDragInfo->hScope = hWnd;
1524 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1526 /* find out drop point and drop window */
1527 if( x < 0 || y < 0 ||
1528 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1529 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1530 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1531 else
1533 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1534 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1536 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1537 WIN_ReleaseWndPtr(pWnd);
1539 GlobalFree16( hDragInfo );
1541 if( bAccept )
1543 TSXGetWindowProperty( display, DefaultRootWindow(display),
1544 dndSelection, 0, 65535, FALSE,
1545 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1546 &data_length, &aux_long, &p_data);
1548 if( !aux_long && p_data) /* don't bother if > 64K */
1550 char *p = (char*) p_data;
1551 char *p_drop;
1553 aux_long = 0;
1554 while( *p ) /* calculate buffer size */
1556 p_drop = p;
1557 if((u.i = *p) != -1 )
1558 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1559 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1560 else
1562 INT len = GetShortPathNameA( p, NULL, 0 );
1563 if (len) aux_long += len + 1;
1564 else *p = -1;
1566 p += strlen(p) + 1;
1568 if( aux_long && aux_long < 65535 )
1570 HDROP16 hDrop;
1571 LPDROPFILESTRUCT16 lpDrop;
1573 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1574 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1575 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1577 if( lpDrop )
1579 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1580 lpDrop->ptMousePos.x = (INT16)x;
1581 lpDrop->ptMousePos.y = (INT16)y;
1582 lpDrop->fInNonClientArea = (BOOL16)
1583 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1584 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1585 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1586 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1587 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1588 p = p_data;
1589 while(*p)
1591 if( *p != -1 ) /* use only "good" entries */
1593 GetShortPathNameA( p, p_drop, 65535 );
1594 p_drop += strlen( p_drop ) + 1;
1596 p += strlen(p) + 1;
1598 *p_drop = '\0';
1599 PostMessage16( hWnd, WM_DROPFILES,
1600 (WPARAM16)hDrop, 0L );
1604 if( p_data ) TSXFree(p_data);
1606 } /* WS_EX_ACCEPTFILES */
1608 WIN_ReleaseWndPtr(pDropWnd);
1611 /**********************************************************************
1612 * EVENT_DropURLs
1614 * drop items are separated by \n
1615 * each item is prefixed by its mime type
1617 * event->data.l[3], event->data.l[4] contains drop x,y position
1619 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1621 WND *pDropWnd;
1622 WND *pWnd;
1623 unsigned long data_length;
1624 unsigned long aux_long, drop_len = 0;
1625 unsigned char *p_data = NULL; /* property data */
1626 char *p_drop = NULL;
1627 char *p, *next;
1628 int x, y, drop32 = FALSE ;
1629 union {
1630 Atom atom_aux;
1631 int i;
1632 Window w_aux;
1633 } u; /* unused */
1634 union {
1635 HDROP16 h16;
1636 HDROP h32;
1637 } hDrop;
1639 pWnd = WIN_FindWndPtr(hWnd);
1640 drop32 = pWnd->flags & WIN_ISWIN32;
1642 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1644 WIN_ReleaseWndPtr(pWnd);
1645 return;
1647 WIN_ReleaseWndPtr(pWnd);
1649 TSXGetWindowProperty( display, DefaultRootWindow(display),
1650 dndSelection, 0, 65535, FALSE,
1651 AnyPropertyType, &u.atom_aux, &u.i,
1652 &data_length, &aux_long, &p_data);
1653 if (aux_long)
1654 WARN("property too large, truncated!\n");
1655 TRACE("urls=%s\n", p_data);
1657 if( !aux_long && p_data) { /* don't bother if > 64K */
1658 /* calculate length */
1659 p = p_data;
1660 next = strchr(p, '\n');
1661 while (p) {
1662 if (next) *next=0;
1663 if (strncmp(p,"file:",5) == 0 ) {
1664 INT len = GetShortPathNameA( p+5, NULL, 0 );
1665 if (len) drop_len += len + 1;
1667 if (next) {
1668 *next = '\n';
1669 p = next + 1;
1670 next = strchr(p, '\n');
1671 } else {
1672 p = NULL;
1676 if( drop_len && drop_len < 65535 ) {
1677 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
1678 &x, &y, &u.i, &u.i, &u.i);
1680 pDropWnd = WIN_FindWndPtr( hWnd );
1682 if (drop32) {
1683 LPDROPFILESTRUCT lpDrop;
1684 drop_len += sizeof(DROPFILESTRUCT) + 1;
1685 hDrop.h32 = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
1686 lpDrop = (LPDROPFILESTRUCT) GlobalLock( hDrop.h32 );
1688 if( lpDrop ) {
1689 lpDrop->lSize = sizeof(DROPFILESTRUCT);
1690 lpDrop->ptMousePos.x = (INT)x;
1691 lpDrop->ptMousePos.y = (INT)y;
1692 lpDrop->fInNonClientArea = (BOOL)
1693 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1694 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1695 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1696 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1697 lpDrop->fWideChar = FALSE;
1698 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1700 } else {
1701 LPDROPFILESTRUCT16 lpDrop;
1702 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1703 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1704 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1706 if( lpDrop ) {
1707 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1708 lpDrop->ptMousePos.x = (INT16)x;
1709 lpDrop->ptMousePos.y = (INT16)y;
1710 lpDrop->fInNonClientArea = (BOOL16)
1711 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1712 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1713 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1714 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1715 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1719 /* create message content */
1720 if (p_drop) {
1721 p = p_data;
1722 next = strchr(p, '\n');
1723 while (p) {
1724 if (next) *next=0;
1725 if (strncmp(p,"file:",5) == 0 ) {
1726 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1727 if (len) {
1728 TRACE("drop file %s as %s\n", p+5, p_drop);
1729 p_drop += len+1;
1730 } else {
1731 WARN("can't convert file %s to dos name \n", p+5);
1733 } else {
1734 WARN("unknown mime type %s\n", p);
1736 if (next) {
1737 *next = '\n';
1738 p = next + 1;
1739 next = strchr(p, '\n');
1740 } else {
1741 p = NULL;
1743 *p_drop = '\0';
1746 if (drop32) {
1747 /* can not use PostMessage32A because it is currently based on
1748 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1750 GlobalUnlock(hDrop.h32);
1751 SendMessageA( hWnd, WM_DROPFILES,
1752 (WPARAM)hDrop.h32, 0L );
1753 } else {
1754 GlobalUnlock16(hDrop.h16);
1755 PostMessage16( hWnd, WM_DROPFILES,
1756 (WPARAM16)hDrop.h16, 0L );
1759 WIN_ReleaseWndPtr(pDropWnd);
1761 if( p_data ) TSXFree(p_data);
1765 /**********************************************************************
1766 * EVENT_ClientMessage
1768 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1770 if (event->message_type != None && event->format == 32) {
1771 if ((event->message_type == wmProtocols) &&
1772 (((Atom) event->data.l[0]) == wmDeleteWindow))
1774 /* Ignore the delete window request if the window has been disabled
1775 * and we are in managed mode. This is to disallow applications from
1776 * being closed by the window manager while in a modal state.
1778 BOOL bIsDisabled;
1779 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
1781 if ( !Options.managed || !bIsDisabled )
1782 PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1784 else if ( event->message_type == dndProtocol &&
1785 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1786 EVENT_DropFromOffiX(hWnd, event);
1787 else if ( event->message_type == dndProtocol &&
1788 event->data.l[0] == DndURL )
1789 EVENT_DropURLs(hWnd, event);
1790 else {
1791 #if 0
1792 /* enable this if you want to see the message */
1793 unsigned char* p_data = NULL;
1794 union {
1795 unsigned long l;
1796 int i;
1797 Atom atom;
1798 } u; /* unused */
1799 TSXGetWindowProperty( display, DefaultRootWindow(display),
1800 dndSelection, 0, 65535, FALSE,
1801 AnyPropertyType, &u.atom, &u.i,
1802 &u.l, &u.l, &p_data);
1803 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1804 event->message_type, event->data.l[0], event->data.l[1],
1805 event->data.l[2], event->data.l[3], event->data.l[4],
1806 p_data);
1807 #endif
1808 TRACE("unrecognized ClientMessage\n" );
1813 /**********************************************************************
1814 * EVENT_EnterNotify
1816 * Install colormap when Wine window is focused in
1817 * self-managed mode with private colormap
1819 #if 0
1820 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
1822 if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1823 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1824 TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
1826 #endif
1828 /**********************************************************************
1829 * EVENT_MapNotify
1831 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1833 HWND hwndFocus = GetFocus();
1834 WND *wndFocus = WIN_FindWndPtr(hwndFocus);
1835 WND *pWnd = WIN_FindWndPtr(hWnd);
1836 if (pWnd->flags & WIN_MANAGED)
1838 DCE_InvalidateDCE( pWnd, &pWnd->rectWindow );
1839 pWnd->dwStyle &= ~WS_MINIMIZE;
1840 pWnd->dwStyle |= WS_VISIBLE;
1841 ShowOwnedPopups(hWnd,TRUE);
1843 WIN_ReleaseWndPtr(pWnd);
1845 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1846 X11DRV_WND_SetFocus(wndFocus);
1848 WIN_ReleaseWndPtr(wndFocus);
1850 return;
1854 /**********************************************************************
1855 * EVENT_MapNotify
1857 void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
1859 WND *pWnd = WIN_FindWndPtr(hWnd);
1860 if (pWnd->flags & WIN_MANAGED)
1862 EndMenu();
1863 if( pWnd->dwStyle & WS_VISIBLE )
1865 pWnd->dwStyle |= WS_MINIMIZE;
1866 pWnd->dwStyle &= ~WS_VISIBLE;
1867 ShowOwnedPopups(hWnd,FALSE);
1870 WIN_ReleaseWndPtr(pWnd);
1873 /***********************************************************************
1874 * EVENT_MappingNotify
1876 static void EVENT_MappingNotify( XMappingEvent *event )
1878 TSXRefreshKeyboardMapping(event);
1880 /* reinitialize Wine-X11 driver keyboard table */
1881 X11DRV_KEYBOARD_Init();
1885 /**********************************************************************
1886 * X11DRV_EVENT_SetInputMethod
1888 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1890 INPUT_TYPE prev = current_input_type;
1892 /* Flag not used yet */
1893 in_transition = FALSE;
1894 current_input_type = type;
1896 return prev;
1899 #ifdef HAVE_LIBXXF86DGA2
1900 /**********************************************************************
1901 * X11DRV_EVENT_SetDGAStatus
1903 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1905 if (event_base < 0) {
1906 DGAUsed = FALSE;
1907 DGAhwnd = 0;
1908 } else {
1909 DGAUsed = TRUE;
1910 DGAhwnd = hwnd;
1911 DGAMotionEventType = event_base + MotionNotify;
1912 DGAButtonPressEventType = event_base + ButtonPress;
1913 DGAButtonReleaseEventType = event_base + ButtonRelease;
1914 DGAKeyPressEventType = event_base + KeyPress;
1915 DGAKeyReleaseEventType = event_base + KeyRelease;
1919 /* DGA2 event handlers */
1920 static void EVENT_DGAMotionEvent( XDGAMotionEvent *event )
1922 X11DRV_MOUSE_SendEvent( MOUSEEVENTF_MOVE,
1923 event->dx, event->dy,
1924 X11DRV_EVENT_XStateToKeyState( event->state ),
1925 event->time, DGAhwnd );
1928 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent *event )
1930 static WORD statusCodes[NB_BUTTONS] =
1931 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
1932 int buttonNum = event->button - 1;
1934 WORD keystate;
1936 if (buttonNum >= NB_BUTTONS) return;
1938 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1940 switch (buttonNum)
1942 case 0:
1943 keystate |= MK_LBUTTON;
1944 break;
1945 case 1:
1946 keystate |= MK_MBUTTON;
1947 break;
1948 case 2:
1949 keystate |= MK_RBUTTON;
1950 break;
1953 X11DRV_MOUSE_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time, DGAhwnd );
1956 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent *event )
1958 static WORD statusCodes[NB_BUTTONS] =
1959 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
1960 int buttonNum = event->button - 1;
1962 WORD keystate;
1964 if (buttonNum >= NB_BUTTONS) return;
1966 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1968 switch (buttonNum)
1970 case 0:
1971 keystate &= ~MK_LBUTTON;
1972 break;
1973 case 1:
1974 keystate &= ~MK_MBUTTON;
1975 break;
1976 case 2:
1977 keystate &= ~MK_RBUTTON;
1978 break;
1981 X11DRV_MOUSE_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time, DGAhwnd );
1984 #endif
1986 #ifdef HAVE_LIBXXSHM
1989 Normal XShm operation:
1991 X11 service thread app thread
1992 ------------- ----------------- ------------------------
1993 (idle) ddraw calls XShmPutImage
1994 (copies data) (waiting for shm_event)
1995 ShmCompletion -> (waiting for shm_event)
1996 (idle) signal shm_event ->
1997 (idle) returns to app
1999 However, this situation can occur for some reason:
2001 X11 service thread app thread
2002 ------------- ----------------- ------------------------
2003 Expose ->
2004 WM_ERASEBKGND? ->
2005 (waiting for app) ddraw calls XShmPutImage
2006 (copies data) (waiting for app) (waiting for shm_event)
2007 ShmCompletion (waiting for app) (waiting for shm_event)
2008 (idle) DEADLOCK DEADLOCK
2010 which is why I also wait for shm_read and do XCheckTypedEvent()
2011 calls in the wait loop. This results in:
2013 X11 service thread app thread
2014 ------------- ----------------- ------------------------
2015 ShmCompletion (waiting for app) waking up on shm_read
2016 (idle) (waiting for app) XCheckTypedEvent() -> signal shm_event
2017 (waiting for app) returns
2018 (idle)
2021 typedef struct {
2022 Drawable draw;
2023 LONG state, waiter;
2024 HANDLE sema;
2025 } shm_qs;
2027 /* FIXME: this is not pretty */
2028 static HANDLE shm_read = 0;
2030 #define SHM_MAX_Q 4
2031 static volatile shm_qs shm_q[SHM_MAX_Q];
2033 static void EVENT_ShmCompletion( XShmCompletionEvent *event )
2035 int n;
2037 TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event->drawable, GetTickCount() );
2039 for (n=0; n<SHM_MAX_Q; n++)
2040 if ((shm_q[n].draw == event->drawable) && (shm_q[n].state == 0)) {
2041 HANDLE sema = shm_q[n].sema;
2042 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].state, (PVOID)1, (PVOID)0)) {
2043 ReleaseSemaphore(sema, 1, NULL);
2044 TRACE("Signaling ShmCompletion (#%d) (semaphore %x)\n", n, sema);
2046 return;
2049 ERR("Got ShmCompletion for unknown drawable %ld\n", event->drawable );
2052 int X11DRV_EVENT_PrepareShmCompletion( Drawable dw )
2054 int n;
2056 if (!shm_read)
2057 shm_read = FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE );
2059 for (n=0; n<SHM_MAX_Q; n++)
2060 if (!shm_q[n].draw)
2061 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].draw, (PVOID)dw, (PVOID)0))
2062 break;
2064 if (n>=SHM_MAX_Q) {
2065 ERR("Maximum number of outstanding ShmCompletions exceeded!\n");
2066 return 0;
2069 shm_q[n].state = 0;
2070 if (!shm_q[n].sema) {
2071 shm_q[n].sema = CreateSemaphoreA( NULL, 0, 256, NULL );
2072 TRACE("Allocated ShmCompletion slots have been increased to %d, new semaphore is %x\n", n+1, shm_q[n].sema);
2075 TRACE("Prepared ShmCompletion (#%d) wait for drawable %ld (thread %lx) (time %ld)\n", n, dw, GetCurrentThreadId(), GetTickCount() );
2076 return n+1;
2079 static void X11DRV_EVENT_WaitReplaceShmCompletionInternal( int *compl, Drawable dw, int creat )
2081 int n = *compl;
2082 LONG nn, st;
2083 HANDLE sema;
2085 if ((!n) || (creat && (!shm_q[n-1].draw))) {
2086 nn = X11DRV_EVENT_PrepareShmCompletion(dw);
2087 if (!(n=(LONG)InterlockedCompareExchange((PVOID*)compl, (PVOID)nn, (PVOID)n)))
2088 return;
2089 /* race for compl lost, clear slot */
2090 shm_q[nn-1].draw = 0;
2091 return;
2094 if (dw && (shm_q[n-1].draw != dw)) {
2095 /* this shouldn't happen with the current ddraw implementation */
2096 FIXME("ShmCompletion replace with different drawable!\n");
2097 return;
2100 sema = shm_q[n-1].sema;
2101 if (!sema) {
2102 /* nothing to wait on (PrepareShmCompletion not done yet?), so probably nothing to wait for */
2103 return;
2106 nn = InterlockedExchangeAdd((PLONG)&shm_q[n-1].waiter, 1);
2107 if ((!shm_q[n-1].draw) || (shm_q[n-1].state == 2)) {
2108 /* too late, the wait was just cleared (wait complete) */
2109 TRACE("Wait skip for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2110 } else {
2111 TRACE("Waiting for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2112 if (nn) {
2113 /* another thread is already waiting, let the primary waiter do the dirty work
2114 * (to avoid TSX critical section contention - that could get really slow) */
2115 WaitForSingleObject( sema, INFINITE );
2116 } else
2117 /* we're primary waiter - first check if it's already triggered */
2118 if ( WaitForSingleObject( sema, 0 ) != WAIT_OBJECT_0 ) {
2119 /* nope, may need to poll X event queue, in case the service thread is blocked */
2120 XEvent event;
2121 HANDLE hnd[2];
2123 hnd[0] = sema;
2124 hnd[1] = shm_read;
2125 do {
2126 /* check X event queue */
2127 if (TSXCheckTypedEvent( display, ShmCompletionType, &event)) {
2128 EVENT_ProcessEvent( &event );
2130 } while ( WaitForMultipleObjects(2, hnd, FALSE, INFINITE) > WAIT_OBJECT_0 );
2132 TRACE("Wait complete (thread %lx) (time %ld)\n", GetCurrentThreadId(), GetTickCount() );
2134 /* clear wait */
2135 st = InterlockedExchange((LPLONG)&shm_q[n-1].state, 2);
2136 if (st != 2) {
2137 /* first waiter to return, release all other waiters */
2138 nn = shm_q[n-1].waiter;
2139 TRACE("Signaling %ld additional ShmCompletion (#%d) waiter(s), semaphore %x\n", nn-1, n-1, sema);
2140 ReleaseSemaphore(sema, nn-1, NULL);
2143 nn = InterlockedDecrement((LPLONG)&shm_q[n-1].waiter);
2144 if (!nn) {
2145 /* last waiter to return, replace drawable and prepare new wait */
2146 shm_q[n-1].draw = dw;
2147 shm_q[n-1].state = 0;
2151 void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw )
2153 X11DRV_EVENT_WaitReplaceShmCompletionInternal( compl, dw, 1 );
2156 void X11DRV_EVENT_WaitShmCompletion( int compl )
2158 if (!compl) return;
2159 X11DRV_EVENT_WaitReplaceShmCompletionInternal( &compl, 0, 0 );
2162 void X11DRV_EVENT_WaitShmCompletions( Drawable dw )
2164 int n;
2166 for (n=0; n<SHM_MAX_Q; n++)
2167 if (shm_q[n].draw == dw)
2168 X11DRV_EVENT_WaitShmCompletion( n+1 );
2171 #endif /* defined(HAVE_LIBXXSHM) */