Moved more things to the X11 driver.
[wine/multimedia.git] / windows / x11drv / event.c
blobfc4b0b7f10adcc9cc2389bb0ebb905ca87bb096d
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 */
7 #include "config.h"
9 #ifndef X_DISPLAY_MISSING
11 #include <X11/Xatom.h>
12 #include <X11/keysym.h>
13 #include "ts_xlib.h"
14 #include "ts_xresource.h"
15 #include "ts_xutil.h"
17 #include <assert.h>
18 #include <ctype.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <errno.h>
25 #include "windows.h"
26 #include "winnt.h"
27 #include "gdi.h"
28 #include "heap.h"
29 #include "queue.h"
30 #include "class.h"
31 #include "dce.h"
32 #include "module.h"
33 #include "options.h"
34 #include "winpos.h"
35 #include "drive.h"
36 #include "shell.h"
37 #include "keyboard.h"
38 #include "mouse.h"
39 #include "debug.h"
40 #include "dde_proc.h"
41 #include "winsock.h"
42 #include "mouse.h"
43 #include "x11drv.h"
45 /* X context to associate a hwnd to an X window */
46 extern XContext winContext;
48 extern Atom wmProtocols;
49 extern Atom wmDeleteWindow;
50 extern Atom dndProtocol;
51 extern Atom dndSelection;
53 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
55 #define DndNotDnd -1 /* OffiX drag&drop */
56 #define DndUnknown 0
57 #define DndRawData 1
58 #define DndFile 2
59 #define DndFiles 3
60 #define DndText 4
61 #define DndDir 5
62 #define DndLink 6
63 #define DndExe 7
65 #define DndEND 8
67 #define DndURL 128 /* KDE drag&drop */
69 /* EVENT_WaitNetEvent() master fd sets */
71 static fd_set __event_io_set[3];
72 static int __event_max_fd = 0;
73 static int __event_x_connection = 0;
75 static const char * const event_names[] =
77 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
78 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
79 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
80 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
81 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
82 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
83 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
84 "ClientMessage", "MappingNotify"
87 static void EVENT_ProcessEvent( XEvent *event );
89 /* Event handlers */
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 void 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 );
113 static BOOL32 (WINAPI *EVENT_RedrawWindow)( HWND32 hwnd, const RECT32 *rectUpdate,
114 HRGN32 hrgnUpdate, UINT32 flags ) = NULL;
117 /***********************************************************************
118 * EVENT_Init
120 * Initialize network IO.
122 BOOL32 X11DRV_EVENT_Init(void)
124 int i;
125 for( i = 0; i < 3; i++ )
126 FD_ZERO( __event_io_set + i );
128 __event_max_fd = __event_x_connection = ConnectionNumber(display);
129 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
130 __event_max_fd++;
131 return TRUE;
134 /***********************************************************************
135 * X11DRV_EVENT_AddIO
137 void X11DRV_EVENT_AddIO( int fd, unsigned io_type )
139 FD_SET( fd, &__event_io_set[io_type] );
140 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
143 /***********************************************************************
144 * X11DRV_EVENT_DeleteIO
146 void X11DRV_EVENT_DeleteIO( int fd, unsigned io_type )
148 FD_CLR( fd, &__event_io_set[io_type] );
151 /***********************************************************************
152 * X11DRV_EVENT_IsUserIdle
154 BOOL16 X11DRV_EVENT_IsUserIdle(void)
156 struct timeval timeout = {0, 0};
157 fd_set check_set;
159 FD_ZERO(&check_set);
160 FD_SET(__event_x_connection, &check_set);
161 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
162 return TRUE;
163 return FALSE;
166 /***********************************************************************
167 * X11DRV_EVENT_WaitNetEvent
169 * Wait for a network event, optionally sleeping until one arrives.
170 * Returns TRUE if an event is pending that cannot be processed in
171 * 'peek' mode, FALSE otherwise.
174 BOOL32 X11DRV_EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
176 XEvent event;
177 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
178 int pending = TSXPending(display);
180 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
181 * in this case, we fall through directly to the XNextEvent loop.
184 if ((maxWait != -1) && !pending)
186 int num_pending;
187 struct timeval timeout;
188 fd_set io_set[3];
190 memcpy( io_set, __event_io_set, sizeof(io_set) );
192 timeout.tv_usec = (maxWait % 1000) * 1000;
193 timeout.tv_sec = maxWait / 1000;
195 #ifdef CONFIG_IPC
196 sigsetjmp(env_wait_x, 1);
197 stop_wait_op= CONT;
199 if (DDE_GetRemoteMessage()) {
200 while(DDE_GetRemoteMessage())
202 return FALSE;
204 stop_wait_op = STOP_WAIT_X;
205 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
206 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
207 &io_set[EVENT_IO_WRITE],
208 &io_set[EVENT_IO_EXCEPT], &timeout );
209 if ( num_pending == 0 )
211 stop_wait_op = CONT;
212 TIMER_ExpireTimers();
213 return FALSE;
215 else stop_wait_op = CONT;
216 #else /* CONFIG_IPC */
217 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
218 &io_set[EVENT_IO_WRITE],
219 &io_set[EVENT_IO_EXCEPT], &timeout );
220 if ( num_pending == 0)
222 /* Timeout or error */
223 TIMER_ExpireTimers();
224 return FALSE;
226 #endif /* CONFIG_IPC */
228 /* Winsock asynchronous services */
230 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
232 num_pending--;
233 if( num_pending )
234 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
236 else /* no X events */
238 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
239 return FALSE;
242 else if(!pending)
243 { /* Wait for X11 input. */
244 fd_set set;
246 FD_ZERO(&set);
247 FD_SET(__event_x_connection, &set);
248 select(__event_x_connection + 1, &set, 0, 0, 0 );
251 /* Process current X event (and possibly others that occurred in the meantime) */
253 EnterCriticalSection(&X11DRV_CritSection);
254 while (XPending( display ))
257 #ifdef CONFIG_IPC
258 if (DDE_GetRemoteMessage())
260 LeaveCriticalSection(&X11DRV_CritSection);
261 while(DDE_GetRemoteMessage()) ;
262 return FALSE;
264 #endif /* CONFIG_IPC */
266 XNextEvent( display, &event );
268 if( peek )
270 /* Check only for those events which can be processed
271 * internally. */
273 if( event.type == MotionNotify ||
274 event.type == ButtonPress || event.type == ButtonRelease ||
275 event.type == KeyPress || event.type == KeyRelease ||
276 event.type == SelectionRequest || event.type == SelectionClear ||
277 event.type == ClientMessage )
279 LeaveCriticalSection(&X11DRV_CritSection);
280 EVENT_ProcessEvent( &event );
281 EnterCriticalSection(&X11DRV_CritSection);
282 continue;
285 if ( event.type == NoExpose )
286 continue;
288 XPutBackEvent(display, &event);
289 LeaveCriticalSection(&X11DRV_CritSection);
290 return TRUE;
292 else
294 LeaveCriticalSection(&X11DRV_CritSection);
295 EVENT_ProcessEvent( &event );
296 EnterCriticalSection(&X11DRV_CritSection);
299 LeaveCriticalSection(&X11DRV_CritSection);
301 return FALSE;
304 /***********************************************************************
305 * EVENT_Synchronize
307 * Synchronize with the X server. Should not be used too often.
309 void X11DRV_EVENT_Synchronize()
311 XEvent event;
313 /* Use of the X critical section is needed or we have a small
314 * race between XPending() and XNextEvent().
316 EnterCriticalSection( &X11DRV_CritSection );
317 XSync( display, False );
318 while (XPending( display ))
320 XNextEvent( display, &event );
321 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
322 LeaveCriticalSection( &X11DRV_CritSection );
323 EVENT_ProcessEvent( &event );
324 EnterCriticalSection( &X11DRV_CritSection );
326 LeaveCriticalSection( &X11DRV_CritSection );
329 /***********************************************************************
330 * EVENT_ProcessEvent
332 * Process an X event.
334 static void EVENT_ProcessEvent( XEvent *event )
336 WND *pWnd;
338 if ( TSXFindContext( display, event->xany.window, winContext,
339 (char **)&pWnd ) != 0) {
340 if ( event->type == ClientMessage) {
341 /* query window (drag&drop event contains only drag window) */
342 Window root, child;
343 int root_x, root_y, child_x, child_y;
344 unsigned u;
345 TSXQueryPointer( display, rootWindow, &root, &child,
346 &root_x, &root_y, &child_x, &child_y, &u);
347 if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
348 return;
349 } else {
350 pWnd = NULL; /* Not for a registered window */
354 TRACE(event, "Got event %s for hwnd %04x\n",
355 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
357 switch(event->type)
359 case KeyPress:
360 case KeyRelease:
361 EVENT_Key( pWnd, (XKeyEvent*)event );
362 break;
364 case ButtonPress:
365 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
366 break;
368 case ButtonRelease:
369 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
370 break;
372 case MotionNotify:
373 /* Wine between two fast machines across the overloaded campus
374 ethernet gets very boged down in MotionEvents. The following
375 simply finds the last motion event in the queue and drops
376 the rest. On a good link events are servered before they build
377 up so this doesn't take place. On a slow link this may cause
378 problems if the event order is important. I'm not yet seen
379 of any problems. Jon 7/6/96.
381 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
382 MotionNotify, event));
383 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
384 break;
386 case FocusIn:
387 if (!pWnd) return;
388 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
389 break;
391 case FocusOut:
392 if (!pWnd) return;
393 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
394 break;
396 case Expose:
397 EVENT_Expose( pWnd, (XExposeEvent *)event );
398 break;
400 case GraphicsExpose:
401 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
402 break;
404 case ConfigureNotify:
405 if (!pWnd) return;
406 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
407 break;
409 case SelectionRequest:
410 if (!pWnd) return;
411 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
412 break;
414 case SelectionNotify:
415 if (!pWnd) return;
416 EVENT_SelectionNotify( (XSelectionEvent *)event );
417 break;
419 case SelectionClear:
420 if (!pWnd) return;
421 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
422 break;
424 case ClientMessage:
425 if (!pWnd) return;
426 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
427 break;
429 #if 0
430 case EnterNotify:
431 EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
432 break;
433 #endif
435 case NoExpose:
436 break;
438 /* We get all these because of StructureNotifyMask. */
439 case UnmapNotify:
440 case CirculateNotify:
441 case CreateNotify:
442 case DestroyNotify:
443 case GravityNotify:
444 case ReparentNotify:
445 break;
447 case MapNotify:
448 if (!pWnd) return;
449 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
450 break;
452 default:
453 WARN(event, "Unprocessed event %s for hwnd %04x\n",
454 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
455 break;
459 /***********************************************************************
460 * EVENT_QueryZOrder
462 * Try to synchronize internal z-order with the window manager's.
463 * Probably a futile endeavor.
465 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
467 /* return TRUE if we have at least two managed windows */
469 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
470 if( (*pWndA)->flags & WIN_MANAGED &&
471 (*pWndA)->dwStyle & WS_VISIBLE ) break;
472 if( *pWndA )
473 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
474 if( (*pWndB)->flags & WIN_MANAGED &&
475 (*pWndB)->dwStyle & WS_VISIBLE ) break;
476 return ((*pWndB) != NULL);
479 static Window __get_common_ancestor( Window A, Window B,
480 Window** children, unsigned* total )
482 /* find the real root window */
484 Window root, *childrenB;
485 unsigned totalB;
489 if( *children ) TSXFree( *children );
490 TSXQueryTree( display, A, &root, &A, children, total );
491 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
492 if( childrenB ) TSXFree( childrenB );
493 } while( A != B && A && B );
494 return ( A && B ) ? A : 0 ;
497 static Window __get_top_decoration( Window w, Window ancestor )
499 Window* children, root, prev = w, parent = w;
500 unsigned total;
504 w = parent;
505 TSXQueryTree( display, w, &root, &parent, &children, &total );
506 if( children ) TSXFree( children );
507 } while( parent && parent != ancestor );
508 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
509 return ( parent ) ? w : 0 ;
512 static unsigned __td_lookup( Window w, Window* list, unsigned max )
514 unsigned i;
515 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
516 return i;
519 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
521 BOOL32 bRet = FALSE;
522 HWND32 hwndInsertAfter = HWND_TOP;
523 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
524 Window w, parent, *children = NULL;
525 unsigned total, check, pos, best;
527 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
529 parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ),
530 X11DRV_WND_GetXWindow(pWnd),
531 &children, &total );
532 if( parent && children )
534 w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
535 if( w != children[total - 1] )
537 check = __td_lookup( w, children, total );
538 best = total;
539 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
541 if( pWnd != pWndCheck )
543 if( !(pWnd->flags & WIN_MANAGED) ||
544 !(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
545 continue;
546 pos = __td_lookup( w, children, total );
547 if( pos < best && pos > check )
549 best = pos;
550 hwndInsertAfter = pWnd->hwndSelf;
552 if( check - best == 1 ) break;
555 WIN_UnlinkWindow( pWndCheck->hwndSelf );
556 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
559 if( children ) TSXFree( children );
560 return bRet;
564 /***********************************************************************
565 * EVENT_XStateToKeyState
567 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
568 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
570 static WORD EVENT_XStateToKeyState( int state )
572 int kstate = 0;
574 if (state & Button1Mask) kstate |= MK_LBUTTON;
575 if (state & Button2Mask) kstate |= MK_MBUTTON;
576 if (state & Button3Mask) kstate |= MK_RBUTTON;
577 if (state & ShiftMask) kstate |= MK_SHIFT;
578 if (state & ControlMask) kstate |= MK_CONTROL;
579 return kstate;
582 /***********************************************************************
583 * X11DRV_EVENT_QueryPointer
585 BOOL32 X11DRV_EVENT_QueryPointer(DWORD *posX, DWORD *posY, DWORD *state)
587 Window root, child;
588 int rootX, rootY, winX, winY;
589 unsigned int xstate;
591 if (!TSXQueryPointer( display, rootWindow, &root, &child,
592 &rootX, &rootY, &winX, &winY, &xstate ))
593 return FALSE;
595 if(posX)
596 *posX = (DWORD)winX;
597 if(posY)
598 *posY = (DWORD)winY;
599 if(state)
600 *state = EVENT_XStateToKeyState( xstate );
602 return TRUE;
605 /***********************************************************************
606 * EVENT_Expose
608 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
610 RECT32 rect;
612 /* Make position relative to client area instead of window */
613 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
614 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
615 rect.right = rect.left + event->width;
616 rect.bottom = rect.top + event->height;
618 if ( !EVENT_RedrawWindow )
620 HMODULE32 hModule = GetModuleHandle32A( "USER32" );
621 EVENT_RedrawWindow = GetProcAddress32( hModule, "RedrawWindow" );
624 EVENT_RedrawWindow( pWnd? pWnd->hwndSelf : 0, &rect, 0,
625 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
626 (event->count ? 0 : RDW_ERASENOW) );
630 /***********************************************************************
631 * EVENT_GraphicsExpose
633 * This is needed when scrolling area is partially obscured
634 * by non-Wine X window.
636 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
638 RECT32 rect;
640 /* Make position relative to client area instead of window */
641 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
642 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
643 rect.right = rect.left + event->width;
644 rect.bottom = rect.top + event->height;
646 if ( !EVENT_RedrawWindow )
648 HMODULE32 hModule = GetModuleHandle32A( "USER32" );
649 EVENT_RedrawWindow = GetProcAddress32( hModule, "RedrawWindow" );
652 EVENT_RedrawWindow( pWnd? pWnd->hwndSelf : 0, &rect, 0,
653 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
654 (event->count ? 0 : RDW_ERASENOW) );
658 /***********************************************************************
659 * EVENT_Key
661 * Handle a X key event
663 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
665 KEYBOARD_HandleEvent( pWnd, event );
669 /***********************************************************************
670 * EVENT_MotionNotify
672 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
674 int xOffset = pWnd? pWnd->rectWindow.left : 0;
675 int yOffset = pWnd? pWnd->rectWindow.top : 0;
677 MOUSE_SendEvent( MOUSEEVENTF_MOVE,
678 xOffset + event->x, yOffset + event->y,
679 EVENT_XStateToKeyState( event->state ),
680 event->time - MSG_WineStartTicks,
681 pWnd? pWnd->hwndSelf : 0 );
685 /***********************************************************************
686 * X11DRV_EVENT_DummyMotionNotify
688 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
690 void X11DRV_EVENT_DummyMotionNotify(void)
692 DWORD winX, winY, state;
694 if ( EVENT_QueryPointer( &winX, &winY, &state ) )
696 MOUSE_SendEvent( MOUSEEVENTF_MOVE, winX, winY, state,
697 GetTickCount(), 0 );
702 /***********************************************************************
703 * EVENT_ButtonPress
705 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
707 static WORD statusCodes[NB_BUTTONS] =
708 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
709 int buttonNum = event->button - 1;
711 int xOffset = pWnd? pWnd->rectWindow.left : 0;
712 int yOffset = pWnd? pWnd->rectWindow.top : 0;
714 if (buttonNum >= NB_BUTTONS) return;
716 MOUSE_SendEvent( statusCodes[buttonNum],
717 xOffset + event->x, yOffset + event->y,
718 EVENT_XStateToKeyState( event->state ),
719 event->time - MSG_WineStartTicks,
720 pWnd? pWnd->hwndSelf : 0 );
724 /***********************************************************************
725 * EVENT_ButtonRelease
727 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
729 static WORD statusCodes[NB_BUTTONS] =
730 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
731 int buttonNum = event->button - 1;
733 int xOffset = pWnd? pWnd->rectWindow.left : 0;
734 int yOffset = pWnd? pWnd->rectWindow.top : 0;
736 if (buttonNum >= NB_BUTTONS) return;
738 MOUSE_SendEvent( statusCodes[buttonNum],
739 xOffset + event->x, yOffset + event->y,
740 EVENT_XStateToKeyState( event->state ),
741 event->time - MSG_WineStartTicks,
742 pWnd? pWnd->hwndSelf : 0 );
746 /**********************************************************************
747 * EVENT_FocusIn
749 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
751 if (Options.managed) EVENT_QueryZOrder( pWnd );
753 if (event->detail != NotifyPointer)
755 HWND32 hwnd = pWnd->hwndSelf;
757 if (hwnd != GetActiveWindow32())
759 WINPOS_ChangeActiveWindow( hwnd, FALSE );
760 KEYBOARD_UpdateState();
762 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
763 SetFocus32( hwnd );
768 /**********************************************************************
769 * EVENT_FocusOut
771 * Note: only top-level override-redirect windows get FocusOut events.
773 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
775 if (event->detail != NotifyPointer)
777 HWND32 hwnd = pWnd->hwndSelf;
779 if (hwnd == GetActiveWindow32())
780 WINPOS_ChangeActiveWindow( 0, FALSE );
781 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
782 SetFocus32( 0 );
786 /**********************************************************************
787 * X11DRV_EVENT_CheckFocus
789 BOOL32 X11DRV_EVENT_CheckFocus(void)
791 WND* pWnd;
792 Window xW;
793 int state;
795 TSXGetInputFocus(display, &xW, &state);
796 if( xW == None ||
797 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
798 return FALSE;
799 return TRUE;
802 /**********************************************************************
803 * EVENT_GetGeometry
805 * Helper function for ConfigureNotify handling.
806 * Get the new geometry of a window relative to the root window.
808 static void EVENT_GetGeometry( Window win, int *px, int *py,
809 unsigned int *pwidth, unsigned int *pheight )
811 Window root, parent, *children;
812 int xpos, ypos;
813 unsigned int width, height, border, depth, nb_children;
815 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
816 &border, &depth )) return;
817 if (win == rootWindow)
819 *px = *py = 0;
820 return;
823 for (;;)
825 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
826 return;
827 TSXFree( children );
828 if (parent == rootWindow) break;
829 win = parent;
830 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
831 &width, &height, &border, &depth )) return;
832 *px += xpos;
833 *py += ypos;
838 /**********************************************************************
839 * EVENT_ConfigureNotify
841 * The ConfigureNotify event is only selected on top-level windows
842 * when the -managed flag is used.
844 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
846 WINDOWPOS32 winpos;
847 RECT32 newWindowRect, newClientRect;
848 HRGN32 hrgnOldPos, hrgnNewPos;
849 Window above = event->above;
850 int x, y;
851 unsigned int width, height;
853 assert (pWnd->flags & WIN_MANAGED);
855 /* We don't rely on the event geometry info, because it is relative
856 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
857 * if the window hasn't moved).
859 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
861 /* Fill WINDOWPOS struct */
862 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
863 winpos.hwnd = pWnd->hwndSelf;
864 winpos.x = x;
865 winpos.y = y;
866 winpos.cx = width;
867 winpos.cy = height;
869 /* Check for unchanged attributes */
870 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
871 winpos.flags |= SWP_NOMOVE;
872 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
873 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
874 winpos.flags |= SWP_NOSIZE;
875 else
877 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
878 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
879 DCE_InvalidateDCE( pWnd, &rect );
882 /* Send WM_WINDOWPOSCHANGING */
883 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
885 /* Calculate new position and size */
886 newWindowRect.left = x;
887 newWindowRect.right = x + width;
888 newWindowRect.top = y;
889 newWindowRect.bottom = y + height;
891 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
892 &pWnd->rectWindow, &pWnd->rectClient,
893 &winpos, &newClientRect );
895 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
896 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
897 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
898 DeleteObject32(hrgnOldPos);
899 DeleteObject32(hrgnNewPos);
901 /* Set new size and position */
902 pWnd->rectWindow = newWindowRect;
903 pWnd->rectClient = newClientRect;
904 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
906 if (!IsWindow32( winpos.hwnd )) return;
907 if( above == None ) /* absolute bottom */
909 WIN_UnlinkWindow( winpos.hwnd );
910 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
912 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
916 /***********************************************************************
917 * EVENT_SelectionRequest
919 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
921 XSelectionEvent result;
922 Atom rprop = None;
923 Window request = event->requestor;
925 if(event->target == XA_STRING)
927 HANDLE16 hText;
928 LPSTR text;
929 int size,i,j;
931 rprop = event->property;
933 if(rprop == None) rprop = event->target;
935 if(event->selection!=XA_PRIMARY) rprop = None;
936 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
937 else
939 /* open to make sure that clipboard is available */
941 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
942 char* lpstr = 0;
944 hText = GetClipboardData16(CF_TEXT);
945 text = GlobalLock16(hText);
946 size = GlobalSize16(hText);
948 /* remove carriage returns */
950 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
951 for(i=0,j=0; i < size && text[i]; i++ )
953 if( text[i] == '\r' &&
954 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
955 lpstr[j++] = text[i];
957 lpstr[j]='\0';
959 TSXChangeProperty(display, request, rprop,
960 XA_STRING, 8, PropModeReplace,
961 lpstr, j);
962 HeapFree( GetProcessHeap(), 0, lpstr );
964 /* close only if we opened before */
966 if(couldOpen) CloseClipboard32();
970 if(rprop == None)
971 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
973 result.type = SelectionNotify;
974 result.display = display;
975 result.requestor = request;
976 result.selection = event->selection;
977 result.property = rprop;
978 result.target = event->target;
979 result.time = event->time;
980 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
984 /***********************************************************************
985 * EVENT_SelectionNotify
987 static void EVENT_SelectionNotify( XSelectionEvent *event )
989 if (event->selection != XA_PRIMARY) return;
991 if (event->target != XA_STRING) X11DRV_CLIPBOARD_ReadSelection( 0, None );
992 else X11DRV_CLIPBOARD_ReadSelection( event->requestor, event->property );
994 TRACE(clipboard,"\tSelectionNotify done!\n");
998 /***********************************************************************
999 * EVENT_SelectionClear
1001 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1003 if (event->selection != XA_PRIMARY) return;
1004 X11DRV_CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1008 /**********************************************************************
1009 * EVENT_DropFromOffix
1011 * don't know if it still works (last Changlog is from 96/11/04)
1013 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1015 unsigned long data_length;
1016 unsigned long aux_long;
1017 unsigned char* p_data = NULL;
1018 union {
1019 Atom atom_aux;
1020 POINT32 pt_aux;
1021 int i;
1022 } u;
1023 int x, y;
1024 BOOL16 bAccept;
1025 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1026 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1027 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1028 Window w_aux_root, w_aux_child;
1029 WND* pDropWnd;
1031 if( !lpDragInfo || !spDragInfo ) return;
1033 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
1034 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1036 lpDragInfo->hScope = pWnd->hwndSelf;
1037 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1039 /* find out drop point and drop window */
1040 if( x < 0 || y < 0 ||
1041 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1042 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1043 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1044 else
1046 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1047 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1049 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1050 GlobalFree16( hDragInfo );
1052 if( bAccept )
1054 TSXGetWindowProperty( display, DefaultRootWindow(display),
1055 dndSelection, 0, 65535, FALSE,
1056 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1057 &data_length, &aux_long, &p_data);
1059 if( !aux_long && p_data) /* don't bother if > 64K */
1061 char *p = (char*) p_data;
1062 char *p_drop;
1064 aux_long = 0;
1065 while( *p ) /* calculate buffer size */
1067 p_drop = p;
1068 if((u.i = *p) != -1 )
1069 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1070 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1071 else
1073 INT32 len = GetShortPathName32A( p, NULL, 0 );
1074 if (len) aux_long += len + 1;
1075 else *p = -1;
1077 p += strlen(p) + 1;
1079 if( aux_long && aux_long < 65535 )
1081 HDROP16 hDrop;
1082 LPDROPFILESTRUCT16 lpDrop;
1084 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1085 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1086 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1088 if( lpDrop )
1090 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1091 lpDrop->ptMousePos.x = (INT16)x;
1092 lpDrop->ptMousePos.y = (INT16)y;
1093 lpDrop->fInNonClientArea = (BOOL16)
1094 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1095 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1096 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1097 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1098 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1099 p = p_data;
1100 while(*p)
1102 if( *p != -1 ) /* use only "good" entries */
1104 GetShortPathName32A( p, p_drop, 65535 );
1105 p_drop += strlen( p_drop ) + 1;
1107 p += strlen(p) + 1;
1109 *p_drop = '\0';
1110 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1111 (WPARAM16)hDrop, 0L );
1115 if( p_data ) TSXFree(p_data);
1117 } /* WS_EX_ACCEPTFILES */
1120 /**********************************************************************
1121 * EVENT_DropURLs
1123 * drop items are separated by \n
1124 * each item is prefixed by its mime type
1126 * event->data.l[3], event->data.l[4] contains drop x,y position
1128 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1130 WND *pDropWnd;
1131 unsigned long data_length;
1132 unsigned long aux_long, drop_len = 0;
1133 unsigned char *p_data = NULL; /* property data */
1134 char *p_drop = NULL;
1135 char *p, *next;
1136 int x, y, drop32 = FALSE ;
1137 union {
1138 Atom atom_aux;
1139 POINT32 pt_aux;
1140 int i;
1141 Window w_aux;
1142 } u; /* unused */
1143 union {
1144 HDROP16 h16;
1145 HDROP32 h32;
1146 } hDrop;
1148 drop32 = pWnd->flags & WIN_ISWIN32;
1150 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1151 return;
1153 TSXGetWindowProperty( display, DefaultRootWindow(display),
1154 dndSelection, 0, 65535, FALSE,
1155 AnyPropertyType, &u.atom_aux, &u.i,
1156 &data_length, &aux_long, &p_data);
1157 if (aux_long)
1158 WARN(event,"property too large, truncated!\n");
1159 TRACE(event,"urls=%s\n", p_data);
1161 if( !aux_long && p_data) { /* don't bother if > 64K */
1162 /* calculate length */
1163 p = p_data;
1164 next = strchr(p, '\n');
1165 while (p) {
1166 if (next) *next=0;
1167 if (strncmp(p,"file:",5) == 0 ) {
1168 INT32 len = GetShortPathName32A( p+5, NULL, 0 );
1169 if (len) drop_len += len + 1;
1171 if (next) {
1172 *next = '\n';
1173 p = next + 1;
1174 next = strchr(p, '\n');
1175 } else {
1176 p = NULL;
1180 if( drop_len && drop_len < 65535 ) {
1181 TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux,
1182 &x, &y, &u.i, &u.i, &u.i);
1183 pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1185 if (drop32) {
1186 LPDROPFILESTRUCT32 lpDrop;
1187 drop_len += sizeof(DROPFILESTRUCT32) + 1;
1188 hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
1189 lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
1191 if( lpDrop ) {
1192 lpDrop->lSize = sizeof(DROPFILESTRUCT32);
1193 lpDrop->ptMousePos.x = (INT32)x;
1194 lpDrop->ptMousePos.y = (INT32)y;
1195 lpDrop->fInNonClientArea = (BOOL32)
1196 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1197 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1198 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1199 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1200 lpDrop->fWideChar = FALSE;
1201 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
1203 } else {
1204 LPDROPFILESTRUCT16 lpDrop;
1205 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1206 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1207 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1209 if( lpDrop ) {
1210 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1211 lpDrop->ptMousePos.x = (INT16)x;
1212 lpDrop->ptMousePos.y = (INT16)y;
1213 lpDrop->fInNonClientArea = (BOOL16)
1214 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1215 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1216 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1217 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1218 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1222 /* create message content */
1223 if (p_drop) {
1224 p = p_data;
1225 next = strchr(p, '\n');
1226 while (p) {
1227 if (next) *next=0;
1228 if (strncmp(p,"file:",5) == 0 ) {
1229 INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
1230 if (len) {
1231 TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1232 p_drop += len+1;
1233 } else {
1234 WARN(event, "can't convert file %s to dos name \n", p+5);
1236 } else {
1237 WARN(event, "unknown mime type %s\n", p);
1239 if (next) {
1240 *next = '\n';
1241 p = next + 1;
1242 next = strchr(p, '\n');
1243 } else {
1244 p = NULL;
1246 *p_drop = '\0';
1249 if (drop32) {
1250 /* can not use PostMessage32A because it is currently based on
1251 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1253 GlobalUnlock32(hDrop.h32);
1254 SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
1255 (WPARAM32)hDrop.h32, 0L );
1256 } else {
1257 GlobalUnlock16(hDrop.h16);
1258 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1259 (WPARAM16)hDrop.h16, 0L );
1263 if( p_data ) TSXFree(p_data);
1267 /**********************************************************************
1268 * EVENT_ClientMessage
1270 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1272 if (event->message_type != None && event->format == 32) {
1273 if ((event->message_type == wmProtocols) &&
1274 (((Atom) event->data.l[0]) == wmDeleteWindow))
1275 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1276 else if ( event->message_type == dndProtocol &&
1277 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1278 EVENT_DropFromOffiX(pWnd, event);
1279 else if ( event->message_type == dndProtocol &&
1280 event->data.l[0] == DndURL )
1281 EVENT_DropURLs(pWnd, event);
1282 else {
1283 #if 0
1284 /* enable this if you want to see the message */
1285 unsigned char* p_data = NULL;
1286 union {
1287 unsigned long l;
1288 int i;
1289 Atom atom;
1290 } u; /* unused */
1291 TSXGetWindowProperty( display, DefaultRootWindow(display),
1292 dndSelection, 0, 65535, FALSE,
1293 AnyPropertyType, &u.atom, &u.i,
1294 &u.l, &u.l, &p_data);
1295 TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1296 event->message_type, event->data.l[0], event->data.l[1],
1297 event->data.l[2], event->data.l[3], event->data.l[4],
1298 p_data);
1299 #endif
1300 TRACE(event, "unrecognized ClientMessage\n" );
1305 /**********************************************************************
1306 * EVENT_EnterNotify
1308 * Install colormap when Wine window is focused in
1309 * self-managed mode with private colormap
1311 #if 0
1312 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1314 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1315 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1316 TSXInstallColormap( display, COLOR_GetColormap() );
1318 #endif
1320 /**********************************************************************
1321 * EVENT_MapNotify
1323 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1325 HWND32 hwndFocus = GetFocus32();
1327 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1328 X11DRV_WND_SetFocus( WIN_FindWndPtr( hwndFocus ) );
1330 return;
1333 /**********************************************************************
1334 * X11DRV_EVENT_Pending
1336 BOOL32 X11DRV_EVENT_Pending()
1338 return TSXPending(display);
1341 #endif /* !defined(X_DISPLAY_MISSING) */