winex11: Handle Expose events on top-level client windows.
[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 (event->window != data->client_window)
833     {
834         if (data->surface)
835         {
836             surface_region = expose_surface( data->surface, &rect );
837             if (!surface_region) flags = 0;
838             else OffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
839                             data->whole_rect.top - data->client_rect.top );
840
841             if (data->vis.visualid != default_visual.visualid)
842                 data->surface->funcs->flush( data->surface );
843         }
844         OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
845                     data->whole_rect.top - data->client_rect.top );
846     }
847
848     if (event->window != root_window)
849     {
850         if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
851             mirror_rect( &data->client_rect, &rect );
852
853         SERVER_START_REQ( update_window_zorder )
854         {
855             req->window      = wine_server_user_handle( hwnd );
856             req->rect.left   = rect.left;
857             req->rect.top    = rect.top;
858             req->rect.right  = rect.right;
859             req->rect.bottom = rect.bottom;
860             wine_server_call( req );
861         }
862         SERVER_END_REQ;
863     }
864     else
865     {
866         OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
867         flags &= ~RDW_ALLCHILDREN;
868     }
869     release_win_data( data );
870
871     if (flags) RedrawWindow( hwnd, &rect, surface_region, flags );
872     if (surface_region) DeleteObject( surface_region );
873 }
874
875
876 /**********************************************************************
877  *              X11DRV_MapNotify
878  */
879 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
880 {
881     struct x11drv_win_data *data;
882
883     if (event->xany.window == x11drv_thread_data()->clip_window)
884     {
885         clipping_cursor = 1;
886         return;
887     }
888     if (!(data = get_win_data( hwnd ))) return;
889
890     if (!data->managed && !data->embedded && data->mapped)
891     {
892         HWND hwndFocus = GetFocus();
893         if (hwndFocus && IsChild( hwnd, hwndFocus ))
894             set_input_focus( data->display, data->whole_window );
895     }
896     release_win_data( data );
897 }
898
899
900 /**********************************************************************
901  *              X11DRV_UnmapNotify
902  */
903 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
904 {
905     if (event->xany.window == x11drv_thread_data()->clip_window) clipping_cursor = 0;
906 }
907
908
909 /***********************************************************************
910  *     is_net_wm_state_maximized
911  */
912 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
913 {
914     Atom type, *state;
915     int format, ret = 0;
916     unsigned long i, count, remaining;
917
918     if (!data->whole_window) return FALSE;
919
920     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
921                              65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
922                              &remaining, (unsigned char **)&state ))
923     {
924         if (type == XA_ATOM && format == 32)
925         {
926             for (i = 0; i < count; i++)
927             {
928                 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
929                     state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
930                     ret++;
931             }
932         }
933         XFree( state );
934     }
935     return (ret == 2);
936 }
937
938
939 /***********************************************************************
940  *           X11DRV_ReparentNotify
941  */
942 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
943 {
944     XReparentEvent *event = &xev->xreparent;
945     struct x11drv_win_data *data;
946     HWND parent, old_parent;
947     DWORD style;
948
949     if (!(data = get_win_data( hwnd ))) return;
950
951     if (!data->embedded)
952     {
953         release_win_data( data );
954         return;
955     }
956
957     if (data->whole_window)
958     {
959         if (event->parent == root_window)
960         {
961             TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
962             data->embedder = 0;
963             release_win_data( data );
964             SendMessageW( hwnd, WM_CLOSE, 0, 0 );
965             return;
966         }
967         data->embedder = event->parent;
968     }
969
970     TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
971     release_win_data( data );
972
973     style = GetWindowLongW( hwnd, GWL_STYLE );
974     if (event->parent == root_window)
975     {
976         parent = GetDesktopWindow();
977         style = (style & ~WS_CHILD) | WS_POPUP;
978     }
979     else
980     {
981         if (!(parent = create_foreign_window( event->display, event->parent ))) return;
982         style = (style & ~WS_POPUP) | WS_CHILD;
983     }
984
985     ShowWindow( hwnd, SW_HIDE );
986     old_parent = SetParent( hwnd, parent );
987     SetWindowLongW( hwnd, GWL_STYLE, style );
988     SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
989                   SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
990                   ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
991
992     /* make old parent destroy itself if it no longer has children */
993     if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
994 }
995
996
997 /***********************************************************************
998  *              X11DRV_ConfigureNotify
999  */
1000 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
1001 {
1002     XConfigureEvent *event = &xev->xconfigure;
1003     struct x11drv_win_data *data;
1004     RECT rect;
1005     UINT flags;
1006     HWND parent;
1007     BOOL root_coords;
1008     int cx, cy, x = event->x, y = event->y;
1009     DWORD style;
1010
1011     if (!hwnd) return;
1012     if (!(data = get_win_data( hwnd ))) return;
1013     if (!data->mapped || data->iconic) goto done;
1014     if (data->whole_window && !data->managed) goto done;
1015     /* ignore synthetic events on foreign windows */
1016     if (event->send_event && !data->whole_window) goto done;
1017     if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
1018     {
1019         TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1020                hwnd, data->whole_window, event->x, event->y, event->width, event->height,
1021                event->serial, data->configure_serial );
1022         goto done;
1023     }
1024
1025     /* Get geometry */
1026
1027     parent = GetAncestor( hwnd, GA_PARENT );
1028     root_coords = event->send_event;  /* synthetic events are always in root coords */
1029
1030     if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
1031     {
1032         Window child;
1033         XTranslateCoordinates( event->display, event->window, root_window,
1034                                0, 0, &x, &y, &child );
1035         root_coords = TRUE;
1036     }
1037     rect.left   = x;
1038     rect.top    = y;
1039     rect.right  = x + event->width;
1040     rect.bottom = y + event->height;
1041     if (root_coords) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
1042     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1043            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1044            event->x, event->y, event->width, event->height );
1045
1046     X11DRV_X_to_window_rect( data, &rect );
1047     if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1048
1049     /* Compare what has changed */
1050
1051     x     = rect.left;
1052     y     = rect.top;
1053     cx    = rect.right - rect.left;
1054     cy    = rect.bottom - rect.top;
1055     flags = SWP_NOACTIVATE | SWP_NOZORDER;
1056
1057     if (!data->whole_window) flags |= SWP_NOCOPYBITS;  /* we can't copy bits of foreign windows */
1058
1059     if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1060     else
1061         TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1062                hwnd, data->window_rect.left, data->window_rect.top, x, y );
1063
1064     if ((data->window_rect.right - data->window_rect.left == cx &&
1065          data->window_rect.bottom - data->window_rect.top == cy) ||
1066         (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
1067         flags |= SWP_NOSIZE;
1068     else
1069         TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1070                hwnd, data->window_rect.right - data->window_rect.left,
1071                data->window_rect.bottom - data->window_rect.top, cx, cy );
1072
1073     style = GetWindowLongW( data->hwnd, GWL_STYLE );
1074     if ((style & WS_CAPTION) == WS_CAPTION)
1075     {
1076         if (is_net_wm_state_maximized( event->display, data ))
1077         {
1078             if (!(style & WS_MAXIMIZE))
1079             {
1080                 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1081                 release_win_data( data );
1082                 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1083                 return;
1084             }
1085         }
1086         else if (style & WS_MAXIMIZE)
1087         {
1088             TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1089             release_win_data( data );
1090             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1091             return;
1092         }
1093     }
1094
1095     if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
1096     {
1097         release_win_data( data );
1098         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1099         return;
1100     }
1101
1102 done:
1103     release_win_data( data );
1104 }
1105
1106
1107 /**********************************************************************
1108  *           X11DRV_GravityNotify
1109  */
1110 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1111 {
1112     XGravityEvent *event = &xev->xgravity;
1113     struct x11drv_win_data *data = get_win_data( hwnd );
1114     RECT rect, window_rect;
1115
1116     if (!data) return;
1117
1118     if (data->whole_window)  /* only handle this for foreign windows */
1119     {
1120         release_win_data( data );
1121         return;
1122     }
1123
1124     rect.left   = event->x;
1125     rect.top    = event->y;
1126     rect.right  = rect.left + data->whole_rect.right - data->whole_rect.left;
1127     rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1128
1129     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1130            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1131            event->x, event->y );
1132
1133     X11DRV_X_to_window_rect( data, &rect );
1134     window_rect = data->window_rect;
1135     release_win_data( data );
1136
1137     if (window_rect.left != rect.left || window_rect.top != rect.top)
1138         SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1139                       SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1140 }
1141
1142
1143 /***********************************************************************
1144  *           get_window_wm_state
1145  */
1146 static int get_window_wm_state( Display *display, Window window )
1147 {
1148     struct
1149     {
1150         CARD32 state;
1151         XID     icon;
1152     } *state;
1153     Atom type;
1154     int format, ret = -1;
1155     unsigned long count, remaining;
1156
1157     if (!XGetWindowProperty( display, window, x11drv_atom(WM_STATE), 0,
1158                              sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1159                              &type, &format, &count, &remaining, (unsigned char **)&state ))
1160     {
1161         if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1162             ret = state->state;
1163         XFree( state );
1164     }
1165     return ret;
1166 }
1167
1168
1169 /***********************************************************************
1170  *           handle_wm_state_notify
1171  *
1172  * Handle a PropertyNotify for WM_STATE.
1173  */
1174 static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
1175 {
1176     struct x11drv_win_data *data = get_win_data( hwnd );
1177     DWORD style;
1178
1179     if (!data) return;
1180
1181     switch(event->state)
1182     {
1183     case PropertyDelete:
1184         TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1185         data->wm_state = WithdrawnState;
1186         break;
1187     case PropertyNewValue:
1188         {
1189             int old_state = data->wm_state;
1190             int new_state = get_window_wm_state( event->display, data->whole_window );
1191             if (new_state != -1 && new_state != data->wm_state)
1192             {
1193                 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1194                        data->hwnd, data->whole_window, new_state, old_state );
1195                 data->wm_state = new_state;
1196                 /* ignore the initial state transition out of withdrawn state */
1197                 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1198                 if (!old_state) goto done;
1199             }
1200         }
1201         break;
1202     }
1203
1204     if (!update_window || !data->managed || !data->mapped) goto done;
1205
1206     style = GetWindowLongW( data->hwnd, GWL_STYLE );
1207
1208     if (data->iconic && data->wm_state == NormalState)  /* restore window */
1209     {
1210         data->iconic = FALSE;
1211         if ((style & WS_CAPTION) == WS_CAPTION && is_net_wm_state_maximized( event->display, data ))
1212         {
1213             if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1214             {
1215                 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1216                 release_win_data( data );
1217                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1218                 return;
1219             }
1220             TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1221         }
1222         else
1223         {
1224             if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1225             {
1226                 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1227                 release_win_data( data );
1228                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1229                 return;
1230             }
1231             TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1232         }
1233     }
1234     else if (!data->iconic && data->wm_state == IconicState)
1235     {
1236         data->iconic = TRUE;
1237         if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1238         {
1239             TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1240             release_win_data( data );
1241             SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1242             return;
1243         }
1244         TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1245     }
1246 done:
1247     release_win_data( data );
1248 }
1249
1250
1251 /***********************************************************************
1252  *           X11DRV_PropertyNotify
1253  */
1254 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1255 {
1256     XPropertyEvent *event = &xev->xproperty;
1257
1258     if (!hwnd) return;
1259     if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
1260 }
1261
1262
1263 /* event filter to wait for a WM_STATE change notification on a window */
1264 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1265 {
1266     if (event->xany.window != (Window)arg) return 0;
1267     return (event->type == DestroyNotify ||
1268             (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1269 }
1270
1271 /***********************************************************************
1272  *           wait_for_withdrawn_state
1273  */
1274 void wait_for_withdrawn_state( HWND hwnd, BOOL set )
1275 {
1276     Display *display = thread_display();
1277     struct x11drv_win_data *data;
1278     DWORD end = GetTickCount() + 2000;
1279
1280     TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
1281
1282     for (;;)
1283     {
1284         XEvent event;
1285         Window window;
1286         int count = 0;
1287
1288         if (!(data = get_win_data( hwnd ))) break;
1289         if (!data->managed || data->embedded || data->display != display) break;
1290         if (!(window = data->whole_window)) break;
1291         if (!data->mapped == !set)
1292         {
1293             TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
1294             break;
1295         }
1296         if ((data->wm_state == WithdrawnState) != !set)
1297         {
1298             TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
1299             break;
1300         }
1301         release_win_data( data );
1302
1303         while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
1304         {
1305             count++;
1306             if (XFilterEvent( &event, None )) continue;  /* filtered, ignore it */
1307             if (event.type == DestroyNotify) call_event_handler( display, &event );
1308             else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
1309         }
1310
1311         if (!count)
1312         {
1313             struct pollfd pfd;
1314             int timeout = end - GetTickCount();
1315
1316             pfd.fd = ConnectionNumber(display);
1317             pfd.events = POLLIN;
1318             if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1319             {
1320                 FIXME( "window %p/%lx wait timed out\n", hwnd, window );
1321                 return;
1322             }
1323         }
1324     }
1325     release_win_data( data );
1326 }
1327
1328
1329 /*****************************************************************
1330  *              SetFocus   (X11DRV.@)
1331  *
1332  * Set the X focus.
1333  */
1334 void CDECL X11DRV_SetFocus( HWND hwnd )
1335 {
1336     struct x11drv_win_data *data;
1337
1338     if (!(hwnd = GetAncestor( hwnd, GA_ROOT ))) return;
1339     if (!(data = get_win_data( hwnd ))) return;
1340     if (!data->managed) set_input_focus( data->display, data->whole_window );
1341     release_win_data( data );
1342 }
1343
1344
1345 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1346 {
1347     RECT tempRect;
1348
1349     if (!IsWindowEnabled(hQueryWnd)) return 0;
1350     
1351     GetWindowRect(hQueryWnd, &tempRect);
1352
1353     if(!PtInRect(&tempRect, *lpPt)) return 0;
1354
1355     if (!IsIconic( hQueryWnd ))
1356     {
1357         POINT pt = *lpPt;
1358         ScreenToClient( hQueryWnd, &pt );
1359         GetClientRect( hQueryWnd, &tempRect );
1360
1361         if (PtInRect( &tempRect, pt))
1362         {
1363             HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1364             if (ret && ret != hQueryWnd)
1365             {
1366                 ret = find_drop_window( ret, lpPt );
1367                 if (ret) return ret;
1368             }
1369         }
1370     }
1371
1372     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1373     
1374     ScreenToClient(hQueryWnd, lpPt);
1375
1376     return hQueryWnd;
1377 }
1378
1379 /**********************************************************************
1380  *           EVENT_DropFromOffix
1381  *
1382  * don't know if it still works (last Changelog is from 96/11/04)
1383  */
1384 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1385 {
1386     struct x11drv_win_data *data;
1387     unsigned long       data_length;
1388     unsigned long       aux_long;
1389     unsigned char*      p_data = NULL;
1390     Atom atom_aux;
1391     int                 x, y, cx, cy, dummy;
1392     BOOL                bAccept;
1393     Window              win, w_aux_root, w_aux_child;
1394
1395     if (!(data = get_win_data( hWnd ))) return;
1396     cx = data->whole_rect.right - data->whole_rect.left;
1397     cy = data->whole_rect.bottom - data->whole_rect.top;
1398     win = data->whole_window;
1399     release_win_data( data );
1400
1401     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1402                    &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1403     x += virtual_screen_rect.left;
1404     y += virtual_screen_rect.top;
1405
1406     /* find out drop point and drop window */
1407     if (x < 0 || y < 0 || x > cx || y > cy)
1408     {
1409         bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1410         x = 0;
1411         y = 0; 
1412     }
1413     else
1414     {
1415         POINT   pt = { x, y };
1416         HWND    hwndDrop = find_drop_window( hWnd, &pt );
1417         if (hwndDrop)
1418         {
1419             x = pt.x;
1420             y = pt.y;
1421             bAccept = TRUE;
1422         }
1423         else
1424         {
1425             bAccept = FALSE;
1426         }
1427     }
1428
1429     if (!bAccept) return;
1430
1431     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1432                         x11drv_atom(DndSelection), 0, 65535, FALSE,
1433                         AnyPropertyType, &atom_aux, &dummy,
1434                         &data_length, &aux_long, &p_data);
1435
1436     if( !aux_long && p_data)  /* don't bother if > 64K */
1437     {
1438         char *p = (char *)p_data;
1439         char *p_drop;
1440
1441         aux_long = 0;
1442         while( *p )  /* calculate buffer size */
1443         {
1444             INT len = GetShortPathNameA( p, NULL, 0 );
1445             if (len) aux_long += len + 1;
1446             p += strlen(p) + 1;
1447         }
1448         if( aux_long && aux_long < 65535 )
1449         {
1450             HDROP                 hDrop;
1451             DROPFILES *lpDrop;
1452
1453             aux_long += sizeof(DROPFILES) + 1;
1454             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1455             lpDrop = GlobalLock( hDrop );
1456
1457             if( lpDrop )
1458             {
1459                 lpDrop->pFiles = sizeof(DROPFILES);
1460                 lpDrop->pt.x = x;
1461                 lpDrop->pt.y = y;
1462                 lpDrop->fNC = FALSE;
1463                 lpDrop->fWide = FALSE;
1464                 p_drop = (char *)(lpDrop + 1);
1465                 p = (char *)p_data;
1466                 while(*p)
1467                 {
1468                     if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1469                         p_drop += strlen( p_drop ) + 1;
1470                     p += strlen(p) + 1;
1471                 }
1472                 *p_drop = '\0';
1473                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1474             }
1475         }
1476     }
1477     if( p_data ) XFree(p_data);
1478 }
1479
1480 /**********************************************************************
1481  *           EVENT_DropURLs
1482  *
1483  * drop items are separated by \n
1484  * each item is prefixed by its mime type
1485  *
1486  * event->data.l[3], event->data.l[4] contains drop x,y position
1487  */
1488 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1489 {
1490   struct x11drv_win_data *win_data;
1491   unsigned long data_length;
1492   unsigned long aux_long, drop_len = 0;
1493   unsigned char *p_data = NULL; /* property data */
1494   char          *p_drop = NULL;
1495   char          *p, *next;
1496   int           x, y;
1497   DROPFILES *lpDrop;
1498   HDROP hDrop;
1499   union {
1500     Atom        atom_aux;
1501     int         i;
1502     Window      w_aux;
1503     unsigned int u;
1504   }             u; /* unused */
1505
1506   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1507
1508   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1509                       x11drv_atom(DndSelection), 0, 65535, FALSE,
1510                       AnyPropertyType, &u.atom_aux, &u.i,
1511                       &data_length, &aux_long, &p_data);
1512   if (aux_long)
1513     WARN("property too large, truncated!\n");
1514   TRACE("urls=%s\n", p_data);
1515
1516   if( !aux_long && p_data) {    /* don't bother if > 64K */
1517     /* calculate length */
1518     p = (char*) p_data;
1519     next = strchr(p, '\n');
1520     while (p) {
1521       if (next) *next=0;
1522       if (strncmp(p,"file:",5) == 0 ) {
1523         INT len = GetShortPathNameA( p+5, NULL, 0 );
1524         if (len) drop_len += len + 1;
1525       }
1526       if (next) {
1527         *next = '\n';
1528         p = next + 1;
1529         next = strchr(p, '\n');
1530       } else {
1531         p = NULL;
1532       }
1533     }
1534
1535     if( drop_len && drop_len < 65535 ) {
1536       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1537                      &x, &y, &u.i, &u.i, &u.u);
1538       x += virtual_screen_rect.left;
1539       y += virtual_screen_rect.top;
1540
1541       drop_len += sizeof(DROPFILES) + 1;
1542       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1543       lpDrop = GlobalLock( hDrop );
1544
1545       if( lpDrop && (win_data = get_win_data( hWnd )))
1546       {
1547           lpDrop->pFiles = sizeof(DROPFILES);
1548           lpDrop->pt.x = x;
1549           lpDrop->pt.y = y;
1550           lpDrop->fNC =
1551             ( x < (win_data->client_rect.left - win_data->whole_rect.left)  ||
1552               y < (win_data->client_rect.top - win_data->whole_rect.top)    ||
1553               x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1554               y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1555           lpDrop->fWide = FALSE;
1556           p_drop = (char*)(lpDrop + 1);
1557           release_win_data( win_data );
1558       }
1559
1560       /* create message content */
1561       if (p_drop) {
1562         p = (char*) p_data;
1563         next = strchr(p, '\n');
1564         while (p) {
1565           if (next) *next=0;
1566           if (strncmp(p,"file:",5) == 0 ) {
1567             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1568             if (len) {
1569               TRACE("drop file %s as %s\n", p+5, p_drop);
1570               p_drop += len+1;
1571             } else {
1572               WARN("can't convert file %s to dos name\n", p+5);
1573             }
1574           } else {
1575             WARN("unknown mime type %s\n", p);
1576           }
1577           if (next) {
1578             *next = '\n';
1579             p = next + 1;
1580             next = strchr(p, '\n');
1581           } else {
1582             p = NULL;
1583           }
1584           *p_drop = '\0';
1585         }
1586
1587         GlobalUnlock(hDrop);
1588         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1589       }
1590     }
1591     if( p_data ) XFree(p_data);
1592   }
1593 }
1594
1595
1596 /**********************************************************************
1597  *              handle_xembed_protocol
1598  */
1599 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1600 {
1601     struct x11drv_win_data *data = get_win_data( hwnd );
1602
1603     if (!data) return;
1604
1605     switch (event->data.l[1])
1606     {
1607     case XEMBED_EMBEDDED_NOTIFY:
1608         TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1609         data->embedder = event->data.l[3];
1610         break;
1611     default:
1612         TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1613                hwnd, event->window, event->data.l[1], event->data.l[2] );
1614         break;
1615     }
1616     release_win_data( data );
1617 }
1618
1619
1620 /**********************************************************************
1621  *              handle_dnd_protocol
1622  */
1623 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1624 {
1625     Window root, child;
1626     int root_x, root_y, child_x, child_y;
1627     unsigned int u;
1628
1629     /* query window (drag&drop event contains only drag window) */
1630     XQueryPointer( event->display, root_window, &root, &child,
1631                    &root_x, &root_y, &child_x, &child_y, &u);
1632     if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1633     if (!hwnd) return;
1634     if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1635         EVENT_DropFromOffiX(hwnd, event);
1636     else if (event->data.l[0] == DndURL)
1637         EVENT_DropURLs(hwnd, event);
1638 }
1639
1640
1641 struct client_message_handler
1642 {
1643     int    atom;                                  /* protocol atom */
1644     void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1645 };
1646
1647 static const struct client_message_handler client_messages[] =
1648 {
1649     { XATOM_MANAGER,      handle_manager_message },
1650     { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1651     { XATOM__XEMBED,      handle_xembed_protocol },
1652     { XATOM_DndProtocol,  handle_dnd_protocol },
1653     { XATOM_XdndEnter,    X11DRV_XDND_EnterEvent },
1654     { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1655     { XATOM_XdndDrop,     X11DRV_XDND_DropEvent },
1656     { XATOM_XdndLeave,    X11DRV_XDND_LeaveEvent }
1657 };
1658
1659
1660 /**********************************************************************
1661  *           X11DRV_ClientMessage
1662  */
1663 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1664 {
1665     XClientMessageEvent *event = &xev->xclient;
1666     unsigned int i;
1667
1668     if (!hwnd) return;
1669
1670     if (event->format != 32)
1671     {
1672         WARN( "Don't know how to handle format %d\n", event->format );
1673         return;
1674     }
1675
1676     for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1677     {
1678         if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1679         {
1680             client_messages[i].handler( hwnd, event );
1681             return;
1682         }
1683     }
1684     TRACE( "no handler found for %ld\n", event->message_type );
1685 }