winemac.drv: Implement GetMonitorInfo.
[wine] / dlls / winex11.drv / event.c
1 /*
2  * X11 event driver
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1999 Noel Borthwick
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #ifdef HAVE_POLL_H
25 #include <poll.h>
26 #endif
27 #ifdef HAVE_SYS_POLL_H
28 #include <sys/poll.h>
29 #endif
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
35 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
36 #include <X11/extensions/XInput2.h>
37 #endif
38
39 #include <assert.h>
40 #include <stdarg.h>
41 #include <string.h>
42
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winuser.h"
48 #include "wingdi.h"
49
50 #include "x11drv.h"
51
52 /* avoid conflict with field names in included win32 headers */
53 #undef Status
54 #include "shlobj.h"  /* DROPFILES */
55 #include "shellapi.h"
56
57 #include "wine/server.h"
58 #include "wine/debug.h"
59
60 WINE_DEFAULT_DEBUG_CHANNEL(event);
61
62 extern BOOL ximInComposeMode;
63
64 #define DndNotDnd       -1    /* OffiX drag&drop */
65 #define DndUnknown      0
66 #define DndRawData      1
67 #define DndFile         2
68 #define DndFiles        3
69 #define DndText         4
70 #define DndDir          5
71 #define DndLink         6
72 #define DndExe          7
73
74 #define DndEND          8
75
76 #define DndURL          128   /* KDE drag&drop */
77
78 #define XEMBED_EMBEDDED_NOTIFY        0
79 #define XEMBED_WINDOW_ACTIVATE        1
80 #define XEMBED_WINDOW_DEACTIVATE      2
81 #define XEMBED_REQUEST_FOCUS          3
82 #define XEMBED_FOCUS_IN               4
83 #define XEMBED_FOCUS_OUT              5
84 #define XEMBED_FOCUS_NEXT             6
85 #define XEMBED_FOCUS_PREV             7
86 #define XEMBED_MODALITY_ON            10
87 #define XEMBED_MODALITY_OFF           11
88 #define XEMBED_REGISTER_ACCELERATOR   12
89 #define XEMBED_UNREGISTER_ACCELERATOR 13
90 #define XEMBED_ACTIVATE_ACCELERATOR   14
91
92 Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
93 void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
94
95   /* Event handlers */
96 static void X11DRV_FocusIn( HWND hwnd, XEvent *event );
97 static void X11DRV_FocusOut( HWND hwnd, XEvent *event );
98 static void X11DRV_Expose( HWND hwnd, XEvent *event );
99 static void X11DRV_MapNotify( HWND hwnd, XEvent *event );
100 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
101 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
102 static void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
103 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
104 static void X11DRV_ClientMessage( HWND hwnd, XEvent *event );
105 static void X11DRV_GravityNotify( HWND hwnd, XEvent *event );
106
107 #define MAX_EVENT_HANDLERS 128
108
109 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
110 {
111     NULL,                     /*  0 reserved */
112     NULL,                     /*  1 reserved */
113     X11DRV_KeyEvent,          /*  2 KeyPress */
114     X11DRV_KeyEvent,          /*  3 KeyRelease */
115     X11DRV_ButtonPress,       /*  4 ButtonPress */
116     X11DRV_ButtonRelease,     /*  5 ButtonRelease */
117     X11DRV_MotionNotify,      /*  6 MotionNotify */
118     X11DRV_EnterNotify,       /*  7 EnterNotify */
119     NULL,                     /*  8 LeaveNotify */
120     X11DRV_FocusIn,           /*  9 FocusIn */
121     X11DRV_FocusOut,          /* 10 FocusOut */
122     X11DRV_KeymapNotify,      /* 11 KeymapNotify */
123     X11DRV_Expose,            /* 12 Expose */
124     NULL,                     /* 13 GraphicsExpose */
125     NULL,                     /* 14 NoExpose */
126     NULL,                     /* 15 VisibilityNotify */
127     NULL,                     /* 16 CreateNotify */
128     X11DRV_DestroyNotify,     /* 17 DestroyNotify */
129     X11DRV_UnmapNotify,       /* 18 UnmapNotify */
130     X11DRV_MapNotify,         /* 19 MapNotify */
131     NULL,                     /* 20 MapRequest */
132     X11DRV_ReparentNotify,    /* 21 ReparentNotify */
133     X11DRV_ConfigureNotify,   /* 22 ConfigureNotify */
134     NULL,                     /* 23 ConfigureRequest */
135     X11DRV_GravityNotify,     /* 24 GravityNotify */
136     NULL,                     /* 25 ResizeRequest */
137     NULL,                     /* 26 CirculateNotify */
138     NULL,                     /* 27 CirculateRequest */
139     X11DRV_PropertyNotify,    /* 28 PropertyNotify */
140     X11DRV_SelectionClear,    /* 29 SelectionClear */
141     X11DRV_SelectionRequest,  /* 30 SelectionRequest */
142     NULL,                     /* 31 SelectionNotify */
143     NULL,                     /* 32 ColormapNotify */
144     X11DRV_ClientMessage,     /* 33 ClientMessage */
145     X11DRV_MappingNotify,     /* 34 MappingNotify */
146     X11DRV_GenericEvent       /* 35 GenericEvent */
147 };
148
149 static const char * event_names[MAX_EVENT_HANDLERS] =
150 {
151     NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
152     "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
153     "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
154     "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
155     "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
156     "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
157     "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
158 };
159
160 int xinput2_opcode = 0;
161
162 /* return the name of an X event */
163 static const char *dbgstr_event( int type )
164 {
165     if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
166     return wine_dbg_sprintf( "Unknown event %d", type );
167 }
168
169 static inline void get_event_data( XEvent *event )
170 {
171 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
172     if (event->xany.type != GenericEvent) return;
173     if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
174 #endif
175 }
176
177 static inline void free_event_data( XEvent *event )
178 {
179 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
180     if (event->xany.type != GenericEvent) return;
181     if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
182 #endif
183 }
184
185 /***********************************************************************
186  *           X11DRV_register_event_handler
187  *
188  * Register a handler for a given event type.
189  * If already registered, overwrite the previous handler.
190  */
191 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
192 {
193     assert( type < MAX_EVENT_HANDLERS );
194     assert( !handlers[type] || handlers[type] == handler );
195     handlers[type] = handler;
196     event_names[type] = name;
197     TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
198 }
199
200
201 /***********************************************************************
202  *           filter_event
203  */
204 static Bool filter_event( Display *display, XEvent *event, char *arg )
205 {
206     ULONG_PTR mask = (ULONG_PTR)arg;
207
208     if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
209
210     switch(event->type)
211     {
212     case KeyPress:
213     case KeyRelease:
214     case KeymapNotify:
215     case MappingNotify:
216         return (mask & (QS_KEY|QS_HOTKEY)) != 0;
217     case ButtonPress:
218     case ButtonRelease:
219         return (mask & QS_MOUSEBUTTON) != 0;
220     case MotionNotify:
221     case EnterNotify:
222     case LeaveNotify:
223         return (mask & QS_MOUSEMOVE) != 0;
224     case Expose:
225         return (mask & QS_PAINT) != 0;
226     case FocusIn:
227     case FocusOut:
228     case MapNotify:
229     case UnmapNotify:
230     case ConfigureNotify:
231     case PropertyNotify:
232     case ClientMessage:
233         return (mask & QS_POSTMESSAGE) != 0;
234     default:
235         return (mask & QS_SENDMESSAGE) != 0;
236     }
237 }
238
239
240 enum event_merge_action
241 {
242     MERGE_DISCARD,  /* discard the old event */
243     MERGE_HANDLE,   /* handle the old event */
244     MERGE_KEEP,     /* keep the old event for future merging */
245     MERGE_IGNORE    /* ignore the new event, keep the old one */
246 };
247
248 /***********************************************************************
249  *           merge_raw_motion_events
250  */
251 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
252 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
253 {
254     int i, j, k;
255     unsigned char mask;
256
257     if (!prev->valuators.mask_len) return MERGE_HANDLE;
258     if (!next->valuators.mask_len) return MERGE_HANDLE;
259
260     mask = prev->valuators.mask[0] | next->valuators.mask[0];
261     if (mask == next->valuators.mask[0])  /* keep next */
262     {
263         for (i = j = k = 0; i < 8; i++)
264         {
265             if (XIMaskIsSet( prev->valuators.mask, i ))
266                 next->valuators.values[j] += prev->valuators.values[k++];
267             if (XIMaskIsSet( next->valuators.mask, i )) j++;
268         }
269         TRACE( "merging duplicate GenericEvent\n" );
270         return MERGE_DISCARD;
271     }
272     if (mask == prev->valuators.mask[0])  /* keep prev */
273     {
274         for (i = j = k = 0; i < 8; i++)
275         {
276             if (XIMaskIsSet( next->valuators.mask, i ))
277                 prev->valuators.values[j] += next->valuators.values[k++];
278             if (XIMaskIsSet( prev->valuators.mask, i )) j++;
279         }
280         TRACE( "merging duplicate GenericEvent\n" );
281         return MERGE_IGNORE;
282     }
283     /* can't merge events with disjoint masks */
284     return MERGE_HANDLE;
285 }
286 #endif
287
288 /***********************************************************************
289  *           merge_events
290  *
291  * Try to merge 2 consecutive events.
292  */
293 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
294 {
295     switch (prev->type)
296     {
297     case ConfigureNotify:
298         switch (next->type)
299         {
300         case ConfigureNotify:
301             if (prev->xany.window == next->xany.window)
302             {
303                 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
304                 return MERGE_DISCARD;
305             }
306             break;
307         case Expose:
308         case PropertyNotify:
309             return MERGE_KEEP;
310         }
311         break;
312     case MotionNotify:
313         switch (next->type)
314         {
315         case MotionNotify:
316             if (prev->xany.window == next->xany.window)
317             {
318                 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
319                 return MERGE_DISCARD;
320             }
321             break;
322 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
323         case GenericEvent:
324             if (next->xcookie.extension != xinput2_opcode) break;
325             if (next->xcookie.evtype != XI_RawMotion) break;
326             if (x11drv_thread_data()->warp_serial) break;
327             return MERGE_KEEP;
328         }
329         break;
330     case GenericEvent:
331         if (prev->xcookie.extension != xinput2_opcode) break;
332         if (prev->xcookie.evtype != XI_RawMotion) break;
333         switch (next->type)
334         {
335         case GenericEvent:
336             if (next->xcookie.extension != xinput2_opcode) break;
337             if (next->xcookie.evtype != XI_RawMotion) break;
338             if (x11drv_thread_data()->warp_serial) break;
339             return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
340 #endif
341         }
342         break;
343     }
344     return MERGE_HANDLE;
345 }
346
347
348 /***********************************************************************
349  *           call_event_handler
350  */
351 static inline void call_event_handler( Display *display, XEvent *event )
352 {
353     HWND hwnd;
354     XEvent *prev;
355     struct x11drv_thread_data *thread_data;
356
357     if (!handlers[event->type])
358     {
359         TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
360         return;  /* no handler, ignore it */
361     }
362
363     if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
364         hwnd = 0;  /* not for a registered window */
365     if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
366
367     TRACE( "%lu %s for hwnd/window %p/%lx\n",
368            event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
369     thread_data = x11drv_thread_data();
370     prev = thread_data->current_event;
371     thread_data->current_event = event;
372     handlers[event->type]( hwnd, event );
373     thread_data->current_event = prev;
374 }
375
376
377 /***********************************************************************
378  *           process_events
379  */
380 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
381 {
382     XEvent event, prev_event;
383     int count = 0;
384     enum event_merge_action action = MERGE_DISCARD;
385
386     prev_event.type = 0;
387     while (XCheckIfEvent( display, &event, filter, (char *)arg ))
388     {
389         count++;
390         if (XFilterEvent( &event, None ))
391         {
392             /*
393              * SCIM on linux filters key events strangely. It does not filter the
394              * KeyPress events for these keys however it does filter the
395              * KeyRelease events. This causes wine to become very confused as
396              * to the keyboard state.
397              *
398              * We need to let those KeyRelease events be processed so that the
399              * keyboard state is correct.
400              */
401             if (event.type == KeyRelease)
402             {
403                 KeySym keysym = 0;
404                 XKeyEvent *keyevent = &event.xkey;
405
406                 XLookupString(keyevent, NULL, 0, &keysym, NULL);
407                 if (!(keysym == XK_Shift_L ||
408                     keysym == XK_Shift_R ||
409                     keysym == XK_Control_L ||
410                     keysym == XK_Control_R ||
411                     keysym == XK_Alt_R ||
412                     keysym == XK_Alt_L ||
413                     keysym == XK_Meta_R ||
414                     keysym == XK_Meta_L))
415                         continue; /* not a key we care about, ignore it */
416             }
417             else
418                 continue;  /* filtered, ignore it */
419         }
420         get_event_data( &event );
421         if (prev_event.type) action = merge_events( &prev_event, &event );
422         switch( action )
423         {
424         case MERGE_HANDLE:  /* handle prev, keep new */
425             call_event_handler( display, &prev_event );
426             /* fall through */
427         case MERGE_DISCARD:  /* discard prev, keep new */
428             free_event_data( &prev_event );
429             prev_event = event;
430             break;
431         case MERGE_KEEP:  /* handle new, keep prev for future merging */
432             call_event_handler( display, &event );
433             /* fall through */
434         case MERGE_IGNORE: /* ignore new, keep prev for future merging */
435             free_event_data( &event );
436             break;
437         }
438     }
439     if (prev_event.type) call_event_handler( display, &prev_event );
440     free_event_data( &prev_event );
441     XFlush( gdi_display );
442     if (count) TRACE( "processed %d events\n", count );
443     return count;
444 }
445
446
447 /***********************************************************************
448  *           MsgWaitForMultipleObjectsEx   (X11DRV.@)
449  */
450 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
451                                                 DWORD timeout, DWORD mask, DWORD flags )
452 {
453     DWORD ret;
454     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
455
456     if (!data)
457     {
458         if (!count && !timeout) return WAIT_TIMEOUT;
459         return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
460                                          timeout, flags & MWMO_ALERTABLE );
461     }
462
463     if (data->current_event) mask = 0;  /* don't process nested events */
464
465     if (process_events( data->display, filter_event, mask )) ret = count - 1;
466     else if (count || timeout)
467     {
468         ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
469                                         timeout, flags & MWMO_ALERTABLE );
470         if (ret == count - 1) process_events( data->display, filter_event, mask );
471     }
472     else ret = WAIT_TIMEOUT;
473
474     return ret;
475 }
476
477 /***********************************************************************
478  *           EVENT_x11_time_to_win32_time
479  *
480  * Make our timer and the X timer line up as best we can
481  *  Pass 0 to retrieve the current adjustment value (times -1)
482  */
483 DWORD EVENT_x11_time_to_win32_time(Time time)
484 {
485   static DWORD adjust = 0;
486   DWORD now = GetTickCount();
487   DWORD ret;
488
489   if (! adjust && time != 0)
490   {
491     ret = now;
492     adjust = time - now;
493   }
494   else
495   {
496       /* If we got an event in the 'future', then our clock is clearly wrong. 
497          If we got it more than 10000 ms in the future, then it's most likely
498          that the clock has wrapped.  */
499
500       ret = time - adjust;
501       if (ret > now && ((ret - now) < 10000) && time != 0)
502       {
503         adjust += ret - now;
504         ret    -= ret - now;
505       }
506   }
507
508   return ret;
509
510 }
511
512 /*******************************************************************
513  *         can_activate_window
514  *
515  * Check if we can activate the specified window.
516  */
517 static inline BOOL can_activate_window( HWND hwnd )
518 {
519     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
520     RECT rect;
521
522     if (!(style & WS_VISIBLE)) return FALSE;
523     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
524     if (style & WS_MINIMIZE) return FALSE;
525     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
526     if (hwnd == GetDesktopWindow()) return FALSE;
527     if (GetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE;
528     return !(style & WS_DISABLED);
529 }
530
531
532 /**********************************************************************
533  *              set_input_focus
534  *
535  * Try to force focus for non-managed windows.
536  */
537 static void set_input_focus( Display *display, Window window )
538 {
539     XWindowChanges changes;
540     DWORD timestamp;
541
542     if (!window) return;
543
544     if (EVENT_x11_time_to_win32_time(0))
545         /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
546         /* FIXME: this is not entirely correct */
547         timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
548     else
549         timestamp = CurrentTime;
550
551     /* Set X focus and install colormap */
552     changes.stack_mode = Above;
553     XConfigureWindow( display, window, CWStackMode, &changes );
554     XSetInputFocus( display, window, RevertToParent, timestamp );
555 }
556
557 /**********************************************************************
558  *              set_focus
559  */
560 static void set_focus( Display *display, HWND hwnd, Time time )
561 {
562     HWND focus;
563     Window win;
564     GUITHREADINFO threadinfo;
565
566     TRACE( "setting foreground window to %p\n", hwnd );
567     SetForegroundWindow( hwnd );
568
569     threadinfo.cbSize = sizeof(threadinfo);
570     GetGUIThreadInfo(0, &threadinfo);
571     focus = threadinfo.hwndFocus;
572     if (!focus) focus = threadinfo.hwndActive;
573     if (focus) focus = GetAncestor( focus, GA_ROOT );
574     win = X11DRV_get_whole_window(focus);
575
576     if (win)
577     {
578         TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
579         XSetInputFocus( display, win, RevertToParent, time );
580     }
581 }
582
583
584 /**********************************************************************
585  *              handle_manager_message
586  */
587 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
588 {
589     if (hwnd != GetDesktopWindow()) return;
590     if (systray_atom && event->data.l[1] == systray_atom)
591         change_systray_owner( event->display, event->data.l[2] );
592 }
593
594
595 /**********************************************************************
596  *              handle_wm_protocols
597  */
598 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
599 {
600     Atom protocol = (Atom)event->data.l[0];
601     Time event_time = (Time)event->data.l[1];
602
603     if (!protocol) return;
604
605     if (protocol == x11drv_atom(WM_DELETE_WINDOW))
606     {
607         update_user_time( event_time );
608
609         if (hwnd == GetDesktopWindow())
610         {
611             /* The desktop window does not have a close button that we can
612              * pretend to click. Therefore, we simply send it a close command. */
613             SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
614             return;
615         }
616
617         /* Ignore the delete window request if the window has been disabled
618          * and we are in managed mode. This is to disallow applications from
619          * being closed by the window manager while in a modal state.
620          */
621         if (IsWindowEnabled(hwnd))
622         {
623             HMENU hSysMenu;
624
625             if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
626             hSysMenu = GetSystemMenu(hwnd, FALSE);
627             if (hSysMenu)
628             {
629                 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
630                 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
631                     return;
632             }
633             if (GetActiveWindow() != hwnd)
634             {
635                 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
636                                            (WPARAM)GetAncestor( hwnd, GA_ROOT ),
637                                            MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
638                 switch(ma)
639                 {
640                     case MA_NOACTIVATEANDEAT:
641                     case MA_ACTIVATEANDEAT:
642                         return;
643                     case MA_NOACTIVATE:
644                         break;
645                     case MA_ACTIVATE:
646                     case 0:
647                         SetActiveWindow(hwnd);
648                         break;
649                     default:
650                         WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
651                         break;
652                 }
653             }
654
655             PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
656         }
657     }
658     else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
659     {
660         HWND last_focus = x11drv_thread_data()->last_focus;
661
662         TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
663                hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
664                GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
665
666         if (can_activate_window(hwnd))
667         {
668             /* simulate a mouse click on the caption to find out
669              * whether the window wants to be activated */
670             LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
671                                        (WPARAM)GetAncestor( hwnd, GA_ROOT ),
672                                        MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
673             if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
674             {
675                 set_focus( event->display, hwnd, event_time );
676                 return;
677             }
678         }
679         else if (hwnd == GetDesktopWindow())
680         {
681             hwnd = GetForegroundWindow();
682             if (!hwnd) hwnd = last_focus;
683             if (!hwnd) hwnd = GetDesktopWindow();
684             set_focus( event->display, hwnd, event_time );
685             return;
686         }
687         /* try to find some other window to give the focus to */
688         hwnd = GetFocus();
689         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
690         if (!hwnd) hwnd = GetActiveWindow();
691         if (!hwnd) hwnd = last_focus;
692         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
693     }
694     else if (protocol == x11drv_atom(_NET_WM_PING))
695     {
696       XClientMessageEvent xev;
697       xev = *event;
698       
699       TRACE("NET_WM Ping\n");
700       xev.window = DefaultRootWindow(xev.display);
701       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
702     }
703 }
704
705
706 static const char * const focus_details[] =
707 {
708     "NotifyAncestor",
709     "NotifyVirtual",
710     "NotifyInferior",
711     "NotifyNonlinear",
712     "NotifyNonlinearVirtual",
713     "NotifyPointer",
714     "NotifyPointerRoot",
715     "NotifyDetailNone"
716 };
717
718 /**********************************************************************
719  *              X11DRV_FocusIn
720  */
721 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
722 {
723     XFocusChangeEvent *event = &xev->xfocus;
724     XIC xic;
725
726     if (!hwnd) return;
727
728     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
729
730     if (event->detail == NotifyPointer) return;
731     if (hwnd == GetDesktopWindow()) return;
732
733     if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic );
734     if (use_take_focus)
735     {
736         if (hwnd == GetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE );
737         return;
738     }
739
740     if (!can_activate_window(hwnd))
741     {
742         HWND hwnd = GetFocus();
743         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
744         if (!hwnd) hwnd = GetActiveWindow();
745         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
746         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
747     }
748     else SetForegroundWindow( hwnd );
749 }
750
751
752 /**********************************************************************
753  *              X11DRV_FocusOut
754  *
755  * Note: only top-level windows get FocusOut events.
756  */
757 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
758 {
759     XFocusChangeEvent *event = &xev->xfocus;
760     HWND hwnd_tmp;
761     Window focus_win;
762     int revert;
763     XIC xic;
764
765     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
766
767     if (event->detail == NotifyPointer)
768     {
769         if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
770         return;
771     }
772     if (!hwnd) return;
773     if (ximInComposeMode) return;
774
775     x11drv_thread_data()->last_focus = hwnd;
776     if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
777
778     if (root_window != DefaultRootWindow(event->display))
779     {
780         if (hwnd == GetDesktopWindow()) reset_clipping_window();
781         return;
782     }
783     if (hwnd != GetForegroundWindow()) return;
784     SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
785
786     /* don't reset the foreground window, if the window which is
787        getting the focus is a Wine window */
788
789     XGetInputFocus( event->display, &focus_win, &revert );
790     if (focus_win)
791     {
792         if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
793             focus_win = 0;
794     }
795
796     if (!focus_win)
797     {
798         /* Abey : 6-Oct-99. Check again if the focus out window is the
799            Foreground window, because in most cases the messages sent
800            above must have already changed the foreground window, in which
801            case we don't have to change the foreground window to 0 */
802         if (hwnd == GetForegroundWindow())
803         {
804             TRACE( "lost focus, setting fg to desktop\n" );
805             SetForegroundWindow( GetDesktopWindow() );
806         }
807     }
808 }
809
810
811 /***********************************************************************
812  *           X11DRV_Expose
813  */
814 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
815 {
816     XExposeEvent *event = &xev->xexpose;
817     RECT rect;
818     struct x11drv_win_data *data;
819     HRGN surface_region = 0;
820     UINT flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN;
821
822     TRACE( "win %p (%lx) %d,%d %dx%d\n",
823            hwnd, event->window, event->x, event->y, event->width, event->height );
824
825     if (!(data = get_win_data( hwnd ))) return;
826
827     rect.left   = event->x;
828     rect.top    = event->y;
829     rect.right  = event->x + event->width;
830     rect.bottom = event->y + event->height;
831
832     if (data->surface)
833     {
834         surface_region = expose_surface( data->surface, &rect );
835         if (!surface_region) flags = 0;
836         if (data->vis.visualid != default_visual.visualid)
837             data->surface->funcs->flush( data->surface );
838     }
839
840     if (event->window != root_window)
841     {
842         OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
843                     data->whole_rect.top - data->client_rect.top );
844         if (surface_region) OffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
845                                        data->whole_rect.top - data->client_rect.top );
846
847         if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
848             mirror_rect( &data->client_rect, &rect );
849
850         SERVER_START_REQ( update_window_zorder )
851         {
852             req->window      = wine_server_user_handle( hwnd );
853             req->rect.left   = rect.left;
854             req->rect.top    = rect.top;
855             req->rect.right  = rect.right;
856             req->rect.bottom = rect.bottom;
857             wine_server_call( req );
858         }
859         SERVER_END_REQ;
860     }
861     else
862     {
863         OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
864         flags &= ~RDW_ALLCHILDREN;
865     }
866     release_win_data( data );
867
868     if (flags) RedrawWindow( hwnd, &rect, surface_region, flags );
869     if (surface_region) DeleteObject( surface_region );
870 }
871
872
873 /**********************************************************************
874  *              X11DRV_MapNotify
875  */
876 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
877 {
878     struct x11drv_win_data *data;
879
880     if (event->xany.window == x11drv_thread_data()->clip_window)
881     {
882         clipping_cursor = 1;
883         return;
884     }
885     if (!(data = get_win_data( hwnd ))) return;
886
887     if (!data->managed && !data->embedded && data->mapped)
888     {
889         HWND hwndFocus = GetFocus();
890         if (hwndFocus && IsChild( hwnd, hwndFocus ))
891             set_input_focus( data->display, data->whole_window );
892     }
893     release_win_data( data );
894 }
895
896
897 /**********************************************************************
898  *              X11DRV_UnmapNotify
899  */
900 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
901 {
902     if (event->xany.window == x11drv_thread_data()->clip_window) clipping_cursor = 0;
903 }
904
905
906 /***********************************************************************
907  *     is_net_wm_state_maximized
908  */
909 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
910 {
911     Atom type, *state;
912     int format, ret = 0;
913     unsigned long i, count, remaining;
914
915     if (!data->whole_window) return FALSE;
916
917     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
918                              65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
919                              &remaining, (unsigned char **)&state ))
920     {
921         if (type == XA_ATOM && format == 32)
922         {
923             for (i = 0; i < count; i++)
924             {
925                 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
926                     state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
927                     ret++;
928             }
929         }
930         XFree( state );
931     }
932     return (ret == 2);
933 }
934
935
936 /***********************************************************************
937  *           X11DRV_ReparentNotify
938  */
939 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
940 {
941     XReparentEvent *event = &xev->xreparent;
942     struct x11drv_win_data *data;
943     HWND parent, old_parent;
944     DWORD style;
945
946     if (!(data = get_win_data( hwnd ))) return;
947
948     if (!data->embedded)
949     {
950         release_win_data( data );
951         return;
952     }
953
954     if (data->whole_window)
955     {
956         if (event->parent == root_window)
957         {
958             TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
959             data->embedder = 0;
960             release_win_data( data );
961             SendMessageW( hwnd, WM_CLOSE, 0, 0 );
962             return;
963         }
964         data->embedder = event->parent;
965     }
966
967     TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
968     release_win_data( data );
969
970     style = GetWindowLongW( hwnd, GWL_STYLE );
971     if (event->parent == root_window)
972     {
973         parent = GetDesktopWindow();
974         style = (style & ~WS_CHILD) | WS_POPUP;
975     }
976     else
977     {
978         if (!(parent = create_foreign_window( event->display, event->parent ))) return;
979         style = (style & ~WS_POPUP) | WS_CHILD;
980     }
981
982     ShowWindow( hwnd, SW_HIDE );
983     old_parent = SetParent( hwnd, parent );
984     SetWindowLongW( hwnd, GWL_STYLE, style );
985     SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
986                   SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
987                   ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
988
989     /* make old parent destroy itself if it no longer has children */
990     if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
991 }
992
993
994 /***********************************************************************
995  *              X11DRV_ConfigureNotify
996  */
997 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
998 {
999     XConfigureEvent *event = &xev->xconfigure;
1000     struct x11drv_win_data *data;
1001     RECT rect;
1002     UINT flags;
1003     HWND parent;
1004     BOOL root_coords;
1005     int cx, cy, x = event->x, y = event->y;
1006     DWORD style;
1007
1008     if (!hwnd) return;
1009     if (!(data = get_win_data( hwnd ))) return;
1010     if (!data->mapped || data->iconic) goto done;
1011     if (data->whole_window && !data->managed) goto done;
1012     /* ignore synthetic events on foreign windows */
1013     if (event->send_event && !data->whole_window) goto done;
1014     if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
1015     {
1016         TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1017                hwnd, data->whole_window, event->x, event->y, event->width, event->height,
1018                event->serial, data->configure_serial );
1019         goto done;
1020     }
1021
1022     /* Get geometry */
1023
1024     parent = GetAncestor( hwnd, GA_PARENT );
1025     root_coords = event->send_event;  /* synthetic events are always in root coords */
1026
1027     if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
1028     {
1029         Window child;
1030         XTranslateCoordinates( event->display, event->window, root_window,
1031                                0, 0, &x, &y, &child );
1032         root_coords = TRUE;
1033     }
1034     rect.left   = x;
1035     rect.top    = y;
1036     rect.right  = x + event->width;
1037     rect.bottom = y + event->height;
1038     if (root_coords) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
1039     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1040            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1041            event->x, event->y, event->width, event->height );
1042
1043     X11DRV_X_to_window_rect( data, &rect );
1044     if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1045
1046     /* Compare what has changed */
1047
1048     x     = rect.left;
1049     y     = rect.top;
1050     cx    = rect.right - rect.left;
1051     cy    = rect.bottom - rect.top;
1052     flags = SWP_NOACTIVATE | SWP_NOZORDER;
1053
1054     if (!data->whole_window) flags |= SWP_NOCOPYBITS;  /* we can't copy bits of foreign windows */
1055
1056     if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1057     else
1058         TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1059                hwnd, data->window_rect.left, data->window_rect.top, x, y );
1060
1061     if ((data->window_rect.right - data->window_rect.left == cx &&
1062          data->window_rect.bottom - data->window_rect.top == cy) ||
1063         (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
1064         flags |= SWP_NOSIZE;
1065     else
1066         TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1067                hwnd, data->window_rect.right - data->window_rect.left,
1068                data->window_rect.bottom - data->window_rect.top, cx, cy );
1069
1070     style = GetWindowLongW( data->hwnd, GWL_STYLE );
1071     if ((style & WS_CAPTION) == WS_CAPTION)
1072     {
1073         if (is_net_wm_state_maximized( event->display, data ))
1074         {
1075             if (!(style & WS_MAXIMIZE))
1076             {
1077                 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1078                 release_win_data( data );
1079                 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1080                 return;
1081             }
1082         }
1083         else if (style & WS_MAXIMIZE)
1084         {
1085             TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1086             release_win_data( data );
1087             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1088             return;
1089         }
1090     }
1091
1092     if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
1093     {
1094         release_win_data( data );
1095         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1096         return;
1097     }
1098
1099 done:
1100     release_win_data( data );
1101 }
1102
1103
1104 /**********************************************************************
1105  *           X11DRV_GravityNotify
1106  */
1107 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1108 {
1109     XGravityEvent *event = &xev->xgravity;
1110     struct x11drv_win_data *data = get_win_data( hwnd );
1111     RECT rect, window_rect;
1112
1113     if (!data) return;
1114
1115     if (data->whole_window)  /* only handle this for foreign windows */
1116     {
1117         release_win_data( data );
1118         return;
1119     }
1120
1121     rect.left   = event->x;
1122     rect.top    = event->y;
1123     rect.right  = rect.left + data->whole_rect.right - data->whole_rect.left;
1124     rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1125
1126     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1127            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1128            event->x, event->y );
1129
1130     X11DRV_X_to_window_rect( data, &rect );
1131     window_rect = data->window_rect;
1132     release_win_data( data );
1133
1134     if (window_rect.left != rect.left || window_rect.top != rect.top)
1135         SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1136                       SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1137 }
1138
1139
1140 /***********************************************************************
1141  *           get_window_wm_state
1142  */
1143 static int get_window_wm_state( Display *display, Window window )
1144 {
1145     struct
1146     {
1147         CARD32 state;
1148         XID     icon;
1149     } *state;
1150     Atom type;
1151     int format, ret = -1;
1152     unsigned long count, remaining;
1153
1154     if (!XGetWindowProperty( display, window, x11drv_atom(WM_STATE), 0,
1155                              sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1156                              &type, &format, &count, &remaining, (unsigned char **)&state ))
1157     {
1158         if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1159             ret = state->state;
1160         XFree( state );
1161     }
1162     return ret;
1163 }
1164
1165
1166 /***********************************************************************
1167  *           handle_wm_state_notify
1168  *
1169  * Handle a PropertyNotify for WM_STATE.
1170  */
1171 static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
1172 {
1173     struct x11drv_win_data *data = get_win_data( hwnd );
1174     DWORD style;
1175
1176     if (!data) return;
1177
1178     switch(event->state)
1179     {
1180     case PropertyDelete:
1181         TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1182         data->wm_state = WithdrawnState;
1183         break;
1184     case PropertyNewValue:
1185         {
1186             int old_state = data->wm_state;
1187             int new_state = get_window_wm_state( event->display, data->whole_window );
1188             if (new_state != -1 && new_state != data->wm_state)
1189             {
1190                 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1191                        data->hwnd, data->whole_window, new_state, old_state );
1192                 data->wm_state = new_state;
1193                 /* ignore the initial state transition out of withdrawn state */
1194                 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1195                 if (!old_state) goto done;
1196             }
1197         }
1198         break;
1199     }
1200
1201     if (!update_window || !data->managed || !data->mapped) goto done;
1202
1203     style = GetWindowLongW( data->hwnd, GWL_STYLE );
1204
1205     if (data->iconic && data->wm_state == NormalState)  /* restore window */
1206     {
1207         data->iconic = FALSE;
1208         if ((style & WS_CAPTION) == WS_CAPTION && is_net_wm_state_maximized( event->display, data ))
1209         {
1210             if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1211             {
1212                 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1213                 release_win_data( data );
1214                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1215                 return;
1216             }
1217             TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1218         }
1219         else
1220         {
1221             if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1222             {
1223                 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1224                 release_win_data( data );
1225                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1226                 return;
1227             }
1228             TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1229         }
1230     }
1231     else if (!data->iconic && data->wm_state == IconicState)
1232     {
1233         data->iconic = TRUE;
1234         if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1235         {
1236             TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1237             release_win_data( data );
1238             SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1239             return;
1240         }
1241         TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1242     }
1243 done:
1244     release_win_data( data );
1245 }
1246
1247
1248 /***********************************************************************
1249  *           X11DRV_PropertyNotify
1250  */
1251 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1252 {
1253     XPropertyEvent *event = &xev->xproperty;
1254
1255     if (!hwnd) return;
1256     if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
1257 }
1258
1259
1260 /* event filter to wait for a WM_STATE change notification on a window */
1261 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1262 {
1263     if (event->xany.window != (Window)arg) return 0;
1264     return (event->type == DestroyNotify ||
1265             (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1266 }
1267
1268 /***********************************************************************
1269  *           wait_for_withdrawn_state
1270  */
1271 void wait_for_withdrawn_state( HWND hwnd, BOOL set )
1272 {
1273     Display *display = thread_display();
1274     struct x11drv_win_data *data;
1275     DWORD end = GetTickCount() + 2000;
1276
1277     TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
1278
1279     for (;;)
1280     {
1281         XEvent event;
1282         Window window;
1283         int count = 0;
1284
1285         if (!(data = get_win_data( hwnd ))) break;
1286         if (!data->managed || data->embedded || data->display != display) break;
1287         if (!(window = data->whole_window)) break;
1288         if (!data->mapped == !set)
1289         {
1290             TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
1291             break;
1292         }
1293         if ((data->wm_state == WithdrawnState) != !set)
1294         {
1295             TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
1296             break;
1297         }
1298         release_win_data( data );
1299
1300         while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
1301         {
1302             count++;
1303             if (XFilterEvent( &event, None )) continue;  /* filtered, ignore it */
1304             if (event.type == DestroyNotify) call_event_handler( display, &event );
1305             else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
1306         }
1307
1308         if (!count)
1309         {
1310             struct pollfd pfd;
1311             int timeout = end - GetTickCount();
1312
1313             pfd.fd = ConnectionNumber(display);
1314             pfd.events = POLLIN;
1315             if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1316             {
1317                 FIXME( "window %p/%lx wait timed out\n", hwnd, window );
1318                 return;
1319             }
1320         }
1321     }
1322     release_win_data( data );
1323 }
1324
1325
1326 /*****************************************************************
1327  *              SetFocus   (X11DRV.@)
1328  *
1329  * Set the X focus.
1330  */
1331 void CDECL X11DRV_SetFocus( HWND hwnd )
1332 {
1333     struct x11drv_win_data *data;
1334
1335     if (!(hwnd = GetAncestor( hwnd, GA_ROOT ))) return;
1336     if (!(data = get_win_data( hwnd ))) return;
1337     if (!data->managed) set_input_focus( data->display, data->whole_window );
1338     release_win_data( data );
1339 }
1340
1341
1342 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1343 {
1344     RECT tempRect;
1345
1346     if (!IsWindowEnabled(hQueryWnd)) return 0;
1347     
1348     GetWindowRect(hQueryWnd, &tempRect);
1349
1350     if(!PtInRect(&tempRect, *lpPt)) return 0;
1351
1352     if (!IsIconic( hQueryWnd ))
1353     {
1354         POINT pt = *lpPt;
1355         ScreenToClient( hQueryWnd, &pt );
1356         GetClientRect( hQueryWnd, &tempRect );
1357
1358         if (PtInRect( &tempRect, pt))
1359         {
1360             HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1361             if (ret && ret != hQueryWnd)
1362             {
1363                 ret = find_drop_window( ret, lpPt );
1364                 if (ret) return ret;
1365             }
1366         }
1367     }
1368
1369     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1370     
1371     ScreenToClient(hQueryWnd, lpPt);
1372
1373     return hQueryWnd;
1374 }
1375
1376 /**********************************************************************
1377  *           EVENT_DropFromOffix
1378  *
1379  * don't know if it still works (last Changelog is from 96/11/04)
1380  */
1381 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1382 {
1383     struct x11drv_win_data *data;
1384     unsigned long       data_length;
1385     unsigned long       aux_long;
1386     unsigned char*      p_data = NULL;
1387     Atom atom_aux;
1388     int                 x, y, cx, cy, dummy;
1389     BOOL                bAccept;
1390     Window              win, w_aux_root, w_aux_child;
1391
1392     if (!(data = get_win_data( hWnd ))) return;
1393     cx = data->whole_rect.right - data->whole_rect.left;
1394     cy = data->whole_rect.bottom - data->whole_rect.top;
1395     win = data->whole_window;
1396     release_win_data( data );
1397
1398     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1399                    &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1400     x += virtual_screen_rect.left;
1401     y += virtual_screen_rect.top;
1402
1403     /* find out drop point and drop window */
1404     if (x < 0 || y < 0 || x > cx || y > cy)
1405     {
1406         bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1407         x = 0;
1408         y = 0; 
1409     }
1410     else
1411     {
1412         POINT   pt = { x, y };
1413         HWND    hwndDrop = find_drop_window( hWnd, &pt );
1414         if (hwndDrop)
1415         {
1416             x = pt.x;
1417             y = pt.y;
1418             bAccept = TRUE;
1419         }
1420         else
1421         {
1422             bAccept = FALSE;
1423         }
1424     }
1425
1426     if (!bAccept) return;
1427
1428     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1429                         x11drv_atom(DndSelection), 0, 65535, FALSE,
1430                         AnyPropertyType, &atom_aux, &dummy,
1431                         &data_length, &aux_long, &p_data);
1432
1433     if( !aux_long && p_data)  /* don't bother if > 64K */
1434     {
1435         char *p = (char *)p_data;
1436         char *p_drop;
1437
1438         aux_long = 0;
1439         while( *p )  /* calculate buffer size */
1440         {
1441             INT len = GetShortPathNameA( p, NULL, 0 );
1442             if (len) aux_long += len + 1;
1443             p += strlen(p) + 1;
1444         }
1445         if( aux_long && aux_long < 65535 )
1446         {
1447             HDROP                 hDrop;
1448             DROPFILES *lpDrop;
1449
1450             aux_long += sizeof(DROPFILES) + 1;
1451             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1452             lpDrop = GlobalLock( hDrop );
1453
1454             if( lpDrop )
1455             {
1456                 lpDrop->pFiles = sizeof(DROPFILES);
1457                 lpDrop->pt.x = x;
1458                 lpDrop->pt.y = y;
1459                 lpDrop->fNC = FALSE;
1460                 lpDrop->fWide = FALSE;
1461                 p_drop = (char *)(lpDrop + 1);
1462                 p = (char *)p_data;
1463                 while(*p)
1464                 {
1465                     if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1466                         p_drop += strlen( p_drop ) + 1;
1467                     p += strlen(p) + 1;
1468                 }
1469                 *p_drop = '\0';
1470                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1471             }
1472         }
1473     }
1474     if( p_data ) XFree(p_data);
1475 }
1476
1477 /**********************************************************************
1478  *           EVENT_DropURLs
1479  *
1480  * drop items are separated by \n
1481  * each item is prefixed by its mime type
1482  *
1483  * event->data.l[3], event->data.l[4] contains drop x,y position
1484  */
1485 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1486 {
1487   struct x11drv_win_data *win_data;
1488   unsigned long data_length;
1489   unsigned long aux_long, drop_len = 0;
1490   unsigned char *p_data = NULL; /* property data */
1491   char          *p_drop = NULL;
1492   char          *p, *next;
1493   int           x, y;
1494   DROPFILES *lpDrop;
1495   HDROP hDrop;
1496   union {
1497     Atom        atom_aux;
1498     int         i;
1499     Window      w_aux;
1500     unsigned int u;
1501   }             u; /* unused */
1502
1503   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1504
1505   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1506                       x11drv_atom(DndSelection), 0, 65535, FALSE,
1507                       AnyPropertyType, &u.atom_aux, &u.i,
1508                       &data_length, &aux_long, &p_data);
1509   if (aux_long)
1510     WARN("property too large, truncated!\n");
1511   TRACE("urls=%s\n", p_data);
1512
1513   if( !aux_long && p_data) {    /* don't bother if > 64K */
1514     /* calculate length */
1515     p = (char*) p_data;
1516     next = strchr(p, '\n');
1517     while (p) {
1518       if (next) *next=0;
1519       if (strncmp(p,"file:",5) == 0 ) {
1520         INT len = GetShortPathNameA( p+5, NULL, 0 );
1521         if (len) drop_len += len + 1;
1522       }
1523       if (next) {
1524         *next = '\n';
1525         p = next + 1;
1526         next = strchr(p, '\n');
1527       } else {
1528         p = NULL;
1529       }
1530     }
1531
1532     if( drop_len && drop_len < 65535 ) {
1533       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1534                      &x, &y, &u.i, &u.i, &u.u);
1535       x += virtual_screen_rect.left;
1536       y += virtual_screen_rect.top;
1537
1538       drop_len += sizeof(DROPFILES) + 1;
1539       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1540       lpDrop = GlobalLock( hDrop );
1541
1542       if( lpDrop && (win_data = get_win_data( hWnd )))
1543       {
1544           lpDrop->pFiles = sizeof(DROPFILES);
1545           lpDrop->pt.x = x;
1546           lpDrop->pt.y = y;
1547           lpDrop->fNC =
1548             ( x < (win_data->client_rect.left - win_data->whole_rect.left)  ||
1549               y < (win_data->client_rect.top - win_data->whole_rect.top)    ||
1550               x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1551               y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1552           lpDrop->fWide = FALSE;
1553           p_drop = (char*)(lpDrop + 1);
1554           release_win_data( win_data );
1555       }
1556
1557       /* create message content */
1558       if (p_drop) {
1559         p = (char*) p_data;
1560         next = strchr(p, '\n');
1561         while (p) {
1562           if (next) *next=0;
1563           if (strncmp(p,"file:",5) == 0 ) {
1564             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1565             if (len) {
1566               TRACE("drop file %s as %s\n", p+5, p_drop);
1567               p_drop += len+1;
1568             } else {
1569               WARN("can't convert file %s to dos name\n", p+5);
1570             }
1571           } else {
1572             WARN("unknown mime type %s\n", p);
1573           }
1574           if (next) {
1575             *next = '\n';
1576             p = next + 1;
1577             next = strchr(p, '\n');
1578           } else {
1579             p = NULL;
1580           }
1581           *p_drop = '\0';
1582         }
1583
1584         GlobalUnlock(hDrop);
1585         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1586       }
1587     }
1588     if( p_data ) XFree(p_data);
1589   }
1590 }
1591
1592
1593 /**********************************************************************
1594  *              handle_xembed_protocol
1595  */
1596 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1597 {
1598     struct x11drv_win_data *data = get_win_data( hwnd );
1599
1600     if (!data) return;
1601
1602     switch (event->data.l[1])
1603     {
1604     case XEMBED_EMBEDDED_NOTIFY:
1605         TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1606         data->embedder = event->data.l[3];
1607         break;
1608     default:
1609         TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1610                hwnd, event->window, event->data.l[1], event->data.l[2] );
1611         break;
1612     }
1613     release_win_data( data );
1614 }
1615
1616
1617 /**********************************************************************
1618  *              handle_dnd_protocol
1619  */
1620 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1621 {
1622     Window root, child;
1623     int root_x, root_y, child_x, child_y;
1624     unsigned int u;
1625
1626     /* query window (drag&drop event contains only drag window) */
1627     XQueryPointer( event->display, root_window, &root, &child,
1628                    &root_x, &root_y, &child_x, &child_y, &u);
1629     if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1630     if (!hwnd) return;
1631     if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1632         EVENT_DropFromOffiX(hwnd, event);
1633     else if (event->data.l[0] == DndURL)
1634         EVENT_DropURLs(hwnd, event);
1635 }
1636
1637
1638 struct client_message_handler
1639 {
1640     int    atom;                                  /* protocol atom */
1641     void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1642 };
1643
1644 static const struct client_message_handler client_messages[] =
1645 {
1646     { XATOM_MANAGER,      handle_manager_message },
1647     { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1648     { XATOM__XEMBED,      handle_xembed_protocol },
1649     { XATOM_DndProtocol,  handle_dnd_protocol },
1650     { XATOM_XdndEnter,    X11DRV_XDND_EnterEvent },
1651     { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1652     { XATOM_XdndDrop,     X11DRV_XDND_DropEvent },
1653     { XATOM_XdndLeave,    X11DRV_XDND_LeaveEvent }
1654 };
1655
1656
1657 /**********************************************************************
1658  *           X11DRV_ClientMessage
1659  */
1660 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1661 {
1662     XClientMessageEvent *event = &xev->xclient;
1663     unsigned int i;
1664
1665     if (!hwnd) return;
1666
1667     if (event->format != 32)
1668     {
1669         WARN( "Don't know how to handle format %d\n", event->format );
1670         return;
1671     }
1672
1673     for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1674     {
1675         if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1676         {
1677             client_messages[i].handler( hwnd, event );
1678             return;
1679         }
1680     }
1681     TRACE( "no handler found for %ld\n", event->message_type );
1682 }