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"
46 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
48 #define DndNotDnd -1 /* OffiX drag&drop */
60 #define DndURL 128 /* KDE drag&drop */
63 /* X context to associate a hwnd to an X window */
64 static XContext winContext = 0;
66 static Atom wmProtocols = None;
67 static Atom wmDeleteWindow = None;
68 static Atom dndProtocol = None;
69 static Atom dndSelection = None;
71 /* EVENT_WaitNetEvent() master fd sets */
73 static fd_set __event_io_set[3];
74 static int __event_max_fd = 0;
75 static int __event_x_connection = 0;
77 static const char * const event_names[] =
79 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
80 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
81 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
82 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
83 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
84 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
85 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
86 "ClientMessage", "MappingNotify"
90 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
91 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
92 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
93 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
94 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
95 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
96 static int EVENT_Expose( WND *pWnd, XExposeEvent *event );
97 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
98 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
99 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
100 static void EVENT_SelectionNotify( XSelectionEvent *event);
101 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
102 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
103 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
105 /* Usable only with OLVWM - compile option perhaps?
106 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
109 static void EVENT_GetGeometry( Window win, int *px, int *py,
110 unsigned int *pwidth, unsigned int *pheight );
112 /***********************************************************************
115 * Initialize network IO.
117 BOOL32 EVENT_Init(void)
120 for( i = 0; i < 3; i++ )
121 FD_ZERO( __event_io_set + i );
123 __event_max_fd = __event_x_connection = ConnectionNumber(display);
124 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
129 /***********************************************************************
132 void EVENT_AddIO( int fd, unsigned io_type )
134 FD_SET( fd, &__event_io_set[io_type] );
135 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
138 void EVENT_DeleteIO( int fd, unsigned io_type )
140 FD_CLR( fd, &__event_io_set[io_type] );
143 /***********************************************************************
146 * Process an X event.
148 void EVENT_ProcessEvent( XEvent *event )
152 if ( TSXFindContext( display, event->xany.window, winContext,
153 (char **)&pWnd ) != 0) {
154 if ( event->type == ClientMessage) {
155 /* query window (drag&drop event contains only drag window) */
157 int root_x, root_y, child_x, child_y;
159 TSXQueryPointer( display, rootWindow, &root, &child,
160 &root_x, &root_y, &child_x, &child_y, &u);
161 if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
164 pWnd = NULL; /* Not for a registered window */
168 TRACE(event, "Got event %s for hwnd %04x\n",
169 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
175 EVENT_Key( pWnd, (XKeyEvent*)event );
179 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
183 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
187 /* Wine between two fast machines across the overloaded campus
188 ethernet gets very boged down in MotionEvents. The following
189 simply finds the last motion event in the queue and drops
190 the rest. On a good link events are servered before they build
191 up so this doesn't take place. On a slow link this may cause
192 problems if the event order is important. I'm not yet seen
193 of any problems. Jon 7/6/96.
195 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
196 MotionNotify, event));
197 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
202 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
207 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
212 if (EVENT_Expose( pWnd, (XExposeEvent *)event )) {
213 /* need to process ConfigureNotify first */
216 /* attempt to find and process the ConfigureNotify event now */
217 if (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
218 ConfigureNotify, &new_event)) {
219 EVENT_ProcessEvent( &new_event );
220 if (!EVENT_Expose( pWnd, (XExposeEvent *)event ))
224 /* no luck at this time, defer Expose event for later */
225 /* use "type" for an event counter, it is never rechecked */
226 if (!pWnd->expose_event) {
227 pWnd->expose_event = malloc( sizeof(XExposeEvent) );
228 pWnd->expose_event[0] = *(XExposeEvent *)event;
229 pWnd->expose_event[0].type = 1;
233 i = ++pWnd->expose_event[0].type;
234 pWnd->expose_event = realloc( pWnd->expose_event,
235 i * sizeof(XExposeEvent) );
236 pWnd->expose_event[i-1] = *(XExposeEvent *)event;
237 FIXME(x11, "Try and combine Expose events? %d queued.\n", i);
244 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
247 case ConfigureNotify:
249 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
250 if (pWnd->expose_event) {
251 /* process deferred Expose event(s) */
254 for (i=0; i<pWnd->expose_event[0].type; i++) {
255 if(EVENT_Expose( pWnd, &pWnd->expose_event[i] ))
256 ERR(x11, "Unprocessed expose event discarded\n");
258 free( pWnd->expose_event );
259 pWnd->expose_event = NULL;
263 case SelectionRequest:
265 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
268 case SelectionNotify:
270 EVENT_SelectionNotify( (XSelectionEvent *)event );
275 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
280 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
284 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
290 /* We get all these because of StructureNotifyMask. */
292 case CirculateNotify:
301 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
305 WARN(event, "Unprocessed event %s for hwnd %04x\n",
306 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
312 /***********************************************************************
313 * EVENT_RegisterWindow
315 * Associate an X window to a HWND.
317 void EVENT_RegisterWindow( WND *pWnd )
319 if (wmProtocols == None)
320 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
321 if (wmDeleteWindow == None)
322 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
323 if( dndProtocol == None )
324 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
325 if( dndSelection == None )
326 dndSelection = TSXInternAtom( display, "DndSelection" , False );
328 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
330 if (!winContext) winContext = TSXUniqueContext();
331 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
334 /***********************************************************************
335 * EVENT_DestroyWindow
337 void EVENT_DestroyWindow( WND *pWnd )
341 if (pWnd->expose_event) {
342 free( pWnd->expose_event );
343 pWnd->expose_event = NULL;
345 TSXDeleteContext( display, pWnd->window, winContext );
346 TSXDestroyWindow( display, pWnd->window );
347 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
351 /***********************************************************************
352 * IsUserIdle (USER.333)
354 * Check if we have pending X events.
356 BOOL16 WINAPI IsUserIdle(void)
358 struct timeval timeout = {0, 0};
362 FD_SET(__event_x_connection, &check_set);
363 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
369 /***********************************************************************
372 * Wait for a network event, optionally sleeping until one arrives.
373 * Return TRUE if an event is pending, FALSE on timeout or error
374 * (for instance lost connection with the server).
376 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
379 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
380 int pending = TSXPending(display);
382 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
383 * in this case, we fall through directly to the XNextEvent loop.
386 if ((maxWait != -1) && !pending)
389 struct timeval timeout;
392 memcpy( io_set, __event_io_set, sizeof(io_set) );
394 timeout.tv_usec = (maxWait % 1000) * 1000;
395 timeout.tv_sec = maxWait / 1000;
398 sigsetjmp(env_wait_x, 1);
401 if (DDE_GetRemoteMessage()) {
402 while(DDE_GetRemoteMessage())
406 stop_wait_op = STOP_WAIT_X;
407 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
408 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
409 &io_set[EVENT_IO_WRITE],
410 &io_set[EVENT_IO_EXCEPT], &timeout );
411 if ( num_pending == 0 )
414 TIMER_ExpireTimers();
417 else stop_wait_op = CONT;
418 #else /* CONFIG_IPC */
419 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
420 &io_set[EVENT_IO_WRITE],
421 &io_set[EVENT_IO_EXCEPT], &timeout );
422 if ( num_pending == 0)
424 /* Timeout or error */
425 TIMER_ExpireTimers();
428 #endif /* CONFIG_IPC */
430 /* Winsock asynchronous services */
432 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
436 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
438 else /* no X events */
439 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
442 { /* Wait for X11 input. */
446 FD_SET(__event_x_connection, &set);
447 select(__event_x_connection + 1, &set, 0, 0, 0 );
450 /* Process current X event (and possibly others that occurred in the meantime) */
452 EnterCriticalSection(&X11DRV_CritSection);
453 while (XPending( display ))
457 if (DDE_GetRemoteMessage())
459 LeaveCriticalSection(&X11DRV_CritSection);
460 while(DDE_GetRemoteMessage()) ;
463 #endif /* CONFIG_IPC */
465 XNextEvent( display, &event );
467 LeaveCriticalSection(&X11DRV_CritSection);
474 /* Check only for those events which can be processed
477 if( event.type == MotionNotify ||
478 event.type == ButtonPress || event.type == ButtonRelease ||
479 event.type == KeyPress || event.type == KeyRelease ||
480 event.type == SelectionRequest || event.type == SelectionClear ||
481 event.type == ClientMessage )
483 EVENT_ProcessEvent( &event );
487 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
488 (char **)&pWnd ) || (event.type == NoExpose))
493 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
495 pQ->flags |= QUEUE_FLAG_XEVENT;
496 PostEvent(pQ->hTask);
497 TSXPutBackEvent(display, &event);
502 else EVENT_ProcessEvent( &event );
503 EnterCriticalSection(&X11DRV_CritSection);
505 LeaveCriticalSection(&X11DRV_CritSection);
510 /***********************************************************************
513 * Synchronize with the X server. Should not be used too often.
515 void EVENT_Synchronize()
519 /* Use of the X critical section is needed or we have a small
520 * race between XPending() and XNextEvent().
522 EnterCriticalSection( &X11DRV_CritSection );
523 XSync( display, False );
524 while (XPending( display ))
526 XNextEvent( display, &event );
527 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
528 LeaveCriticalSection( &X11DRV_CritSection );
529 EVENT_ProcessEvent( &event );
530 EnterCriticalSection( &X11DRV_CritSection );
532 LeaveCriticalSection( &X11DRV_CritSection );
535 /***********************************************************************
538 * Try to synchronize internal z-order with the window manager's.
539 * Probably a futile endeavor.
541 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
543 /* return TRUE if we have at least two managed windows */
545 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
546 if( (*pWndA)->flags & WIN_MANAGED &&
547 (*pWndA)->dwStyle & WS_VISIBLE ) break;
549 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
550 if( (*pWndB)->flags & WIN_MANAGED &&
551 (*pWndB)->dwStyle & WS_VISIBLE ) break;
552 return ((*pWndB) != NULL);
555 static Window __get_common_ancestor( Window A, Window B,
556 Window** children, unsigned* total )
558 /* find the real root window */
560 Window root, *childrenB;
565 if( *children ) TSXFree( *children );
566 TSXQueryTree( display, A, &root, &A, children, total );
567 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
568 if( childrenB ) TSXFree( childrenB );
569 } while( A != B && A && B );
570 return ( A && B ) ? A : 0 ;
573 static Window __get_top_decoration( Window w, Window ancestor )
575 Window* children, root, prev = w, parent = w;
581 TSXQueryTree( display, w, &root, &parent, &children, &total );
582 if( children ) TSXFree( children );
583 } while( parent && parent != ancestor );
584 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
585 return ( parent ) ? w : 0 ;
588 static unsigned __td_lookup( Window w, Window* list, unsigned max )
591 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
595 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
598 HWND32 hwndInsertAfter = HWND_TOP;
599 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
600 Window w, parent, *children = NULL;
601 unsigned total, check, pos, best;
603 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
605 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
607 if( parent && children )
609 w = __get_top_decoration( pWndCheck->window, parent );
610 if( w != children[total - 1] )
612 check = __td_lookup( w, children, total );
614 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
616 if( pWnd != pWndCheck )
618 if( !(pWnd->flags & WIN_MANAGED) ||
619 !(w = __get_top_decoration( pWnd->window, parent )) )
621 pos = __td_lookup( w, children, total );
622 if( pos < best && pos > check )
625 hwndInsertAfter = pWnd->hwndSelf;
627 if( check - best == 1 ) break;
630 WIN_UnlinkWindow( pWndCheck->hwndSelf );
631 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
634 if( children ) TSXFree( children );
639 /***********************************************************************
640 * EVENT_XStateToKeyState
642 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
643 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
645 static WORD EVENT_XStateToKeyState( int state )
649 if (state & Button1Mask) kstate |= MK_LBUTTON;
650 if (state & Button2Mask) kstate |= MK_MBUTTON;
651 if (state & Button3Mask) kstate |= MK_RBUTTON;
652 if (state & ShiftMask) kstate |= MK_SHIFT;
653 if (state & ControlMask) kstate |= MK_CONTROL;
657 /***********************************************************************
660 BOOL32 EVENT_QueryPointer( DWORD *posX, DWORD *posY, DWORD *state )
663 int rootX, rootY, winX, winY;
666 if (!TSXQueryPointer( display, rootWindow, &root, &child,
667 &rootX, &rootY, &winX, &winY, &xstate ))
672 *state = EVENT_XStateToKeyState( xstate );
677 /***********************************************************************
680 static int EVENT_Expose( WND *pWnd, XExposeEvent *event )
684 unsigned int width, height;
686 /* When scrolling, many (fvwm2-based) window managers send the Expose
687 * event before sending the ConfigureNotify event, and we don't like
688 * that, so before processing the Expose event, we check whether the
689 * geometry has changed, and if so, we defer the Expose event until
690 * we get the ConfigureNotify event. -Ove KÃ¥ven */
691 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
693 if ( x != pWnd->rectWindow.left || y != pWnd->rectWindow.top ||
694 (width != pWnd->rectWindow.right - pWnd->rectWindow.left) ||
695 (height != pWnd->rectWindow.bottom - pWnd->rectWindow.top))
696 return 1; /* tell EVENT_ProcessEvent() to defer it */
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_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
706 (event->count ? 0 : RDW_ERASENOW), 0 );
711 /***********************************************************************
712 * EVENT_GraphicsExpose
714 * This is needed when scrolling area is partially obscured
715 * by non-Wine X window.
717 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
721 /* Make position relative to client area instead of window */
722 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
723 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
724 rect.right = rect.left + event->width;
725 rect.bottom = rect.top + event->height;
727 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
728 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
729 (event->count ? 0 : RDW_ERASENOW), 0 );
733 /***********************************************************************
736 * Handle a X key event
738 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
740 KEYBOARD_HandleEvent( pWnd, event );
744 /***********************************************************************
747 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
749 int xOffset = pWnd? pWnd->rectWindow.left : 0;
750 int yOffset = pWnd? pWnd->rectWindow.top : 0;
752 MOUSE_SendEvent( MOUSEEVENTF_MOVE,
753 xOffset + event->x, yOffset + event->y,
754 EVENT_XStateToKeyState( event->state ),
755 event->time - MSG_WineStartTicks,
756 pWnd? pWnd->hwndSelf : 0 );
760 /***********************************************************************
761 * EVENT_DummyMotionNotify
763 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
765 void EVENT_DummyMotionNotify(void)
767 DWORD winX, winY, state;
769 if ( EVENT_QueryPointer( &winX, &winY, &state ) )
771 MOUSE_SendEvent( MOUSEEVENTF_MOVE, winX, winY, state,
777 /***********************************************************************
780 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
782 static WORD statusCodes[NB_BUTTONS] =
783 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
784 int buttonNum = event->button - 1;
786 int xOffset = pWnd? pWnd->rectWindow.left : 0;
787 int yOffset = pWnd? pWnd->rectWindow.top : 0;
789 if (buttonNum >= NB_BUTTONS) return;
791 MOUSE_SendEvent( statusCodes[buttonNum],
792 xOffset + event->x, yOffset + event->y,
793 EVENT_XStateToKeyState( event->state ),
794 event->time - MSG_WineStartTicks,
795 pWnd? pWnd->hwndSelf : 0 );
799 /***********************************************************************
800 * EVENT_ButtonRelease
802 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
804 static WORD statusCodes[NB_BUTTONS] =
805 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
806 int buttonNum = event->button - 1;
808 int xOffset = pWnd? pWnd->rectWindow.left : 0;
809 int yOffset = pWnd? pWnd->rectWindow.top : 0;
811 if (buttonNum >= NB_BUTTONS) return;
813 MOUSE_SendEvent( statusCodes[buttonNum],
814 xOffset + event->x, yOffset + event->y,
815 EVENT_XStateToKeyState( event->state ),
816 event->time - MSG_WineStartTicks,
817 pWnd? pWnd->hwndSelf : 0 );
821 /**********************************************************************
824 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
826 if (Options.managed) EVENT_QueryZOrder( pWnd );
828 if (event->detail != NotifyPointer)
830 HWND32 hwnd = pWnd->hwndSelf;
832 if (hwnd != GetActiveWindow32())
834 WINPOS_ChangeActiveWindow( hwnd, FALSE );
835 KEYBOARD_UpdateState();
837 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
843 /**********************************************************************
846 * Note: only top-level override-redirect windows get FocusOut events.
848 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
850 if (event->detail != NotifyPointer)
852 HWND32 hwnd = pWnd->hwndSelf;
854 if (hwnd == GetActiveWindow32())
855 WINPOS_ChangeActiveWindow( 0, FALSE );
856 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
861 /**********************************************************************
864 BOOL32 EVENT_CheckFocus(void)
870 TSXGetInputFocus(display, &xW, &state);
872 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
878 /**********************************************************************
881 * Helper function for ConfigureNotify handling.
882 * Get the new geometry of a window relative to the root window.
884 static void EVENT_GetGeometry( Window win, int *px, int *py,
885 unsigned int *pwidth, unsigned int *pheight )
887 Window root, parent, *children;
889 unsigned int width, height, border, depth, nb_children;
891 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
892 &border, &depth )) return;
893 if (win == rootWindow)
901 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
904 if (parent == rootWindow) break;
906 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
907 &width, &height, &border, &depth )) return;
914 /**********************************************************************
915 * EVENT_ConfigureNotify
917 * The ConfigureNotify event is only selected on top-level windows
918 * when the -managed flag is used.
920 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
923 RECT32 newWindowRect, newClientRect;
924 HRGN32 hrgnOldPos, hrgnNewPos;
925 Window above = event->above;
927 unsigned int width, height;
929 assert (pWnd->flags & WIN_MANAGED);
931 /* We don't rely on the event geometry info, because it is relative
932 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
933 * if the window hasn't moved).
935 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
937 /* Fill WINDOWPOS struct */
938 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
939 winpos.hwnd = pWnd->hwndSelf;
945 /* Check for unchanged attributes */
946 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
947 winpos.flags |= SWP_NOMOVE;
948 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
949 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
950 winpos.flags |= SWP_NOSIZE;
953 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
954 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
955 DCE_InvalidateDCE( pWnd, &rect );
958 /* Send WM_WINDOWPOSCHANGING */
959 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
961 /* Calculate new position and size */
962 newWindowRect.left = x;
963 newWindowRect.right = x + width;
964 newWindowRect.top = y;
965 newWindowRect.bottom = y + height;
967 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
968 &pWnd->rectWindow, &pWnd->rectClient,
969 &winpos, &newClientRect );
971 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
972 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
973 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
974 DeleteObject32(hrgnOldPos);
975 DeleteObject32(hrgnNewPos);
977 /* Set new size and position */
978 pWnd->rectWindow = newWindowRect;
979 pWnd->rectClient = newClientRect;
980 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
982 if (!IsWindow32( winpos.hwnd )) return;
983 if( above == None ) /* absolute bottom */
985 WIN_UnlinkWindow( winpos.hwnd );
986 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
988 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
992 /***********************************************************************
993 * EVENT_SelectionRequest
995 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
997 XSelectionEvent result;
999 Window request = event->requestor;
1001 if(event->target == XA_STRING)
1007 rprop = event->property;
1009 if(rprop == None) rprop = event->target;
1011 if(event->selection!=XA_PRIMARY) rprop = None;
1012 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
1015 /* open to make sure that clipboard is available */
1017 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
1020 hText = GetClipboardData16(CF_TEXT);
1021 text = GlobalLock16(hText);
1022 size = GlobalSize16(hText);
1024 /* remove carriage returns */
1026 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
1027 for(i=0,j=0; i < size && text[i]; i++ )
1029 if( text[i] == '\r' &&
1030 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1031 lpstr[j++] = text[i];
1035 TSXChangeProperty(display, request, rprop,
1036 XA_STRING, 8, PropModeReplace,
1038 HeapFree( GetProcessHeap(), 0, lpstr );
1040 /* close only if we opened before */
1042 if(couldOpen) CloseClipboard32();
1047 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
1049 result.type = SelectionNotify;
1050 result.display = display;
1051 result.requestor = request;
1052 result.selection = event->selection;
1053 result.property = rprop;
1054 result.target = event->target;
1055 result.time = event->time;
1056 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1060 /***********************************************************************
1061 * EVENT_SelectionNotify
1063 static void EVENT_SelectionNotify( XSelectionEvent *event )
1065 if (event->selection != XA_PRIMARY) return;
1067 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
1068 else CLIPBOARD_ReadSelection( event->requestor, event->property );
1070 TRACE(clipboard,"\tSelectionNotify done!\n");
1074 /***********************************************************************
1075 * EVENT_SelectionClear
1077 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1079 if (event->selection != XA_PRIMARY) return;
1080 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1084 /**********************************************************************
1085 * EVENT_DropFromOffix
1087 * don't know if it still works (last Changlog is from 96/11/04)
1089 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1091 unsigned long data_length;
1092 unsigned long aux_long;
1093 unsigned char* p_data = NULL;
1101 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1102 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1103 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1104 Window w_aux_root, w_aux_child;
1107 if( !lpDragInfo || !spDragInfo ) return;
1109 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1110 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1112 lpDragInfo->hScope = pWnd->hwndSelf;
1113 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1115 /* find out drop point and drop window */
1116 if( x < 0 || y < 0 ||
1117 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1118 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1119 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1122 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1123 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1125 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1126 GlobalFree16( hDragInfo );
1130 TSXGetWindowProperty( display, DefaultRootWindow(display),
1131 dndSelection, 0, 65535, FALSE,
1132 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1133 &data_length, &aux_long, &p_data);
1135 if( !aux_long && p_data) /* don't bother if > 64K */
1137 char *p = (char*) p_data;
1141 while( *p ) /* calculate buffer size */
1144 if((u.i = *p) != -1 )
1145 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1146 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1149 INT32 len = GetShortPathName32A( p, NULL, 0 );
1150 if (len) aux_long += len + 1;
1155 if( aux_long && aux_long < 65535 )
1158 LPDROPFILESTRUCT16 lpDrop;
1160 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1161 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1162 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1166 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1167 lpDrop->ptMousePos.x = (INT16)x;
1168 lpDrop->ptMousePos.y = (INT16)y;
1169 lpDrop->fInNonClientArea = (BOOL16)
1170 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1171 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1172 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1173 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1174 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1178 if( *p != -1 ) /* use only "good" entries */
1180 GetShortPathName32A( p, p_drop, 65535 );
1181 p_drop += strlen( p_drop ) + 1;
1186 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1187 (WPARAM16)hDrop, 0L );
1191 if( p_data ) TSXFree(p_data);
1193 } /* WS_EX_ACCEPTFILES */
1196 /**********************************************************************
1199 * drop items are separated by \n
1200 * each item is prefixed by its mime type
1202 * event->data.l[3], event->data.l[4] contains drop x,y position
1204 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1207 unsigned long data_length;
1208 unsigned long aux_long, drop_len = 0;
1209 unsigned char *p_data = NULL; /* property data */
1210 char *p_drop = NULL;
1212 int x, y, drop32 = FALSE ;
1224 drop32 = pWnd->flags & WIN_ISWIN32;
1226 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1229 TSXGetWindowProperty( display, DefaultRootWindow(display),
1230 dndSelection, 0, 65535, FALSE,
1231 AnyPropertyType, &u.atom_aux, &u.i,
1232 &data_length, &aux_long, &p_data);
1234 WARN(event,"property too large, truncated!\n");
1235 TRACE(event,"urls=%s\n", p_data);
1237 if( !aux_long && p_data) { /* don't bother if > 64K */
1238 /* calculate length */
1240 next = strchr(p, '\n');
1243 if (strncmp(p,"file:",5) == 0 ) {
1244 INT32 len = GetShortPathName32A( p+5, NULL, 0 );
1245 if (len) drop_len += len + 1;
1250 next = strchr(p, '\n');
1256 if( drop_len && drop_len < 65535 ) {
1257 TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux,
1258 &x, &y, &u.i, &u.i, &u.i);
1259 pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1262 LPDROPFILESTRUCT32 lpDrop;
1263 drop_len += sizeof(DROPFILESTRUCT32) + 1;
1264 hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
1265 lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
1268 lpDrop->lSize = sizeof(DROPFILESTRUCT32);
1269 lpDrop->ptMousePos.x = (INT32)x;
1270 lpDrop->ptMousePos.y = (INT32)y;
1271 lpDrop->fInNonClientArea = (BOOL32)
1272 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1273 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1274 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1275 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1276 lpDrop->fWideChar = FALSE;
1277 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
1280 LPDROPFILESTRUCT16 lpDrop;
1281 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1282 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1283 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1286 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1287 lpDrop->ptMousePos.x = (INT16)x;
1288 lpDrop->ptMousePos.y = (INT16)y;
1289 lpDrop->fInNonClientArea = (BOOL16)
1290 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1291 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1292 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1293 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1294 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1298 /* create message content */
1301 next = strchr(p, '\n');
1304 if (strncmp(p,"file:",5) == 0 ) {
1305 INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
1307 TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1310 WARN(event, "can't convert file %s to dos name \n", p+5);
1313 WARN(event, "unknown mime type %s\n", p);
1318 next = strchr(p, '\n');
1326 /* can not use PostMessage32A because it is currently based on
1327 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1329 GlobalUnlock32(hDrop.h32);
1330 SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
1331 (WPARAM32)hDrop.h32, 0L );
1333 GlobalUnlock16(hDrop.h16);
1334 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1335 (WPARAM16)hDrop.h16, 0L );
1339 if( p_data ) TSXFree(p_data);
1343 /**********************************************************************
1344 * EVENT_ClientMessage
1346 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1348 if (event->message_type != None && event->format == 32) {
1349 if ((event->message_type == wmProtocols) &&
1350 (((Atom) event->data.l[0]) == wmDeleteWindow))
1351 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1352 else if ( event->message_type == dndProtocol &&
1353 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1354 EVENT_DropFromOffiX(pWnd, event);
1355 else if ( event->message_type == dndProtocol &&
1356 event->data.l[0] == DndURL )
1357 EVENT_DropURLs(pWnd, event);
1360 /* enable this if you want to see the message */
1361 unsigned char* p_data = NULL;
1367 TSXGetWindowProperty( display, DefaultRootWindow(display),
1368 dndSelection, 0, 65535, FALSE,
1369 AnyPropertyType, &u.atom, &u.i,
1370 &u.l, &u.l, &p_data);
1371 TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1372 event->message_type, event->data.l[0], event->data.l[1],
1373 event->data.l[2], event->data.l[3], event->data.l[4],
1376 TRACE(event, "unrecognized ClientMessage\n" );
1381 /**********************************************************************
1384 * Install colormap when Wine window is focused in
1385 * self-managed mode with private colormap
1388 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1390 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1391 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1392 TSXInstallColormap( display, COLOR_GetColormap() );
1396 /**********************************************************************
1399 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1401 HWND32 hwndFocus = GetFocus32();
1403 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1404 FOCUS_SetXFocus( (HWND32)hwndFocus );