Added a typedef for __int64 which is a builtin Visual C++ type
[wine/multimedia.git] / windows / x11drv / event.c
blob0a47590ddffeddad44aa67b0afee2d57d30f9bcd
1 /*
2 * X11 windows 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( pWndZ->window, pWnd->window,
530 &children, &total );
531 if( parent && children )
533 w = __get_top_decoration( pWndCheck->window, parent );
534 if( w != children[total - 1] )
536 check = __td_lookup( w, children, total );
537 best = total;
538 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
540 if( pWnd != pWndCheck )
542 if( !(pWnd->flags & WIN_MANAGED) ||
543 !(w = __get_top_decoration( pWnd->window, parent )) )
544 continue;
545 pos = __td_lookup( w, children, total );
546 if( pos < best && pos > check )
548 best = pos;
549 hwndInsertAfter = pWnd->hwndSelf;
551 if( check - best == 1 ) break;
554 WIN_UnlinkWindow( pWndCheck->hwndSelf );
555 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
558 if( children ) TSXFree( children );
559 return bRet;
563 /***********************************************************************
564 * EVENT_XStateToKeyState
566 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
567 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
569 static WORD EVENT_XStateToKeyState( int state )
571 int kstate = 0;
573 if (state & Button1Mask) kstate |= MK_LBUTTON;
574 if (state & Button2Mask) kstate |= MK_MBUTTON;
575 if (state & Button3Mask) kstate |= MK_RBUTTON;
576 if (state & ShiftMask) kstate |= MK_SHIFT;
577 if (state & ControlMask) kstate |= MK_CONTROL;
578 return kstate;
581 /***********************************************************************
582 * X11DRV_EVENT_QueryPointer
584 BOOL32 X11DRV_EVENT_QueryPointer(DWORD *posX, DWORD *posY, DWORD *state)
586 Window root, child;
587 int rootX, rootY, winX, winY;
588 unsigned int xstate;
590 if (!TSXQueryPointer( display, rootWindow, &root, &child,
591 &rootX, &rootY, &winX, &winY, &xstate ))
592 return FALSE;
594 if(posX)
595 *posX = (DWORD)winX;
596 if(posY)
597 *posY = (DWORD)winY;
598 if(state)
599 *state = EVENT_XStateToKeyState( xstate );
601 return TRUE;
604 /***********************************************************************
605 * EVENT_Expose
607 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
609 RECT32 rect;
611 /* Make position relative to client area instead of window */
612 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
613 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
614 rect.right = rect.left + event->width;
615 rect.bottom = rect.top + event->height;
617 if ( !EVENT_RedrawWindow )
619 HMODULE32 hModule = GetModuleHandle32A( "USER32" );
620 EVENT_RedrawWindow = GetProcAddress32( hModule, "RedrawWindow" );
623 EVENT_RedrawWindow( pWnd? pWnd->hwndSelf : 0, &rect, 0,
624 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
625 (event->count ? 0 : RDW_ERASENOW) );
629 /***********************************************************************
630 * EVENT_GraphicsExpose
632 * This is needed when scrolling area is partially obscured
633 * by non-Wine X window.
635 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
637 RECT32 rect;
639 /* Make position relative to client area instead of window */
640 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
641 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
642 rect.right = rect.left + event->width;
643 rect.bottom = rect.top + event->height;
645 if ( !EVENT_RedrawWindow )
647 HMODULE32 hModule = GetModuleHandle32A( "USER32" );
648 EVENT_RedrawWindow = GetProcAddress32( hModule, "RedrawWindow" );
651 EVENT_RedrawWindow( pWnd? pWnd->hwndSelf : 0, &rect, 0,
652 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
653 (event->count ? 0 : RDW_ERASENOW) );
657 /***********************************************************************
658 * EVENT_Key
660 * Handle a X key event
662 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
664 KEYBOARD_HandleEvent( pWnd, event );
668 /***********************************************************************
669 * EVENT_MotionNotify
671 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
673 int xOffset = pWnd? pWnd->rectWindow.left : 0;
674 int yOffset = pWnd? pWnd->rectWindow.top : 0;
676 MOUSE_SendEvent( MOUSEEVENTF_MOVE,
677 xOffset + event->x, yOffset + event->y,
678 EVENT_XStateToKeyState( event->state ),
679 event->time - MSG_WineStartTicks,
680 pWnd? pWnd->hwndSelf : 0 );
684 /***********************************************************************
685 * X11DRV_EVENT_DummyMotionNotify
687 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
689 void X11DRV_EVENT_DummyMotionNotify(void)
691 DWORD winX, winY, state;
693 if ( EVENT_QueryPointer( &winX, &winY, &state ) )
695 MOUSE_SendEvent( MOUSEEVENTF_MOVE, winX, winY, state,
696 GetTickCount(), 0 );
701 /***********************************************************************
702 * EVENT_ButtonPress
704 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
706 static WORD statusCodes[NB_BUTTONS] =
707 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
708 int buttonNum = event->button - 1;
710 int xOffset = pWnd? pWnd->rectWindow.left : 0;
711 int yOffset = pWnd? pWnd->rectWindow.top : 0;
713 if (buttonNum >= NB_BUTTONS) return;
715 MOUSE_SendEvent( statusCodes[buttonNum],
716 xOffset + event->x, yOffset + event->y,
717 EVENT_XStateToKeyState( event->state ),
718 event->time - MSG_WineStartTicks,
719 pWnd? pWnd->hwndSelf : 0 );
723 /***********************************************************************
724 * EVENT_ButtonRelease
726 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
728 static WORD statusCodes[NB_BUTTONS] =
729 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
730 int buttonNum = event->button - 1;
732 int xOffset = pWnd? pWnd->rectWindow.left : 0;
733 int yOffset = pWnd? pWnd->rectWindow.top : 0;
735 if (buttonNum >= NB_BUTTONS) return;
737 MOUSE_SendEvent( statusCodes[buttonNum],
738 xOffset + event->x, yOffset + event->y,
739 EVENT_XStateToKeyState( event->state ),
740 event->time - MSG_WineStartTicks,
741 pWnd? pWnd->hwndSelf : 0 );
745 /**********************************************************************
746 * EVENT_FocusIn
748 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
750 if (Options.managed) EVENT_QueryZOrder( pWnd );
752 if (event->detail != NotifyPointer)
754 HWND32 hwnd = pWnd->hwndSelf;
756 if (hwnd != GetActiveWindow32())
758 WINPOS_ChangeActiveWindow( hwnd, FALSE );
759 KEYBOARD_UpdateState();
761 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
762 SetFocus32( hwnd );
767 /**********************************************************************
768 * EVENT_FocusOut
770 * Note: only top-level override-redirect windows get FocusOut events.
772 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
774 if (event->detail != NotifyPointer)
776 HWND32 hwnd = pWnd->hwndSelf;
778 if (hwnd == GetActiveWindow32())
779 WINPOS_ChangeActiveWindow( 0, FALSE );
780 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
781 SetFocus32( 0 );
785 /**********************************************************************
786 * X11DRV_EVENT_CheckFocus
788 BOOL32 X11DRV_EVENT_CheckFocus(void)
790 WND* pWnd;
791 Window xW;
792 int state;
794 TSXGetInputFocus(display, &xW, &state);
795 if( xW == None ||
796 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
797 return FALSE;
798 return TRUE;
801 /**********************************************************************
802 * EVENT_GetGeometry
804 * Helper function for ConfigureNotify handling.
805 * Get the new geometry of a window relative to the root window.
807 static void EVENT_GetGeometry( Window win, int *px, int *py,
808 unsigned int *pwidth, unsigned int *pheight )
810 Window root, parent, *children;
811 int xpos, ypos;
812 unsigned int width, height, border, depth, nb_children;
814 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
815 &border, &depth )) return;
816 if (win == rootWindow)
818 *px = *py = 0;
819 return;
822 for (;;)
824 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
825 return;
826 TSXFree( children );
827 if (parent == rootWindow) break;
828 win = parent;
829 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
830 &width, &height, &border, &depth )) return;
831 *px += xpos;
832 *py += ypos;
837 /**********************************************************************
838 * EVENT_ConfigureNotify
840 * The ConfigureNotify event is only selected on top-level windows
841 * when the -managed flag is used.
843 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
845 WINDOWPOS32 winpos;
846 RECT32 newWindowRect, newClientRect;
847 HRGN32 hrgnOldPos, hrgnNewPos;
848 Window above = event->above;
849 int x, y;
850 unsigned int width, height;
852 assert (pWnd->flags & WIN_MANAGED);
854 /* We don't rely on the event geometry info, because it is relative
855 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
856 * if the window hasn't moved).
858 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
860 /* Fill WINDOWPOS struct */
861 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
862 winpos.hwnd = pWnd->hwndSelf;
863 winpos.x = x;
864 winpos.y = y;
865 winpos.cx = width;
866 winpos.cy = height;
868 /* Check for unchanged attributes */
869 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
870 winpos.flags |= SWP_NOMOVE;
871 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
872 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
873 winpos.flags |= SWP_NOSIZE;
874 else
876 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
877 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
878 DCE_InvalidateDCE( pWnd, &rect );
881 /* Send WM_WINDOWPOSCHANGING */
882 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
884 /* Calculate new position and size */
885 newWindowRect.left = x;
886 newWindowRect.right = x + width;
887 newWindowRect.top = y;
888 newWindowRect.bottom = y + height;
890 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
891 &pWnd->rectWindow, &pWnd->rectClient,
892 &winpos, &newClientRect );
894 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
895 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
896 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
897 DeleteObject32(hrgnOldPos);
898 DeleteObject32(hrgnNewPos);
900 /* Set new size and position */
901 pWnd->rectWindow = newWindowRect;
902 pWnd->rectClient = newClientRect;
903 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
905 if (!IsWindow32( winpos.hwnd )) return;
906 if( above == None ) /* absolute bottom */
908 WIN_UnlinkWindow( winpos.hwnd );
909 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
911 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
915 /***********************************************************************
916 * EVENT_SelectionRequest
918 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
920 XSelectionEvent result;
921 Atom rprop = None;
922 Window request = event->requestor;
924 if(event->target == XA_STRING)
926 HANDLE16 hText;
927 LPSTR text;
928 int size,i,j;
930 rprop = event->property;
932 if(rprop == None) rprop = event->target;
934 if(event->selection!=XA_PRIMARY) rprop = None;
935 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
936 else
938 /* open to make sure that clipboard is available */
940 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
941 char* lpstr = 0;
943 hText = GetClipboardData16(CF_TEXT);
944 text = GlobalLock16(hText);
945 size = GlobalSize16(hText);
947 /* remove carriage returns */
949 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
950 for(i=0,j=0; i < size && text[i]; i++ )
952 if( text[i] == '\r' &&
953 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
954 lpstr[j++] = text[i];
956 lpstr[j]='\0';
958 TSXChangeProperty(display, request, rprop,
959 XA_STRING, 8, PropModeReplace,
960 lpstr, j);
961 HeapFree( GetProcessHeap(), 0, lpstr );
963 /* close only if we opened before */
965 if(couldOpen) CloseClipboard32();
969 if(rprop == None)
970 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
972 result.type = SelectionNotify;
973 result.display = display;
974 result.requestor = request;
975 result.selection = event->selection;
976 result.property = rprop;
977 result.target = event->target;
978 result.time = event->time;
979 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
983 /***********************************************************************
984 * EVENT_SelectionNotify
986 static void EVENT_SelectionNotify( XSelectionEvent *event )
988 if (event->selection != XA_PRIMARY) return;
990 if (event->target != XA_STRING) X11DRV_CLIPBOARD_ReadSelection( 0, None );
991 else X11DRV_CLIPBOARD_ReadSelection( event->requestor, event->property );
993 TRACE(clipboard,"\tSelectionNotify done!\n");
997 /***********************************************************************
998 * EVENT_SelectionClear
1000 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1002 if (event->selection != XA_PRIMARY) return;
1003 X11DRV_CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1007 /**********************************************************************
1008 * EVENT_DropFromOffix
1010 * don't know if it still works (last Changlog is from 96/11/04)
1012 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1014 unsigned long data_length;
1015 unsigned long aux_long;
1016 unsigned char* p_data = NULL;
1017 union {
1018 Atom atom_aux;
1019 POINT32 pt_aux;
1020 int i;
1021 } u;
1022 int x, y;
1023 BOOL16 bAccept;
1024 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1025 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1026 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1027 Window w_aux_root, w_aux_child;
1028 WND* pDropWnd;
1030 if( !lpDragInfo || !spDragInfo ) return;
1032 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1033 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1035 lpDragInfo->hScope = pWnd->hwndSelf;
1036 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1038 /* find out drop point and drop window */
1039 if( x < 0 || y < 0 ||
1040 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1041 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1042 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1043 else
1045 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1046 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1048 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1049 GlobalFree16( hDragInfo );
1051 if( bAccept )
1053 TSXGetWindowProperty( display, DefaultRootWindow(display),
1054 dndSelection, 0, 65535, FALSE,
1055 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1056 &data_length, &aux_long, &p_data);
1058 if( !aux_long && p_data) /* don't bother if > 64K */
1060 char *p = (char*) p_data;
1061 char *p_drop;
1063 aux_long = 0;
1064 while( *p ) /* calculate buffer size */
1066 p_drop = p;
1067 if((u.i = *p) != -1 )
1068 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1069 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1070 else
1072 INT32 len = GetShortPathName32A( p, NULL, 0 );
1073 if (len) aux_long += len + 1;
1074 else *p = -1;
1076 p += strlen(p) + 1;
1078 if( aux_long && aux_long < 65535 )
1080 HDROP16 hDrop;
1081 LPDROPFILESTRUCT16 lpDrop;
1083 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1084 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1085 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1087 if( lpDrop )
1089 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1090 lpDrop->ptMousePos.x = (INT16)x;
1091 lpDrop->ptMousePos.y = (INT16)y;
1092 lpDrop->fInNonClientArea = (BOOL16)
1093 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1094 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1095 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1096 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1097 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1098 p = p_data;
1099 while(*p)
1101 if( *p != -1 ) /* use only "good" entries */
1103 GetShortPathName32A( p, p_drop, 65535 );
1104 p_drop += strlen( p_drop ) + 1;
1106 p += strlen(p) + 1;
1108 *p_drop = '\0';
1109 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1110 (WPARAM16)hDrop, 0L );
1114 if( p_data ) TSXFree(p_data);
1116 } /* WS_EX_ACCEPTFILES */
1119 /**********************************************************************
1120 * EVENT_DropURLs
1122 * drop items are separated by \n
1123 * each item is prefixed by its mime type
1125 * event->data.l[3], event->data.l[4] contains drop x,y position
1127 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1129 WND *pDropWnd;
1130 unsigned long data_length;
1131 unsigned long aux_long, drop_len = 0;
1132 unsigned char *p_data = NULL; /* property data */
1133 char *p_drop = NULL;
1134 char *p, *next;
1135 int x, y, drop32 = FALSE ;
1136 union {
1137 Atom atom_aux;
1138 POINT32 pt_aux;
1139 int i;
1140 Window w_aux;
1141 } u; /* unused */
1142 union {
1143 HDROP16 h16;
1144 HDROP32 h32;
1145 } hDrop;
1147 drop32 = pWnd->flags & WIN_ISWIN32;
1149 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1150 return;
1152 TSXGetWindowProperty( display, DefaultRootWindow(display),
1153 dndSelection, 0, 65535, FALSE,
1154 AnyPropertyType, &u.atom_aux, &u.i,
1155 &data_length, &aux_long, &p_data);
1156 if (aux_long)
1157 WARN(event,"property too large, truncated!\n");
1158 TRACE(event,"urls=%s\n", p_data);
1160 if( !aux_long && p_data) { /* don't bother if > 64K */
1161 /* calculate length */
1162 p = p_data;
1163 next = strchr(p, '\n');
1164 while (p) {
1165 if (next) *next=0;
1166 if (strncmp(p,"file:",5) == 0 ) {
1167 INT32 len = GetShortPathName32A( p+5, NULL, 0 );
1168 if (len) drop_len += len + 1;
1170 if (next) {
1171 *next = '\n';
1172 p = next + 1;
1173 next = strchr(p, '\n');
1174 } else {
1175 p = NULL;
1179 if( drop_len && drop_len < 65535 ) {
1180 TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux,
1181 &x, &y, &u.i, &u.i, &u.i);
1182 pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1184 if (drop32) {
1185 LPDROPFILESTRUCT32 lpDrop;
1186 drop_len += sizeof(DROPFILESTRUCT32) + 1;
1187 hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
1188 lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
1190 if( lpDrop ) {
1191 lpDrop->lSize = sizeof(DROPFILESTRUCT32);
1192 lpDrop->ptMousePos.x = (INT32)x;
1193 lpDrop->ptMousePos.y = (INT32)y;
1194 lpDrop->fInNonClientArea = (BOOL32)
1195 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1196 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1197 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1198 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1199 lpDrop->fWideChar = FALSE;
1200 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
1202 } else {
1203 LPDROPFILESTRUCT16 lpDrop;
1204 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1205 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1206 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1208 if( lpDrop ) {
1209 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1210 lpDrop->ptMousePos.x = (INT16)x;
1211 lpDrop->ptMousePos.y = (INT16)y;
1212 lpDrop->fInNonClientArea = (BOOL16)
1213 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1214 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1215 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1216 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1217 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1221 /* create message content */
1222 if (p_drop) {
1223 p = p_data;
1224 next = strchr(p, '\n');
1225 while (p) {
1226 if (next) *next=0;
1227 if (strncmp(p,"file:",5) == 0 ) {
1228 INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
1229 if (len) {
1230 TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1231 p_drop += len+1;
1232 } else {
1233 WARN(event, "can't convert file %s to dos name \n", p+5);
1235 } else {
1236 WARN(event, "unknown mime type %s\n", p);
1238 if (next) {
1239 *next = '\n';
1240 p = next + 1;
1241 next = strchr(p, '\n');
1242 } else {
1243 p = NULL;
1245 *p_drop = '\0';
1248 if (drop32) {
1249 /* can not use PostMessage32A because it is currently based on
1250 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1252 GlobalUnlock32(hDrop.h32);
1253 SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
1254 (WPARAM32)hDrop.h32, 0L );
1255 } else {
1256 GlobalUnlock16(hDrop.h16);
1257 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1258 (WPARAM16)hDrop.h16, 0L );
1262 if( p_data ) TSXFree(p_data);
1266 /**********************************************************************
1267 * EVENT_ClientMessage
1269 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1271 if (event->message_type != None && event->format == 32) {
1272 if ((event->message_type == wmProtocols) &&
1273 (((Atom) event->data.l[0]) == wmDeleteWindow))
1274 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1275 else if ( event->message_type == dndProtocol &&
1276 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1277 EVENT_DropFromOffiX(pWnd, event);
1278 else if ( event->message_type == dndProtocol &&
1279 event->data.l[0] == DndURL )
1280 EVENT_DropURLs(pWnd, event);
1281 else {
1282 #if 0
1283 /* enable this if you want to see the message */
1284 unsigned char* p_data = NULL;
1285 union {
1286 unsigned long l;
1287 int i;
1288 Atom atom;
1289 } u; /* unused */
1290 TSXGetWindowProperty( display, DefaultRootWindow(display),
1291 dndSelection, 0, 65535, FALSE,
1292 AnyPropertyType, &u.atom, &u.i,
1293 &u.l, &u.l, &p_data);
1294 TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1295 event->message_type, event->data.l[0], event->data.l[1],
1296 event->data.l[2], event->data.l[3], event->data.l[4],
1297 p_data);
1298 #endif
1299 TRACE(event, "unrecognized ClientMessage\n" );
1304 /**********************************************************************
1305 * EVENT_EnterNotify
1307 * Install colormap when Wine window is focused in
1308 * self-managed mode with private colormap
1310 #if 0
1311 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1313 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1314 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1315 TSXInstallColormap( display, COLOR_GetColormap() );
1317 #endif
1319 /**********************************************************************
1320 * EVENT_MapNotify
1322 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1324 HWND32 hwndFocus = GetFocus32();
1326 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1327 X11DRV_WND_SetFocus( WIN_FindWndPtr( hwndFocus ) );
1329 return;
1332 /**********************************************************************
1333 * X11DRV_EVENT_Pending
1335 BOOL32 X11DRV_EVENT_Pending()
1337 return TSXPending(display);
1340 #endif /* !defined(X_DISPLAY_MISSING) */