4 * Copyright 1993 Alexandre Julliard
10 #include <X11/Xatom.h>
11 #include <X11/keysym.h>
14 #include "ts_xresource.h"
19 #ifdef HAVE_LIBXXF86DGA2
20 #include "ts_xf86dga2.h"
25 #include "wine/winuser16.h"
26 #include "shlobj.h" /* DROPFILES */
28 #include "clipboard.h"
30 #include "debugtools.h"
46 DEFAULT_DEBUG_CHANNEL(event);
47 DECLARE_DEBUG_CHANNEL(win);
49 /* X context to associate a hwnd to an X window */
50 extern XContext winContext;
52 extern Atom wmProtocols;
53 extern Atom wmDeleteWindow;
54 extern Atom dndProtocol;
55 extern Atom dndSelection;
57 extern void X11DRV_KEYBOARD_UpdateState(void);
58 extern void X11DRV_KEYBOARD_HandleEvent(WND *pWnd, XKeyEvent *event);
60 #define NB_BUTTONS 5 /* Windows can handle 3 buttons and the wheel too */
63 #define DndNotDnd -1 /* OffiX drag&drop */
75 #define DndURL 128 /* KDE drag&drop */
77 /* The last X window which had the focus */
78 static Window glastXFocusWin = 0;
80 static const char * const event_names[] =
82 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
83 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
84 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
85 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
86 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
87 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
88 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
89 "ClientMessage", "MappingNotify"
93 static void CALLBACK EVENT_Flush( ULONG_PTR arg );
94 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg );
95 static void EVENT_ProcessEvent( XEvent *event );
96 BOOL X11DRV_CheckFocus(void);
99 static void EVENT_Key( HWND hWnd, XKeyEvent *event );
100 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event );
101 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event );
102 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event );
103 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
104 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
105 static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
106 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event );
107 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event );
108 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
109 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
110 static void EVENT_PropertyNotify( XPropertyEvent *event );
111 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
112 static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
113 static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
114 static void EVENT_MappingNotify( XMappingEvent *event );
117 static void EVENT_ShmCompletion( XShmCompletionEvent *event );
118 static int ShmAvailable, ShmCompletionType;
119 extern int XShmGetEventBase( Display * );/* Missing prototype for function in libXext. */
122 #ifdef HAVE_LIBXXF86DGA2
123 static int DGAMotionEventType;
124 static int DGAButtonPressEventType;
125 static int DGAButtonReleaseEventType;
126 static int DGAKeyPressEventType;
127 static int DGAKeyReleaseEventType;
129 static BOOL DGAUsed = FALSE;
130 static HWND DGAhwnd = 0;
132 static void EVENT_DGAMotionEvent( XDGAMotionEvent *event );
133 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent *event );
134 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent *event );
137 /* Usable only with OLVWM - compile option perhaps?
138 static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
141 static void EVENT_GetGeometry( Window win, int *px, int *py,
142 unsigned int *pwidth, unsigned int *pheight );
145 static BOOL bUserRepaintDisabled = TRUE;
147 /* Static used for the current input method */
148 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
149 static BOOL in_transition = FALSE; /* This is not used as for today */
151 /***********************************************************************
154 void X11DRV_EVENT_Init(void)
157 ShmAvailable = XShmQueryExtension( display );
159 ShmCompletionType = XShmGetEventBase( display ) + ShmCompletion;
163 /* Install the X event processing callback */
164 if (SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ|SYNCHRONIZE ),
165 EVENT_ProcessAllEvents, 0 ) == INVALID_HANDLE_VALUE)
167 ERR("cannot add service object\n");
171 /* Install the XFlush timer callback */
172 if ( Options.synchronous )
173 TSXSynchronize( display, True );
175 SERVICE_AddTimer( 200, EVENT_Flush, 0 );
178 /***********************************************************************
181 static void CALLBACK EVENT_Flush( ULONG_PTR arg )
186 /***********************************************************************
187 * EVENT_ProcessAllEvents
189 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
193 TRACE( "called (thread %lx).\n", GetCurrentThreadId() );
196 while ( XPending( display ) )
198 XNextEvent( display, &event );
200 EVENT_ProcessEvent( &event );
206 /***********************************************************************
207 * Synchronize (X11DRV.@)
209 * Synchronize with the X server. Should not be used too often.
211 void X11DRV_Synchronize( void )
213 TSXSync( display, False );
214 EVENT_ProcessAllEvents( 0 );
217 /***********************************************************************
218 * UserRepaintDisable (X11DRV.@)
220 void X11DRV_UserRepaintDisable( BOOL bDisabled )
222 bUserRepaintDisabled = bDisabled;
225 /***********************************************************************
228 * Process an X event.
230 static void EVENT_ProcessEvent( XEvent *event )
234 TRACE( "called.\n" );
238 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
239 FIXME("Got SelectionNotify - must not happen!\n");
242 /* We get all these because of StructureNotifyMask.
243 This check is placed here to avoid getting error messages below,
244 as X might send some of these even for windows that have already
246 case CirculateNotify:
255 if (ShmAvailable && (event->type == ShmCompletionType)) {
256 EVENT_ShmCompletion( (XShmCompletionEvent*)event );
261 #ifdef HAVE_LIBXXF86DGA2
263 if (event->type == DGAMotionEventType) {
264 TRACE("DGAMotionEvent received.\n");
265 EVENT_DGAMotionEvent((XDGAMotionEvent *) event);
268 if (event->type == DGAButtonPressEventType) {
269 TRACE("DGAButtonPressEvent received.\n");
270 EVENT_DGAButtonPressEvent((XDGAButtonEvent *) event);
273 if (event->type == DGAButtonReleaseEventType) {
274 TRACE("DGAButtonReleaseEvent received.\n");
275 EVENT_DGAButtonReleaseEvent((XDGAButtonEvent *) event);
278 if ((event->type == DGAKeyPressEventType) ||
279 (event->type == DGAKeyReleaseEventType)) {
280 /* Fill a XKeyEvent to send to EVENT_Key */
283 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
285 TRACE("DGAKeyPress/ReleaseEvent received.\n");
288 if (evt->type == DGAKeyReleaseEventType)
289 ke.type = KeyRelease;
292 ke.serial = evt->serial;
293 ke.send_event = FALSE;
294 ke.display = evt->display;
303 ke.state = evt->state;
304 ke.keycode = evt->keycode;
305 ke.same_screen = TRUE;
307 X11DRV_KEYBOARD_HandleEvent(NULL, &ke);
313 if ( TSXFindContext( display, event->xany.window, winContext,
314 (char **)&hWnd ) != 0) {
315 if ( event->type == ClientMessage) {
316 /* query window (drag&drop event contains only drag window) */
318 int root_x, root_y, child_x, child_y;
320 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
321 &root_x, &root_y, &child_x, &child_y, &u);
322 if (TSXFindContext( display, child, winContext, (char **)&hWnd ) != 0)
325 hWnd = 0; /* Not for a registered window */
329 if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow()
330 && event->type != PropertyNotify
331 && event->type != MappingNotify)
332 ERR("Got event %s for unknown Window %08lx\n",
333 event_names[event->type], event->xany.window );
335 TRACE("Got event %s for hwnd %04x\n",
336 event_names[event->type], hWnd );
342 EVENT_Key( hWnd, (XKeyEvent*)event );
346 EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
350 EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
354 /* Wine between two fast machines across the overloaded campus
355 ethernet gets very boged down in MotionEvents. The following
356 simply finds the last motion event in the queue and drops
357 the rest. On a good link events are servered before they build
358 up so this doesn't take place. On a slow link this may cause
359 problems if the event order is important. I'm not yet seen
360 of any problems. Jon 7/6/96.
362 if ((current_input_type == X11DRV_INPUT_ABSOLUTE) &&
363 (in_transition == FALSE))
364 /* Only cumulate events if in absolute mode */
365 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
366 MotionNotify, event));
367 EVENT_MotionNotify( hWnd, (XMotionEvent*)event );
372 WND *pWndLastFocus = 0;
373 XWindowAttributes win_attr;
375 XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
377 if (!hWnd || bUserRepaintDisabled) return;
379 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
381 /* If the window has been disabled and we are in managed mode,
382 * revert the X focus back to the last focus window. This is to disallow
383 * the window manager from switching focus away while the app is
386 if ( Options.managed && bIsDisabled && glastXFocusWin)
388 /* Change focus only if saved focus window is registered and viewable */
389 if ( TSXFindContext( xfocChange->display, glastXFocusWin, winContext,
390 (char **)&pWndLastFocus ) == 0 )
392 if ( TSXGetWindowAttributes( display, glastXFocusWin, &win_attr ) &&
393 (win_attr.map_state == IsViewable) )
395 TSXSetInputFocus( xfocChange->display, glastXFocusWin, RevertToParent, CurrentTime );
402 EVENT_FocusIn( hWnd, xfocChange );
408 /* Save the last window which had the focus */
409 XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
410 glastXFocusWin = xfocChange->window;
411 if (!hWnd || bUserRepaintDisabled) return;
412 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
413 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
418 if (bUserRepaintDisabled) return;
419 EVENT_Expose( hWnd, (XExposeEvent *)event );
423 if (bUserRepaintDisabled) return;
424 EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
427 case ConfigureNotify:
428 if (!hWnd || bUserRepaintDisabled) return;
429 EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
432 case SelectionRequest:
433 if (!hWnd || bUserRepaintDisabled) return;
434 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
438 if (!hWnd || bUserRepaintDisabled) return;
439 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
443 EVENT_PropertyNotify( (XPropertyEvent *)event );
447 if (!hWnd || bUserRepaintDisabled) return;
448 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
453 EVENT_EnterNotify( hWnd, (XCrossingEvent *) event );
461 if (!hWnd || bUserRepaintDisabled) return;
462 EVENT_MapNotify( hWnd, (XMapEvent *)event );
466 if (!hWnd || bUserRepaintDisabled) return;
467 EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
471 EVENT_MappingNotify( (XMappingEvent *) event );
475 WARN("Unprocessed event %s for hwnd %04x\n",
476 event_names[event->type], hWnd );
479 TRACE( "returns.\n" );
482 /***********************************************************************
485 * Synchronize internal z-order with the window manager's.
487 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
489 /* return TRUE if we have at least two managed windows */
491 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
492 if( ((*pWndA)->dwExStyle & WS_EX_MANAGED) &&
493 ((*pWndA)->dwStyle & WS_VISIBLE )) break;
495 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
496 if( ((*pWndB)->dwExStyle & WS_EX_MANAGED) &&
497 ((*pWndB)->dwStyle & WS_VISIBLE )) break;
498 return ((*pWndB) != NULL);
501 static Window __get_common_ancestor( Window A, Window B,
502 Window** children, unsigned* total )
504 /* find the real root window */
506 Window root, *childrenB;
511 TSXQueryTree( display, A, &root, &A, children, total );
512 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
513 if( childrenB ) TSXFree( childrenB );
514 if( *children ) TSXFree( *children ), *children = NULL;
515 } while( A != B && A && B );
519 TSXQueryTree( display, A, &root, &B, children, total );
525 static Window __get_top_decoration( Window w, Window ancestor )
527 Window* children, root, prev = w, parent = w;
533 TSXQueryTree( display, w, &root, &parent, &children, &total );
534 if( children ) TSXFree( children );
535 } while( parent && parent != ancestor );
536 TRACE("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
537 return ( parent ) ? w : 0 ;
540 static unsigned __td_lookup( Window w, Window* list, unsigned max )
543 for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
547 static HWND EVENT_QueryZOrder( HWND hWndCheck)
549 HWND hwndInsertAfter = HWND_TOP;
550 WND *pWndCheck = WIN_FindWndPtr(hWndCheck);
551 WND *pDesktop = WIN_GetDesktop();
552 WND *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
553 Window w, parent, *children = NULL;
554 unsigned total, check, pos, best;
556 if( !__check_query_condition(&pWndZ, &pWnd) )
558 WIN_ReleaseWndPtr(pWndCheck);
559 WIN_ReleaseWndPtr(pDesktop->child);
560 WIN_ReleaseDesktop();
561 return hwndInsertAfter;
563 WIN_LockWndPtr(pWndZ);
564 WIN_LockWndPtr(pWnd);
565 WIN_ReleaseWndPtr(pDesktop->child);
566 WIN_ReleaseDesktop();
568 parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ),
569 X11DRV_WND_GetXWindow(pWnd),
571 if( parent && children )
573 /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
575 w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
577 if( w != children[total-1] ) /* check if at the top */
579 /* X child at index 0 is at the bottom, at index total-1 is at the top */
580 check = __td_lookup( w, children, total );
583 for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
585 /* go through all windows in Wine z-order... */
587 if( pWnd != pWndCheck )
589 if( !(pWnd->dwExStyle & WS_EX_MANAGED) ||
590 !(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
592 pos = __td_lookup( w, children, total );
593 if( pos < best && pos > check )
595 /* find a nearest Wine window precedes
596 * pWndCheck in the real z-order... */
598 hwndInsertAfter = pWnd->hwndSelf;
600 if( best - check == 1 ) break;
605 if( children ) TSXFree( children );
606 WIN_ReleaseWndPtr(pWnd);
607 WIN_ReleaseWndPtr(pWndZ);
608 WIN_ReleaseWndPtr(pWndCheck);
609 return hwndInsertAfter;
612 /***********************************************************************
613 * X11DRV_EVENT_XStateToKeyState
615 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
616 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
618 WORD X11DRV_EVENT_XStateToKeyState( int state )
622 if (state & Button1Mask) kstate |= MK_LBUTTON;
623 if (state & Button2Mask) kstate |= MK_MBUTTON;
624 if (state & Button3Mask) kstate |= MK_RBUTTON;
625 if (state & ShiftMask) kstate |= MK_SHIFT;
626 if (state & ControlMask) kstate |= MK_CONTROL;
630 /***********************************************************************
633 static void EVENT_Expose( HWND hWnd, XExposeEvent *event )
636 int offx = 0,offy = 0;
638 WND *pWnd = WIN_FindWndPtr(hWnd);
639 /* Make position relative to client area instead of window */
640 offx = (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
641 offy = (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
643 rect.left = event->x - offx;
644 rect.top = event->y - offy;
646 rect.right = rect.left + event->width;
647 rect.bottom = rect.top + event->height;
649 WIN_ReleaseWndPtr(pWnd);
651 RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE );
653 if (event->count == 0)
654 SendNotifyMessageA(hWnd,WM_SYNCPAINT, 0, 0);
658 /***********************************************************************
659 * EVENT_GraphicsExpose
661 * This is needed when scrolling area is partially obscured
662 * by non-Wine X window.
664 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event )
667 int offx = 0,offy = 0;
669 WND *pWnd = WIN_FindWndPtr(hWnd);
670 /* Make position relative to client area instead of window */
671 offx = (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
672 offy = (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
674 rect.left = event->x - offx;
675 rect.top = event->y - offy;
677 rect.right = rect.left + event->width;
678 rect.bottom = rect.top + event->height;
680 WIN_ReleaseWndPtr(pWnd);
682 RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE );
684 if (event->count == 0)
685 SendNotifyMessageA(hWnd,WM_SYNCPAINT, 0, 0);
689 /***********************************************************************
692 * Handle a X key event
694 static void EVENT_Key( HWND hWnd, XKeyEvent *event )
696 WND *pWnd = WIN_FindWndPtr(hWnd);
697 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
698 WIN_ReleaseWndPtr(pWnd);
703 /***********************************************************************
706 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event )
708 if (current_input_type == X11DRV_INPUT_ABSOLUTE) {
709 WND *pWnd = WIN_FindWndPtr(hWnd);
710 int xOffset = pWnd? pWnd->rectWindow.left : 0;
711 int yOffset = pWnd? pWnd->rectWindow.top : 0;
712 WIN_ReleaseWndPtr(pWnd);
714 X11DRV_SendEvent( MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
715 xOffset + event->x, yOffset + event->y,
716 X11DRV_EVENT_XStateToKeyState( event->state ),
717 event->time - X11DRV_server_startticks, hWnd);
719 X11DRV_SendEvent( MOUSEEVENTF_MOVE,
720 event->x_root, event->y_root,
721 X11DRV_EVENT_XStateToKeyState( event->state ),
722 event->time - X11DRV_server_startticks, hWnd);
727 /***********************************************************************
730 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event )
732 static WORD statusCodes[NB_BUTTONS] =
733 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL};
734 int buttonNum = event->button - 1;
736 WND *pWnd = WIN_FindWndPtr(hWnd);
737 int xOffset = pWnd? pWnd->rectWindow.left : 0;
738 int yOffset = pWnd? pWnd->rectWindow.top : 0;
739 WORD keystate,wData = 0;
741 WIN_ReleaseWndPtr(pWnd);
743 if (buttonNum >= NB_BUTTONS) return;
746 * Get the compatible keystate
748 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
751 * Make sure that the state of the button that was just
757 keystate |= MK_LBUTTON;
760 keystate |= MK_MBUTTON;
763 keystate |= MK_RBUTTON;
769 wData = -WHEEL_DELTA;
773 X11DRV_SendEvent( statusCodes[buttonNum],
774 xOffset + event->x, yOffset + event->y,
775 MAKEWPARAM(keystate,wData),
776 event->time - X11DRV_server_startticks, hWnd);
780 /***********************************************************************
781 * EVENT_ButtonRelease
783 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event )
785 static WORD statusCodes[NB_BUTTONS] =
786 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
787 int buttonNum = event->button - 1;
788 WND *pWnd = WIN_FindWndPtr(hWnd);
789 int xOffset = pWnd? pWnd->rectWindow.left : 0;
790 int yOffset = pWnd? pWnd->rectWindow.top : 0;
793 WIN_ReleaseWndPtr(pWnd);
795 if (buttonNum >= NB_BUTTONS) return;
798 * Get the compatible keystate
800 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
803 * Make sure that the state of the button that was just
809 keystate &= ~MK_LBUTTON;
812 keystate &= ~MK_MBUTTON;
815 keystate &= ~MK_RBUTTON;
821 X11DRV_SendEvent( statusCodes[buttonNum],
822 xOffset + event->x, yOffset + event->y,
823 keystate, event->time - X11DRV_server_startticks, hWnd);
827 /**********************************************************************
830 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
832 if (event->detail != NotifyPointer)
833 if (hWnd != GetForegroundWindow())
835 SetForegroundWindow( hWnd );
836 X11DRV_KEYBOARD_UpdateState();
841 /**********************************************************************
844 * Note: only top-level override-redirect windows get FocusOut events.
846 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
848 if (event->detail != NotifyPointer)
849 if (hWnd == GetForegroundWindow())
851 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
854 /* don't reset the foreground window, if the window who's
855 getting the focus is a Wine window */
856 if (!X11DRV_CheckFocus())
858 /* Abey : 6-Oct-99. Check again if the focus out window is the
859 Foreground window, because in most cases the messages sent
860 above must have already changed the foreground window, in which
861 case we don't have to change the foreground window to 0 */
863 if (hWnd == GetForegroundWindow())
864 SetForegroundWindow( 0 );
869 /**********************************************************************
870 * CheckFocus (X11DRV.@)
872 BOOL X11DRV_CheckFocus(void)
878 TSXGetInputFocus(display, &xW, &state);
880 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
885 /**********************************************************************
888 * Helper function for ConfigureNotify handling.
889 * Get the new geometry of a window relative to the root window.
891 static void EVENT_GetGeometry( Window win, int *px, int *py,
892 unsigned int *pwidth, unsigned int *pheight )
895 int x, y, width, height, border, depth;
899 /* Get the geometry of the window */
900 XGetGeometry( display, win, &root, &x, &y, &width, &height,
903 /* Translate the window origin to root coordinates */
904 XTranslateCoordinates( display, win, root, 0, 0, &x, &y, &top );
914 /**********************************************************************
915 * EVENT_ConfigureNotify
917 * The ConfigureNotify event is only selected on top-level windows
918 * when the -managed flag is used.
920 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event )
924 unsigned int width, height;
925 HWND newInsertAfter, oldInsertAfter;
927 /* Get geometry and Z-order according to X */
929 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
930 newInsertAfter = EVENT_QueryZOrder( hWnd );
932 /* Get geometry and Z-order according to Wine */
935 * Needs to find the first Visible Window above the current one
937 oldInsertAfter = hWnd;
940 oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
943 oldInsertAfter = HWND_TOP;
946 if (GetWindowLongA( oldInsertAfter, GWL_STYLE ) & WS_VISIBLE) break;
949 /* Compare what has changed */
951 GetWindowRect( hWnd, &rectWindow );
952 if ( rectWindow.left == x && rectWindow.top == y )
955 TRACE_(win)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd,
956 rectWindow.left, rectWindow.top, x, y );
958 if ( rectWindow.right - rectWindow.left == width
959 && rectWindow.bottom - rectWindow.top == height )
962 TRACE_(win)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd,
963 rectWindow.right - rectWindow.left,
964 rectWindow.bottom - rectWindow.top, width, height );
966 if ( newInsertAfter == oldInsertAfter )
967 flags |= SWP_NOZORDER;
969 TRACE_(win)( "%04x restacking from after %04x to after %04x\n", hWnd,
970 oldInsertAfter, newInsertAfter );
972 /* If anything changed, call SetWindowPos */
974 if ( flags != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) )
975 SetWindowPos( hWnd, newInsertAfter, x, y, width, height,
976 flags | SWP_NOACTIVATE | SWP_WINE_NOHOSTMOVE );
980 /***********************************************************************
981 * EVENT_SelectionRequest_TARGETS
982 * Service a TARGETS selection request event
984 static Atom EVENT_SelectionRequest_TARGETS( Window requestor, Atom target, Atom rprop )
986 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
990 unsigned long cTargets;
994 TRACE("Request for %s\n", TSXGetAtomName(display, target));
997 * Count the number of items we wish to expose as selection targets.
998 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
1000 cTargets = CountClipboardFormats() + 1;
1001 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
1004 /* Allocate temp buffer */
1005 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
1006 if(targets == NULL) return None;
1008 /* Create TARGETS property list (First item in list is TARGETS itself) */
1010 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
1011 (wFormat = EnumClipboardFormats( wFormat )); )
1013 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
1015 /* Scan through what we have so far to avoid duplicates */
1018 for (i = 0, bExists = FALSE; i < cTargets; i++)
1020 if (targets[i] == prop)
1028 targets[cTargets++] = prop;
1030 /* Add PIXMAP prop for bitmaps additionally */
1031 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
1034 targets[cTargets++] = XA_PIXMAP;
1041 if (TRACE_ON(event))
1044 for ( i = 0; i < cTargets; i++)
1048 char *itemFmtName = TSXGetAtomName(display, targets[i]);
1049 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
1050 TSXFree(itemFmtName);
1055 /* Update the X property */
1056 TRACE("\tUpdating property %s...", TSXGetAtomName(display, rprop));
1058 /* We may want to consider setting the type to xaTargets instead,
1059 * in case some apps expect this instead of XA_ATOM */
1060 xRc = TSXChangeProperty(display, requestor, rprop,
1061 XA_ATOM, 32, PropModeReplace,
1062 (unsigned char *)targets, cTargets);
1063 TRACE("(Rc=%d)\n", xRc);
1065 HeapFree( GetProcessHeap(), 0, targets );
1071 /***********************************************************************
1072 * EVENT_SelectionRequest_STRING
1073 * Service a STRING selection request event
1075 static Atom EVENT_SelectionRequest_STRING( Window requestor, Atom target, Atom rprop )
1077 static UINT text_cp = (UINT)-1;
1078 HANDLE hUnicodeText;
1086 if(text_cp == (UINT)-1)
1087 text_cp = PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP);
1090 * Map the requested X selection property type atom name to a
1091 * windows clipboard format ID.
1093 itemFmtName = TSXGetAtomName(display, target);
1094 TRACE("Request for %s (wFormat=%x %s)\n",
1095 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT));
1096 TSXFree(itemFmtName);
1098 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
1101 uni_text = GlobalLock(hUnicodeText);
1105 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
1106 text = HeapAlloc(GetProcessHeap(), 0, size);
1109 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
1111 /* remove carriage returns */
1113 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
1114 if(lpstr == NULL) return None;
1115 for(i=0,j=0; i < size && text[i]; i++ )
1117 if( text[i] == '\r' &&
1118 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1119 lpstr[j++] = text[i];
1123 /* Update the X property */
1124 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
1125 xRc = TSXChangeProperty(display, requestor, rprop,
1126 XA_STRING, 8, PropModeReplace,
1128 TRACE("(Rc=%d)\n", xRc);
1130 GlobalUnlock(hUnicodeText);
1131 HeapFree(GetProcessHeap(), 0, text);
1132 HeapFree( GetProcessHeap(), 0, lpstr );
1137 /***********************************************************************
1138 * EVENT_SelectionRequest_PIXMAP
1139 * Service a PIXMAP selection request event
1141 static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
1143 HANDLE hClipData = 0;
1149 XSetWindowAttributes win_attr;
1150 XWindowAttributes win_attr_src;
1154 * Map the requested X selection property type atom name to a
1155 * windows clipboard format ID.
1157 itemFmtName = TSXGetAtomName(display, target);
1158 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1159 TRACE("Request for %s (wFormat=%x %s)\n",
1160 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1161 TSXFree(itemFmtName);
1163 hClipData = GetClipboardData(wFormat);
1166 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
1167 rprop = None; /* Fail the request */
1171 if (wFormat == CF_DIB)
1173 HWND hwnd = GetOpenClipboardWindow();
1174 HDC hdc = GetDC(hwnd);
1176 /* For convert from packed DIB to Pixmap */
1177 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
1179 ReleaseDC(hdc, hwnd);
1181 else if (wFormat == CF_BITMAP)
1183 HWND hwnd = GetOpenClipboardWindow();
1184 HDC hdc = GetDC(hwnd);
1186 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
1188 ReleaseDC(hdc, hwnd);
1192 FIXME("%s to PIXMAP conversion not yet implemented!\n",
1193 CLIPBOARD_GetFormatName(wFormat));
1198 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
1199 TSXGetAtomName(display, rprop), (long)requestor,
1200 TSXGetAtomName(display, target), pixmap);
1202 /* Store the Pixmap handle in the property */
1203 xRc = TSXChangeProperty(display, requestor, rprop, target,
1204 32, PropModeReplace,
1205 (unsigned char *)&pixmap, 1);
1206 TRACE("(Rc=%d)\n", xRc);
1208 /* Enable the code below if you want to handle destroying Pixmap resources
1209 * in response to property notify events. Clients like XPaint don't
1210 * appear to be duplicating Pixmaps so they don't like us deleting,
1211 * the resource in response to the property being deleted.
1214 /* Express interest in property notify events so that we can delete the
1215 * pixmap when the client deletes the property atom.
1217 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
1218 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
1220 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
1221 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
1223 /* Register the Pixmap we created with the request property Atom.
1224 * When this property is destroyed we also destroy the Pixmap in
1225 * response to the PropertyNotify event.
1227 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
1235 /***********************************************************************
1236 * EVENT_SelectionRequest_WCF
1237 * Service a Wine Clipboard Format selection request event.
1238 * For <WCF>* data types we simply copy the data to X without conversion.
1240 static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
1242 HANDLE hClipData = 0;
1250 * Map the requested X selection property type atom name to a
1251 * windows clipboard format ID.
1253 itemFmtName = TSXGetAtomName(display, target);
1254 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1255 TRACE("Request for %s (wFormat=%x %s)\n",
1256 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1257 TSXFree(itemFmtName);
1259 hClipData = GetClipboardData16(wFormat);
1261 if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
1263 cBytes = GlobalSize16(hClipData);
1265 TRACE("\tUpdating property %s, %d bytes...\n",
1266 TSXGetAtomName(display, rprop), cBytes);
1268 xRc = TSXChangeProperty(display, requestor, rprop,
1269 target, 8, PropModeReplace,
1270 (unsigned char *)lpClipData, cBytes);
1271 TRACE("(Rc=%d)\n", xRc);
1273 GlobalUnlock16(hClipData);
1277 TRACE("\tCould not retrieve native format!\n");
1278 rprop = None; /* Fail the request */
1285 /***********************************************************************
1286 * EVENT_SelectionRequest_MULTIPLE
1287 * Service a MULTIPLE selection request event
1288 * rprop contains a list of (target,property) atom pairs.
1289 * The first atom names a target and the second names a property.
1290 * The effect is as if we have received a sequence of SelectionRequest events
1291 * (one for each atom pair) except that:
1292 * 1. We reply with a SelectionNotify only when all the requested conversions
1293 * have been performed.
1294 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1295 * we replace the atom in the property by None.
1297 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
1300 Atom atype=AnyPropertyType;
1302 unsigned long remain;
1303 Atom* targetPropList=NULL;
1304 unsigned long cTargetPropList = 0;
1305 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1307 /* If the specified property is None the requestor is an obsolete client.
1308 * We support these by using the specified target atom as the reply property.
1310 rprop = pevent->property;
1312 rprop = pevent->target;
1316 /* Read the MULTIPLE property contents. This should contain a list of
1317 * (target,property) atom pairs.
1319 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
1320 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
1321 &cTargetPropList, &remain,
1322 (unsigned char**)&targetPropList) != Success)
1323 TRACE("\tCouldn't read MULTIPLE property\n");
1326 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1327 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
1330 * Make sure we got what we expect.
1331 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1332 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1333 * However some X apps(such as XPaint) are not compliant with this and return
1334 * a user defined atom in atype when XGetWindowProperty is called.
1335 * The data *is* an atom pair but is not denoted as such.
1337 if(aformat == 32 /* atype == xAtomPair */ )
1341 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1342 * for each (target,property) pair */
1344 for (i = 0; i < cTargetPropList; i+=2)
1346 char *targetName = TSXGetAtomName(display, targetPropList[i]);
1347 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
1348 XSelectionRequestEvent event;
1350 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
1351 i/2, targetName, propName);
1352 TSXFree(targetName);
1355 /* We must have a non "None" property to service a MULTIPLE target atom */
1356 if ( !targetPropList[i+1] )
1358 TRACE("\tMULTIPLE(%d): Skipping target with empty property!", i);
1362 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1363 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
1364 event.target = targetPropList[i];
1365 event.property = targetPropList[i+1];
1367 /* Fire a SelectionRequest, informing the handler that we are processing
1368 * a MULTIPLE selection request event.
1370 EVENT_SelectionRequest( hWnd, &event, TRUE );
1374 /* Free the list of targets/properties */
1375 TSXFree(targetPropList);
1383 /***********************************************************************
1384 * EVENT_SelectionRequest
1385 * Process an event selection request event.
1386 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1387 * recursively while servicing a "MULTIPLE" selection target.
1389 * Note: We only receive this event when WINE owns the X selection
1391 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1393 XSelectionEvent result;
1395 Window request = event->requestor;
1396 BOOL couldOpen = FALSE;
1397 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1398 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
1399 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1402 * We can only handle the selection request if :
1403 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1404 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1405 * since this has been already done.
1409 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1410 || !(couldOpen = OpenClipboard(hWnd)) )
1414 /* If the specified property is None the requestor is an obsolete client.
1415 * We support these by using the specified target atom as the reply property.
1417 rprop = event->property;
1419 rprop = event->target;
1421 if(event->target == xaTargets) /* Return a list of all supported targets */
1423 /* TARGETS selection request */
1424 rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
1426 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1428 /* MULTIPLE selection request */
1429 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1431 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1433 /* XA_STRING selection request */
1434 rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
1436 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1438 /* XA_PIXMAP selection request */
1439 rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
1441 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1443 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1444 rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
1446 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1448 /* All <WCF> selection requests */
1449 rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
1452 rprop = None; /* Don't support this format */
1455 /* close clipboard only if we opened before */
1456 if(couldOpen) CloseClipboard();
1459 TRACE("\tRequest ignored\n");
1462 * SelectionNotify should be sent only at the end of a MULTIPLE request
1466 result.type = SelectionNotify;
1467 result.display = display;
1468 result.requestor = request;
1469 result.selection = event->selection;
1470 result.property = rprop;
1471 result.target = event->target;
1472 result.time = event->time;
1473 TRACE("Sending SelectionNotify event...\n");
1474 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1478 /***********************************************************************
1479 * EVENT_SelectionClear
1481 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1483 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1485 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1486 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1489 /***********************************************************************
1490 * EVENT_PropertyNotify
1491 * We use this to release resources like Pixmaps when a selection
1492 * client no longer needs them.
1494 static void EVENT_PropertyNotify( XPropertyEvent *event )
1496 /* Check if we have any resources to free */
1497 TRACE("Received PropertyNotify event: ");
1499 switch(event->state)
1501 case PropertyDelete:
1503 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1504 TSXGetAtomName(event->display, event->atom), (long)event->window);
1506 if (X11DRV_IsSelectionOwner())
1507 X11DRV_CLIPBOARD_FreeResources( event->atom );
1511 case PropertyNewValue:
1513 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1514 TSXGetAtomName(event->display, event->atom), (long)event->window);
1523 /**********************************************************************
1524 * EVENT_DropFromOffix
1526 * don't know if it still works (last Changlog is from 96/11/04)
1528 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1530 unsigned long data_length;
1531 unsigned long aux_long;
1532 unsigned char* p_data = NULL;
1543 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO16));
1544 LPDRAGINFO16 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
1545 SEGPTR spDragInfo = K32WOWGlobalLock16(hDragInfo);
1546 Window w_aux_root, w_aux_child;
1550 if( !lpDragInfo || !spDragInfo ) return;
1552 pWnd = WIN_FindWndPtr(hWnd);
1554 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
1555 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1556 (unsigned int*)&aux_long);
1558 lpDragInfo->hScope = hWnd;
1559 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1561 /* find out drop point and drop window */
1562 if( x < 0 || y < 0 ||
1563 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1564 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1565 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1568 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1569 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1571 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1572 WIN_ReleaseWndPtr(pWnd);
1574 GlobalFree16( hDragInfo );
1578 TSXGetWindowProperty( display, DefaultRootWindow(display),
1579 dndSelection, 0, 65535, FALSE,
1580 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1581 &data_length, &aux_long, &p_data);
1583 if( !aux_long && p_data) /* don't bother if > 64K */
1585 signed char *p = (signed char*) p_data;
1589 while( *p ) /* calculate buffer size */
1592 if((u.i = *p) != -1 )
1594 INT len = GetShortPathNameA( p, NULL, 0 );
1595 if (len) aux_long += len + 1;
1600 if( aux_long && aux_long < 65535 )
1605 aux_long += sizeof(DROPFILES) + 1;
1606 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1607 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1611 lpDrop->pFiles = sizeof(DROPFILES);
1615 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1616 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1617 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1618 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1619 lpDrop->fWide = FALSE;
1620 p_drop = (char *)(lpDrop + 1);
1624 if( *p != -1 ) /* use only "good" entries */
1626 GetShortPathNameA( p, p_drop, 65535 );
1627 p_drop += strlen( p_drop ) + 1;
1632 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1636 if( p_data ) TSXFree(p_data);
1638 } /* WS_EX_ACCEPTFILES */
1640 WIN_ReleaseWndPtr(pDropWnd);
1643 /**********************************************************************
1646 * drop items are separated by \n
1647 * each item is prefixed by its mime type
1649 * event->data.l[3], event->data.l[4] contains drop x,y position
1651 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1655 unsigned long data_length;
1656 unsigned long aux_long, drop_len = 0;
1657 unsigned char *p_data = NULL; /* property data */
1658 char *p_drop = NULL;
1669 pWnd = WIN_FindWndPtr(hWnd);
1671 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1673 WIN_ReleaseWndPtr(pWnd);
1676 WIN_ReleaseWndPtr(pWnd);
1678 TSXGetWindowProperty( display, DefaultRootWindow(display),
1679 dndSelection, 0, 65535, FALSE,
1680 AnyPropertyType, &u.atom_aux, &u.i,
1681 &data_length, &aux_long, &p_data);
1683 WARN("property too large, truncated!\n");
1684 TRACE("urls=%s\n", p_data);
1686 if( !aux_long && p_data) { /* don't bother if > 64K */
1687 /* calculate length */
1689 next = strchr(p, '\n');
1692 if (strncmp(p,"file:",5) == 0 ) {
1693 INT len = GetShortPathNameA( p+5, NULL, 0 );
1694 if (len) drop_len += len + 1;
1699 next = strchr(p, '\n');
1705 if( drop_len && drop_len < 65535 ) {
1706 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
1707 &x, &y, &u.i, &u.i, &u.i);
1709 pDropWnd = WIN_FindWndPtr( hWnd );
1711 drop_len += sizeof(DROPFILES) + 1;
1712 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1713 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1716 lpDrop->pFiles = sizeof(DROPFILES);
1717 lpDrop->pt.x = (INT)x;
1718 lpDrop->pt.y = (INT)y;
1720 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1721 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1722 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1723 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1724 lpDrop->fWide = FALSE;
1725 p_drop = (char*)(lpDrop + 1);
1728 /* create message content */
1731 next = strchr(p, '\n');
1734 if (strncmp(p,"file:",5) == 0 ) {
1735 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1737 TRACE("drop file %s as %s\n", p+5, p_drop);
1740 WARN("can't convert file %s to dos name \n", p+5);
1743 WARN("unknown mime type %s\n", p);
1748 next = strchr(p, '\n');
1755 GlobalUnlock(hDrop);
1756 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1758 WIN_ReleaseWndPtr(pDropWnd);
1760 if( p_data ) TSXFree(p_data);
1764 /**********************************************************************
1765 * EVENT_ClientMessage
1767 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1769 if (event->message_type != None && event->format == 32) {
1770 if ((event->message_type == wmProtocols) &&
1771 (((Atom) event->data.l[0]) == wmDeleteWindow))
1773 /* Ignore the delete window request if the window has been disabled
1774 * and we are in managed mode. This is to disallow applications from
1775 * being closed by the window manager while in a modal state.
1778 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
1780 if ( !Options.managed || !bIsDisabled )
1781 PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1783 else if ( event->message_type == dndProtocol &&
1784 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1785 EVENT_DropFromOffiX(hWnd, event);
1786 else if ( event->message_type == dndProtocol &&
1787 event->data.l[0] == DndURL )
1788 EVENT_DropURLs(hWnd, event);
1791 /* enable this if you want to see the message */
1792 unsigned char* p_data = NULL;
1798 TSXGetWindowProperty( display, DefaultRootWindow(display),
1799 dndSelection, 0, 65535, FALSE,
1800 AnyPropertyType, &u.atom, &u.i,
1801 &u.l, &u.l, &p_data);
1802 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1803 event->message_type, event->data.l[0], event->data.l[1],
1804 event->data.l[2], event->data.l[3], event->data.l[4],
1807 TRACE("unrecognized ClientMessage\n" );
1812 /**********************************************************************
1815 * Install colormap when Wine window is focused in
1816 * self-managed mode with private colormap
1819 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
1821 if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1822 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1823 TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
1827 /**********************************************************************
1830 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1832 HWND hwndFocus = GetFocus();
1833 WND *wndFocus = WIN_FindWndPtr(hwndFocus);
1834 WND *pWnd = WIN_FindWndPtr(hWnd);
1835 if (pWnd && (pWnd->dwExStyle & WS_EX_MANAGED))
1837 DCE_InvalidateDCE( pWnd, &pWnd->rectWindow );
1838 pWnd->dwStyle &= ~WS_MINIMIZE;
1839 pWnd->dwStyle |= WS_VISIBLE;
1840 WIN_InternalShowOwnedPopups(hWnd,TRUE,TRUE);
1842 WIN_ReleaseWndPtr(pWnd);
1844 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1845 X11DRV_WND_SetFocus(wndFocus);
1847 WIN_ReleaseWndPtr(wndFocus);
1853 /**********************************************************************
1856 void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
1858 WND *pWnd = WIN_FindWndPtr(hWnd);
1859 if (pWnd && (pWnd->dwExStyle & WS_EX_MANAGED))
1862 if( pWnd->dwStyle & WS_VISIBLE )
1864 pWnd->dwStyle |= WS_MINIMIZE;
1865 pWnd->dwStyle &= ~WS_VISIBLE;
1866 WIN_InternalShowOwnedPopups(hWnd,FALSE,TRUE);
1869 WIN_ReleaseWndPtr(pWnd);
1872 /***********************************************************************
1873 * EVENT_MappingNotify
1875 static void EVENT_MappingNotify( XMappingEvent *event )
1877 TSXRefreshKeyboardMapping(event);
1879 /* reinitialize Wine-X11 driver keyboard table */
1880 X11DRV_InitKeyboard();
1884 /**********************************************************************
1885 * X11DRV_EVENT_SetInputMethod
1887 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1889 INPUT_TYPE prev = current_input_type;
1891 /* Flag not used yet */
1892 in_transition = FALSE;
1893 current_input_type = type;
1898 #ifdef HAVE_LIBXXF86DGA2
1899 /**********************************************************************
1900 * X11DRV_EVENT_SetDGAStatus
1902 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1904 if (event_base < 0) {
1910 DGAMotionEventType = event_base + MotionNotify;
1911 DGAButtonPressEventType = event_base + ButtonPress;
1912 DGAButtonReleaseEventType = event_base + ButtonRelease;
1913 DGAKeyPressEventType = event_base + KeyPress;
1914 DGAKeyReleaseEventType = event_base + KeyRelease;
1918 /* DGA2 event handlers */
1919 static void EVENT_DGAMotionEvent( XDGAMotionEvent *event )
1921 X11DRV_SendEvent( MOUSEEVENTF_MOVE,
1922 event->dx, event->dy,
1923 X11DRV_EVENT_XStateToKeyState( event->state ),
1924 event->time - X11DRV_server_startticks, DGAhwnd );
1927 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent *event )
1929 static WORD statusCodes[NB_BUTTONS] =
1930 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
1931 int buttonNum = event->button - 1;
1935 if (buttonNum >= NB_BUTTONS) return;
1937 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1942 keystate |= MK_LBUTTON;
1945 keystate |= MK_MBUTTON;
1948 keystate |= MK_RBUTTON;
1952 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time - X11DRV_server_startticks, DGAhwnd );
1955 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent *event )
1957 static WORD statusCodes[NB_BUTTONS] =
1958 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
1959 int buttonNum = event->button - 1;
1963 if (buttonNum >= NB_BUTTONS) return;
1965 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1970 keystate &= ~MK_LBUTTON;
1973 keystate &= ~MK_MBUTTON;
1976 keystate &= ~MK_RBUTTON;
1980 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time - X11DRV_server_startticks, DGAhwnd );
1985 #ifdef HAVE_LIBXXSHM
1988 Normal XShm operation:
1990 X11 service thread app thread
1991 ------------- ----------------- ------------------------
1992 (idle) ddraw calls XShmPutImage
1993 (copies data) (waiting for shm_event)
1994 ShmCompletion -> (waiting for shm_event)
1995 (idle) signal shm_event ->
1996 (idle) returns to app
1998 However, this situation can occur for some reason:
2000 X11 service thread app thread
2001 ------------- ----------------- ------------------------
2004 (waiting for app) ddraw calls XShmPutImage
2005 (copies data) (waiting for app) (waiting for shm_event)
2006 ShmCompletion (waiting for app) (waiting for shm_event)
2007 (idle) DEADLOCK DEADLOCK
2009 which is why I also wait for shm_read and do XCheckTypedEvent()
2010 calls in the wait loop. This results in:
2012 X11 service thread app thread
2013 ------------- ----------------- ------------------------
2014 ShmCompletion (waiting for app) waking up on shm_read
2015 (idle) (waiting for app) XCheckTypedEvent() -> signal shm_event
2016 (waiting for app) returns
2026 /* FIXME: this is not pretty */
2027 static HANDLE shm_read = 0;
2030 static volatile shm_qs shm_q[SHM_MAX_Q];
2032 static void EVENT_ShmCompletion( XShmCompletionEvent *event )
2036 TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event->drawable, GetTickCount() );
2038 for (n=0; n<SHM_MAX_Q; n++)
2039 if ((shm_q[n].draw == event->drawable) && (shm_q[n].state == 0)) {
2040 HANDLE sema = shm_q[n].sema;
2041 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].state, (PVOID)1, (PVOID)0)) {
2042 ReleaseSemaphore(sema, 1, NULL);
2043 TRACE("Signaling ShmCompletion (#%d) (semaphore %x)\n", n, sema);
2048 ERR("Got ShmCompletion for unknown drawable %ld\n", event->drawable );
2051 int X11DRV_EVENT_PrepareShmCompletion( Drawable dw )
2056 shm_read = FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE );
2058 for (n=0; n<SHM_MAX_Q; n++)
2060 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].draw, (PVOID)dw, (PVOID)0))
2064 ERR("Maximum number of outstanding ShmCompletions exceeded!\n");
2069 if (!shm_q[n].sema) {
2070 shm_q[n].sema = CreateSemaphoreA( NULL, 0, 256, NULL );
2071 TRACE("Allocated ShmCompletion slots have been increased to %d, new semaphore is %x\n", n+1, shm_q[n].sema);
2074 TRACE("Prepared ShmCompletion (#%d) wait for drawable %ld (thread %lx) (time %ld)\n", n, dw, GetCurrentThreadId(), GetTickCount() );
2078 static void X11DRV_EVENT_WaitReplaceShmCompletionInternal( int *compl, Drawable dw, int creat )
2084 if ((!n) || (creat && (!shm_q[n-1].draw))) {
2085 nn = X11DRV_EVENT_PrepareShmCompletion(dw);
2086 if (!(n=(LONG)InterlockedCompareExchange((PVOID*)compl, (PVOID)nn, (PVOID)n)))
2088 /* race for compl lost, clear slot */
2089 shm_q[nn-1].draw = 0;
2093 if (dw && (shm_q[n-1].draw != dw)) {
2094 /* this shouldn't happen with the current ddraw implementation */
2095 FIXME("ShmCompletion replace with different drawable!\n");
2099 sema = shm_q[n-1].sema;
2101 /* nothing to wait on (PrepareShmCompletion not done yet?), so probably nothing to wait for */
2105 nn = InterlockedExchangeAdd((PLONG)&shm_q[n-1].waiter, 1);
2106 if ((!shm_q[n-1].draw) || (shm_q[n-1].state == 2)) {
2107 /* too late, the wait was just cleared (wait complete) */
2108 TRACE("Wait skip for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2110 TRACE("Waiting for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2112 /* another thread is already waiting, let the primary waiter do the dirty work
2113 * (to avoid TSX critical section contention - that could get really slow) */
2114 WaitForSingleObject( sema, INFINITE );
2116 /* we're primary waiter - first check if it's already triggered */
2117 if ( WaitForSingleObject( sema, 0 ) != WAIT_OBJECT_0 ) {
2118 /* nope, may need to poll X event queue, in case the service thread is blocked */
2125 /* check X event queue */
2126 if (TSXCheckTypedEvent( display, ShmCompletionType, &event)) {
2127 EVENT_ProcessEvent( &event );
2129 } while ( WaitForMultipleObjects(2, hnd, FALSE, INFINITE) > WAIT_OBJECT_0 );
2131 TRACE("Wait complete (thread %lx) (time %ld)\n", GetCurrentThreadId(), GetTickCount() );
2134 st = InterlockedExchange((LPLONG)&shm_q[n-1].state, 2);
2136 /* first waiter to return, release all other waiters */
2137 nn = shm_q[n-1].waiter;
2138 TRACE("Signaling %ld additional ShmCompletion (#%d) waiter(s), semaphore %x\n", nn-1, n-1, sema);
2139 ReleaseSemaphore(sema, nn-1, NULL);
2142 nn = InterlockedDecrement((LPLONG)&shm_q[n-1].waiter);
2144 /* last waiter to return, replace drawable and prepare new wait */
2145 shm_q[n-1].draw = dw;
2146 shm_q[n-1].state = 0;
2150 void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw )
2152 X11DRV_EVENT_WaitReplaceShmCompletionInternal( compl, dw, 1 );
2155 void X11DRV_EVENT_WaitShmCompletion( int compl )
2158 X11DRV_EVENT_WaitReplaceShmCompletionInternal( &compl, 0, 0 );
2161 void X11DRV_EVENT_WaitShmCompletions( Drawable dw )
2165 for (n=0; n<SHM_MAX_Q; n++)
2166 if (shm_q[n].draw == dw)
2167 X11DRV_EVENT_WaitShmCompletion( n+1 );
2170 #endif /* defined(HAVE_LIBXXSHM) */