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