4 * Copyright 1993 Alexandre Julliard
9 #ifndef X_DISPLAY_MISSING
11 #include <X11/Xatom.h>
12 #include <X11/keysym.h>
14 #include "ts_xresource.h"
22 #include "clipboard.h"
39 /* X context to associate a hwnd to an X window */
40 extern XContext winContext;
42 extern Atom wmProtocols;
43 extern Atom wmDeleteWindow;
44 extern Atom dndProtocol;
45 extern Atom dndSelection;
47 extern void X11DRV_KEYBOARD_UpdateState(void);
48 extern void X11DRV_KEYBOARD_HandleEvent(WND *pWnd, XKeyEvent *event);
50 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
52 #define DndNotDnd -1 /* OffiX drag&drop */
64 #define DndURL 128 /* KDE drag&drop */
66 /* EVENT_WaitNetEvent() master fd sets */
68 static fd_set __event_io_set[3];
69 static int __event_max_fd = 0;
70 static int __event_x_connection = 0;
71 static int __wakeup_pipe[2];
73 static const char * const event_names[] =
75 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
76 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
77 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
78 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
79 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
80 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
81 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
82 "ClientMessage", "MappingNotify"
85 static void EVENT_ProcessEvent( XEvent *event );
88 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
89 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
90 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
91 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
92 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
93 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
94 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
95 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
96 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
97 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
98 static void EVENT_SelectionNotify( XSelectionEvent *event);
99 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
100 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
101 static void EVENT_MapNotify( HWND hwnd, XMapEvent *event );
103 /* Usable only with OLVWM - compile option perhaps?
104 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
107 static void EVENT_GetGeometry( Window win, int *px, int *py,
108 unsigned int *pwidth, unsigned int *pheight );
111 /***********************************************************************
114 * Initialize network IO.
116 BOOL X11DRV_EVENT_Init(void)
119 for( i = 0; i < 3; i++ )
120 FD_ZERO( __event_io_set + i );
122 __event_max_fd = __event_x_connection = ConnectionNumber(display);
123 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
125 /* this pipe is used to be able to wake-up the scheduler(WaitNetEvent) by
126 a 32 bit thread, this will become obsolete when the input thread will be
130 /* make the pipe non-blocking */
131 fcntl(__wakeup_pipe[0], F_SETFL, O_NONBLOCK);
132 fcntl(__wakeup_pipe[1], F_SETFL, O_NONBLOCK);
134 FD_SET( __wakeup_pipe[0], &__event_io_set[EVENT_IO_READ] );
135 if (__wakeup_pipe[0] > __event_max_fd)
136 __event_max_fd = __wakeup_pipe[0];
142 /***********************************************************************
145 void X11DRV_EVENT_AddIO( int fd, unsigned io_type )
147 FD_SET( fd, &__event_io_set[io_type] );
148 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
151 /***********************************************************************
152 * X11DRV_EVENT_DeleteIO
154 void X11DRV_EVENT_DeleteIO( int fd, unsigned io_type )
156 FD_CLR( fd, &__event_io_set[io_type] );
159 /***********************************************************************
160 * X11DRV_EVENT_IsUserIdle
162 BOOL16 X11DRV_EVENT_IsUserIdle(void)
164 struct timeval timeout = {0, 0};
168 FD_SET(__event_x_connection, &check_set);
169 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
175 /***********************************************************************
176 * EVENT_ReadWakeUpPipe
178 * Empty the wake up pipe
180 void EVENT_ReadWakeUpPipe(void)
185 EnterCriticalSection(&X11DRV_CritSection);
187 /* Flush the wake-up pipe, it's just dummy data for waking-up this
188 thread. This will be obsolete when the input thread will be done */
189 while ( (ret = read(__wakeup_pipe[0], &tmpBuf, 10)) == 10 );
191 LeaveCriticalSection(&X11DRV_CritSection);
194 /***********************************************************************
195 * X11DRV_EVENT_WaitNetEvent
197 * Wait for a network event, optionally sleeping until one arrives.
198 * Returns TRUE if an event is pending that cannot be processed in
199 * 'peek' mode, FALSE otherwise.
202 BOOL X11DRV_EVENT_WaitNetEvent( BOOL sleep, BOOL peek )
205 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
206 int pending = TSXPending(display);
208 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
209 * in this case, we fall through directly to the XNextEvent loop.
212 if ((maxWait != -1) && !pending)
215 struct timeval timeout;
218 memcpy( io_set, __event_io_set, sizeof(io_set) );
220 timeout.tv_usec = (maxWait % 1000) * 1000;
221 timeout.tv_sec = maxWait / 1000;
224 sigsetjmp(env_wait_x, 1);
227 if (DDE_GetRemoteMessage()) {
228 while(DDE_GetRemoteMessage())
232 stop_wait_op = STOP_WAIT_X;
233 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
234 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
235 &io_set[EVENT_IO_WRITE],
236 &io_set[EVENT_IO_EXCEPT], &timeout );
237 if ( num_pending == 0 )
240 TIMER_ExpireTimers();
243 else stop_wait_op = CONT;
244 #else /* CONFIG_IPC */
245 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
246 &io_set[EVENT_IO_WRITE],
247 &io_set[EVENT_IO_EXCEPT], &timeout );
249 if ( num_pending == 0)
251 /* Timeout or error */
252 TIMER_ExpireTimers();
255 #endif /* CONFIG_IPC */
257 /* Flush the wake-up pipe, it's just dummy data for waking-up this
258 thread. This will be obsolete when the input thread will be done */
259 if ( FD_ISSET( __wakeup_pipe[0], &io_set[EVENT_IO_READ] ) )
262 EVENT_ReadWakeUpPipe();
265 /* Winsock asynchronous services */
267 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
271 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
273 else /* no X events */
275 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
280 { /* Wait for X11 input. */
285 FD_SET(__event_x_connection, &set);
287 /* wait on wake-up pipe also */
288 FD_SET(__wakeup_pipe[0], &set);
289 if (__event_x_connection > __wakeup_pipe[0])
290 max_fd = __event_x_connection + 1;
292 max_fd = __wakeup_pipe[0] + 1;
294 select(max_fd, &set, 0, 0, 0 );
296 /* Flush the wake-up pipe, it's just dummy data for waking-up this
297 thread. This will be obsolete when the input thread will be done */
298 if ( FD_ISSET( __wakeup_pipe[0], &set ) )
299 EVENT_ReadWakeUpPipe();
302 /* Process current X event (and possibly others that occurred in the meantime) */
304 EnterCriticalSection(&X11DRV_CritSection);
305 while (XPending( display ))
309 if (DDE_GetRemoteMessage())
311 LeaveCriticalSection(&X11DRV_CritSection);
312 while(DDE_GetRemoteMessage()) ;
315 #endif /* CONFIG_IPC */
317 XNextEvent( display, &event );
321 /* Check only for those events which can be processed
324 if( event.type == MotionNotify ||
325 event.type == ButtonPress || event.type == ButtonRelease ||
326 event.type == KeyPress || event.type == KeyRelease ||
327 event.type == SelectionRequest || event.type == SelectionClear ||
328 event.type == ClientMessage )
330 LeaveCriticalSection(&X11DRV_CritSection);
331 EVENT_ProcessEvent( &event );
332 EnterCriticalSection(&X11DRV_CritSection);
336 if ( event.type == NoExpose )
339 XPutBackEvent(display, &event);
340 LeaveCriticalSection(&X11DRV_CritSection);
345 LeaveCriticalSection(&X11DRV_CritSection);
346 EVENT_ProcessEvent( &event );
347 EnterCriticalSection(&X11DRV_CritSection);
350 LeaveCriticalSection(&X11DRV_CritSection);
355 /***********************************************************************
358 * Synchronize with the X server. Should not be used too often.
360 void X11DRV_EVENT_Synchronize()
364 /* Use of the X critical section is needed or we have a small
365 * race between XPending() and XNextEvent().
367 EnterCriticalSection( &X11DRV_CritSection );
368 XSync( display, False );
369 while (XPending( display ))
371 XNextEvent( display, &event );
372 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
373 LeaveCriticalSection( &X11DRV_CritSection );
374 EVENT_ProcessEvent( &event );
375 EnterCriticalSection( &X11DRV_CritSection );
377 LeaveCriticalSection( &X11DRV_CritSection );
380 /***********************************************************************
383 * Process an X event.
385 static void EVENT_ProcessEvent( XEvent *event )
389 if ( TSXFindContext( display, event->xany.window, winContext,
390 (char **)&pWnd ) != 0) {
391 if ( event->type == ClientMessage) {
392 /* query window (drag&drop event contains only drag window) */
394 int root_x, root_y, child_x, child_y;
396 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
397 &root_x, &root_y, &child_x, &child_y, &u);
398 if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
401 pWnd = NULL; /* Not for a registered window */
405 TRACE(event, "Got event %s for hwnd %04x\n",
406 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
412 EVENT_Key( pWnd, (XKeyEvent*)event );
416 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
420 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
424 /* Wine between two fast machines across the overloaded campus
425 ethernet gets very boged down in MotionEvents. The following
426 simply finds the last motion event in the queue and drops
427 the rest. On a good link events are servered before they build
428 up so this doesn't take place. On a slow link this may cause
429 problems if the event order is important. I'm not yet seen
430 of any problems. Jon 7/6/96.
432 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
433 MotionNotify, event));
434 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
439 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
444 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
448 EVENT_Expose( pWnd, (XExposeEvent *)event );
452 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
455 case ConfigureNotify:
457 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
460 case SelectionRequest:
462 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
465 case SelectionNotify:
467 EVENT_SelectionNotify( (XSelectionEvent *)event );
472 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
477 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
482 EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
489 /* We get all these because of StructureNotifyMask. */
491 case CirculateNotify:
500 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
504 WARN(event, "Unprocessed event %s for hwnd %04x\n",
505 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
510 /***********************************************************************
513 * Try to synchronize internal z-order with the window manager's.
514 * Probably a futile endeavor.
516 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
518 /* return TRUE if we have at least two managed windows */
520 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
521 if( (*pWndA)->flags & WIN_MANAGED &&
522 (*pWndA)->dwStyle & WS_VISIBLE ) break;
524 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
525 if( (*pWndB)->flags & WIN_MANAGED &&
526 (*pWndB)->dwStyle & WS_VISIBLE ) break;
527 return ((*pWndB) != NULL);
530 static Window __get_common_ancestor( Window A, Window B,
531 Window** children, unsigned* total )
533 /* find the real root window */
535 Window root, *childrenB;
540 if( *children ) TSXFree( *children );
541 TSXQueryTree( display, A, &root, &A, children, total );
542 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
543 if( childrenB ) TSXFree( childrenB );
544 } while( A != B && A && B );
545 return ( A && B ) ? A : 0 ;
548 static Window __get_top_decoration( Window w, Window ancestor )
550 Window* children, root, prev = w, parent = w;
556 TSXQueryTree( display, w, &root, &parent, &children, &total );
557 if( children ) TSXFree( children );
558 } while( parent && parent != ancestor );
559 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
560 return ( parent ) ? w : 0 ;
563 static unsigned __td_lookup( Window w, Window* list, unsigned max )
566 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
570 static BOOL EVENT_QueryZOrder( WND* pWndCheck )
573 HWND hwndInsertAfter = HWND_TOP;
574 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
575 Window w, parent, *children = NULL;
576 unsigned total, check, pos, best;
578 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
580 parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ),
581 X11DRV_WND_GetXWindow(pWnd),
583 if( parent && children )
585 w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
586 if( w != children[total - 1] )
588 check = __td_lookup( w, children, total );
590 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
592 if( pWnd != pWndCheck )
594 if( !(pWnd->flags & WIN_MANAGED) ||
595 !(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
597 pos = __td_lookup( w, children, total );
598 if( pos < best && pos > check )
601 hwndInsertAfter = pWnd->hwndSelf;
603 if( check - best == 1 ) break;
606 WIN_UnlinkWindow( pWndCheck->hwndSelf );
607 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
610 if( children ) TSXFree( children );
615 /***********************************************************************
616 * EVENT_XStateToKeyState
618 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
619 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
621 static WORD EVENT_XStateToKeyState( int state )
625 if (state & Button1Mask) kstate |= MK_LBUTTON;
626 if (state & Button2Mask) kstate |= MK_MBUTTON;
627 if (state & Button3Mask) kstate |= MK_RBUTTON;
628 if (state & ShiftMask) kstate |= MK_SHIFT;
629 if (state & ControlMask) kstate |= MK_CONTROL;
633 /***********************************************************************
634 * X11DRV_EVENT_QueryPointer
636 BOOL X11DRV_EVENT_QueryPointer(DWORD *posX, DWORD *posY, DWORD *state)
639 int rootX, rootY, winX, winY;
642 if (!TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
643 &rootX, &rootY, &winX, &winY, &xstate ))
651 *state = EVENT_XStateToKeyState( xstate );
656 /***********************************************************************
659 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
663 /* Make position relative to client area instead of window */
664 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
665 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
666 rect.right = rect.left + event->width;
667 rect.bottom = rect.top + event->height;
669 Callout.RedrawWindow( pWnd? pWnd->hwndSelf : 0, &rect, 0,
670 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
671 (event->count ? 0 : RDW_ERASENOW) );
675 /***********************************************************************
676 * EVENT_GraphicsExpose
678 * This is needed when scrolling area is partially obscured
679 * by non-Wine X window.
681 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
685 /* Make position relative to client area instead of window */
686 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
687 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
688 rect.right = rect.left + event->width;
689 rect.bottom = rect.top + event->height;
691 Callout.RedrawWindow( pWnd? pWnd->hwndSelf : 0, &rect, 0,
692 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
693 (event->count ? 0 : RDW_ERASENOW) );
697 /***********************************************************************
700 * Handle a X key event
702 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
704 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
708 /***********************************************************************
711 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
713 int xOffset = pWnd? pWnd->rectWindow.left : 0;
714 int yOffset = pWnd? pWnd->rectWindow.top : 0;
716 MOUSE_SendEvent( MOUSEEVENTF_MOVE,
717 xOffset + event->x, yOffset + event->y,
718 EVENT_XStateToKeyState( event->state ),
719 event->time - MSG_WineStartTicks,
720 pWnd? pWnd->hwndSelf : 0 );
724 /***********************************************************************
725 * X11DRV_EVENT_DummyMotionNotify
727 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
729 void X11DRV_EVENT_DummyMotionNotify(void)
731 DWORD winX, winY, state;
733 if ( EVENT_QueryPointer( &winX, &winY, &state ) )
735 MOUSE_SendEvent( MOUSEEVENTF_MOVE, winX, winY, state,
741 /***********************************************************************
744 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
746 static WORD statusCodes[NB_BUTTONS] =
747 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
748 int buttonNum = event->button - 1;
750 int xOffset = pWnd? pWnd->rectWindow.left : 0;
751 int yOffset = pWnd? pWnd->rectWindow.top : 0;
754 if (buttonNum >= NB_BUTTONS) return;
757 * Get the compatible keystate
759 keystate = EVENT_XStateToKeyState( event->state );
762 * Make sure that the state of the button that was just
768 keystate |= MK_LBUTTON;
771 keystate |= MK_MBUTTON;
774 keystate |= MK_RBUTTON;
778 MOUSE_SendEvent( statusCodes[buttonNum],
779 xOffset + event->x, yOffset + event->y,
781 event->time - MSG_WineStartTicks,
782 pWnd? pWnd->hwndSelf : 0 );
786 /***********************************************************************
787 * EVENT_ButtonRelease
789 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
791 static WORD statusCodes[NB_BUTTONS] =
792 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
793 int buttonNum = event->button - 1;
795 int xOffset = pWnd? pWnd->rectWindow.left : 0;
796 int yOffset = pWnd? pWnd->rectWindow.top : 0;
799 if (buttonNum >= NB_BUTTONS) return;
802 * Get the compatible keystate
804 keystate = 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;
823 MOUSE_SendEvent( statusCodes[buttonNum],
824 xOffset + event->x, yOffset + event->y,
826 event->time - MSG_WineStartTicks,
827 pWnd? pWnd->hwndSelf : 0 );
831 /**********************************************************************
834 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
836 if (Options.managed) EVENT_QueryZOrder( pWnd );
838 if (event->detail != NotifyPointer)
840 HWND hwnd = pWnd->hwndSelf;
842 if (hwnd != GetActiveWindow())
844 WINPOS_ChangeActiveWindow( hwnd, FALSE );
845 X11DRV_KEYBOARD_UpdateState();
847 if ((hwnd != GetFocus()) && !IsChild( hwnd, GetFocus()))
853 /**********************************************************************
856 * Note: only top-level override-redirect windows get FocusOut events.
858 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
860 if (event->detail != NotifyPointer)
862 HWND hwnd = pWnd->hwndSelf;
864 if (hwnd == GetActiveWindow())
865 WINPOS_ChangeActiveWindow( 0, FALSE );
866 if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus()))
871 /**********************************************************************
872 * X11DRV_EVENT_CheckFocus
874 BOOL X11DRV_EVENT_CheckFocus(void)
880 TSXGetInputFocus(display, &xW, &state);
882 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
887 /**********************************************************************
890 * Helper function for ConfigureNotify handling.
891 * Get the new geometry of a window relative to the root window.
893 static void EVENT_GetGeometry( Window win, int *px, int *py,
894 unsigned int *pwidth, unsigned int *pheight )
896 Window root, parent, *children;
898 unsigned int width, height, border, depth, nb_children;
900 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
901 &border, &depth )) return;
902 if (win == X11DRV_GetXRootWindow())
910 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
913 if (parent == X11DRV_GetXRootWindow()) break;
915 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
916 &width, &height, &border, &depth )) return;
923 /**********************************************************************
924 * EVENT_ConfigureNotify
926 * The ConfigureNotify event is only selected on top-level windows
927 * when the -managed flag is used.
929 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
932 RECT newWindowRect, newClientRect;
933 HRGN hrgnOldPos, hrgnNewPos;
934 Window above = event->above;
936 unsigned int width, height;
938 assert (pWnd->flags & WIN_MANAGED);
940 /* We don't rely on the event geometry info, because it is relative
941 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
942 * if the window hasn't moved).
944 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
946 /* Fill WINDOWPOS struct */
947 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
948 winpos.hwnd = pWnd->hwndSelf;
954 /* Check for unchanged attributes */
955 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
956 winpos.flags |= SWP_NOMOVE;
957 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
958 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
959 winpos.flags |= SWP_NOSIZE;
962 RECT rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
963 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
964 DCE_InvalidateDCE( pWnd, &rect );
967 /* Send WM_WINDOWPOSCHANGING */
968 SendMessageA( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
970 /* Calculate new position and size */
971 newWindowRect.left = x;
972 newWindowRect.right = x + width;
973 newWindowRect.top = y;
974 newWindowRect.bottom = y + height;
976 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
977 &pWnd->rectWindow, &pWnd->rectClient,
978 &winpos, &newClientRect );
980 hrgnOldPos = CreateRectRgnIndirect( &pWnd->rectWindow );
981 hrgnNewPos = CreateRectRgnIndirect( &newWindowRect );
982 CombineRgn( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
983 DeleteObject(hrgnOldPos);
984 DeleteObject(hrgnNewPos);
986 /* Set new size and position */
987 pWnd->rectWindow = newWindowRect;
988 pWnd->rectClient = newClientRect;
989 SendMessageA( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
991 if (!IsWindow( winpos.hwnd )) return;
992 if( above == None ) /* absolute bottom */
994 WIN_UnlinkWindow( winpos.hwnd );
995 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
997 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
1001 /***********************************************************************
1002 * EVENT_SelectionRequest
1004 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
1006 XSelectionEvent result;
1008 Window request = event->requestor;
1010 if(event->target == XA_STRING)
1016 rprop = event->property;
1018 if(rprop == None) rprop = event->target;
1020 if(event->selection!=XA_PRIMARY) rprop = None;
1021 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
1024 /* open to make sure that clipboard is available */
1026 BOOL couldOpen = OpenClipboard( pWnd->hwndSelf );
1029 hText = GetClipboardData16(CF_TEXT);
1030 text = GlobalLock16(hText);
1031 size = GlobalSize16(hText);
1033 /* remove carriage returns */
1035 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
1036 for(i=0,j=0; i < size && text[i]; i++ )
1038 if( text[i] == '\r' &&
1039 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1040 lpstr[j++] = text[i];
1044 TSXChangeProperty(display, request, rprop,
1045 XA_STRING, 8, PropModeReplace,
1047 HeapFree( GetProcessHeap(), 0, lpstr );
1049 /* close only if we opened before */
1051 if(couldOpen) CloseClipboard();
1056 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
1058 result.type = SelectionNotify;
1059 result.display = display;
1060 result.requestor = request;
1061 result.selection = event->selection;
1062 result.property = rprop;
1063 result.target = event->target;
1064 result.time = event->time;
1065 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1069 /***********************************************************************
1070 * EVENT_SelectionNotify
1072 static void EVENT_SelectionNotify( XSelectionEvent *event )
1074 if (event->selection != XA_PRIMARY) return;
1076 if (event->target != XA_STRING) X11DRV_CLIPBOARD_ReadSelection( 0, None );
1077 else X11DRV_CLIPBOARD_ReadSelection( event->requestor, event->property );
1079 TRACE(clipboard,"\tSelectionNotify done!\n");
1083 /***********************************************************************
1084 * EVENT_SelectionClear
1086 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1088 if (event->selection != XA_PRIMARY) return;
1089 X11DRV_CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1093 /**********************************************************************
1094 * EVENT_DropFromOffix
1096 * don't know if it still works (last Changlog is from 96/11/04)
1098 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1100 unsigned long data_length;
1101 unsigned long aux_long;
1102 unsigned char* p_data = NULL;
1110 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1111 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1112 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1113 Window w_aux_root, w_aux_child;
1116 if( !lpDragInfo || !spDragInfo ) return;
1118 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
1119 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1120 (unsigned int*)&aux_long);
1122 lpDragInfo->hScope = pWnd->hwndSelf;
1123 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1125 /* find out drop point and drop window */
1126 if( x < 0 || y < 0 ||
1127 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1128 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1129 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1132 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1133 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1135 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1136 GlobalFree16( hDragInfo );
1140 TSXGetWindowProperty( display, DefaultRootWindow(display),
1141 dndSelection, 0, 65535, FALSE,
1142 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1143 &data_length, &aux_long, &p_data);
1145 if( !aux_long && p_data) /* don't bother if > 64K */
1147 char *p = (char*) p_data;
1151 while( *p ) /* calculate buffer size */
1154 if((u.i = *p) != -1 )
1155 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1156 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1159 INT len = GetShortPathNameA( p, NULL, 0 );
1160 if (len) aux_long += len + 1;
1165 if( aux_long && aux_long < 65535 )
1168 LPDROPFILESTRUCT16 lpDrop;
1170 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1171 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1172 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1176 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1177 lpDrop->ptMousePos.x = (INT16)x;
1178 lpDrop->ptMousePos.y = (INT16)y;
1179 lpDrop->fInNonClientArea = (BOOL16)
1180 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1181 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1182 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1183 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1184 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1188 if( *p != -1 ) /* use only "good" entries */
1190 GetShortPathNameA( p, p_drop, 65535 );
1191 p_drop += strlen( p_drop ) + 1;
1196 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1197 (WPARAM16)hDrop, 0L );
1201 if( p_data ) TSXFree(p_data);
1203 } /* WS_EX_ACCEPTFILES */
1206 /**********************************************************************
1209 * drop items are separated by \n
1210 * each item is prefixed by its mime type
1212 * event->data.l[3], event->data.l[4] contains drop x,y position
1214 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1217 unsigned long data_length;
1218 unsigned long aux_long, drop_len = 0;
1219 unsigned char *p_data = NULL; /* property data */
1220 char *p_drop = NULL;
1222 int x, y, drop32 = FALSE ;
1234 drop32 = pWnd->flags & WIN_ISWIN32;
1236 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1239 TSXGetWindowProperty( display, DefaultRootWindow(display),
1240 dndSelection, 0, 65535, FALSE,
1241 AnyPropertyType, &u.atom_aux, &u.i,
1242 &data_length, &aux_long, &p_data);
1244 WARN(event,"property too large, truncated!\n");
1245 TRACE(event,"urls=%s\n", p_data);
1247 if( !aux_long && p_data) { /* don't bother if > 64K */
1248 /* calculate length */
1250 next = strchr(p, '\n');
1253 if (strncmp(p,"file:",5) == 0 ) {
1254 INT len = GetShortPathNameA( p+5, NULL, 0 );
1255 if (len) drop_len += len + 1;
1260 next = strchr(p, '\n');
1266 if( drop_len && drop_len < 65535 ) {
1267 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
1268 &x, &y, &u.i, &u.i, &u.i);
1269 pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1272 LPDROPFILESTRUCT lpDrop;
1273 drop_len += sizeof(DROPFILESTRUCT) + 1;
1274 hDrop.h32 = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
1275 lpDrop = (LPDROPFILESTRUCT) GlobalLock( hDrop.h32 );
1278 lpDrop->lSize = sizeof(DROPFILESTRUCT);
1279 lpDrop->ptMousePos.x = (INT)x;
1280 lpDrop->ptMousePos.y = (INT)y;
1281 lpDrop->fInNonClientArea = (BOOL)
1282 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1283 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1284 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1285 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1286 lpDrop->fWideChar = FALSE;
1287 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1290 LPDROPFILESTRUCT16 lpDrop;
1291 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1292 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1293 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1296 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1297 lpDrop->ptMousePos.x = (INT16)x;
1298 lpDrop->ptMousePos.y = (INT16)y;
1299 lpDrop->fInNonClientArea = (BOOL16)
1300 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1301 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1302 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1303 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1304 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1308 /* create message content */
1311 next = strchr(p, '\n');
1314 if (strncmp(p,"file:",5) == 0 ) {
1315 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1317 TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1320 WARN(event, "can't convert file %s to dos name \n", p+5);
1323 WARN(event, "unknown mime type %s\n", p);
1328 next = strchr(p, '\n');
1336 /* can not use PostMessage32A because it is currently based on
1337 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1339 GlobalUnlock(hDrop.h32);
1340 SendMessageA( pWnd->hwndSelf, WM_DROPFILES,
1341 (WPARAM)hDrop.h32, 0L );
1343 GlobalUnlock16(hDrop.h16);
1344 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1345 (WPARAM16)hDrop.h16, 0L );
1349 if( p_data ) TSXFree(p_data);
1353 /**********************************************************************
1354 * EVENT_ClientMessage
1356 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1358 if (event->message_type != None && event->format == 32) {
1359 if ((event->message_type == wmProtocols) &&
1360 (((Atom) event->data.l[0]) == wmDeleteWindow))
1361 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1362 else if ( event->message_type == dndProtocol &&
1363 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1364 EVENT_DropFromOffiX(pWnd, event);
1365 else if ( event->message_type == dndProtocol &&
1366 event->data.l[0] == DndURL )
1367 EVENT_DropURLs(pWnd, event);
1370 /* enable this if you want to see the message */
1371 unsigned char* p_data = NULL;
1377 TSXGetWindowProperty( display, DefaultRootWindow(display),
1378 dndSelection, 0, 65535, FALSE,
1379 AnyPropertyType, &u.atom, &u.i,
1380 &u.l, &u.l, &p_data);
1381 TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1382 event->message_type, event->data.l[0], event->data.l[1],
1383 event->data.l[2], event->data.l[3], event->data.l[4],
1386 TRACE(event, "unrecognized ClientMessage\n" );
1391 /**********************************************************************
1394 * Install colormap when Wine window is focused in
1395 * self-managed mode with private colormap
1398 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1400 if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1401 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1402 TSXInstallColormap( display, X11DRV_COLOR_GetColormap() );
1406 /**********************************************************************
1409 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1411 HWND hwndFocus = GetFocus();
1413 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1414 X11DRV_WND_SetFocus( WIN_FindWndPtr( hwndFocus ) );
1419 /**********************************************************************
1420 * X11DRV_EVENT_Pending
1422 BOOL X11DRV_EVENT_Pending()
1424 return TSXPending(display);
1427 /**********************************************************************
1428 * X11DRV_EVENT_WakeUp
1430 void X11DRV_EVENT_WakeUp(void)
1432 /* wake-up EVENT_WaitNetEvent function, a 32 bit thread post an event
1433 for a 16 bit task */
1434 if (write (__wakeup_pipe[1], "A", 1) != 1)
1435 ERR(event, "unable to write in wakeup_pipe\n");
1439 #endif /* !defined(X_DISPLAY_MISSING) */