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