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