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"
26 #include "clipboard.h"
28 #include "debugtools.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 */
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 );
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 );
115 static void EVENT_ShmCompletion( XShmCompletionEvent *event );
116 static int ShmAvailable, ShmCompletionType;
117 extern int XShmGetEventBase( Display * );/* Missing prototype for function in libXext. */
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 );
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 /***********************************************************************
152 BOOL X11DRV_EVENT_Init(void)
155 ShmAvailable = XShmQueryExtension( display );
157 ShmCompletionType = XShmGetEventBase( display ) + ShmCompletion;
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 );
170 SERVICE_AddTimer( 200, EVENT_Flush, 0 );
175 /***********************************************************************
178 static void CALLBACK EVENT_Flush( ULONG_PTR arg )
183 /***********************************************************************
184 * EVENT_ProcessAllEvents
186 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
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 /***********************************************************************
207 * Synchronize with the X server. Should not be used too often.
209 void X11DRV_Synchronize( void )
211 TSXSync( display, False );
212 EVENT_ProcessAllEvents( 0 );
215 /***********************************************************************
216 * X11DRV_UserRepaintDisable
218 void X11DRV_UserRepaintDisable( BOOL bDisabled )
220 bUserRepaintDisabled = bDisabled;
223 /***********************************************************************
226 * Process an X event.
228 static void EVENT_ProcessEvent( XEvent *event )
232 TRACE( "called.\n" );
236 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
237 FIXME("Got SelectionNotify - must not happen!\n");
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
244 case CirculateNotify:
253 if (ShmAvailable && (event->type == ShmCompletionType)) {
254 EVENT_ShmCompletion( (XShmCompletionEvent*)event );
259 #ifdef HAVE_LIBXXF86DGA2
261 if (event->type == DGAMotionEventType) {
262 TRACE("DGAMotionEvent received.\n");
263 EVENT_DGAMotionEvent((XDGAMotionEvent *) event);
266 if (event->type == DGAButtonPressEventType) {
267 TRACE("DGAButtonPressEvent received.\n");
268 EVENT_DGAButtonPressEvent((XDGAButtonEvent *) event);
271 if (event->type == DGAButtonReleaseEventType) {
272 TRACE("DGAButtonReleaseEvent received.\n");
273 EVENT_DGAButtonReleaseEvent((XDGAButtonEvent *) event);
276 if ((event->type == DGAKeyPressEventType) ||
277 (event->type == DGAKeyReleaseEventType)) {
278 /* Fill a XKeyEvent to send to EVENT_Key */
280 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
282 TRACE("DGAKeyPress/ReleaseEvent received.\n");
284 if (evt->type == DGAKeyReleaseEventType)
285 ke.type = KeyRelease;
288 ke.serial = evt->serial;
289 ke.send_event = FALSE;
290 ke.display = evt->display;
299 ke.state = evt->state;
300 ke.keycode = evt->keycode;
301 ke.same_screen = TRUE;
303 X11DRV_KEYBOARD_HandleEvent(NULL, &ke);
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) */
314 int root_x, root_y, child_x, child_y;
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)
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 );
331 TRACE("Got event %s for hwnd %04x\n",
332 event_names[event->type], hWnd );
338 EVENT_Key( hWnd, (XKeyEvent*)event );
342 EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
346 EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
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 );
368 WND *pWndLastFocus = 0;
369 XWindowAttributes win_attr;
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
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 );
398 EVENT_FocusIn( hWnd, xfocChange );
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 );
414 if (bUserRepaintDisabled) return;
415 EVENT_Expose( hWnd, (XExposeEvent *)event );
419 if (bUserRepaintDisabled) return;
420 EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
423 case ConfigureNotify:
424 if (!hWnd || bUserRepaintDisabled) return;
425 EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
428 case SelectionRequest:
429 if (!hWnd || bUserRepaintDisabled) return;
430 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
434 if (!hWnd || bUserRepaintDisabled) return;
435 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
439 EVENT_PropertyNotify( (XPropertyEvent *)event );
443 if (!hWnd || bUserRepaintDisabled) return;
444 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
449 EVENT_EnterNotify( hWnd, (XCrossingEvent *) event );
457 if (!hWnd || bUserRepaintDisabled) return;
458 EVENT_MapNotify( hWnd, (XMapEvent *)event );
462 if (!hWnd || bUserRepaintDisabled) return;
463 EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
467 EVENT_MappingNotify( (XMappingEvent *) event );
471 WARN("Unprocessed event %s for hwnd %04x\n",
472 event_names[event->type], hWnd );
475 TRACE( "returns.\n" );
478 /***********************************************************************
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;
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;
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 );
515 TSXQueryTree( display, A, &root, &B, children, total );
521 static Window __get_top_decoration( Window w, Window ancestor )
523 Window* children, root, prev = w, parent = w;
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 )
539 for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
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),
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 );
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 )) )
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... */
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 )
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;
626 /***********************************************************************
629 static void EVENT_Expose( HWND hWnd, XExposeEvent *event )
632 int offx = 0,offy = 0;
634 WND *pWnd = WIN_FindWndPtr(hWnd);
635 /* Make position relative to client area instead of window */
636 offx = (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
637 offy = (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
639 rect.left = event->x - offx;
640 rect.top = event->y - offy;
642 rect.right = rect.left + event->width;
643 rect.bottom = rect.top + event->height;
645 WIN_ReleaseWndPtr(pWnd);
647 Callout.RedrawWindow( hWnd, &rect, 0,
648 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE );
650 /* FIXME: We should use SendNotifyMessage here, but this function is not
651 implemented correctly, so for now we used SendMessage */
652 /*SendNotifyMessageA(hWnd,WM_SYNCPAINT, 0, 0);*/
653 if (event->count == 0)
654 SendMessageA(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 Callout.RedrawWindow( hWnd, &rect, 0,
683 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE );
685 /* FIXME: We should use SendNotifyMessage here, but this function is not
686 implemented correctly, so for now we used SendMessage */
687 /*SendNotifyMessageA(hWnd,WM_SYNCPAINT, 0, 0);*/
688 if (event->count == 0)
689 SendMessageA(hWnd,WM_SYNCPAINT, 0, 0);
693 /***********************************************************************
696 * Handle a X key event
698 static void EVENT_Key( HWND hWnd, XKeyEvent *event )
700 WND *pWnd = WIN_FindWndPtr(hWnd);
701 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
702 WIN_ReleaseWndPtr(pWnd);
707 /***********************************************************************
710 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event )
712 if (current_input_type == X11DRV_INPUT_ABSOLUTE) {
713 WND *pWnd = WIN_FindWndPtr(hWnd);
714 int xOffset = pWnd? pWnd->rectWindow.left : 0;
715 int yOffset = pWnd? pWnd->rectWindow.top : 0;
716 WIN_ReleaseWndPtr(pWnd);
718 X11DRV_SendEvent( MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
719 xOffset + event->x, yOffset + event->y,
720 X11DRV_EVENT_XStateToKeyState( event->state ),
723 X11DRV_SendEvent( MOUSEEVENTF_MOVE,
724 event->x_root, event->y_root,
725 X11DRV_EVENT_XStateToKeyState( event->state ),
731 /***********************************************************************
734 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event )
736 static WORD statusCodes[NB_BUTTONS] =
737 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL};
738 int buttonNum = event->button - 1;
740 WND *pWnd = WIN_FindWndPtr(hWnd);
741 int xOffset = pWnd? pWnd->rectWindow.left : 0;
742 int yOffset = pWnd? pWnd->rectWindow.top : 0;
743 WORD keystate,wData = 0;
745 WIN_ReleaseWndPtr(pWnd);
747 if (buttonNum >= NB_BUTTONS) return;
750 * Get the compatible keystate
752 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
755 * Make sure that the state of the button that was just
761 keystate |= MK_LBUTTON;
764 keystate |= MK_MBUTTON;
767 keystate |= MK_RBUTTON;
773 wData = -WHEEL_DELTA;
777 X11DRV_SendEvent( statusCodes[buttonNum],
778 xOffset + event->x, yOffset + event->y,
779 MAKEWPARAM(keystate,wData),
784 /***********************************************************************
785 * EVENT_ButtonRelease
787 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event )
789 static WORD statusCodes[NB_BUTTONS] =
790 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
791 int buttonNum = event->button - 1;
792 WND *pWnd = WIN_FindWndPtr(hWnd);
793 int xOffset = pWnd? pWnd->rectWindow.left : 0;
794 int yOffset = pWnd? pWnd->rectWindow.top : 0;
797 WIN_ReleaseWndPtr(pWnd);
799 if (buttonNum >= NB_BUTTONS) return;
802 * Get the compatible keystate
804 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
807 * Make sure that the state of the button that was just
813 keystate &= ~MK_LBUTTON;
816 keystate &= ~MK_MBUTTON;
819 keystate &= ~MK_RBUTTON;
825 X11DRV_SendEvent( statusCodes[buttonNum],
826 xOffset + event->x, yOffset + event->y,
827 keystate, event->time, hWnd);
831 /**********************************************************************
834 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
836 if (event->detail != NotifyPointer)
837 if (hWnd != GetForegroundWindow())
839 SetForegroundWindow( hWnd );
840 X11DRV_KEYBOARD_UpdateState();
845 /**********************************************************************
848 * Note: only top-level override-redirect windows get FocusOut events.
850 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
852 if (event->detail != NotifyPointer)
853 if (hWnd == GetForegroundWindow())
855 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
857 /* Abey : 6-Oct-99. Check again if the focus out window is the
858 Foreground window, because in most cases the messages sent
859 above must have already changed the foreground window, in which
860 case we don't have to change the foreground window to 0 */
862 if (hWnd == GetForegroundWindow())
863 SetForegroundWindow( 0 );
867 /**********************************************************************
870 BOOL X11DRV_CheckFocus(void)
876 TSXGetInputFocus(display, &xW, &state);
878 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
883 /**********************************************************************
886 * Helper function for ConfigureNotify handling.
887 * Get the new geometry of a window relative to the root window.
889 static void EVENT_GetGeometry( Window win, int *px, int *py,
890 unsigned int *pwidth, unsigned int *pheight )
893 int x, y, width, height, border, depth;
895 EnterCriticalSection( &X11DRV_CritSection );
897 /* Get the geometry of the window */
898 XGetGeometry( display, win, &root, &x, &y, &width, &height,
901 /* Translate the window origin to root coordinates */
902 XTranslateCoordinates( display, win, root, 0, 0, &x, &y, &top );
904 LeaveCriticalSection( &X11DRV_CritSection );
912 /**********************************************************************
913 * EVENT_ConfigureNotify
915 * The ConfigureNotify event is only selected on top-level windows
916 * when the -managed flag is used.
918 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event )
922 unsigned int width, height;
923 HWND newInsertAfter, oldInsertAfter;
925 /* Get geometry and Z-order according to X */
927 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
928 newInsertAfter = EVENT_QueryZOrder( hWnd );
930 /* Get geometry and Z-order according to Wine */
933 * Needs to find the first Visible Window above the current one
935 oldInsertAfter = hWnd;
938 oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
941 oldInsertAfter = HWND_TOP;
944 if (GetWindowLongA( oldInsertAfter, GWL_STYLE ) & WS_VISIBLE) break;
947 /* Compare what has changed */
949 GetWindowRect( hWnd, &rectWindow );
950 if ( rectWindow.left == x && rectWindow.top == y )
953 TRACE_(win)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd,
954 rectWindow.left, rectWindow.top, x, y );
956 if ( rectWindow.right - rectWindow.left == width
957 && rectWindow.bottom - rectWindow.top == height )
960 TRACE_(win)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd,
961 rectWindow.right - rectWindow.left,
962 rectWindow.bottom - rectWindow.top, width, height );
964 if ( newInsertAfter == oldInsertAfter )
965 flags |= SWP_NOZORDER;
967 TRACE_(win)( "%04x restacking from after %04x to after %04x\n", hWnd,
968 oldInsertAfter, newInsertAfter );
970 /* If anything changed, call SetWindowPos */
972 if ( flags != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) )
973 SetWindowPos( hWnd, newInsertAfter, x, y, width, height,
974 flags | SWP_NOACTIVATE | SWP_WINE_NOHOSTMOVE );
978 /***********************************************************************
979 * EVENT_SelectionRequest_TARGETS
980 * Service a TARGETS selection request event
982 static Atom EVENT_SelectionRequest_TARGETS( Window requestor, Atom target, Atom rprop )
984 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
988 unsigned long cTargets;
992 TRACE("Request for %s\n", TSXGetAtomName(display, target));
995 * Count the number of items we wish to expose as selection targets.
996 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
998 cTargets = CountClipboardFormats() + 1;
999 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
1002 /* Allocate temp buffer */
1003 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
1004 if(targets == NULL) return None;
1006 /* Create TARGETS property list (First item in list is TARGETS itself) */
1008 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
1009 (wFormat = EnumClipboardFormats( wFormat )); )
1011 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
1013 /* Scan through what we have so far to avoid duplicates */
1016 for (i = 0, bExists = FALSE; i < cTargets; i++)
1018 if (targets[i] == prop)
1026 targets[cTargets++] = prop;
1028 /* Add PIXMAP prop for bitmaps additionally */
1029 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
1032 targets[cTargets++] = XA_PIXMAP;
1039 if (TRACE_ON(event))
1042 for ( i = 0; i < cTargets; i++)
1046 char *itemFmtName = TSXGetAtomName(display, targets[i]);
1047 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
1048 TSXFree(itemFmtName);
1053 /* Update the X property */
1054 TRACE("\tUpdating property %s...", TSXGetAtomName(display, rprop));
1056 /* We may want to consider setting the type to xaTargets instead,
1057 * in case some apps expect this instead of XA_ATOM */
1058 xRc = TSXChangeProperty(display, requestor, rprop,
1059 XA_ATOM, 32, PropModeReplace,
1060 (unsigned char *)targets, cTargets);
1061 TRACE("(Rc=%d)\n", xRc);
1063 HeapFree( GetProcessHeap(), 0, targets );
1069 /***********************************************************************
1070 * EVENT_SelectionRequest_STRING
1071 * Service a STRING selection request event
1073 static Atom EVENT_SelectionRequest_STRING( Window requestor, Atom target, Atom rprop )
1083 * Map the requested X selection property type atom name to a
1084 * windows clipboard format ID.
1086 itemFmtName = TSXGetAtomName(display, target);
1087 TRACE("Request for %s (wFormat=%x %s)\n",
1088 itemFmtName, CF_TEXT, CLIPBOARD_GetFormatName(CF_TEXT));
1089 TSXFree(itemFmtName);
1091 hText = GetClipboardData16(CF_TEXT);
1094 text = GlobalLock16(hText);
1097 size = GlobalSize16(hText);
1098 /* remove carriage returns */
1100 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
1101 if(lpstr == NULL) return None;
1102 for(i=0,j=0; i < size && text[i]; i++ )
1104 if( text[i] == '\r' &&
1105 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1106 lpstr[j++] = text[i];
1110 /* Update the X property */
1111 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
1112 xRc = TSXChangeProperty(display, requestor, rprop,
1113 XA_STRING, 8, PropModeReplace,
1115 TRACE("(Rc=%d)\n", xRc);
1117 GlobalUnlock16(hText);
1118 HeapFree( GetProcessHeap(), 0, lpstr );
1123 /***********************************************************************
1124 * EVENT_SelectionRequest_PIXMAP
1125 * Service a PIXMAP selection request event
1127 static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
1129 HANDLE hClipData = 0;
1135 XSetWindowAttributes win_attr;
1136 XWindowAttributes win_attr_src;
1140 * Map the requested X selection property type atom name to a
1141 * windows clipboard format ID.
1143 itemFmtName = TSXGetAtomName(display, target);
1144 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1145 TRACE("Request for %s (wFormat=%x %s)\n",
1146 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1147 TSXFree(itemFmtName);
1149 hClipData = GetClipboardData(wFormat);
1152 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
1153 rprop = None; /* Fail the request */
1157 if (wFormat == CF_DIB)
1159 HWND hwnd = GetOpenClipboardWindow();
1160 HDC hdc = GetDC(hwnd);
1162 /* For convert from packed DIB to Pixmap */
1163 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
1165 ReleaseDC(hdc, hwnd);
1167 else if (wFormat == CF_BITMAP)
1169 HWND hwnd = GetOpenClipboardWindow();
1170 HDC hdc = GetDC(hwnd);
1172 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
1174 ReleaseDC(hdc, hwnd);
1178 FIXME("%s to PIXMAP conversion not yet implemented!\n",
1179 CLIPBOARD_GetFormatName(wFormat));
1184 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
1185 TSXGetAtomName(display, rprop), (long)requestor,
1186 TSXGetAtomName(display, target), pixmap);
1188 /* Store the Pixmap handle in the property */
1189 xRc = TSXChangeProperty(display, requestor, rprop, target,
1190 32, PropModeReplace,
1191 (unsigned char *)&pixmap, 1);
1192 TRACE("(Rc=%d)\n", xRc);
1194 /* Enable the code below if you want to handle destroying Pixmap resources
1195 * in response to property notify events. Clients like XPaint don't
1196 * appear to be duplicating Pixmaps so they don't like us deleting,
1197 * the resource in response to the property being deleted.
1200 /* Express interest in property notify events so that we can delete the
1201 * pixmap when the client deletes the property atom.
1203 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
1204 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
1206 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
1207 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
1209 /* Register the Pixmap we created with the request property Atom.
1210 * When this property is destroyed we also destroy the Pixmap in
1211 * response to the PropertyNotify event.
1213 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
1221 /***********************************************************************
1222 * EVENT_SelectionRequest_WCF
1223 * Service a Wine Clipboard Format selection request event.
1224 * For <WCF>* data types we simply copy the data to X without conversion.
1226 static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
1228 HANDLE hClipData = 0;
1236 * Map the requested X selection property type atom name to a
1237 * windows clipboard format ID.
1239 itemFmtName = TSXGetAtomName(display, target);
1240 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1241 TRACE("Request for %s (wFormat=%x %s)\n",
1242 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1243 TSXFree(itemFmtName);
1245 hClipData = GetClipboardData16(wFormat);
1247 if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
1249 cBytes = GlobalSize16(hClipData);
1251 TRACE("\tUpdating property %s, %d bytes...\n",
1252 TSXGetAtomName(display, rprop), cBytes);
1254 xRc = TSXChangeProperty(display, requestor, rprop,
1255 target, 8, PropModeReplace,
1256 (unsigned char *)lpClipData, cBytes);
1257 TRACE("(Rc=%d)\n", xRc);
1259 GlobalUnlock16(hClipData);
1263 TRACE("\tCould not retrieve native format!\n");
1264 rprop = None; /* Fail the request */
1271 /***********************************************************************
1272 * EVENT_SelectionRequest_MULTIPLE
1273 * Service a MULTIPLE selection request event
1274 * rprop contains a list of (target,property) atom pairs.
1275 * The first atom names a target and the second names a property.
1276 * The effect is as if we have received a sequence of SelectionRequest events
1277 * (one for each atom pair) except that:
1278 * 1. We reply with a SelectionNotify only when all the requested conversions
1279 * have been performed.
1280 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1281 * we replace the atom in the property by None.
1283 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
1286 Atom atype=AnyPropertyType;
1288 unsigned long remain;
1289 Atom* targetPropList=NULL;
1290 unsigned long cTargetPropList = 0;
1291 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1293 /* If the specified property is None the requestor is an obsolete client.
1294 * We support these by using the specified target atom as the reply property.
1296 rprop = pevent->property;
1298 rprop = pevent->target;
1302 /* Read the MULTIPLE property contents. This should contain a list of
1303 * (target,property) atom pairs.
1305 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
1306 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
1307 &cTargetPropList, &remain,
1308 (unsigned char**)&targetPropList) != Success)
1309 TRACE("\tCouldn't read MULTIPLE property\n");
1312 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1313 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
1316 * Make sure we got what we expect.
1317 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1318 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1319 * However some X apps(such as XPaint) are not compliant with this and return
1320 * a user defined atom in atype when XGetWindowProperty is called.
1321 * The data *is* an atom pair but is not denoted as such.
1323 if(aformat == 32 /* atype == xAtomPair */ )
1327 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1328 * for each (target,property) pair */
1330 for (i = 0; i < cTargetPropList; i+=2)
1332 char *targetName = TSXGetAtomName(display, targetPropList[i]);
1333 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
1334 XSelectionRequestEvent event;
1336 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
1337 i/2, targetName, propName);
1338 TSXFree(targetName);
1341 /* We must have a non "None" property to service a MULTIPLE target atom */
1342 if ( !targetPropList[i+1] )
1344 TRACE("\tMULTIPLE(%d): Skipping target with empty property!", i);
1348 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1349 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
1350 event.target = targetPropList[i];
1351 event.property = targetPropList[i+1];
1353 /* Fire a SelectionRequest, informing the handler that we are processing
1354 * a MULTIPLE selection request event.
1356 EVENT_SelectionRequest( hWnd, &event, TRUE );
1360 /* Free the list of targets/properties */
1361 TSXFree(targetPropList);
1369 /***********************************************************************
1370 * EVENT_SelectionRequest
1371 * Process an event selection request event.
1372 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1373 * recursively while servicing a "MULTIPLE" selection target.
1375 * Note: We only receive this event when WINE owns the X selection
1377 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1379 XSelectionEvent result;
1381 Window request = event->requestor;
1382 BOOL couldOpen = FALSE;
1383 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1384 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
1385 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1388 * We can only handle the selection request if :
1389 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1390 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1391 * since this has been already done.
1395 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1396 || !(couldOpen = OpenClipboard(hWnd)) )
1400 /* If the specified property is None the requestor is an obsolete client.
1401 * We support these by using the specified target atom as the reply property.
1403 rprop = event->property;
1405 rprop = event->target;
1407 if(event->target == xaTargets) /* Return a list of all supported targets */
1409 /* TARGETS selection request */
1410 rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
1412 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1414 /* MULTIPLE selection request */
1415 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1417 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1419 /* XA_STRING selection request */
1420 rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
1422 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1424 /* XA_PIXMAP selection request */
1425 rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
1427 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1429 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1430 rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
1432 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1434 /* All <WCF> selection requests */
1435 rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
1438 rprop = None; /* Don't support this format */
1441 /* close clipboard only if we opened before */
1442 if(couldOpen) CloseClipboard();
1445 TRACE("\tRequest ignored\n");
1448 * SelectionNotify should be sent only at the end of a MULTIPLE request
1452 result.type = SelectionNotify;
1453 result.display = display;
1454 result.requestor = request;
1455 result.selection = event->selection;
1456 result.property = rprop;
1457 result.target = event->target;
1458 result.time = event->time;
1459 TRACE("Sending SelectionNotify event...\n");
1460 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1464 /***********************************************************************
1465 * EVENT_SelectionClear
1467 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1469 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1471 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1472 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1475 /***********************************************************************
1476 * EVENT_PropertyNotify
1477 * We use this to release resources like Pixmaps when a selection
1478 * client no longer needs them.
1480 static void EVENT_PropertyNotify( XPropertyEvent *event )
1482 /* Check if we have any resources to free */
1483 TRACE("Received PropertyNotify event: ");
1485 switch(event->state)
1487 case PropertyDelete:
1489 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1490 TSXGetAtomName(event->display, event->atom), (long)event->window);
1492 if (X11DRV_IsSelectionOwner())
1493 X11DRV_CLIPBOARD_FreeResources( event->atom );
1497 case PropertyNewValue:
1499 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1500 TSXGetAtomName(event->display, event->atom), (long)event->window);
1509 /**********************************************************************
1510 * EVENT_DropFromOffix
1512 * don't know if it still works (last Changlog is from 96/11/04)
1514 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1516 unsigned long data_length;
1517 unsigned long aux_long;
1518 unsigned char* p_data = NULL;
1529 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1530 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1531 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1532 Window w_aux_root, w_aux_child;
1536 if( !lpDragInfo || !spDragInfo ) return;
1538 pWnd = WIN_FindWndPtr(hWnd);
1540 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
1541 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1542 (unsigned int*)&aux_long);
1544 lpDragInfo->hScope = hWnd;
1545 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1547 /* find out drop point and drop window */
1548 if( x < 0 || y < 0 ||
1549 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1550 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1551 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1554 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1555 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1557 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1558 WIN_ReleaseWndPtr(pWnd);
1560 GlobalFree16( hDragInfo );
1564 TSXGetWindowProperty( display, DefaultRootWindow(display),
1565 dndSelection, 0, 65535, FALSE,
1566 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1567 &data_length, &aux_long, &p_data);
1569 if( !aux_long && p_data) /* don't bother if > 64K */
1571 char *p = (char*) p_data;
1575 while( *p ) /* calculate buffer size */
1578 if((u.i = *p) != -1 )
1579 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1580 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1583 INT len = GetShortPathNameA( p, NULL, 0 );
1584 if (len) aux_long += len + 1;
1589 if( aux_long && aux_long < 65535 )
1592 LPDROPFILESTRUCT16 lpDrop;
1594 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1595 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1596 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1600 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1601 lpDrop->ptMousePos.x = (INT16)x;
1602 lpDrop->ptMousePos.y = (INT16)y;
1603 lpDrop->fInNonClientArea = (BOOL16)
1604 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1605 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1606 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1607 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1608 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1612 if( *p != -1 ) /* use only "good" entries */
1614 GetShortPathNameA( p, p_drop, 65535 );
1615 p_drop += strlen( p_drop ) + 1;
1620 PostMessage16( hWnd, WM_DROPFILES,
1621 (WPARAM16)hDrop, 0L );
1625 if( p_data ) TSXFree(p_data);
1627 } /* WS_EX_ACCEPTFILES */
1629 WIN_ReleaseWndPtr(pDropWnd);
1632 /**********************************************************************
1635 * drop items are separated by \n
1636 * each item is prefixed by its mime type
1638 * event->data.l[3], event->data.l[4] contains drop x,y position
1640 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1644 unsigned long data_length;
1645 unsigned long aux_long, drop_len = 0;
1646 unsigned char *p_data = NULL; /* property data */
1647 char *p_drop = NULL;
1649 int x, y, drop32 = FALSE ;
1660 pWnd = WIN_FindWndPtr(hWnd);
1661 drop32 = pWnd->flags & WIN_ISWIN32;
1663 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1665 WIN_ReleaseWndPtr(pWnd);
1668 WIN_ReleaseWndPtr(pWnd);
1670 TSXGetWindowProperty( display, DefaultRootWindow(display),
1671 dndSelection, 0, 65535, FALSE,
1672 AnyPropertyType, &u.atom_aux, &u.i,
1673 &data_length, &aux_long, &p_data);
1675 WARN("property too large, truncated!\n");
1676 TRACE("urls=%s\n", p_data);
1678 if( !aux_long && p_data) { /* don't bother if > 64K */
1679 /* calculate length */
1681 next = strchr(p, '\n');
1684 if (strncmp(p,"file:",5) == 0 ) {
1685 INT len = GetShortPathNameA( p+5, NULL, 0 );
1686 if (len) drop_len += len + 1;
1691 next = strchr(p, '\n');
1697 if( drop_len && drop_len < 65535 ) {
1698 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
1699 &x, &y, &u.i, &u.i, &u.i);
1701 pDropWnd = WIN_FindWndPtr( hWnd );
1704 LPDROPFILESTRUCT lpDrop;
1705 drop_len += sizeof(DROPFILESTRUCT) + 1;
1706 hDrop.h32 = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
1707 lpDrop = (LPDROPFILESTRUCT) GlobalLock( hDrop.h32 );
1710 lpDrop->lSize = sizeof(DROPFILESTRUCT);
1711 lpDrop->ptMousePos.x = (INT)x;
1712 lpDrop->ptMousePos.y = (INT)y;
1713 lpDrop->fInNonClientArea = (BOOL)
1714 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1715 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1716 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1717 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1718 lpDrop->fWideChar = FALSE;
1719 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1722 LPDROPFILESTRUCT16 lpDrop;
1723 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1724 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1725 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1728 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1729 lpDrop->ptMousePos.x = (INT16)x;
1730 lpDrop->ptMousePos.y = (INT16)y;
1731 lpDrop->fInNonClientArea = (BOOL16)
1732 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1733 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1734 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1735 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1736 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1740 /* create message content */
1743 next = strchr(p, '\n');
1746 if (strncmp(p,"file:",5) == 0 ) {
1747 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1749 TRACE("drop file %s as %s\n", p+5, p_drop);
1752 WARN("can't convert file %s to dos name \n", p+5);
1755 WARN("unknown mime type %s\n", p);
1760 next = strchr(p, '\n');
1768 /* can not use PostMessage32A because it is currently based on
1769 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1771 GlobalUnlock(hDrop.h32);
1772 SendMessageA( hWnd, WM_DROPFILES,
1773 (WPARAM)hDrop.h32, 0L );
1775 GlobalUnlock16(hDrop.h16);
1776 PostMessage16( hWnd, WM_DROPFILES,
1777 (WPARAM16)hDrop.h16, 0L );
1780 WIN_ReleaseWndPtr(pDropWnd);
1782 if( p_data ) TSXFree(p_data);
1786 /**********************************************************************
1787 * EVENT_ClientMessage
1789 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1791 if (event->message_type != None && event->format == 32) {
1792 if ((event->message_type == wmProtocols) &&
1793 (((Atom) event->data.l[0]) == wmDeleteWindow))
1795 /* Ignore the delete window request if the window has been disabled
1796 * and we are in managed mode. This is to disallow applications from
1797 * being closed by the window manager while in a modal state.
1800 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
1802 if ( !Options.managed || !bIsDisabled )
1803 PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1805 else if ( event->message_type == dndProtocol &&
1806 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1807 EVENT_DropFromOffiX(hWnd, event);
1808 else if ( event->message_type == dndProtocol &&
1809 event->data.l[0] == DndURL )
1810 EVENT_DropURLs(hWnd, event);
1813 /* enable this if you want to see the message */
1814 unsigned char* p_data = NULL;
1820 TSXGetWindowProperty( display, DefaultRootWindow(display),
1821 dndSelection, 0, 65535, FALSE,
1822 AnyPropertyType, &u.atom, &u.i,
1823 &u.l, &u.l, &p_data);
1824 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1825 event->message_type, event->data.l[0], event->data.l[1],
1826 event->data.l[2], event->data.l[3], event->data.l[4],
1829 TRACE("unrecognized ClientMessage\n" );
1834 /**********************************************************************
1837 * Install colormap when Wine window is focused in
1838 * self-managed mode with private colormap
1841 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
1843 if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1844 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1845 TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
1849 /**********************************************************************
1852 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1854 HWND hwndFocus = GetFocus();
1855 WND *wndFocus = WIN_FindWndPtr(hwndFocus);
1856 WND *pWnd = WIN_FindWndPtr(hWnd);
1857 if (pWnd->flags & WIN_MANAGED)
1859 DCE_InvalidateDCE( pWnd, &pWnd->rectWindow );
1860 pWnd->dwStyle &= ~WS_MINIMIZE;
1861 pWnd->dwStyle |= WS_VISIBLE;
1862 ShowOwnedPopups(hWnd,TRUE);
1864 WIN_ReleaseWndPtr(pWnd);
1866 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1867 X11DRV_WND_SetFocus(wndFocus);
1869 WIN_ReleaseWndPtr(wndFocus);
1875 /**********************************************************************
1878 void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
1880 WND *pWnd = WIN_FindWndPtr(hWnd);
1881 if (pWnd && (pWnd->flags & WIN_MANAGED))
1884 if( pWnd->dwStyle & WS_VISIBLE )
1886 pWnd->dwStyle |= WS_MINIMIZE;
1887 pWnd->dwStyle &= ~WS_VISIBLE;
1888 ShowOwnedPopups(hWnd,FALSE);
1891 WIN_ReleaseWndPtr(pWnd);
1894 /***********************************************************************
1895 * EVENT_MappingNotify
1897 static void EVENT_MappingNotify( XMappingEvent *event )
1899 TSXRefreshKeyboardMapping(event);
1901 /* reinitialize Wine-X11 driver keyboard table */
1902 X11DRV_InitKeyboard();
1906 /**********************************************************************
1907 * X11DRV_EVENT_SetInputMethod
1909 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1911 INPUT_TYPE prev = current_input_type;
1913 /* Flag not used yet */
1914 in_transition = FALSE;
1915 current_input_type = type;
1920 #ifdef HAVE_LIBXXF86DGA2
1921 /**********************************************************************
1922 * X11DRV_EVENT_SetDGAStatus
1924 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1926 if (event_base < 0) {
1932 DGAMotionEventType = event_base + MotionNotify;
1933 DGAButtonPressEventType = event_base + ButtonPress;
1934 DGAButtonReleaseEventType = event_base + ButtonRelease;
1935 DGAKeyPressEventType = event_base + KeyPress;
1936 DGAKeyReleaseEventType = event_base + KeyRelease;
1940 /* DGA2 event handlers */
1941 static void EVENT_DGAMotionEvent( XDGAMotionEvent *event )
1943 X11DRV_SendEvent( MOUSEEVENTF_MOVE,
1944 event->dx, event->dy,
1945 X11DRV_EVENT_XStateToKeyState( event->state ),
1946 event->time, DGAhwnd );
1949 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent *event )
1951 static WORD statusCodes[NB_BUTTONS] =
1952 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
1953 int buttonNum = event->button - 1;
1957 if (buttonNum >= NB_BUTTONS) return;
1959 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1964 keystate |= MK_LBUTTON;
1967 keystate |= MK_MBUTTON;
1970 keystate |= MK_RBUTTON;
1974 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time, DGAhwnd );
1977 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent *event )
1979 static WORD statusCodes[NB_BUTTONS] =
1980 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
1981 int buttonNum = event->button - 1;
1985 if (buttonNum >= NB_BUTTONS) return;
1987 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1992 keystate &= ~MK_LBUTTON;
1995 keystate &= ~MK_MBUTTON;
1998 keystate &= ~MK_RBUTTON;
2002 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, event->time, DGAhwnd );
2007 #ifdef HAVE_LIBXXSHM
2010 Normal XShm operation:
2012 X11 service thread app thread
2013 ------------- ----------------- ------------------------
2014 (idle) ddraw calls XShmPutImage
2015 (copies data) (waiting for shm_event)
2016 ShmCompletion -> (waiting for shm_event)
2017 (idle) signal shm_event ->
2018 (idle) returns to app
2020 However, this situation can occur for some reason:
2022 X11 service thread app thread
2023 ------------- ----------------- ------------------------
2026 (waiting for app) ddraw calls XShmPutImage
2027 (copies data) (waiting for app) (waiting for shm_event)
2028 ShmCompletion (waiting for app) (waiting for shm_event)
2029 (idle) DEADLOCK DEADLOCK
2031 which is why I also wait for shm_read and do XCheckTypedEvent()
2032 calls in the wait loop. This results in:
2034 X11 service thread app thread
2035 ------------- ----------------- ------------------------
2036 ShmCompletion (waiting for app) waking up on shm_read
2037 (idle) (waiting for app) XCheckTypedEvent() -> signal shm_event
2038 (waiting for app) returns
2048 /* FIXME: this is not pretty */
2049 static HANDLE shm_read = 0;
2052 static volatile shm_qs shm_q[SHM_MAX_Q];
2054 static void EVENT_ShmCompletion( XShmCompletionEvent *event )
2058 TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event->drawable, GetTickCount() );
2060 for (n=0; n<SHM_MAX_Q; n++)
2061 if ((shm_q[n].draw == event->drawable) && (shm_q[n].state == 0)) {
2062 HANDLE sema = shm_q[n].sema;
2063 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].state, (PVOID)1, (PVOID)0)) {
2064 ReleaseSemaphore(sema, 1, NULL);
2065 TRACE("Signaling ShmCompletion (#%d) (semaphore %x)\n", n, sema);
2070 ERR("Got ShmCompletion for unknown drawable %ld\n", event->drawable );
2073 int X11DRV_EVENT_PrepareShmCompletion( Drawable dw )
2078 shm_read = FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE );
2080 for (n=0; n<SHM_MAX_Q; n++)
2082 if (!InterlockedCompareExchange((PVOID*)&shm_q[n].draw, (PVOID)dw, (PVOID)0))
2086 ERR("Maximum number of outstanding ShmCompletions exceeded!\n");
2091 if (!shm_q[n].sema) {
2092 shm_q[n].sema = CreateSemaphoreA( NULL, 0, 256, NULL );
2093 TRACE("Allocated ShmCompletion slots have been increased to %d, new semaphore is %x\n", n+1, shm_q[n].sema);
2096 TRACE("Prepared ShmCompletion (#%d) wait for drawable %ld (thread %lx) (time %ld)\n", n, dw, GetCurrentThreadId(), GetTickCount() );
2100 static void X11DRV_EVENT_WaitReplaceShmCompletionInternal( int *compl, Drawable dw, int creat )
2106 if ((!n) || (creat && (!shm_q[n-1].draw))) {
2107 nn = X11DRV_EVENT_PrepareShmCompletion(dw);
2108 if (!(n=(LONG)InterlockedCompareExchange((PVOID*)compl, (PVOID)nn, (PVOID)n)))
2110 /* race for compl lost, clear slot */
2111 shm_q[nn-1].draw = 0;
2115 if (dw && (shm_q[n-1].draw != dw)) {
2116 /* this shouldn't happen with the current ddraw implementation */
2117 FIXME("ShmCompletion replace with different drawable!\n");
2121 sema = shm_q[n-1].sema;
2123 /* nothing to wait on (PrepareShmCompletion not done yet?), so probably nothing to wait for */
2127 nn = InterlockedExchangeAdd((PLONG)&shm_q[n-1].waiter, 1);
2128 if ((!shm_q[n-1].draw) || (shm_q[n-1].state == 2)) {
2129 /* too late, the wait was just cleared (wait complete) */
2130 TRACE("Wait skip for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2132 TRACE("Waiting for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
2134 /* another thread is already waiting, let the primary waiter do the dirty work
2135 * (to avoid TSX critical section contention - that could get really slow) */
2136 WaitForSingleObject( sema, INFINITE );
2138 /* we're primary waiter - first check if it's already triggered */
2139 if ( WaitForSingleObject( sema, 0 ) != WAIT_OBJECT_0 ) {
2140 /* nope, may need to poll X event queue, in case the service thread is blocked */
2147 /* check X event queue */
2148 if (TSXCheckTypedEvent( display, ShmCompletionType, &event)) {
2149 EVENT_ProcessEvent( &event );
2151 } while ( WaitForMultipleObjects(2, hnd, FALSE, INFINITE) > WAIT_OBJECT_0 );
2153 TRACE("Wait complete (thread %lx) (time %ld)\n", GetCurrentThreadId(), GetTickCount() );
2156 st = InterlockedExchange((LPLONG)&shm_q[n-1].state, 2);
2158 /* first waiter to return, release all other waiters */
2159 nn = shm_q[n-1].waiter;
2160 TRACE("Signaling %ld additional ShmCompletion (#%d) waiter(s), semaphore %x\n", nn-1, n-1, sema);
2161 ReleaseSemaphore(sema, nn-1, NULL);
2164 nn = InterlockedDecrement((LPLONG)&shm_q[n-1].waiter);
2166 /* last waiter to return, replace drawable and prepare new wait */
2167 shm_q[n-1].draw = dw;
2168 shm_q[n-1].state = 0;
2172 void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw )
2174 X11DRV_EVENT_WaitReplaceShmCompletionInternal( compl, dw, 1 );
2177 void X11DRV_EVENT_WaitShmCompletion( int compl )
2180 X11DRV_EVENT_WaitReplaceShmCompletionInternal( &compl, 0, 0 );
2183 void X11DRV_EVENT_WaitShmCompletions( Drawable dw )
2187 for (n=0; n<SHM_MAX_Q; n++)
2188 if (shm_q[n].draw == dw)
2189 X11DRV_EVENT_WaitShmCompletion( n+1 );
2192 #endif /* defined(HAVE_LIBXXSHM) */