2 * X events handling functions
4 * Copyright 1993 Alexandre Julliard
14 #include <sys/types.h>
16 #include <X11/keysym.h>
18 #include "ts_xresource.h"
20 #include <X11/Xatom.h>
29 #include "clipboard.h"
45 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
47 #define DndNotDnd -1 /* OffiX drag&drop */
59 #define DndURL 128 /* KDE drag&drop */
62 /* X context to associate a hwnd to an X window */
63 static XContext winContext = 0;
65 static INT16 captureHT = HTCLIENT;
66 static HWND32 captureWnd = 0;
67 static BOOL32 InputEnabled = TRUE;
68 static BOOL32 SwappedButtons = FALSE;
70 static Atom wmProtocols = None;
71 static Atom wmDeleteWindow = None;
72 static Atom dndProtocol = None;
73 static Atom dndSelection = None;
75 /* EVENT_WaitNetEvent() master fd sets */
77 static fd_set __event_io_set[3];
78 static int __event_max_fd = 0;
79 static int __event_x_connection = 0;
81 static const char * const event_names[] =
83 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
84 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
85 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
86 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
87 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
88 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
89 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
90 "ClientMessage", "MappingNotify"
94 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
95 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
96 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
97 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
98 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
99 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
100 static int EVENT_Expose( WND *pWnd, XExposeEvent *event );
101 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
102 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
103 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
104 static void EVENT_SelectionNotify( XSelectionEvent *event);
105 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
106 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
107 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
109 /* Usable only with OLVWM - compile option perhaps?
110 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
113 static void EVENT_GetGeometry( Window win, int *px, int *py,
114 unsigned int *pwidth, unsigned int *pheight );
115 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY,
116 WORD buttonCount, DWORD extraInfo );
118 /***********************************************************************
121 * Initialize network IO.
123 BOOL32 EVENT_Init(void)
126 for( i = 0; i < 3; i++ )
127 FD_ZERO( __event_io_set + i );
129 __event_max_fd = __event_x_connection = ConnectionNumber(display);
130 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
135 /***********************************************************************
138 void EVENT_AddIO( int fd, unsigned io_type )
140 FD_SET( fd, &__event_io_set[io_type] );
141 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
144 void EVENT_DeleteIO( int fd, unsigned io_type )
146 FD_CLR( fd, &__event_io_set[io_type] );
149 /***********************************************************************
152 * Process an X event.
154 void EVENT_ProcessEvent( XEvent *event )
158 if ( TSXFindContext( display, event->xany.window, winContext,
159 (char **)&pWnd ) != 0) {
160 if ( event->type == ClientMessage) {
161 /* query window (drag&drop event contains only drag window) */
163 int root_x, root_y, child_x, child_y;
165 TSXQueryPointer( display, rootWindow, &root, &child,
166 &root_x, &root_y, &child_x, &child_y, &u);
167 if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
170 pWnd = NULL; /* Not for a registered window */
174 TRACE(event, "Got event %s for hwnd %04x\n",
175 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
182 if (InputEnabled) EVENT_Key( pWnd, (XKeyEvent*)event );
187 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
192 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
196 /* Wine between two fast machines across the overloaded campus
197 ethernet gets very boged down in MotionEvents. The following
198 simply finds the last motion event in the queue and drops
199 the rest. On a good link events are servered before they build
200 up so this doesn't take place. On a slow link this may cause
201 problems if the event order is important. I'm not yet seen
202 of any problems. Jon 7/6/96.
206 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
207 MotionNotify, event));
208 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
214 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
219 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
224 if (EVENT_Expose( pWnd, (XExposeEvent *)event )) {
225 /* need to process ConfigureNotify first */
228 /* attempt to find and process the ConfigureNotify event now */
229 if (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
230 ConfigureNotify, &new_event)) {
231 EVENT_ProcessEvent( &new_event );
232 EVENT_Expose( pWnd, (XExposeEvent *)event );
236 /* no luck at this time, defer Expose event for later */
237 if (!pWnd->expose_event) pWnd->expose_event = malloc( sizeof(XExposeEvent) );
238 else { FIXME(x11,"can't handle more than one deferred Expose events\n"); }
239 *(pWnd->expose_event) = *(XExposeEvent *)event;
245 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
248 case ConfigureNotify:
250 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
251 if (pWnd->expose_event) {
252 /* process deferred Expose event */
253 EVENT_Expose( pWnd, pWnd->expose_event );
254 free( pWnd->expose_event );
255 pWnd->expose_event = NULL;
259 case SelectionRequest:
261 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
264 case SelectionNotify:
266 EVENT_SelectionNotify( (XSelectionEvent *)event );
271 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
276 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
280 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
286 /* We get all these because of StructureNotifyMask. */
288 case CirculateNotify:
297 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
301 WARN(event, "Unprocessed event %s for hwnd %04x\n",
302 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
308 /***********************************************************************
309 * EVENT_RegisterWindow
311 * Associate an X window to a HWND.
313 void EVENT_RegisterWindow( WND *pWnd )
315 if (wmProtocols == None)
316 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
317 if (wmDeleteWindow == None)
318 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
319 if( dndProtocol == None )
320 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
321 if( dndSelection == None )
322 dndSelection = TSXInternAtom( display, "DndSelection" , False );
324 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
326 if (!winContext) winContext = TSXUniqueContext();
327 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
330 /***********************************************************************
331 * EVENT_DestroyWindow
333 void EVENT_DestroyWindow( WND *pWnd )
337 if (pWnd->expose_event) {
338 free( pWnd->expose_event );
339 pWnd->expose_event = NULL;
341 TSXDeleteContext( display, pWnd->window, winContext );
342 TSXDestroyWindow( display, pWnd->window );
343 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
347 /***********************************************************************
348 * IsUserIdle (USER.333)
350 * Check if we have pending X events.
352 BOOL16 WINAPI IsUserIdle(void)
354 struct timeval timeout = {0, 0};
358 FD_SET(__event_x_connection, &check_set);
359 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
365 /***********************************************************************
368 * Wait for a network event, optionally sleeping until one arrives.
369 * Return TRUE if an event is pending, FALSE on timeout or error
370 * (for instance lost connection with the server).
372 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
375 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
376 int pending = TSXPending(display);
378 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
379 * in this case, we fall through directly to the XNextEvent loop.
382 if ((maxWait != -1) && !pending)
385 struct timeval timeout;
388 memcpy( io_set, __event_io_set, sizeof(io_set) );
390 timeout.tv_usec = (maxWait % 1000) * 1000;
391 timeout.tv_sec = maxWait / 1000;
394 sigsetjmp(env_wait_x, 1);
397 if (DDE_GetRemoteMessage()) {
398 while(DDE_GetRemoteMessage())
402 stop_wait_op = STOP_WAIT_X;
403 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
404 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
405 &io_set[EVENT_IO_WRITE],
406 &io_set[EVENT_IO_EXCEPT], &timeout );
407 if ( num_pending == 0 )
410 TIMER_ExpireTimers();
413 else stop_wait_op = CONT;
414 #else /* CONFIG_IPC */
415 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
416 &io_set[EVENT_IO_WRITE],
417 &io_set[EVENT_IO_EXCEPT], &timeout );
418 if ( num_pending == 0)
420 /* Timeout or error */
421 TIMER_ExpireTimers();
424 #endif /* CONFIG_IPC */
426 /* Winsock asynchronous services */
428 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
432 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
434 else /* no X events */
435 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
438 { /* Wait for X11 input. */
442 FD_SET(__event_x_connection, &set);
443 select(__event_x_connection + 1, &set, 0, 0, 0 );
446 /* Process current X event (and possibly others that occurred in the meantime) */
448 EnterCriticalSection(&X11DRV_CritSection);
449 while (XPending( display ))
453 if (DDE_GetRemoteMessage())
455 LeaveCriticalSection(&X11DRV_CritSection);
456 while(DDE_GetRemoteMessage()) ;
459 #endif /* CONFIG_IPC */
461 XNextEvent( display, &event );
463 LeaveCriticalSection(&X11DRV_CritSection);
470 /* Check only for those events which can be processed
473 if( event.type == MotionNotify ||
474 event.type == ButtonPress || event.type == ButtonRelease ||
475 event.type == KeyPress || event.type == KeyRelease ||
476 event.type == SelectionRequest || event.type == SelectionClear ||
477 event.type == ClientMessage )
479 EVENT_ProcessEvent( &event );
483 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
484 (char **)&pWnd ) || (event.type == NoExpose))
489 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
491 pQ->flags |= QUEUE_FLAG_XEVENT;
492 PostEvent(pQ->hTask);
493 TSXPutBackEvent(display, &event);
498 else EVENT_ProcessEvent( &event );
499 EnterCriticalSection(&X11DRV_CritSection);
501 LeaveCriticalSection(&X11DRV_CritSection);
506 /***********************************************************************
509 * Synchronize with the X server. Should not be used too often.
511 void EVENT_Synchronize()
515 /* Use of the X critical section is needed or we have a small
516 * race between XPending() and XNextEvent().
518 EnterCriticalSection( &X11DRV_CritSection );
519 XSync( display, False );
520 while (XPending( display ))
522 XNextEvent( display, &event );
523 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
524 LeaveCriticalSection( &X11DRV_CritSection );
525 EVENT_ProcessEvent( &event );
526 EnterCriticalSection( &X11DRV_CritSection );
528 LeaveCriticalSection( &X11DRV_CritSection );
531 /***********************************************************************
534 * Try to synchronize internal z-order with the window manager's.
535 * Probably a futile endeavor.
537 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
539 /* return TRUE if we have at least two managed windows */
541 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
542 if( (*pWndA)->flags & WIN_MANAGED &&
543 (*pWndA)->dwStyle & WS_VISIBLE ) break;
545 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
546 if( (*pWndB)->flags & WIN_MANAGED &&
547 (*pWndB)->dwStyle & WS_VISIBLE ) break;
548 return ((*pWndB) != NULL);
551 static Window __get_common_ancestor( Window A, Window B,
552 Window** children, unsigned* total )
554 /* find the real root window */
556 Window root, *childrenB;
561 if( *children ) TSXFree( *children );
562 TSXQueryTree( display, A, &root, &A, children, total );
563 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
564 if( childrenB ) TSXFree( childrenB );
565 } while( A != B && A && B );
566 return ( A && B ) ? A : 0 ;
569 static Window __get_top_decoration( Window w, Window ancestor )
571 Window* children, root, prev = w, parent = w;
577 TSXQueryTree( display, w, &root, &parent, &children, &total );
578 if( children ) TSXFree( children );
579 } while( parent && parent != ancestor );
580 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
581 return ( parent ) ? w : 0 ;
584 static unsigned __td_lookup( Window w, Window* list, unsigned max )
587 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
591 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
594 HWND32 hwndInsertAfter = HWND_TOP;
595 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
596 Window w, parent, *children = NULL;
597 unsigned total, check, pos, best;
599 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
601 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
603 if( parent && children )
605 w = __get_top_decoration( pWndCheck->window, parent );
606 if( w != children[total - 1] )
608 check = __td_lookup( w, children, total );
610 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
612 if( pWnd != pWndCheck )
614 if( !(pWnd->flags & WIN_MANAGED) ||
615 !(w = __get_top_decoration( pWnd->window, parent )) )
617 pos = __td_lookup( w, children, total );
618 if( pos < best && pos > check )
621 hwndInsertAfter = pWnd->hwndSelf;
623 if( check - best == 1 ) break;
626 WIN_UnlinkWindow( pWndCheck->hwndSelf );
627 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
630 if( children ) TSXFree( children );
635 /***********************************************************************
636 * EVENT_XStateToKeyState
638 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
639 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
641 static WORD EVENT_XStateToKeyState( int state )
645 if (state & Button1Mask) kstate |= MK_LBUTTON;
646 if (state & Button2Mask) kstate |= MK_MBUTTON;
647 if (state & Button3Mask) kstate |= MK_RBUTTON;
648 if (state & ShiftMask) kstate |= MK_SHIFT;
649 if (state & ControlMask) kstate |= MK_CONTROL;
654 /***********************************************************************
657 static int EVENT_Expose( WND *pWnd, XExposeEvent *event )
661 unsigned int width, height;
663 /* When scrolling, many (fvwm2-based) window managers send the Expose
664 * event before sending the ConfigureNotify event, and we don't like
665 * that, so before processing the Expose event, we check whether the
666 * geometry has changed, and if so, we defer the Expose event until
667 * we get the ConfigureNotify event. -Ove KÃ¥ven */
668 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
670 if ( x != pWnd->rectWindow.left || y != pWnd->rectWindow.top ||
671 (width != pWnd->rectWindow.right - pWnd->rectWindow.left) ||
672 (height != pWnd->rectWindow.bottom - pWnd->rectWindow.top))
673 return 1; /* tell EVENT_ProcessEvent() to defer it */
675 /* Make position relative to client area instead of window */
676 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
677 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
678 rect.right = rect.left + event->width;
679 rect.bottom = rect.top + event->height;
681 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
682 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
683 (event->count ? 0 : RDW_ERASENOW), 0 );
688 /***********************************************************************
689 * EVENT_GraphicsExpose
691 * This is needed when scrolling area is partially obscured
692 * by non-Wine X window.
694 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
698 /* Make position relative to client area instead of window */
699 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
700 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
701 rect.right = rect.left + event->width;
702 rect.bottom = rect.top + event->height;
704 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
705 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
706 (event->count ? 0 : RDW_ERASENOW), 0 );
710 /***********************************************************************
713 * Handle a X key event
715 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
717 KEYBOARD_HandleEvent( pWnd, event );
721 /***********************************************************************
724 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
726 int xOffset = pWnd? pWnd->rectWindow.left : 0;
727 int yOffset = pWnd? pWnd->rectWindow.top : 0;
730 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
733 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
735 EVENT_SendMouseEvent( ME_MOVE,
742 /***********************************************************************
743 * EVENT_DummyMotionNotify
745 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
747 void EVENT_DummyMotionNotify(void)
750 int rootX, rootY, winX, winY;
753 if (TSXQueryPointer( display, rootWindow, &root, &child,
754 &rootX, &rootY, &winX, &winY, &state ))
756 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
757 winX, winY, GetTickCount(), 0 );
762 /***********************************************************************
765 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
767 static WORD messages[NB_BUTTONS] =
768 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
769 static WORD statusCodes[NB_BUTTONS] =
770 { ME_LDOWN, 0, ME_RDOWN };
771 int buttonNum = event->button - 1;
773 int xOffset = pWnd? pWnd->rectWindow.left : 0;
774 int yOffset = pWnd? pWnd->rectWindow.top : 0;
776 if (buttonNum >= NB_BUTTONS) return;
777 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
778 MouseButtonsStates[buttonNum] = TRUE;
779 AsyncMouseButtonsStates[buttonNum] = TRUE;
782 hardware_event( messages[buttonNum],
783 EVENT_XStateToKeyState( event->state ), 0L,
786 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
788 EVENT_SendMouseEvent( statusCodes[buttonNum],
795 /***********************************************************************
796 * EVENT_ButtonRelease
798 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
800 static const WORD messages[NB_BUTTONS] =
801 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
802 static WORD statusCodes[NB_BUTTONS] =
803 { ME_LUP, 0, ME_RUP };
804 int buttonNum = event->button - 1;
806 int xOffset = pWnd? pWnd->rectWindow.left : 0;
807 int yOffset = pWnd? pWnd->rectWindow.top : 0;
809 if (buttonNum >= NB_BUTTONS) return;
810 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
811 MouseButtonsStates[buttonNum] = FALSE;
814 hardware_event( messages[buttonNum],
815 EVENT_XStateToKeyState( event->state ), 0L,
818 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
820 EVENT_SendMouseEvent( statusCodes[buttonNum],
827 /**********************************************************************
830 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
832 if (Options.managed) EVENT_QueryZOrder( pWnd );
834 if (event->detail != NotifyPointer)
836 HWND32 hwnd = pWnd->hwndSelf;
838 if (hwnd != GetActiveWindow32())
840 WINPOS_ChangeActiveWindow( hwnd, FALSE );
841 KEYBOARD_UpdateState();
843 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
849 /**********************************************************************
852 * Note: only top-level override-redirect windows get FocusOut events.
854 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
856 if (event->detail != NotifyPointer)
858 HWND32 hwnd = pWnd->hwndSelf;
860 if (hwnd == GetActiveWindow32())
861 WINPOS_ChangeActiveWindow( 0, FALSE );
862 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
867 /**********************************************************************
870 BOOL32 EVENT_CheckFocus(void)
876 TSXGetInputFocus(display, &xW, &state);
878 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
884 /**********************************************************************
887 * Helper function for ConfigureNotify handling.
888 * Get the new geometry of a window relative to the root window.
890 static void EVENT_GetGeometry( Window win, int *px, int *py,
891 unsigned int *pwidth, unsigned int *pheight )
893 Window root, parent, *children;
895 unsigned int width, height, border, depth, nb_children;
897 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
898 &border, &depth )) return;
899 if (win == rootWindow)
907 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
910 if (parent == rootWindow) break;
912 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
913 &width, &height, &border, &depth )) return;
920 /**********************************************************************
921 * EVENT_ConfigureNotify
923 * The ConfigureNotify event is only selected on top-level windows
924 * when the -managed flag is used.
926 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
929 RECT32 newWindowRect, newClientRect;
930 HRGN32 hrgnOldPos, hrgnNewPos;
931 Window above = event->above;
933 unsigned int width, height;
935 assert (pWnd->flags & WIN_MANAGED);
937 /* We don't rely on the event geometry info, because it is relative
938 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
939 * if the window hasn't moved).
941 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
943 /* Fill WINDOWPOS struct */
944 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
945 winpos.hwnd = pWnd->hwndSelf;
951 /* Check for unchanged attributes */
952 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
953 winpos.flags |= SWP_NOMOVE;
954 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
955 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
956 winpos.flags |= SWP_NOSIZE;
959 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
960 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
961 DCE_InvalidateDCE( pWnd, &rect );
964 /* Send WM_WINDOWPOSCHANGING */
965 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
967 /* Calculate new position and size */
968 newWindowRect.left = x;
969 newWindowRect.right = x + width;
970 newWindowRect.top = y;
971 newWindowRect.bottom = y + height;
973 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
974 &pWnd->rectWindow, &pWnd->rectClient,
975 &winpos, &newClientRect );
977 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
978 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
979 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
980 DeleteObject32(hrgnOldPos);
981 DeleteObject32(hrgnNewPos);
983 /* Set new size and position */
984 pWnd->rectWindow = newWindowRect;
985 pWnd->rectClient = newClientRect;
986 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
988 if (!IsWindow32( winpos.hwnd )) return;
989 if( above == None ) /* absolute bottom */
991 WIN_UnlinkWindow( winpos.hwnd );
992 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
994 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
998 /***********************************************************************
999 * EVENT_SelectionRequest
1001 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
1003 XSelectionEvent result;
1005 Window request = event->requestor;
1007 if(event->target == XA_STRING)
1013 rprop = event->property;
1015 if(rprop == None) rprop = event->target;
1017 if(event->selection!=XA_PRIMARY) rprop = None;
1018 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
1021 /* open to make sure that clipboard is available */
1023 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
1026 hText = GetClipboardData16(CF_TEXT);
1027 text = GlobalLock16(hText);
1028 size = GlobalSize16(hText);
1030 /* remove carriage returns */
1032 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
1033 for(i=0,j=0; i < size && text[i]; i++ )
1035 if( text[i] == '\r' &&
1036 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1037 lpstr[j++] = text[i];
1041 TSXChangeProperty(display, request, rprop,
1042 XA_STRING, 8, PropModeReplace,
1044 HeapFree( GetProcessHeap(), 0, lpstr );
1046 /* close only if we opened before */
1048 if(couldOpen) CloseClipboard32();
1053 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
1055 result.type = SelectionNotify;
1056 result.display = display;
1057 result.requestor = request;
1058 result.selection = event->selection;
1059 result.property = rprop;
1060 result.target = event->target;
1061 result.time = event->time;
1062 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1066 /***********************************************************************
1067 * EVENT_SelectionNotify
1069 static void EVENT_SelectionNotify( XSelectionEvent *event )
1071 if (event->selection != XA_PRIMARY) return;
1073 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
1074 else CLIPBOARD_ReadSelection( event->requestor, event->property );
1076 TRACE(clipboard,"\tSelectionNotify done!\n");
1080 /***********************************************************************
1081 * EVENT_SelectionClear
1083 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1085 if (event->selection != XA_PRIMARY) return;
1086 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1090 /**********************************************************************
1091 * EVENT_DropFromOffix
1093 * don't know if it still works (last Changlog is from 96/11/04)
1095 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1097 unsigned long data_length;
1098 unsigned long aux_long;
1099 unsigned char* p_data = NULL;
1107 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1108 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1109 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1110 Window w_aux_root, w_aux_child;
1113 if( !lpDragInfo || !spDragInfo ) return;
1115 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1116 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1118 lpDragInfo->hScope = pWnd->hwndSelf;
1119 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1121 /* find out drop point and drop window */
1122 if( x < 0 || y < 0 ||
1123 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1124 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1125 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1128 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1129 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1131 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1132 GlobalFree16( hDragInfo );
1136 TSXGetWindowProperty( display, DefaultRootWindow(display),
1137 dndSelection, 0, 65535, FALSE,
1138 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1139 &data_length, &aux_long, &p_data);
1141 if( !aux_long && p_data) /* don't bother if > 64K */
1143 char *p = (char*) p_data;
1147 while( *p ) /* calculate buffer size */
1150 if((u.i = *p) != -1 )
1151 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1152 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1155 INT32 len = GetShortPathName32A( p, NULL, 0 );
1156 if (len) aux_long += len + 1;
1161 if( aux_long && aux_long < 65535 )
1164 LPDROPFILESTRUCT16 lpDrop;
1166 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1167 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1168 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1172 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1173 lpDrop->ptMousePos.x = (INT16)x;
1174 lpDrop->ptMousePos.y = (INT16)y;
1175 lpDrop->fInNonClientArea = (BOOL16)
1176 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1177 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1178 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1179 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1180 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1184 if( *p != -1 ) /* use only "good" entries */
1186 GetShortPathName32A( p, p_drop, 65535 );
1187 p_drop += strlen( p_drop ) + 1;
1192 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1193 (WPARAM16)hDrop, 0L );
1197 if( p_data ) TSXFree(p_data);
1199 } /* WS_EX_ACCEPTFILES */
1202 /**********************************************************************
1205 * drop items are separated by \n
1206 * each item is prefixed by its mime type
1208 * event->data.l[3], event->data.l[4] contains drop x,y position
1210 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1213 unsigned long data_length;
1214 unsigned long aux_long, drop_len = 0;
1215 unsigned char *p_data = NULL; /* property data */
1216 char *p_drop = NULL;
1218 int x, y, drop32 = FALSE ;
1230 drop32 = pWnd->flags & WIN_ISWIN32;
1232 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1235 TSXGetWindowProperty( display, DefaultRootWindow(display),
1236 dndSelection, 0, 65535, FALSE,
1237 AnyPropertyType, &u.atom_aux, &u.i,
1238 &data_length, &aux_long, &p_data);
1240 WARN(event,"property too large, truncated!\n");
1241 TRACE(event,"urls=%s\n", p_data);
1243 if( !aux_long && p_data) { /* don't bother if > 64K */
1244 /* calculate length */
1246 next = strchr(p, '\n');
1249 if (strncmp(p,"file:",5) == 0 ) {
1250 INT32 len = GetShortPathName32A( p+5, NULL, 0 );
1251 if (len) drop_len += len + 1;
1256 next = strchr(p, '\n');
1262 if( drop_len && drop_len < 65535 ) {
1263 TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux,
1264 &x, &y, &u.i, &u.i, &u.i);
1265 pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1268 LPDROPFILESTRUCT32 lpDrop;
1269 drop_len += sizeof(DROPFILESTRUCT32) + 1;
1270 hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
1271 lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
1274 lpDrop->lSize = sizeof(DROPFILESTRUCT32);
1275 lpDrop->ptMousePos.x = (INT32)x;
1276 lpDrop->ptMousePos.y = (INT32)y;
1277 lpDrop->fInNonClientArea = (BOOL32)
1278 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1279 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1280 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1281 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1282 lpDrop->fWideChar = FALSE;
1283 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
1286 LPDROPFILESTRUCT16 lpDrop;
1287 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1288 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1289 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1292 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1293 lpDrop->ptMousePos.x = (INT16)x;
1294 lpDrop->ptMousePos.y = (INT16)y;
1295 lpDrop->fInNonClientArea = (BOOL16)
1296 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1297 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1298 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1299 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1300 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1304 /* create message content */
1307 next = strchr(p, '\n');
1310 if (strncmp(p,"file:",5) == 0 ) {
1311 INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
1313 TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1316 WARN(event, "can't convert file %s to dos name \n", p+5);
1319 WARN(event, "unknown mime type %s\n", p);
1324 next = strchr(p, '\n');
1332 /* can not use PostMessage32A because it is currently based on
1333 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1335 GlobalUnlock32(hDrop.h32);
1336 SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
1337 (WPARAM32)hDrop.h32, 0L );
1339 GlobalUnlock16(hDrop.h16);
1340 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1341 (WPARAM16)hDrop.h16, 0L );
1345 if( p_data ) TSXFree(p_data);
1349 /**********************************************************************
1350 * EVENT_ClientMessage
1352 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1354 if (event->message_type != None && event->format == 32) {
1355 if ((event->message_type == wmProtocols) &&
1356 (((Atom) event->data.l[0]) == wmDeleteWindow))
1357 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1358 else if ( event->message_type == dndProtocol &&
1359 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1360 EVENT_DropFromOffiX(pWnd, event);
1361 else if ( event->message_type == dndProtocol &&
1362 event->data.l[0] == DndURL )
1363 EVENT_DropURLs(pWnd, event);
1366 /* enable this if you want to see the message */
1367 unsigned char* p_data = NULL;
1373 TSXGetWindowProperty( display, DefaultRootWindow(display),
1374 dndSelection, 0, 65535, FALSE,
1375 AnyPropertyType, &u.atom, &u.i,
1376 &u.l, &u.l, &p_data);
1377 TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1378 event->message_type, event->data.l[0], event->data.l[1],
1379 event->data.l[2], event->data.l[3], event->data.l[4],
1382 TRACE(event, "unrecognized ClientMessage\n" );
1387 /**********************************************************************
1390 * Install colormap when Wine window is focused in
1391 * self-managed mode with private colormap
1394 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1396 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1397 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1398 TSXInstallColormap( display, COLOR_GetColormap() );
1402 /**********************************************************************
1405 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1407 HWND32 hwndFocus = GetFocus32();
1409 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1410 FOCUS_SetXFocus( (HWND32)hwndFocus );
1415 /**********************************************************************
1418 * We need this to be able to generate double click messages
1419 * when menu code captures mouse in the window without CS_DBLCLK style.
1421 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1423 HWND32 capturePrev = captureWnd;
1432 WND* wndPtr = WIN_FindWndPtr( hwnd );
1435 TRACE(win, "(0x%04x)\n", hwnd );
1441 if( capturePrev && capturePrev != captureWnd )
1443 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1444 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1445 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1450 /**********************************************************************
1451 * EVENT_GetCaptureInfo
1453 INT16 EVENT_GetCaptureInfo()
1458 /**********************************************************************
1459 * SetCapture16 (USER.18)
1461 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1463 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1467 /**********************************************************************
1468 * SetCapture32 (USER32.464)
1470 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1472 return EVENT_Capture( hwnd, HTCLIENT );
1476 /**********************************************************************
1477 * ReleaseCapture (USER.19) (USER32.439)
1479 void WINAPI ReleaseCapture(void)
1481 TRACE(win, "captureWnd=%04x\n", captureWnd );
1482 if( captureWnd ) EVENT_Capture( 0, 0 );
1486 /**********************************************************************
1487 * GetCapture16 (USER.236)
1489 HWND16 WINAPI GetCapture16(void)
1495 /**********************************************************************
1496 * GetCapture32 (USER32.208)
1498 HWND32 WINAPI GetCapture32(void)
1505 /***********************************************************************
1506 * Mouse driver routines:
1510 typedef struct _MOUSEINFO
1520 WORD msMouseCommPort;
1524 static SEGPTR MouseEventProc = 0;
1526 /***********************************************************************
1527 * MouseInquire (MOUSE.1)
1530 WORD WINAPI MouseInquire(MOUSEINFO *mouseInfo)
1532 mouseInfo->msExist = TRUE;
1533 mouseInfo->msRelative = FALSE;
1534 mouseInfo->msNumButtons = 2;
1535 mouseInfo->msRate = 34; /* the DDK says so ... */
1536 mouseInfo->msXThreshold = 0;
1537 mouseInfo->msYThreshold = 0;
1538 mouseInfo->msXRes = 0;
1539 mouseInfo->msYRes = 0;
1540 mouseInfo->msMouseCommPort = 0;
1542 return sizeof(MOUSEINFO);
1545 /***********************************************************************
1546 * MouseEnable (MOUSE.2)
1548 VOID WINAPI MouseEnable(SEGPTR eventProc)
1550 MouseEventProc = eventProc;
1553 /***********************************************************************
1554 * MouseDisable (MOUSE.3)
1556 VOID WINAPI MouseDisable(VOID)
1561 /***********************************************************************
1562 * EVENT_SendMouseEvent
1564 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY,
1565 WORD buttonCount, DWORD extraInfo )
1569 if ( !MouseEventProc ) return;
1571 TRACE( event, "(%04X,%d,%d,%d,%ld)\n", mouseStatus, deltaX, deltaY, buttonCount, extraInfo );
1573 mouseStatus |= 0x8000;
1574 deltaX = (((long)deltaX << 16) + screenWidth-1) / screenWidth;
1575 deltaY = (((long)deltaY << 16) + screenHeight-1) / screenHeight;
1577 memset( &context, 0, sizeof(context) );
1578 CS_reg(&context) = SELECTOROF( MouseEventProc );
1579 EIP_reg(&context) = OFFSETOF( MouseEventProc );
1580 EAX_reg(&context) = mouseStatus;
1581 EBX_reg(&context) = deltaX;
1582 ECX_reg(&context) = deltaY;
1583 EDX_reg(&context) = buttonCount;
1584 ESI_reg(&context) = LOWORD( extraInfo );
1585 EDI_reg(&context) = HIWORD( extraInfo );
1587 Callbacks->CallRegisterShortProc( &context, 0 );
1593 /***********************************************************************
1594 * GetMouseEventProc (USER.337)
1596 FARPROC16 WINAPI GetMouseEventProc(void)
1598 HMODULE16 hmodule = GetModuleHandle16("USER");
1599 return NE_GetEntryPoint( hmodule, NE_GetOrdinal( hmodule, "Mouse_Event" ));
1603 /***********************************************************************
1604 * Mouse_Event (USER.299)
1606 void WINAPI Mouse_Event( CONTEXT *context )
1610 * BX = horizontal displacement if AX & ME_MOVE
1611 * CX = vertical displacement if AX & ME_MOVE
1612 * DX = button state (?)
1613 * SI = mouse event flags (?)
1616 int rootX, rootY, winX, winY;
1619 if (AX_reg(context) & ME_MOVE)
1621 /* We have to actually move the cursor */
1622 TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1623 (short)BX_reg(context), (short)CX_reg(context) );
1626 if (!TSXQueryPointer( display, rootWindow, &root, &child,
1627 &rootX, &rootY, &winX, &winY, &state )) return;
1628 if (AX_reg(context) & ME_LDOWN)
1629 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1630 0L, winX, winY, GetTickCount(), 0 );
1631 if (AX_reg(context) & ME_LUP)
1632 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1633 0L, winX, winY, GetTickCount(), 0 );
1634 if (AX_reg(context) & ME_RDOWN)
1635 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1636 0L, winX, winY, GetTickCount(), 0 );
1637 if (AX_reg(context) & ME_RUP)
1638 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1639 0L, winX, winY, GetTickCount(), 0 );
1643 /**********************************************************************
1644 * EnableHardwareInput (USER.331)
1646 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1648 BOOL16 bOldState = InputEnabled;
1649 FIXME(event,"(%d) - stub\n", bEnable);
1650 InputEnabled = bEnable;
1655 /***********************************************************************
1656 * SwapMouseButton16 (USER.186)
1658 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1660 BOOL16 ret = SwappedButtons;
1661 SwappedButtons = fSwap;
1666 /***********************************************************************
1667 * SwapMouseButton32 (USER32.537)
1669 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1671 BOOL32 ret = SwappedButtons;
1672 SwappedButtons = fSwap;