mmdevapi/tests: Add tests for volume control interfaces.
[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) != 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         if (prev->xany.window == next->xany.window && next->type == MotionNotify)
314         {
315             TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
316             return MERGE_DISCARD;
317         }
318         break;
319 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
320     case GenericEvent:
321         if (prev->xcookie.extension != xinput2_opcode) break;
322         if (prev->xcookie.evtype != XI_RawMotion) break;
323         switch (next->type)
324         {
325         case MotionNotify:
326             if (next->xany.window == x11drv_thread_data()->clip_window)
327             {
328                 TRACE( "ignoring MotionNotify for clip window\n" );
329                 return MERGE_IGNORE;
330             }
331             break;
332         case GenericEvent:
333             if (next->xcookie.extension != xinput2_opcode) break;
334             if (next->xcookie.evtype != XI_RawMotion) break;
335             return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
336         }
337         break;
338 #endif
339     }
340     return MERGE_HANDLE;
341 }
342
343
344 /***********************************************************************
345  *           call_event_handler
346  */
347 static inline void call_event_handler( Display *display, XEvent *event )
348 {
349     HWND hwnd;
350     XEvent *prev;
351     struct x11drv_thread_data *thread_data;
352
353     if (!handlers[event->type])
354     {
355         TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
356         return;  /* no handler, ignore it */
357     }
358
359     if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
360         hwnd = 0;  /* not for a registered window */
361     if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
362
363     TRACE( "%lu %s for hwnd/window %p/%lx\n",
364            event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
365     wine_tsx11_unlock();
366     thread_data = x11drv_thread_data();
367     prev = thread_data->current_event;
368     thread_data->current_event = event;
369     handlers[event->type]( hwnd, event );
370     thread_data->current_event = prev;
371     wine_tsx11_lock();
372 }
373
374
375 /***********************************************************************
376  *           process_events
377  */
378 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
379 {
380     XEvent event, prev_event;
381     int count = 0;
382     enum event_merge_action action = MERGE_DISCARD;
383
384     prev_event.type = 0;
385     wine_tsx11_lock();
386     while (XCheckIfEvent( display, &event, filter, (char *)arg ))
387     {
388         count++;
389         if (XFilterEvent( &event, None ))
390         {
391             /*
392              * SCIM on linux filters key events strangely. It does not filter the
393              * KeyPress events for these keys however it does filter the
394              * KeyRelease events. This causes wine to become very confused as
395              * to the keyboard state.
396              *
397              * We need to let those KeyRelease events be processed so that the
398              * keyboard state is correct.
399              */
400             if (event.type == KeyRelease)
401             {
402                 KeySym keysym = 0;
403                 XKeyEvent *keyevent = &event.xkey;
404
405                 XLookupString(keyevent, NULL, 0, &keysym, NULL);
406                 if (!(keysym == XK_Shift_L ||
407                     keysym == XK_Shift_R ||
408                     keysym == XK_Control_L ||
409                     keysym == XK_Control_R ||
410                     keysym == XK_Alt_R ||
411                     keysym == XK_Alt_L ||
412                     keysym == XK_Meta_R ||
413                     keysym == XK_Meta_L))
414                         continue; /* not a key we care about, ignore it */
415             }
416             else
417                 continue;  /* filtered, ignore it */
418         }
419         get_event_data( &event );
420         if (prev_event.type) action = merge_events( &prev_event, &event );
421         switch( action )
422         {
423         case MERGE_HANDLE:  /* handle prev, keep new */
424             call_event_handler( display, &prev_event );
425             /* fall through */
426         case MERGE_DISCARD:  /* discard prev, keep new */
427             free_event_data( &prev_event );
428             prev_event = event;
429             break;
430         case MERGE_KEEP:  /* handle new, keep prev for future merging */
431             call_event_handler( display, &event );
432             /* fall through */
433         case MERGE_IGNORE: /* ignore new, keep prev for future merging */
434             free_event_data( &event );
435             break;
436         }
437     }
438     if (prev_event.type) call_event_handler( display, &prev_event );
439     free_event_data( &prev_event );
440     XFlush( gdi_display );
441     wine_tsx11_unlock();
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     if (!(style & WS_VISIBLE)) return FALSE;
521     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
522     if (style & WS_MINIMIZE) return FALSE;
523     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
524     if (hwnd == GetDesktopWindow()) return FALSE;
525     return !(style & WS_DISABLED);
526 }
527
528
529 /**********************************************************************
530  *              set_focus
531  */
532 static void set_focus( Display *display, HWND hwnd, Time time )
533 {
534     HWND focus;
535     Window win;
536     GUITHREADINFO threadinfo;
537
538     TRACE( "setting foreground window to %p\n", hwnd );
539     SetForegroundWindow( hwnd );
540
541     threadinfo.cbSize = sizeof(threadinfo);
542     GetGUIThreadInfo(0, &threadinfo);
543     focus = threadinfo.hwndFocus;
544     if (!focus) focus = threadinfo.hwndActive;
545     if (focus) focus = GetAncestor( focus, GA_ROOT );
546     win = X11DRV_get_whole_window(focus);
547
548     if (win)
549     {
550         TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
551         wine_tsx11_lock();
552         XSetInputFocus( display, win, RevertToParent, time );
553         wine_tsx11_unlock();
554     }
555 }
556
557
558 /**********************************************************************
559  *              handle_manager_message
560  */
561 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
562 {
563     if (hwnd != GetDesktopWindow()) return;
564     if (systray_atom && event->data.l[1] == systray_atom)
565         change_systray_owner( event->display, event->data.l[2] );
566 }
567
568
569 /**********************************************************************
570  *              handle_wm_protocols
571  */
572 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
573 {
574     Atom protocol = (Atom)event->data.l[0];
575     Time event_time = (Time)event->data.l[1];
576
577     if (!protocol) return;
578
579     if (protocol == x11drv_atom(WM_DELETE_WINDOW))
580     {
581         update_user_time( event_time );
582
583         if (hwnd == GetDesktopWindow())
584         {
585             /* The desktop window does not have a close button that we can
586              * pretend to click. Therefore, we simply send it a close command. */
587             SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
588             return;
589         }
590
591         /* Ignore the delete window request if the window has been disabled
592          * and we are in managed mode. This is to disallow applications from
593          * being closed by the window manager while in a modal state.
594          */
595         if (IsWindowEnabled(hwnd))
596         {
597             HMENU hSysMenu;
598
599             if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
600             hSysMenu = GetSystemMenu(hwnd, FALSE);
601             if (hSysMenu)
602             {
603                 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
604                 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
605                     return;
606             }
607             if (GetActiveWindow() != hwnd)
608             {
609                 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
610                                            (WPARAM)GetAncestor( hwnd, GA_ROOT ),
611                                            MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
612                 switch(ma)
613                 {
614                     case MA_NOACTIVATEANDEAT:
615                     case MA_ACTIVATEANDEAT:
616                         return;
617                     case MA_NOACTIVATE:
618                         break;
619                     case MA_ACTIVATE:
620                     case 0:
621                         SetActiveWindow(hwnd);
622                         break;
623                     default:
624                         WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
625                         break;
626                 }
627             }
628
629             PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
630         }
631     }
632     else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
633     {
634         HWND last_focus = x11drv_thread_data()->last_focus;
635
636         TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
637                hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
638                GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
639
640         if (can_activate_window(hwnd))
641         {
642             /* simulate a mouse click on the caption to find out
643              * whether the window wants to be activated */
644             LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
645                                        (WPARAM)GetAncestor( hwnd, GA_ROOT ),
646                                        MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
647             if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
648             {
649                 set_focus( event->display, hwnd, event_time );
650                 return;
651             }
652         }
653         else if (hwnd == GetDesktopWindow())
654         {
655             hwnd = GetForegroundWindow();
656             if (!hwnd) hwnd = last_focus;
657             if (!hwnd) hwnd = GetDesktopWindow();
658             set_focus( event->display, hwnd, event_time );
659             return;
660         }
661         /* try to find some other window to give the focus to */
662         hwnd = GetFocus();
663         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
664         if (!hwnd) hwnd = GetActiveWindow();
665         if (!hwnd) hwnd = last_focus;
666         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
667     }
668     else if (protocol == x11drv_atom(_NET_WM_PING))
669     {
670       XClientMessageEvent xev;
671       xev = *event;
672       
673       TRACE("NET_WM Ping\n");
674       wine_tsx11_lock();
675       xev.window = DefaultRootWindow(xev.display);
676       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
677       wine_tsx11_unlock();
678       /* this line is semi-stolen from gtk2 */
679       TRACE("NET_WM Pong\n");
680     }
681 }
682
683
684 static const char * const focus_details[] =
685 {
686     "NotifyAncestor",
687     "NotifyVirtual",
688     "NotifyInferior",
689     "NotifyNonlinear",
690     "NotifyNonlinearVirtual",
691     "NotifyPointer",
692     "NotifyPointerRoot",
693     "NotifyDetailNone"
694 };
695
696 /**********************************************************************
697  *              X11DRV_FocusIn
698  */
699 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
700 {
701     XFocusChangeEvent *event = &xev->xfocus;
702     XIC xic;
703
704     if (!hwnd) return;
705
706     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
707
708     if (event->detail == NotifyPointer) return;
709
710     if ((xic = X11DRV_get_ic( hwnd )))
711     {
712         wine_tsx11_lock();
713         XSetICFocus( xic );
714         wine_tsx11_unlock();
715     }
716     if (use_take_focus) return;  /* ignore FocusIn if we are using take focus */
717
718     if (!can_activate_window(hwnd))
719     {
720         HWND hwnd = GetFocus();
721         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
722         if (!hwnd) hwnd = GetActiveWindow();
723         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
724         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
725     }
726     else SetForegroundWindow( hwnd );
727 }
728
729
730 /**********************************************************************
731  *              X11DRV_FocusOut
732  *
733  * Note: only top-level windows get FocusOut events.
734  */
735 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
736 {
737     XFocusChangeEvent *event = &xev->xfocus;
738     HWND hwnd_tmp;
739     Window focus_win;
740     int revert;
741     XIC xic;
742
743     if (!hwnd)
744     {
745         if (event->detail == NotifyPointer && event->window == x11drv_thread_data()->clip_window)
746         {
747             TRACE( "clip window lost focus\n" );
748             ungrab_clipping_window();
749             ClipCursor( NULL );  /* make sure the clip rectangle is reset too */
750         }
751         return;
752     }
753
754     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
755
756     if (event->detail == NotifyPointer) return;
757     if (ximInComposeMode) return;
758
759     x11drv_thread_data()->last_focus = hwnd;
760     if ((xic = X11DRV_get_ic( hwnd )))
761     {
762         wine_tsx11_lock();
763         XUnsetICFocus( xic );
764         wine_tsx11_unlock();
765     }
766     if (hwnd != GetForegroundWindow()) return;
767     if (root_window != DefaultRootWindow(event->display)) return;
768     SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
769
770     /* don't reset the foreground window, if the window which is
771        getting the focus is a Wine window */
772
773     wine_tsx11_lock();
774     XGetInputFocus( event->display, &focus_win, &revert );
775     if (focus_win)
776     {
777         if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
778             focus_win = 0;
779     }
780     wine_tsx11_unlock();
781
782     if (!focus_win)
783     {
784         /* Abey : 6-Oct-99. Check again if the focus out window is the
785            Foreground window, because in most cases the messages sent
786            above must have already changed the foreground window, in which
787            case we don't have to change the foreground window to 0 */
788         if (hwnd == GetForegroundWindow())
789         {
790             TRACE( "lost focus, setting fg to desktop\n" );
791             SetForegroundWindow( GetDesktopWindow() );
792         }
793     }
794 }
795
796
797 /***********************************************************************
798  *           X11DRV_Expose
799  */
800 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
801 {
802     XExposeEvent *event = &xev->xexpose;
803     RECT rect;
804     struct x11drv_win_data *data;
805     int flags = RDW_INVALIDATE | RDW_ERASE;
806
807     TRACE( "win %p (%lx) %d,%d %dx%d\n",
808            hwnd, event->window, event->x, event->y, event->width, event->height );
809
810     if (!(data = X11DRV_get_win_data( hwnd ))) return;
811
812     rect.left   = event->x;
813     rect.top    = event->y;
814     rect.right  = event->x + event->width;
815     rect.bottom = event->y + event->height;
816     if (event->window == data->whole_window)
817     {
818         OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
819                     data->whole_rect.top - data->client_rect.top );
820         flags |= RDW_FRAME;
821     }
822
823     if (event->window != root_window)
824     {
825         if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
826             mirror_rect( &data->client_rect, &rect );
827
828         SERVER_START_REQ( update_window_zorder )
829         {
830             req->window      = wine_server_user_handle( hwnd );
831             req->rect.left   = rect.left;
832             req->rect.top    = rect.top;
833             req->rect.right  = rect.right;
834             req->rect.bottom = rect.bottom;
835             wine_server_call( req );
836         }
837         SERVER_END_REQ;
838
839         flags |= RDW_ALLCHILDREN;
840     }
841     else OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
842
843     RedrawWindow( hwnd, &rect, 0, flags );
844 }
845
846
847 /**********************************************************************
848  *              X11DRV_MapNotify
849  */
850 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
851 {
852     struct x11drv_win_data *data;
853
854     if (event->xany.window == x11drv_thread_data()->clip_window)
855     {
856         clipping_cursor = 1;
857         return;
858     }
859     if (!(data = X11DRV_get_win_data( hwnd ))) return;
860     if (!data->mapped || data->embedded) return;
861
862     if (!data->managed)
863     {
864         HWND hwndFocus = GetFocus();
865         if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
866     }
867 }
868
869
870 /**********************************************************************
871  *              X11DRV_UnmapNotify
872  */
873 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
874 {
875     if (event->xany.window == x11drv_thread_data()->clip_window) clipping_cursor = 0;
876 }
877
878
879 /***********************************************************************
880  *     is_net_wm_state_maximized
881  */
882 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
883 {
884     Atom type, *state;
885     int format, ret = 0;
886     unsigned long i, count, remaining;
887
888     if (!data->whole_window) return FALSE;
889
890     wine_tsx11_lock();
891     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
892                              65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
893                              &remaining, (unsigned char **)&state ))
894     {
895         if (type == XA_ATOM && format == 32)
896         {
897             for (i = 0; i < count; i++)
898             {
899                 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
900                     state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
901                     ret++;
902             }
903         }
904         XFree( state );
905     }
906     wine_tsx11_unlock();
907     return (ret == 2);
908 }
909
910
911 /***********************************************************************
912  *           X11DRV_ReparentNotify
913  */
914 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
915 {
916     XReparentEvent *event = &xev->xreparent;
917     struct x11drv_win_data *data;
918     HWND parent, old_parent;
919     DWORD style;
920
921     if (!(data = X11DRV_get_win_data( hwnd ))) return;
922     if (!data->embedded) return;
923
924     if (data->whole_window)
925     {
926         if (event->parent == root_window)
927         {
928             TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
929             data->embedder = 0;
930             SendMessageW( hwnd, WM_CLOSE, 0, 0 );
931             return;
932         }
933         data->embedder = event->parent;
934     }
935
936     TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
937
938     style = GetWindowLongW( hwnd, GWL_STYLE );
939     if (event->parent == root_window)
940     {
941         parent = GetDesktopWindow();
942         style = (style & ~WS_CHILD) | WS_POPUP;
943     }
944     else
945     {
946         if (!(parent = create_foreign_window( event->display, event->parent ))) return;
947         style = (style & ~WS_POPUP) | WS_CHILD;
948     }
949
950     ShowWindow( hwnd, SW_HIDE );
951     old_parent = SetParent( hwnd, parent );
952     SetWindowLongW( hwnd, GWL_STYLE, style );
953     SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
954                   SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
955                   ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
956
957     /* make old parent destroy itself if it no longer has children */
958     if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
959 }
960
961
962 /***********************************************************************
963  *              X11DRV_ConfigureNotify
964  */
965 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
966 {
967     XConfigureEvent *event = &xev->xconfigure;
968     struct x11drv_win_data *data;
969     RECT rect;
970     UINT flags;
971     HWND parent;
972     BOOL root_coords;
973     int cx, cy, x = event->x, y = event->y;
974
975     if (!hwnd) return;
976     if (!(data = X11DRV_get_win_data( hwnd ))) return;
977     if (!data->mapped || data->iconic) return;
978     if (data->whole_window && !data->managed) return;
979     /* ignore synthetic events on foreign windows */
980     if (event->send_event && !data->whole_window) return;
981     if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
982     {
983         TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
984                hwnd, data->whole_window, event->x, event->y, event->width, event->height,
985                event->serial, data->configure_serial );
986         return;
987     }
988
989     /* Get geometry */
990
991     parent = GetAncestor( hwnd, GA_PARENT );
992     root_coords = event->send_event;  /* synthetic events are always in root coords */
993
994     if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
995     {
996         Window child;
997         wine_tsx11_lock();
998         XTranslateCoordinates( event->display, event->window, root_window,
999                                0, 0, &x, &y, &child );
1000         wine_tsx11_unlock();
1001         root_coords = TRUE;
1002     }
1003     rect.left   = x;
1004     rect.top    = y;
1005     rect.right  = x + event->width;
1006     rect.bottom = y + event->height;
1007     if (root_coords) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
1008     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1009            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1010            event->x, event->y, event->width, event->height );
1011
1012     X11DRV_X_to_window_rect( data, &rect );
1013     if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1014
1015     /* Compare what has changed */
1016
1017     x     = rect.left;
1018     y     = rect.top;
1019     cx    = rect.right - rect.left;
1020     cy    = rect.bottom - rect.top;
1021     flags = SWP_NOACTIVATE | SWP_NOZORDER;
1022
1023     if (!data->whole_window) flags |= SWP_NOCOPYBITS;  /* we can't copy bits of foreign windows */
1024
1025     if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1026     else
1027         TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1028                hwnd, data->window_rect.left, data->window_rect.top, x, y );
1029
1030     if ((data->window_rect.right - data->window_rect.left == cx &&
1031          data->window_rect.bottom - data->window_rect.top == cy) ||
1032         (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
1033     {
1034         if (flags & SWP_NOMOVE)  /* if nothing changed, don't do anything */
1035         {
1036             TRACE( "Nothing has changed, ignoring event\n" );
1037             return;
1038         }
1039         flags |= SWP_NOSIZE;
1040     }
1041     else
1042         TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1043                hwnd, data->window_rect.right - data->window_rect.left,
1044                data->window_rect.bottom - data->window_rect.top, cx, cy );
1045
1046     if (is_net_wm_state_maximized( event->display, data ))
1047     {
1048         if (!IsZoomed( data->hwnd ))
1049         {
1050             TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1051             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1052             return;
1053         }
1054     }
1055     else
1056     {
1057         if (IsZoomed( data->hwnd ))
1058         {
1059             TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1060             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1061             return;
1062         }
1063     }
1064
1065     SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1066 }
1067
1068
1069 /**********************************************************************
1070  *           X11DRV_GravityNotify
1071  */
1072 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1073 {
1074     XGravityEvent *event = &xev->xgravity;
1075     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1076     RECT rect;
1077
1078     if (!data || data->whole_window) return;  /* only handle this for foreign windows */
1079
1080     rect.left   = event->x;
1081     rect.top    = event->y;
1082     rect.right  = rect.left + data->whole_rect.right - data->whole_rect.left;
1083     rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1084
1085     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1086            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1087            event->x, event->y );
1088
1089     X11DRV_X_to_window_rect( data, &rect );
1090
1091     if (data->window_rect.left != rect.left || data ->window_rect.top != rect.top)
1092         SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1093                       SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1094 }
1095
1096
1097 /***********************************************************************
1098  *           get_window_wm_state
1099  */
1100 static int get_window_wm_state( Display *display, struct x11drv_win_data *data )
1101 {
1102     struct
1103     {
1104         CARD32 state;
1105         XID     icon;
1106     } *state;
1107     Atom type;
1108     int format, ret = -1;
1109     unsigned long count, remaining;
1110
1111     wine_tsx11_lock();
1112     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
1113                              sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1114                              &type, &format, &count, &remaining, (unsigned char **)&state ))
1115     {
1116         if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1117             ret = state->state;
1118         XFree( state );
1119     }
1120     wine_tsx11_unlock();
1121     return ret;
1122 }
1123
1124
1125 /***********************************************************************
1126  *           handle_wm_state_notify
1127  *
1128  * Handle a PropertyNotify for WM_STATE.
1129  */
1130 static void handle_wm_state_notify( struct x11drv_win_data *data, XPropertyEvent *event,
1131                                     BOOL update_window )
1132 {
1133     DWORD style;
1134
1135     switch(event->state)
1136     {
1137     case PropertyDelete:
1138         TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1139         data->wm_state = WithdrawnState;
1140         break;
1141     case PropertyNewValue:
1142         {
1143             int old_state = data->wm_state;
1144             int new_state = get_window_wm_state( event->display, data );
1145             if (new_state != -1 && new_state != data->wm_state)
1146             {
1147                 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1148                        data->hwnd, data->whole_window, new_state, old_state );
1149                 data->wm_state = new_state;
1150                 /* ignore the initial state transition out of withdrawn state */
1151                 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1152                 if (!old_state) return;
1153             }
1154         }
1155         break;
1156     }
1157
1158     if (!update_window || !data->managed || !data->mapped) return;
1159
1160     style = GetWindowLongW( data->hwnd, GWL_STYLE );
1161
1162     if (data->iconic && data->wm_state == NormalState)  /* restore window */
1163     {
1164         data->iconic = FALSE;
1165         if (is_net_wm_state_maximized( event->display, data ))
1166         {
1167             if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1168             {
1169                 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1170                 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1171             }
1172             else TRACE( "not restoring to max win %p/%lx style %08x\n",
1173                         data->hwnd, data->whole_window, style );
1174         }
1175         else if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1176         {
1177             TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1178             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1179         }
1180         else TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1181     }
1182     else if (!data->iconic && data->wm_state == IconicState)
1183     {
1184         data->iconic = TRUE;
1185         if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1186         {
1187             TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1188             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1189         }
1190         else TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1191     }
1192 }
1193
1194
1195 /***********************************************************************
1196  *           X11DRV_PropertyNotify
1197  */
1198 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1199 {
1200     XPropertyEvent *event = &xev->xproperty;
1201     struct x11drv_win_data *data;
1202
1203     if (!hwnd) return;
1204     if (!(data = X11DRV_get_win_data( hwnd ))) return;
1205
1206     if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( data, event, TRUE );
1207 }
1208
1209
1210 /* event filter to wait for a WM_STATE change notification on a window */
1211 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1212 {
1213     if (event->xany.window != (Window)arg) return 0;
1214     return (event->type == DestroyNotify ||
1215             (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1216 }
1217
1218 /***********************************************************************
1219  *           wait_for_withdrawn_state
1220  */
1221 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data, BOOL set )
1222 {
1223     DWORD end = GetTickCount() + 2000;
1224
1225     if (!data->managed) return;
1226
1227     TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
1228            data->hwnd, data->whole_window, set ? "" : "not " );
1229
1230     while (data->whole_window && ((data->wm_state == WithdrawnState) == !set))
1231     {
1232         XEvent event;
1233         int count = 0;
1234
1235         wine_tsx11_lock();
1236         while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)data->whole_window ))
1237         {
1238             count++;
1239             if (XFilterEvent( &event, None )) continue;  /* filtered, ignore it */
1240             if (event.type == DestroyNotify) call_event_handler( display, &event );
1241             else
1242             {
1243                 wine_tsx11_unlock();
1244                 handle_wm_state_notify( data, &event.xproperty, FALSE );
1245                 wine_tsx11_lock();
1246             }
1247         }
1248         wine_tsx11_unlock();
1249
1250         if (!count)
1251         {
1252             struct pollfd pfd;
1253             int timeout = end - GetTickCount();
1254
1255             pfd.fd = ConnectionNumber(display);
1256             pfd.events = POLLIN;
1257             if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1258             {
1259                 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
1260                 break;
1261             }
1262         }
1263     }
1264     TRACE( "window %p/%lx state now %d\n", data->hwnd, data->whole_window, data->wm_state );
1265 }
1266
1267
1268 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1269 {
1270     RECT tempRect;
1271
1272     if (!IsWindowEnabled(hQueryWnd)) return 0;
1273     
1274     GetWindowRect(hQueryWnd, &tempRect);
1275
1276     if(!PtInRect(&tempRect, *lpPt)) return 0;
1277
1278     if (!IsIconic( hQueryWnd ))
1279     {
1280         POINT pt = *lpPt;
1281         ScreenToClient( hQueryWnd, &pt );
1282         GetClientRect( hQueryWnd, &tempRect );
1283
1284         if (PtInRect( &tempRect, pt))
1285         {
1286             HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1287             if (ret && ret != hQueryWnd)
1288             {
1289                 ret = find_drop_window( ret, lpPt );
1290                 if (ret) return ret;
1291             }
1292         }
1293     }
1294
1295     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1296     
1297     ScreenToClient(hQueryWnd, lpPt);
1298
1299     return hQueryWnd;
1300 }
1301
1302 /**********************************************************************
1303  *           EVENT_DropFromOffix
1304  *
1305  * don't know if it still works (last Changelog is from 96/11/04)
1306  */
1307 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1308 {
1309     struct x11drv_win_data *data;
1310     unsigned long       data_length;
1311     unsigned long       aux_long;
1312     unsigned char*      p_data = NULL;
1313     Atom atom_aux;
1314     int                 x, y, dummy;
1315     BOOL                bAccept;
1316     Window              win, w_aux_root, w_aux_child;
1317
1318     win = X11DRV_get_whole_window(hWnd);
1319     wine_tsx11_lock();
1320     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1321                    &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1322     x += virtual_screen_rect.left;
1323     y += virtual_screen_rect.top;
1324     wine_tsx11_unlock();
1325
1326     if (!(data = X11DRV_get_win_data( hWnd ))) return;
1327
1328     /* find out drop point and drop window */
1329     if( x < 0 || y < 0 ||
1330         x > (data->whole_rect.right - data->whole_rect.left) ||
1331         y > (data->whole_rect.bottom - data->whole_rect.top) )
1332     {   
1333         bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1334         x = 0;
1335         y = 0; 
1336     }
1337     else
1338     {
1339         POINT   pt = { x, y };
1340         HWND    hwndDrop = find_drop_window( hWnd, &pt );
1341         if (hwndDrop)
1342         {
1343             x = pt.x;
1344             y = pt.y;
1345             bAccept = TRUE;
1346         }
1347         else
1348         {
1349             bAccept = FALSE;
1350         }
1351     }
1352
1353     if (!bAccept) return;
1354
1355     wine_tsx11_lock();
1356     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1357                         x11drv_atom(DndSelection), 0, 65535, FALSE,
1358                         AnyPropertyType, &atom_aux, &dummy,
1359                         &data_length, &aux_long, &p_data);
1360     wine_tsx11_unlock();
1361
1362     if( !aux_long && p_data)  /* don't bother if > 64K */
1363     {
1364         char *p = (char *)p_data;
1365         char *p_drop;
1366
1367         aux_long = 0;
1368         while( *p )  /* calculate buffer size */
1369         {
1370             INT len = GetShortPathNameA( p, NULL, 0 );
1371             if (len) aux_long += len + 1;
1372             p += strlen(p) + 1;
1373         }
1374         if( aux_long && aux_long < 65535 )
1375         {
1376             HDROP                 hDrop;
1377             DROPFILES *lpDrop;
1378
1379             aux_long += sizeof(DROPFILES) + 1;
1380             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1381             lpDrop = GlobalLock( hDrop );
1382
1383             if( lpDrop )
1384             {
1385                 lpDrop->pFiles = sizeof(DROPFILES);
1386                 lpDrop->pt.x = x;
1387                 lpDrop->pt.y = y;
1388                 lpDrop->fNC = FALSE;
1389                 lpDrop->fWide = FALSE;
1390                 p_drop = (char *)(lpDrop + 1);
1391                 p = (char *)p_data;
1392                 while(*p)
1393                 {
1394                     if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1395                         p_drop += strlen( p_drop ) + 1;
1396                     p += strlen(p) + 1;
1397                 }
1398                 *p_drop = '\0';
1399                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1400             }
1401         }
1402     }
1403     wine_tsx11_lock();
1404     if( p_data ) XFree(p_data);
1405     wine_tsx11_unlock();
1406 }
1407
1408 /**********************************************************************
1409  *           EVENT_DropURLs
1410  *
1411  * drop items are separated by \n
1412  * each item is prefixed by its mime type
1413  *
1414  * event->data.l[3], event->data.l[4] contains drop x,y position
1415  */
1416 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1417 {
1418   struct x11drv_win_data *win_data;
1419   unsigned long data_length;
1420   unsigned long aux_long, drop_len = 0;
1421   unsigned char *p_data = NULL; /* property data */
1422   char          *p_drop = NULL;
1423   char          *p, *next;
1424   int           x, y;
1425   DROPFILES *lpDrop;
1426   HDROP hDrop;
1427   union {
1428     Atom        atom_aux;
1429     int         i;
1430     Window      w_aux;
1431     unsigned int u;
1432   }             u; /* unused */
1433
1434   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1435
1436   wine_tsx11_lock();
1437   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1438                       x11drv_atom(DndSelection), 0, 65535, FALSE,
1439                       AnyPropertyType, &u.atom_aux, &u.i,
1440                       &data_length, &aux_long, &p_data);
1441   wine_tsx11_unlock();
1442   if (aux_long)
1443     WARN("property too large, truncated!\n");
1444   TRACE("urls=%s\n", p_data);
1445
1446   if( !aux_long && p_data) {    /* don't bother if > 64K */
1447     /* calculate length */
1448     p = (char*) p_data;
1449     next = strchr(p, '\n');
1450     while (p) {
1451       if (next) *next=0;
1452       if (strncmp(p,"file:",5) == 0 ) {
1453         INT len = GetShortPathNameA( p+5, NULL, 0 );
1454         if (len) drop_len += len + 1;
1455       }
1456       if (next) {
1457         *next = '\n';
1458         p = next + 1;
1459         next = strchr(p, '\n');
1460       } else {
1461         p = NULL;
1462       }
1463     }
1464
1465     if( drop_len && drop_len < 65535 ) {
1466       wine_tsx11_lock();
1467       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1468                      &x, &y, &u.i, &u.i, &u.u);
1469       x += virtual_screen_rect.left;
1470       y += virtual_screen_rect.top;
1471       wine_tsx11_unlock();
1472
1473       drop_len += sizeof(DROPFILES) + 1;
1474       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1475       lpDrop = GlobalLock( hDrop );
1476
1477       if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
1478       {
1479           lpDrop->pFiles = sizeof(DROPFILES);
1480           lpDrop->pt.x = x;
1481           lpDrop->pt.y = y;
1482           lpDrop->fNC =
1483             ( x < (win_data->client_rect.left - win_data->whole_rect.left)  ||
1484               y < (win_data->client_rect.top - win_data->whole_rect.top)    ||
1485               x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1486               y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1487           lpDrop->fWide = FALSE;
1488           p_drop = (char*)(lpDrop + 1);
1489       }
1490
1491       /* create message content */
1492       if (p_drop) {
1493         p = (char*) p_data;
1494         next = strchr(p, '\n');
1495         while (p) {
1496           if (next) *next=0;
1497           if (strncmp(p,"file:",5) == 0 ) {
1498             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1499             if (len) {
1500               TRACE("drop file %s as %s\n", p+5, p_drop);
1501               p_drop += len+1;
1502             } else {
1503               WARN("can't convert file %s to dos name\n", p+5);
1504             }
1505           } else {
1506             WARN("unknown mime type %s\n", p);
1507           }
1508           if (next) {
1509             *next = '\n';
1510             p = next + 1;
1511             next = strchr(p, '\n');
1512           } else {
1513             p = NULL;
1514           }
1515           *p_drop = '\0';
1516         }
1517
1518         GlobalUnlock(hDrop);
1519         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1520       }
1521     }
1522     wine_tsx11_lock();
1523     if( p_data ) XFree(p_data);
1524     wine_tsx11_unlock();
1525   }
1526 }
1527
1528
1529 /**********************************************************************
1530  *              handle_xembed_protocol
1531  */
1532 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1533 {
1534     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1535
1536     if (!data) return;
1537
1538     switch (event->data.l[1])
1539     {
1540     case XEMBED_EMBEDDED_NOTIFY:
1541         TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1542         data->embedder = event->data.l[3];
1543         break;
1544     default:
1545         TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1546                hwnd, event->window, event->data.l[1], event->data.l[2] );
1547         break;
1548     }
1549 }
1550
1551
1552 /**********************************************************************
1553  *              handle_dnd_protocol
1554  */
1555 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1556 {
1557     Window root, child;
1558     int root_x, root_y, child_x, child_y;
1559     unsigned int u;
1560
1561     /* query window (drag&drop event contains only drag window) */
1562     wine_tsx11_lock();
1563     XQueryPointer( event->display, root_window, &root, &child,
1564                    &root_x, &root_y, &child_x, &child_y, &u);
1565     if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1566     wine_tsx11_unlock();
1567     if (!hwnd) return;
1568     if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1569         EVENT_DropFromOffiX(hwnd, event);
1570     else if (event->data.l[0] == DndURL)
1571         EVENT_DropURLs(hwnd, event);
1572 }
1573
1574
1575 struct client_message_handler
1576 {
1577     int    atom;                                  /* protocol atom */
1578     void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1579 };
1580
1581 static const struct client_message_handler client_messages[] =
1582 {
1583     { XATOM_MANAGER,      handle_manager_message },
1584     { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1585     { XATOM__XEMBED,      handle_xembed_protocol },
1586     { XATOM_DndProtocol,  handle_dnd_protocol },
1587     { XATOM_XdndEnter,    X11DRV_XDND_EnterEvent },
1588     { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1589     { XATOM_XdndDrop,     X11DRV_XDND_DropEvent },
1590     { XATOM_XdndLeave,    X11DRV_XDND_LeaveEvent }
1591 };
1592
1593
1594 /**********************************************************************
1595  *           X11DRV_ClientMessage
1596  */
1597 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1598 {
1599     XClientMessageEvent *event = &xev->xclient;
1600     unsigned int i;
1601
1602     if (!hwnd) return;
1603
1604     if (event->format != 32)
1605     {
1606         WARN( "Don't know how to handle format %d\n", event->format );
1607         return;
1608     }
1609
1610     for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1611     {
1612         if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1613         {
1614             client_messages[i].handler( hwnd, event );
1615             return;
1616         }
1617     }
1618     TRACE( "no handler found for %ld\n", event->message_type );
1619 }