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