wined3d: Use BOOL instead of char in shader_load_constants().
[wine] / dlls / winex11.drv / event.c
1 /*
2  * X11 event driver
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1999 Noel Borthwick
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #ifdef HAVE_POLL_H
25 #include <poll.h>
26 #endif
27 #ifdef HAVE_SYS_POLL_H
28 #include <sys/poll.h>
29 #endif
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
35 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
36 #include <X11/extensions/XInput2.h>
37 #endif
38
39 #include <assert.h>
40 #include <stdarg.h>
41 #include <string.h>
42
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winuser.h"
48 #include "wingdi.h"
49
50 #include "x11drv.h"
51
52 /* avoid conflict with field names in included win32 headers */
53 #undef Status
54 #include "shlobj.h"  /* DROPFILES */
55 #include "shellapi.h"
56
57 #include "wine/server.h"
58 #include "wine/debug.h"
59
60 WINE_DEFAULT_DEBUG_CHANNEL(event);
61
62 extern BOOL ximInComposeMode;
63
64 #define DndNotDnd       -1    /* OffiX drag&drop */
65 #define DndUnknown      0
66 #define DndRawData      1
67 #define DndFile         2
68 #define DndFiles        3
69 #define DndText         4
70 #define DndDir          5
71 #define DndLink         6
72 #define DndExe          7
73
74 #define DndEND          8
75
76 #define DndURL          128   /* KDE drag&drop */
77
78 #define XEMBED_EMBEDDED_NOTIFY        0
79 #define XEMBED_WINDOW_ACTIVATE        1
80 #define XEMBED_WINDOW_DEACTIVATE      2
81 #define XEMBED_REQUEST_FOCUS          3
82 #define XEMBED_FOCUS_IN               4
83 #define XEMBED_FOCUS_OUT              5
84 #define XEMBED_FOCUS_NEXT             6
85 #define XEMBED_FOCUS_PREV             7
86 #define XEMBED_MODALITY_ON            10
87 #define XEMBED_MODALITY_OFF           11
88 #define XEMBED_REGISTER_ACCELERATOR   12
89 #define XEMBED_UNREGISTER_ACCELERATOR 13
90 #define XEMBED_ACTIVATE_ACCELERATOR   14
91
92 Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
93 void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
94
95   /* Event handlers */
96 static void X11DRV_FocusIn( HWND hwnd, XEvent *event );
97 static void X11DRV_FocusOut( HWND hwnd, XEvent *event );
98 static void X11DRV_Expose( HWND hwnd, XEvent *event );
99 static void X11DRV_MapNotify( HWND hwnd, XEvent *event );
100 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
101 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
102 static void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
103 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
104 static void X11DRV_ClientMessage( HWND hwnd, XEvent *event );
105 static void X11DRV_GravityNotify( HWND hwnd, XEvent *event );
106
107 #define MAX_EVENT_HANDLERS 128
108
109 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
110 {
111     NULL,                     /*  0 reserved */
112     NULL,                     /*  1 reserved */
113     X11DRV_KeyEvent,          /*  2 KeyPress */
114     X11DRV_KeyEvent,          /*  3 KeyRelease */
115     X11DRV_ButtonPress,       /*  4 ButtonPress */
116     X11DRV_ButtonRelease,     /*  5 ButtonRelease */
117     X11DRV_MotionNotify,      /*  6 MotionNotify */
118     X11DRV_EnterNotify,       /*  7 EnterNotify */
119     NULL,                     /*  8 LeaveNotify */
120     X11DRV_FocusIn,           /*  9 FocusIn */
121     X11DRV_FocusOut,          /* 10 FocusOut */
122     X11DRV_KeymapNotify,      /* 11 KeymapNotify */
123     X11DRV_Expose,            /* 12 Expose */
124     NULL,                     /* 13 GraphicsExpose */
125     NULL,                     /* 14 NoExpose */
126     NULL,                     /* 15 VisibilityNotify */
127     NULL,                     /* 16 CreateNotify */
128     X11DRV_DestroyNotify,     /* 17 DestroyNotify */
129     X11DRV_UnmapNotify,       /* 18 UnmapNotify */
130     X11DRV_MapNotify,         /* 19 MapNotify */
131     NULL,                     /* 20 MapRequest */
132     X11DRV_ReparentNotify,    /* 21 ReparentNotify */
133     X11DRV_ConfigureNotify,   /* 22 ConfigureNotify */
134     NULL,                     /* 23 ConfigureRequest */
135     X11DRV_GravityNotify,     /* 24 GravityNotify */
136     NULL,                     /* 25 ResizeRequest */
137     NULL,                     /* 26 CirculateNotify */
138     NULL,                     /* 27 CirculateRequest */
139     X11DRV_PropertyNotify,    /* 28 PropertyNotify */
140     X11DRV_SelectionClear,    /* 29 SelectionClear */
141     X11DRV_SelectionRequest,  /* 30 SelectionRequest */
142     NULL,                     /* 31 SelectionNotify */
143     NULL,                     /* 32 ColormapNotify */
144     X11DRV_ClientMessage,     /* 33 ClientMessage */
145     X11DRV_MappingNotify,     /* 34 MappingNotify */
146     X11DRV_GenericEvent       /* 35 GenericEvent */
147 };
148
149 static const char * event_names[MAX_EVENT_HANDLERS] =
150 {
151     NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
152     "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
153     "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
154     "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
155     "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
156     "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
157     "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
158 };
159
160 int xinput2_opcode = 0;
161
162 /* return the name of an X event */
163 static const char *dbgstr_event( int type )
164 {
165     if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
166     return wine_dbg_sprintf( "Unknown event %d", type );
167 }
168
169 static inline void get_event_data( XEvent *event )
170 {
171 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
172     if (event->xany.type != GenericEvent) return;
173     if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
174 #endif
175 }
176
177 static inline void free_event_data( XEvent *event )
178 {
179 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
180     if (event->xany.type != GenericEvent) return;
181     if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
182 #endif
183 }
184
185 /***********************************************************************
186  *           X11DRV_register_event_handler
187  *
188  * Register a handler for a given event type.
189  * If already registered, overwrite the previous handler.
190  */
191 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
192 {
193     assert( type < MAX_EVENT_HANDLERS );
194     assert( !handlers[type] || handlers[type] == handler );
195     handlers[type] = handler;
196     event_names[type] = name;
197     TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
198 }
199
200
201 /***********************************************************************
202  *           filter_event
203  */
204 static Bool filter_event( Display *display, XEvent *event, char *arg )
205 {
206     ULONG_PTR mask = (ULONG_PTR)arg;
207
208     if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
209
210     switch(event->type)
211     {
212     case KeyPress:
213     case KeyRelease:
214     case KeymapNotify:
215     case MappingNotify:
216         return (mask & (QS_KEY|QS_HOTKEY)) != 0;
217     case ButtonPress:
218     case ButtonRelease:
219         return (mask & QS_MOUSEBUTTON) != 0;
220     case MotionNotify:
221     case EnterNotify:
222     case LeaveNotify:
223         return (mask & QS_MOUSEMOVE) != 0;
224     case Expose:
225         return (mask & QS_PAINT) != 0;
226     case FocusIn:
227     case FocusOut:
228     case MapNotify:
229     case UnmapNotify:
230     case ConfigureNotify:
231     case PropertyNotify:
232     case ClientMessage:
233         return (mask & QS_POSTMESSAGE) != 0;
234     default:
235         return (mask & QS_SENDMESSAGE) != 0;
236     }
237 }
238
239
240 enum event_merge_action
241 {
242     MERGE_DISCARD,  /* discard the old event */
243     MERGE_HANDLE,   /* handle the old event */
244     MERGE_KEEP,     /* keep the old event for future merging */
245     MERGE_IGNORE    /* ignore the new event, keep the old one */
246 };
247
248 /***********************************************************************
249  *           merge_raw_motion_events
250  */
251 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
252 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
253 {
254     int i, j, k;
255     unsigned char mask;
256
257     if (!prev->valuators.mask_len) return MERGE_HANDLE;
258     if (!next->valuators.mask_len) return MERGE_HANDLE;
259
260     mask = prev->valuators.mask[0] | next->valuators.mask[0];
261     if (mask == next->valuators.mask[0])  /* keep next */
262     {
263         for (i = j = k = 0; i < 8; i++)
264         {
265             if (XIMaskIsSet( prev->valuators.mask, i ))
266                 next->valuators.values[j] += prev->valuators.values[k++];
267             if (XIMaskIsSet( next->valuators.mask, i )) j++;
268         }
269         TRACE( "merging duplicate GenericEvent\n" );
270         return MERGE_DISCARD;
271     }
272     if (mask == prev->valuators.mask[0])  /* keep prev */
273     {
274         for (i = j = k = 0; i < 8; i++)
275         {
276             if (XIMaskIsSet( next->valuators.mask, i ))
277                 prev->valuators.values[j] += next->valuators.values[k++];
278             if (XIMaskIsSet( prev->valuators.mask, i )) j++;
279         }
280         TRACE( "merging duplicate GenericEvent\n" );
281         return MERGE_IGNORE;
282     }
283     /* can't merge events with disjoint masks */
284     return MERGE_HANDLE;
285 }
286 #endif
287
288 /***********************************************************************
289  *           merge_events
290  *
291  * Try to merge 2 consecutive events.
292  */
293 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
294 {
295     switch (prev->type)
296     {
297     case ConfigureNotify:
298         switch (next->type)
299         {
300         case ConfigureNotify:
301             if (prev->xany.window == next->xany.window)
302             {
303                 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
304                 return MERGE_DISCARD;
305             }
306             break;
307         case Expose:
308         case PropertyNotify:
309             return MERGE_KEEP;
310         }
311         break;
312     case MotionNotify:
313         switch (next->type)
314         {
315         case MotionNotify:
316             if (prev->xany.window == next->xany.window)
317             {
318                 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
319                 return MERGE_DISCARD;
320             }
321             break;
322 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
323         case GenericEvent:
324             if (next->xcookie.extension != xinput2_opcode) break;
325             if (next->xcookie.evtype != XI_RawMotion) break;
326             if (x11drv_thread_data()->warp_serial) break;
327             return MERGE_KEEP;
328         }
329         break;
330     case GenericEvent:
331         if (prev->xcookie.extension != xinput2_opcode) break;
332         if (prev->xcookie.evtype != XI_RawMotion) break;
333         switch (next->type)
334         {
335         case GenericEvent:
336             if (next->xcookie.extension != xinput2_opcode) break;
337             if (next->xcookie.evtype != XI_RawMotion) break;
338             if (x11drv_thread_data()->warp_serial) break;
339             return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
340 #endif
341         }
342         break;
343     }
344     return MERGE_HANDLE;
345 }
346
347
348 /***********************************************************************
349  *           call_event_handler
350  */
351 static inline void call_event_handler( Display *display, XEvent *event )
352 {
353     HWND hwnd;
354     XEvent *prev;
355     struct x11drv_thread_data *thread_data;
356
357     if (!handlers[event->type])
358     {
359         TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
360         return;  /* no handler, ignore it */
361     }
362
363     if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
364         hwnd = 0;  /* not for a registered window */
365     if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
366
367     TRACE( "%lu %s for hwnd/window %p/%lx\n",
368            event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
369     thread_data = x11drv_thread_data();
370     prev = thread_data->current_event;
371     thread_data->current_event = event;
372     handlers[event->type]( hwnd, event );
373     thread_data->current_event = prev;
374 }
375
376
377 /***********************************************************************
378  *           process_events
379  */
380 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
381 {
382     XEvent event, prev_event;
383     int count = 0;
384     enum event_merge_action action = MERGE_DISCARD;
385
386     prev_event.type = 0;
387     while (XCheckIfEvent( display, &event, filter, (char *)arg ))
388     {
389         count++;
390         if (XFilterEvent( &event, None ))
391         {
392             /*
393              * SCIM on linux filters key events strangely. It does not filter the
394              * KeyPress events for these keys however it does filter the
395              * KeyRelease events. This causes wine to become very confused as
396              * to the keyboard state.
397              *
398              * We need to let those KeyRelease events be processed so that the
399              * keyboard state is correct.
400              */
401             if (event.type == KeyRelease)
402             {
403                 KeySym keysym = 0;
404                 XKeyEvent *keyevent = &event.xkey;
405
406                 XLookupString(keyevent, NULL, 0, &keysym, NULL);
407                 if (!(keysym == XK_Shift_L ||
408                     keysym == XK_Shift_R ||
409                     keysym == XK_Control_L ||
410                     keysym == XK_Control_R ||
411                     keysym == XK_Alt_R ||
412                     keysym == XK_Alt_L ||
413                     keysym == XK_Meta_R ||
414                     keysym == XK_Meta_L))
415                         continue; /* not a key we care about, ignore it */
416             }
417             else
418                 continue;  /* filtered, ignore it */
419         }
420         get_event_data( &event );
421         if (prev_event.type) action = merge_events( &prev_event, &event );
422         switch( action )
423         {
424         case MERGE_HANDLE:  /* handle prev, keep new */
425             call_event_handler( display, &prev_event );
426             /* fall through */
427         case MERGE_DISCARD:  /* discard prev, keep new */
428             free_event_data( &prev_event );
429             prev_event = event;
430             break;
431         case MERGE_KEEP:  /* handle new, keep prev for future merging */
432             call_event_handler( display, &event );
433             /* fall through */
434         case MERGE_IGNORE: /* ignore new, keep prev for future merging */
435             free_event_data( &event );
436             break;
437         }
438     }
439     if (prev_event.type) call_event_handler( display, &prev_event );
440     free_event_data( &prev_event );
441     XFlush( gdi_display );
442     if (count) TRACE( "processed %d events\n", count );
443     return count;
444 }
445
446
447 /***********************************************************************
448  *           MsgWaitForMultipleObjectsEx   (X11DRV.@)
449  */
450 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
451                                                 DWORD timeout, DWORD mask, DWORD flags )
452 {
453     DWORD ret;
454     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
455
456     if (!data)
457     {
458         if (!count && !timeout) return WAIT_TIMEOUT;
459         return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
460                                          timeout, flags & MWMO_ALERTABLE );
461     }
462
463     if (data->current_event) mask = 0;  /* don't process nested events */
464
465     if (process_events( data->display, filter_event, mask )) ret = count - 1;
466     else if (count || timeout)
467     {
468         ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
469                                         timeout, flags & MWMO_ALERTABLE );
470         if (ret == count - 1) process_events( data->display, filter_event, mask );
471     }
472     else ret = WAIT_TIMEOUT;
473
474     return ret;
475 }
476
477 /***********************************************************************
478  *           EVENT_x11_time_to_win32_time
479  *
480  * Make our timer and the X timer line up as best we can
481  *  Pass 0 to retrieve the current adjustment value (times -1)
482  */
483 DWORD EVENT_x11_time_to_win32_time(Time time)
484 {
485   static DWORD adjust = 0;
486   DWORD now = GetTickCount();
487   DWORD ret;
488
489   if (! adjust && time != 0)
490   {
491     ret = now;
492     adjust = time - now;
493   }
494   else
495   {
496       /* If we got an event in the 'future', then our clock is clearly wrong. 
497          If we got it more than 10000 ms in the future, then it's most likely
498          that the clock has wrapped.  */
499
500       ret = time - adjust;
501       if (ret > now && ((ret - now) < 10000) && time != 0)
502       {
503         adjust += ret - now;
504         ret    -= ret - now;
505       }
506   }
507
508   return ret;
509
510 }
511
512 /*******************************************************************
513  *         can_activate_window
514  *
515  * Check if we can activate the specified window.
516  */
517 static inline BOOL can_activate_window( HWND hwnd )
518 {
519     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
520     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
521
522     if (!(style & WS_VISIBLE)) return FALSE;
523     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
524     if (style & WS_MINIMIZE) return FALSE;
525     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
526     if (hwnd == GetDesktopWindow()) return FALSE;
527     if (data && IsRectEmpty( &data->window_rect )) return FALSE;
528     return !(style & WS_DISABLED);
529 }
530
531
532 /**********************************************************************
533  *              set_focus
534  */
535 static void set_focus( Display *display, HWND hwnd, Time time )
536 {
537     HWND focus;
538     Window win;
539     GUITHREADINFO threadinfo;
540
541     TRACE( "setting foreground window to %p\n", hwnd );
542     SetForegroundWindow( hwnd );
543
544     threadinfo.cbSize = sizeof(threadinfo);
545     GetGUIThreadInfo(0, &threadinfo);
546     focus = threadinfo.hwndFocus;
547     if (!focus) focus = threadinfo.hwndActive;
548     if (focus) focus = GetAncestor( focus, GA_ROOT );
549     win = X11DRV_get_whole_window(focus);
550
551     if (win)
552     {
553         TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
554         XSetInputFocus( display, win, RevertToParent, time );
555     }
556 }
557
558
559 /**********************************************************************
560  *              handle_manager_message
561  */
562 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
563 {
564     if (hwnd != GetDesktopWindow()) return;
565     if (systray_atom && event->data.l[1] == systray_atom)
566         change_systray_owner( event->display, event->data.l[2] );
567 }
568
569
570 /**********************************************************************
571  *              handle_wm_protocols
572  */
573 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
574 {
575     Atom protocol = (Atom)event->data.l[0];
576     Time event_time = (Time)event->data.l[1];
577
578     if (!protocol) return;
579
580     if (protocol == x11drv_atom(WM_DELETE_WINDOW))
581     {
582         update_user_time( event_time );
583
584         if (hwnd == GetDesktopWindow())
585         {
586             /* The desktop window does not have a close button that we can
587              * pretend to click. Therefore, we simply send it a close command. */
588             SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
589             return;
590         }
591
592         /* Ignore the delete window request if the window has been disabled
593          * and we are in managed mode. This is to disallow applications from
594          * being closed by the window manager while in a modal state.
595          */
596         if (IsWindowEnabled(hwnd))
597         {
598             HMENU hSysMenu;
599
600             if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
601             hSysMenu = GetSystemMenu(hwnd, FALSE);
602             if (hSysMenu)
603             {
604                 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
605                 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
606                     return;
607             }
608             if (GetActiveWindow() != hwnd)
609             {
610                 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
611                                            (WPARAM)GetAncestor( hwnd, GA_ROOT ),
612                                            MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
613                 switch(ma)
614                 {
615                     case MA_NOACTIVATEANDEAT:
616                     case MA_ACTIVATEANDEAT:
617                         return;
618                     case MA_NOACTIVATE:
619                         break;
620                     case MA_ACTIVATE:
621                     case 0:
622                         SetActiveWindow(hwnd);
623                         break;
624                     default:
625                         WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
626                         break;
627                 }
628             }
629
630             PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
631         }
632     }
633     else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
634     {
635         HWND last_focus = x11drv_thread_data()->last_focus;
636
637         TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
638                hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
639                GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
640
641         if (can_activate_window(hwnd))
642         {
643             /* simulate a mouse click on the caption to find out
644              * whether the window wants to be activated */
645             LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
646                                        (WPARAM)GetAncestor( hwnd, GA_ROOT ),
647                                        MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
648             if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
649             {
650                 set_focus( event->display, hwnd, event_time );
651                 return;
652             }
653         }
654         else if (hwnd == GetDesktopWindow())
655         {
656             hwnd = GetForegroundWindow();
657             if (!hwnd) hwnd = last_focus;
658             if (!hwnd) hwnd = GetDesktopWindow();
659             set_focus( event->display, hwnd, event_time );
660             return;
661         }
662         /* try to find some other window to give the focus to */
663         hwnd = GetFocus();
664         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
665         if (!hwnd) hwnd = GetActiveWindow();
666         if (!hwnd) hwnd = last_focus;
667         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
668     }
669     else if (protocol == x11drv_atom(_NET_WM_PING))
670     {
671       XClientMessageEvent xev;
672       xev = *event;
673       
674       TRACE("NET_WM Ping\n");
675       xev.window = DefaultRootWindow(xev.display);
676       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
677     }
678 }
679
680
681 static const char * const focus_details[] =
682 {
683     "NotifyAncestor",
684     "NotifyVirtual",
685     "NotifyInferior",
686     "NotifyNonlinear",
687     "NotifyNonlinearVirtual",
688     "NotifyPointer",
689     "NotifyPointerRoot",
690     "NotifyDetailNone"
691 };
692
693 /**********************************************************************
694  *              X11DRV_FocusIn
695  */
696 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
697 {
698     XFocusChangeEvent *event = &xev->xfocus;
699     XIC xic;
700
701     if (!hwnd) return;
702
703     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
704
705     if (event->detail == NotifyPointer) return;
706     if (hwnd == GetDesktopWindow()) return;
707
708     if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic );
709     if (use_take_focus)
710     {
711         if (hwnd == GetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE );
712         return;
713     }
714
715     if (!can_activate_window(hwnd))
716     {
717         HWND hwnd = GetFocus();
718         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
719         if (!hwnd) hwnd = GetActiveWindow();
720         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
721         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
722     }
723     else SetForegroundWindow( hwnd );
724 }
725
726
727 /**********************************************************************
728  *              X11DRV_FocusOut
729  *
730  * Note: only top-level windows get FocusOut events.
731  */
732 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
733 {
734     XFocusChangeEvent *event = &xev->xfocus;
735     HWND hwnd_tmp;
736     Window focus_win;
737     int revert;
738     XIC xic;
739
740     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
741
742     if (event->detail == NotifyPointer)
743     {
744         if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
745         return;
746     }
747     if (!hwnd) return;
748     if (ximInComposeMode) return;
749
750     x11drv_thread_data()->last_focus = hwnd;
751     if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
752
753     if (root_window != DefaultRootWindow(event->display))
754     {
755         if (hwnd == GetDesktopWindow()) reset_clipping_window();
756         return;
757     }
758     if (hwnd != GetForegroundWindow()) return;
759     SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
760
761     /* don't reset the foreground window, if the window which is
762        getting the focus is a Wine window */
763
764     XGetInputFocus( event->display, &focus_win, &revert );
765     if (focus_win)
766     {
767         if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
768             focus_win = 0;
769     }
770
771     if (!focus_win)
772     {
773         /* Abey : 6-Oct-99. Check again if the focus out window is the
774            Foreground window, because in most cases the messages sent
775            above must have already changed the foreground window, in which
776            case we don't have to change the foreground window to 0 */
777         if (hwnd == GetForegroundWindow())
778         {
779             TRACE( "lost focus, setting fg to desktop\n" );
780             SetForegroundWindow( GetDesktopWindow() );
781         }
782     }
783 }
784
785
786 /***********************************************************************
787  *           X11DRV_Expose
788  */
789 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
790 {
791     XExposeEvent *event = &xev->xexpose;
792     RECT rect;
793     struct x11drv_win_data *data;
794     int flags = RDW_INVALIDATE | RDW_ERASE;
795
796     TRACE( "win %p (%lx) %d,%d %dx%d\n",
797            hwnd, event->window, event->x, event->y, event->width, event->height );
798
799     if (!(data = X11DRV_get_win_data( hwnd ))) return;
800
801     rect.left   = event->x;
802     rect.top    = event->y;
803     rect.right  = event->x + event->width;
804     rect.bottom = event->y + event->height;
805     if (event->window == data->whole_window)
806     {
807         OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
808                     data->whole_rect.top - data->client_rect.top );
809         flags |= RDW_FRAME;
810     }
811
812     if (event->window != root_window)
813     {
814         if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
815             mirror_rect( &data->client_rect, &rect );
816
817         SERVER_START_REQ( update_window_zorder )
818         {
819             req->window      = wine_server_user_handle( hwnd );
820             req->rect.left   = rect.left;
821             req->rect.top    = rect.top;
822             req->rect.right  = rect.right;
823             req->rect.bottom = rect.bottom;
824             wine_server_call( req );
825         }
826         SERVER_END_REQ;
827
828         flags |= RDW_ALLCHILDREN;
829     }
830     else OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
831
832     RedrawWindow( hwnd, &rect, 0, flags );
833 }
834
835
836 /**********************************************************************
837  *              X11DRV_MapNotify
838  */
839 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
840 {
841     struct x11drv_win_data *data;
842
843     if (event->xany.window == x11drv_thread_data()->clip_window)
844     {
845         clipping_cursor = 1;
846         return;
847     }
848     if (!(data = X11DRV_get_win_data( hwnd ))) return;
849     if (!data->mapped || data->embedded) return;
850
851     if (!data->managed)
852     {
853         HWND hwndFocus = GetFocus();
854         if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
855     }
856 }
857
858
859 /**********************************************************************
860  *              X11DRV_UnmapNotify
861  */
862 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
863 {
864     if (event->xany.window == x11drv_thread_data()->clip_window) clipping_cursor = 0;
865 }
866
867
868 /***********************************************************************
869  *     is_net_wm_state_maximized
870  */
871 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
872 {
873     Atom type, *state;
874     int format, ret = 0;
875     unsigned long i, count, remaining;
876
877     if (!data->whole_window) return FALSE;
878
879     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
880                              65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
881                              &remaining, (unsigned char **)&state ))
882     {
883         if (type == XA_ATOM && format == 32)
884         {
885             for (i = 0; i < count; i++)
886             {
887                 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
888                     state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
889                     ret++;
890             }
891         }
892         XFree( state );
893     }
894     return (ret == 2);
895 }
896
897
898 /***********************************************************************
899  *           X11DRV_ReparentNotify
900  */
901 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
902 {
903     XReparentEvent *event = &xev->xreparent;
904     struct x11drv_win_data *data;
905     HWND parent, old_parent;
906     DWORD style;
907
908     if (!(data = X11DRV_get_win_data( hwnd ))) return;
909     if (!data->embedded) return;
910
911     if (data->whole_window)
912     {
913         if (event->parent == root_window)
914         {
915             TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
916             data->embedder = 0;
917             SendMessageW( hwnd, WM_CLOSE, 0, 0 );
918             return;
919         }
920         data->embedder = event->parent;
921     }
922
923     TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
924
925     style = GetWindowLongW( hwnd, GWL_STYLE );
926     if (event->parent == root_window)
927     {
928         parent = GetDesktopWindow();
929         style = (style & ~WS_CHILD) | WS_POPUP;
930     }
931     else
932     {
933         if (!(parent = create_foreign_window( event->display, event->parent ))) return;
934         style = (style & ~WS_POPUP) | WS_CHILD;
935     }
936
937     ShowWindow( hwnd, SW_HIDE );
938     old_parent = SetParent( hwnd, parent );
939     SetWindowLongW( hwnd, GWL_STYLE, style );
940     SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
941                   SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
942                   ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
943
944     /* make old parent destroy itself if it no longer has children */
945     if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
946 }
947
948
949 /***********************************************************************
950  *              X11DRV_ConfigureNotify
951  */
952 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
953 {
954     XConfigureEvent *event = &xev->xconfigure;
955     struct x11drv_win_data *data;
956     RECT rect;
957     UINT flags;
958     HWND parent;
959     BOOL root_coords;
960     int cx, cy, x = event->x, y = event->y;
961
962     if (!hwnd) return;
963     if (!(data = X11DRV_get_win_data( hwnd ))) return;
964     if (!data->mapped || data->iconic) return;
965     if (data->whole_window && !data->managed) return;
966     /* ignore synthetic events on foreign windows */
967     if (event->send_event && !data->whole_window) return;
968     if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
969     {
970         TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
971                hwnd, data->whole_window, event->x, event->y, event->width, event->height,
972                event->serial, data->configure_serial );
973         return;
974     }
975
976     /* Get geometry */
977
978     parent = GetAncestor( hwnd, GA_PARENT );
979     root_coords = event->send_event;  /* synthetic events are always in root coords */
980
981     if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
982     {
983         Window child;
984         XTranslateCoordinates( event->display, event->window, root_window,
985                                0, 0, &x, &y, &child );
986         root_coords = TRUE;
987     }
988     rect.left   = x;
989     rect.top    = y;
990     rect.right  = x + event->width;
991     rect.bottom = y + event->height;
992     if (root_coords) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
993     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
994            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
995            event->x, event->y, event->width, event->height );
996
997     X11DRV_X_to_window_rect( data, &rect );
998     if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
999
1000     /* Compare what has changed */
1001
1002     x     = rect.left;
1003     y     = rect.top;
1004     cx    = rect.right - rect.left;
1005     cy    = rect.bottom - rect.top;
1006     flags = SWP_NOACTIVATE | SWP_NOZORDER;
1007
1008     if (!data->whole_window) flags |= SWP_NOCOPYBITS;  /* we can't copy bits of foreign windows */
1009
1010     if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1011     else
1012         TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1013                hwnd, data->window_rect.left, data->window_rect.top, x, y );
1014
1015     if ((data->window_rect.right - data->window_rect.left == cx &&
1016          data->window_rect.bottom - data->window_rect.top == cy) ||
1017         (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
1018     {
1019         if (flags & SWP_NOMOVE)  /* if nothing changed, don't do anything */
1020         {
1021             TRACE( "Nothing has changed, ignoring event\n" );
1022             return;
1023         }
1024         flags |= SWP_NOSIZE;
1025     }
1026     else
1027         TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1028                hwnd, data->window_rect.right - data->window_rect.left,
1029                data->window_rect.bottom - data->window_rect.top, cx, cy );
1030
1031     if (is_net_wm_state_maximized( event->display, data ))
1032     {
1033         if (!IsZoomed( data->hwnd ))
1034         {
1035             TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1036             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1037             return;
1038         }
1039     }
1040     else
1041     {
1042         if (IsZoomed( data->hwnd ))
1043         {
1044             TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1045             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1046             return;
1047         }
1048     }
1049
1050     SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1051 }
1052
1053
1054 /**********************************************************************
1055  *           X11DRV_GravityNotify
1056  */
1057 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1058 {
1059     XGravityEvent *event = &xev->xgravity;
1060     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1061     RECT rect;
1062
1063     if (!data || data->whole_window) return;  /* only handle this for foreign windows */
1064
1065     rect.left   = event->x;
1066     rect.top    = event->y;
1067     rect.right  = rect.left + data->whole_rect.right - data->whole_rect.left;
1068     rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1069
1070     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1071            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1072            event->x, event->y );
1073
1074     X11DRV_X_to_window_rect( data, &rect );
1075
1076     if (data->window_rect.left != rect.left || data ->window_rect.top != rect.top)
1077         SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1078                       SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1079 }
1080
1081
1082 /***********************************************************************
1083  *           get_window_wm_state
1084  */
1085 static int get_window_wm_state( Display *display, struct x11drv_win_data *data )
1086 {
1087     struct
1088     {
1089         CARD32 state;
1090         XID     icon;
1091     } *state;
1092     Atom type;
1093     int format, ret = -1;
1094     unsigned long count, remaining;
1095
1096     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
1097                              sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1098                              &type, &format, &count, &remaining, (unsigned char **)&state ))
1099     {
1100         if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1101             ret = state->state;
1102         XFree( state );
1103     }
1104     return ret;
1105 }
1106
1107
1108 /***********************************************************************
1109  *           handle_wm_state_notify
1110  *
1111  * Handle a PropertyNotify for WM_STATE.
1112  */
1113 static void handle_wm_state_notify( struct x11drv_win_data *data, XPropertyEvent *event,
1114                                     BOOL update_window )
1115 {
1116     DWORD style;
1117
1118     switch(event->state)
1119     {
1120     case PropertyDelete:
1121         TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1122         data->wm_state = WithdrawnState;
1123         break;
1124     case PropertyNewValue:
1125         {
1126             int old_state = data->wm_state;
1127             int new_state = get_window_wm_state( event->display, data );
1128             if (new_state != -1 && new_state != data->wm_state)
1129             {
1130                 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1131                        data->hwnd, data->whole_window, new_state, old_state );
1132                 data->wm_state = new_state;
1133                 /* ignore the initial state transition out of withdrawn state */
1134                 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1135                 if (!old_state) return;
1136             }
1137         }
1138         break;
1139     }
1140
1141     if (!update_window || !data->managed || !data->mapped) return;
1142
1143     style = GetWindowLongW( data->hwnd, GWL_STYLE );
1144
1145     if (data->iconic && data->wm_state == NormalState)  /* restore window */
1146     {
1147         data->iconic = FALSE;
1148         if (is_net_wm_state_maximized( event->display, data ))
1149         {
1150             if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1151             {
1152                 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1153                 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1154             }
1155             else TRACE( "not restoring to max win %p/%lx style %08x\n",
1156                         data->hwnd, data->whole_window, style );
1157         }
1158         else if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1159         {
1160             TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1161             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1162         }
1163         else TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1164     }
1165     else if (!data->iconic && data->wm_state == IconicState)
1166     {
1167         data->iconic = TRUE;
1168         if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1169         {
1170             TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1171             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1172         }
1173         else TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1174     }
1175 }
1176
1177
1178 /***********************************************************************
1179  *           X11DRV_PropertyNotify
1180  */
1181 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1182 {
1183     XPropertyEvent *event = &xev->xproperty;
1184     struct x11drv_win_data *data;
1185
1186     if (!hwnd) return;
1187     if (!(data = X11DRV_get_win_data( hwnd ))) return;
1188
1189     if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( data, event, TRUE );
1190 }
1191
1192
1193 /* event filter to wait for a WM_STATE change notification on a window */
1194 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1195 {
1196     if (event->xany.window != (Window)arg) return 0;
1197     return (event->type == DestroyNotify ||
1198             (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1199 }
1200
1201 /***********************************************************************
1202  *           wait_for_withdrawn_state
1203  */
1204 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data, BOOL set )
1205 {
1206     DWORD end = GetTickCount() + 2000;
1207
1208     if (!data->managed) return;
1209
1210     TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
1211            data->hwnd, data->whole_window, set ? "" : "not " );
1212
1213     while (data->whole_window && ((data->wm_state == WithdrawnState) == !set))
1214     {
1215         XEvent event;
1216         int count = 0;
1217
1218         while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)data->whole_window ))
1219         {
1220             count++;
1221             if (XFilterEvent( &event, None )) continue;  /* filtered, ignore it */
1222             if (event.type == DestroyNotify) call_event_handler( display, &event );
1223             else handle_wm_state_notify( data, &event.xproperty, FALSE );
1224         }
1225
1226         if (!count)
1227         {
1228             struct pollfd pfd;
1229             int timeout = end - GetTickCount();
1230
1231             pfd.fd = ConnectionNumber(display);
1232             pfd.events = POLLIN;
1233             if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1234             {
1235                 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
1236                 break;
1237             }
1238         }
1239     }
1240     TRACE( "window %p/%lx state now %d\n", data->hwnd, data->whole_window, data->wm_state );
1241 }
1242
1243
1244 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1245 {
1246     RECT tempRect;
1247
1248     if (!IsWindowEnabled(hQueryWnd)) return 0;
1249     
1250     GetWindowRect(hQueryWnd, &tempRect);
1251
1252     if(!PtInRect(&tempRect, *lpPt)) return 0;
1253
1254     if (!IsIconic( hQueryWnd ))
1255     {
1256         POINT pt = *lpPt;
1257         ScreenToClient( hQueryWnd, &pt );
1258         GetClientRect( hQueryWnd, &tempRect );
1259
1260         if (PtInRect( &tempRect, pt))
1261         {
1262             HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1263             if (ret && ret != hQueryWnd)
1264             {
1265                 ret = find_drop_window( ret, lpPt );
1266                 if (ret) return ret;
1267             }
1268         }
1269     }
1270
1271     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1272     
1273     ScreenToClient(hQueryWnd, lpPt);
1274
1275     return hQueryWnd;
1276 }
1277
1278 /**********************************************************************
1279  *           EVENT_DropFromOffix
1280  *
1281  * don't know if it still works (last Changelog is from 96/11/04)
1282  */
1283 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1284 {
1285     struct x11drv_win_data *data;
1286     unsigned long       data_length;
1287     unsigned long       aux_long;
1288     unsigned char*      p_data = NULL;
1289     Atom atom_aux;
1290     int                 x, y, dummy;
1291     BOOL                bAccept;
1292     Window              win, w_aux_root, w_aux_child;
1293
1294     win = X11DRV_get_whole_window(hWnd);
1295     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1296                    &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1297     x += virtual_screen_rect.left;
1298     y += virtual_screen_rect.top;
1299
1300     if (!(data = X11DRV_get_win_data( hWnd ))) return;
1301
1302     /* find out drop point and drop window */
1303     if( x < 0 || y < 0 ||
1304         x > (data->whole_rect.right - data->whole_rect.left) ||
1305         y > (data->whole_rect.bottom - data->whole_rect.top) )
1306     {   
1307         bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1308         x = 0;
1309         y = 0; 
1310     }
1311     else
1312     {
1313         POINT   pt = { x, y };
1314         HWND    hwndDrop = find_drop_window( hWnd, &pt );
1315         if (hwndDrop)
1316         {
1317             x = pt.x;
1318             y = pt.y;
1319             bAccept = TRUE;
1320         }
1321         else
1322         {
1323             bAccept = FALSE;
1324         }
1325     }
1326
1327     if (!bAccept) return;
1328
1329     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1330                         x11drv_atom(DndSelection), 0, 65535, FALSE,
1331                         AnyPropertyType, &atom_aux, &dummy,
1332                         &data_length, &aux_long, &p_data);
1333
1334     if( !aux_long && p_data)  /* don't bother if > 64K */
1335     {
1336         char *p = (char *)p_data;
1337         char *p_drop;
1338
1339         aux_long = 0;
1340         while( *p )  /* calculate buffer size */
1341         {
1342             INT len = GetShortPathNameA( p, NULL, 0 );
1343             if (len) aux_long += len + 1;
1344             p += strlen(p) + 1;
1345         }
1346         if( aux_long && aux_long < 65535 )
1347         {
1348             HDROP                 hDrop;
1349             DROPFILES *lpDrop;
1350
1351             aux_long += sizeof(DROPFILES) + 1;
1352             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1353             lpDrop = GlobalLock( hDrop );
1354
1355             if( lpDrop )
1356             {
1357                 lpDrop->pFiles = sizeof(DROPFILES);
1358                 lpDrop->pt.x = x;
1359                 lpDrop->pt.y = y;
1360                 lpDrop->fNC = FALSE;
1361                 lpDrop->fWide = FALSE;
1362                 p_drop = (char *)(lpDrop + 1);
1363                 p = (char *)p_data;
1364                 while(*p)
1365                 {
1366                     if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1367                         p_drop += strlen( p_drop ) + 1;
1368                     p += strlen(p) + 1;
1369                 }
1370                 *p_drop = '\0';
1371                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1372             }
1373         }
1374     }
1375     if( p_data ) XFree(p_data);
1376 }
1377
1378 /**********************************************************************
1379  *           EVENT_DropURLs
1380  *
1381  * drop items are separated by \n
1382  * each item is prefixed by its mime type
1383  *
1384  * event->data.l[3], event->data.l[4] contains drop x,y position
1385  */
1386 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1387 {
1388   struct x11drv_win_data *win_data;
1389   unsigned long data_length;
1390   unsigned long aux_long, drop_len = 0;
1391   unsigned char *p_data = NULL; /* property data */
1392   char          *p_drop = NULL;
1393   char          *p, *next;
1394   int           x, y;
1395   DROPFILES *lpDrop;
1396   HDROP hDrop;
1397   union {
1398     Atom        atom_aux;
1399     int         i;
1400     Window      w_aux;
1401     unsigned int u;
1402   }             u; /* unused */
1403
1404   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1405
1406   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1407                       x11drv_atom(DndSelection), 0, 65535, FALSE,
1408                       AnyPropertyType, &u.atom_aux, &u.i,
1409                       &data_length, &aux_long, &p_data);
1410   if (aux_long)
1411     WARN("property too large, truncated!\n");
1412   TRACE("urls=%s\n", p_data);
1413
1414   if( !aux_long && p_data) {    /* don't bother if > 64K */
1415     /* calculate length */
1416     p = (char*) p_data;
1417     next = strchr(p, '\n');
1418     while (p) {
1419       if (next) *next=0;
1420       if (strncmp(p,"file:",5) == 0 ) {
1421         INT len = GetShortPathNameA( p+5, NULL, 0 );
1422         if (len) drop_len += len + 1;
1423       }
1424       if (next) {
1425         *next = '\n';
1426         p = next + 1;
1427         next = strchr(p, '\n');
1428       } else {
1429         p = NULL;
1430       }
1431     }
1432
1433     if( drop_len && drop_len < 65535 ) {
1434       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1435                      &x, &y, &u.i, &u.i, &u.u);
1436       x += virtual_screen_rect.left;
1437       y += virtual_screen_rect.top;
1438
1439       drop_len += sizeof(DROPFILES) + 1;
1440       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1441       lpDrop = GlobalLock( hDrop );
1442
1443       if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
1444       {
1445           lpDrop->pFiles = sizeof(DROPFILES);
1446           lpDrop->pt.x = x;
1447           lpDrop->pt.y = y;
1448           lpDrop->fNC =
1449             ( x < (win_data->client_rect.left - win_data->whole_rect.left)  ||
1450               y < (win_data->client_rect.top - win_data->whole_rect.top)    ||
1451               x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1452               y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1453           lpDrop->fWide = FALSE;
1454           p_drop = (char*)(lpDrop + 1);
1455       }
1456
1457       /* create message content */
1458       if (p_drop) {
1459         p = (char*) p_data;
1460         next = strchr(p, '\n');
1461         while (p) {
1462           if (next) *next=0;
1463           if (strncmp(p,"file:",5) == 0 ) {
1464             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1465             if (len) {
1466               TRACE("drop file %s as %s\n", p+5, p_drop);
1467               p_drop += len+1;
1468             } else {
1469               WARN("can't convert file %s to dos name\n", p+5);
1470             }
1471           } else {
1472             WARN("unknown mime type %s\n", p);
1473           }
1474           if (next) {
1475             *next = '\n';
1476             p = next + 1;
1477             next = strchr(p, '\n');
1478           } else {
1479             p = NULL;
1480           }
1481           *p_drop = '\0';
1482         }
1483
1484         GlobalUnlock(hDrop);
1485         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1486       }
1487     }
1488     if( p_data ) XFree(p_data);
1489   }
1490 }
1491
1492
1493 /**********************************************************************
1494  *              handle_xembed_protocol
1495  */
1496 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1497 {
1498     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1499
1500     if (!data) return;
1501
1502     switch (event->data.l[1])
1503     {
1504     case XEMBED_EMBEDDED_NOTIFY:
1505         TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1506         data->embedder = event->data.l[3];
1507         break;
1508     default:
1509         TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1510                hwnd, event->window, event->data.l[1], event->data.l[2] );
1511         break;
1512     }
1513 }
1514
1515
1516 /**********************************************************************
1517  *              handle_dnd_protocol
1518  */
1519 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1520 {
1521     Window root, child;
1522     int root_x, root_y, child_x, child_y;
1523     unsigned int u;
1524
1525     /* query window (drag&drop event contains only drag window) */
1526     XQueryPointer( event->display, root_window, &root, &child,
1527                    &root_x, &root_y, &child_x, &child_y, &u);
1528     if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1529     if (!hwnd) return;
1530     if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1531         EVENT_DropFromOffiX(hwnd, event);
1532     else if (event->data.l[0] == DndURL)
1533         EVENT_DropURLs(hwnd, event);
1534 }
1535
1536
1537 struct client_message_handler
1538 {
1539     int    atom;                                  /* protocol atom */
1540     void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1541 };
1542
1543 static const struct client_message_handler client_messages[] =
1544 {
1545     { XATOM_MANAGER,      handle_manager_message },
1546     { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1547     { XATOM__XEMBED,      handle_xembed_protocol },
1548     { XATOM_DndProtocol,  handle_dnd_protocol },
1549     { XATOM_XdndEnter,    X11DRV_XDND_EnterEvent },
1550     { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1551     { XATOM_XdndDrop,     X11DRV_XDND_DropEvent },
1552     { XATOM_XdndLeave,    X11DRV_XDND_LeaveEvent }
1553 };
1554
1555
1556 /**********************************************************************
1557  *           X11DRV_ClientMessage
1558  */
1559 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1560 {
1561     XClientMessageEvent *event = &xev->xclient;
1562     unsigned int i;
1563
1564     if (!hwnd) return;
1565
1566     if (event->format != 32)
1567     {
1568         WARN( "Don't know how to handle format %d\n", event->format );
1569         return;
1570     }
1571
1572     for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1573     {
1574         if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1575         {
1576             client_messages[i].handler( hwnd, event );
1577             return;
1578         }
1579     }
1580     TRACE( "no handler found for %ld\n", event->message_type );
1581 }