localspl: Exclude unused headers.
[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 #include <X11/Xatom.h>
25 #include <X11/keysym.h>
26 #include <X11/Xlib.h>
27 #include <X11/Xresource.h>
28 #include <X11/Xutil.h>
29
30 #include <assert.h>
31 #include <stdarg.h>
32 #include <string.h>
33
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winuser.h"
39 #include "wingdi.h"
40 #include "shlobj.h"  /* DROPFILES */
41
42 #include "win.h"
43 #include "winreg.h"
44 #include "x11drv.h"
45 #include "shellapi.h"
46 #include "wine/debug.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(event);
49
50 extern BOOL ximInComposeMode;
51
52 #define DndNotDnd       -1    /* OffiX drag&drop */
53 #define DndUnknown      0
54 #define DndRawData      1
55 #define DndFile         2
56 #define DndFiles        3
57 #define DndText         4
58 #define DndDir          5
59 #define DndLink         6
60 #define DndExe          7
61
62 #define DndEND          8
63
64 #define DndURL          128   /* KDE drag&drop */
65
66   /* Event handlers */
67 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
68 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
69 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
70 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
71
72 struct event_handler
73 {
74     int                  type;    /* event type */
75     x11drv_event_handler handler; /* corresponding handler function */
76 };
77
78 #define MAX_EVENT_HANDLERS 64
79
80 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
81 {
82     /* list must be sorted by event type */
83     { KeyPress,         X11DRV_KeyEvent },
84     { KeyRelease,       X11DRV_KeyEvent },
85     { ButtonPress,      X11DRV_ButtonPress },
86     { ButtonRelease,    X11DRV_ButtonRelease },
87     { MotionNotify,     X11DRV_MotionNotify },
88     { EnterNotify,      X11DRV_EnterNotify },
89     /* LeaveNotify */
90     { FocusIn,          EVENT_FocusIn },
91     { FocusOut,         EVENT_FocusOut },
92     { KeymapNotify,     X11DRV_KeymapNotify },
93     { Expose,           X11DRV_Expose },
94     /* GraphicsExpose */
95     /* NoExpose */
96     /* VisibilityNotify */
97     /* CreateNotify */
98     /* DestroyNotify */
99     { UnmapNotify,      X11DRV_UnmapNotify },
100     { MapNotify,        X11DRV_MapNotify },
101     /* MapRequest */
102     /* ReparentNotify */
103     { ConfigureNotify,  X11DRV_ConfigureNotify },
104     /* ConfigureRequest */
105     /* GravityNotify */
106     /* ResizeRequest */
107     /* CirculateNotify */
108     /* CirculateRequest */
109     { PropertyNotify,   EVENT_PropertyNotify },
110     { SelectionClear,   X11DRV_SelectionClear },
111     { SelectionRequest, X11DRV_SelectionRequest },
112     /* SelectionNotify */
113     /* ColormapNotify */
114     { ClientMessage,    EVENT_ClientMessage },
115     { MappingNotify,    X11DRV_MappingNotify },
116 };
117
118 static int nb_event_handlers = 18;  /* change this if you add handlers above */
119
120
121 /* return the name of an X event */
122 static const char *dbgstr_event( int type )
123 {
124     static const char * const event_names[] =
125     {
126         "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
127         "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
128         "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
129         "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
130         "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
131         "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
132         "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
133         "ClientMessage", "MappingNotify"
134     };
135
136     if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
137     return wine_dbg_sprintf( "Extension event %d", type );
138 }
139
140
141 /***********************************************************************
142  *           find_handler
143  *
144  * Find the handler for a given event type. Caller must hold the x11 lock.
145  */
146 static inline x11drv_event_handler find_handler( int type )
147 {
148     int min = 0, max = nb_event_handlers - 1;
149
150     while (min <= max)
151     {
152         int pos = (min + max) / 2;
153         if (handlers[pos].type == type) return handlers[pos].handler;
154         if (handlers[pos].type > type) max = pos - 1;
155         else min = pos + 1;
156     }
157     return NULL;
158 }
159
160
161 /***********************************************************************
162  *           X11DRV_register_event_handler
163  *
164  * Register a handler for a given event type.
165  * If already registered, overwrite the previous handler.
166  */
167 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
168 {
169     int min, max;
170
171     wine_tsx11_lock();
172     min = 0;
173     max = nb_event_handlers - 1;
174     while (min <= max)
175     {
176         int pos = (min + max) / 2;
177         if (handlers[pos].type == type)
178         {
179             handlers[pos].handler = handler;
180             goto done;
181         }
182         if (handlers[pos].type > type) max = pos - 1;
183         else min = pos + 1;
184     }
185     /* insert it between max and min */
186     memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
187     handlers[min].type = type;
188     handlers[min].handler = handler;
189     nb_event_handlers++;
190     assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
191 done:
192     wine_tsx11_unlock();
193     TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
194 }
195
196
197 /***********************************************************************
198  *           filter_event
199  */
200 static Bool filter_event( Display *display, XEvent *event, char *arg )
201 {
202     ULONG_PTR mask = (ULONG_PTR)arg;
203
204     if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
205
206     switch(event->type)
207     {
208     case KeyPress:
209     case KeyRelease:
210     case KeymapNotify:
211     case MappingNotify:
212         return (mask & QS_KEY) != 0;
213     case ButtonPress:
214     case ButtonRelease:
215         return (mask & QS_MOUSEBUTTON) != 0;
216     case MotionNotify:
217     case EnterNotify:
218     case LeaveNotify:
219         return (mask & QS_MOUSEMOVE) != 0;
220     case Expose:
221         return (mask & QS_PAINT) != 0;
222     case FocusIn:
223     case FocusOut:
224     case MapNotify:
225     case UnmapNotify:
226     case ConfigureNotify:
227     case PropertyNotify:
228     case ClientMessage:
229         return (mask & QS_POSTMESSAGE) != 0;
230     default:
231         return (mask & QS_SENDMESSAGE) != 0;
232     }
233 }
234
235
236 /***********************************************************************
237  *           process_events
238  */
239 static int process_events( Display *display, ULONG_PTR mask )
240 {
241     XEvent event;
242     HWND hwnd;
243     int count = 0;
244     x11drv_event_handler handler;
245
246     wine_tsx11_lock();
247     while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
248     {
249         count++;
250         if (XFilterEvent( &event, None )) continue;  /* filtered, ignore it */
251
252         if (!(handler = find_handler( event.type )))
253         {
254             TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
255             continue;  /* no handler, ignore it */
256         }
257
258         if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
259             hwnd = 0;  /* not for a registered window */
260         if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
261
262         wine_tsx11_unlock();
263         TRACE( "%s for hwnd/window %p/%lx\n",
264                dbgstr_event( event.type ), hwnd, event.xany.window );
265         handler( hwnd, &event );
266         wine_tsx11_lock();
267     }
268     XFlush( gdi_display );
269     wine_tsx11_unlock();
270     if (count) TRACE( "processed %d events\n", count );
271     return count;
272 }
273
274
275 /***********************************************************************
276  *           MsgWaitForMultipleObjectsEx   (X11DRV.@)
277  */
278 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
279                                           DWORD timeout, DWORD mask, DWORD flags )
280 {
281     DWORD ret;
282     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
283
284     if (!data)
285     {
286         if (!count && !timeout) return WAIT_TIMEOUT;
287         return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
288                                          timeout, flags & MWMO_ALERTABLE );
289     }
290
291     if (data->process_event_count) mask = 0;  /* don't process nested events */
292
293     data->process_event_count++;
294
295     if (process_events( data->display, mask )) ret = count - 1;
296     else if (count || timeout)
297     {
298         ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
299                                         timeout, flags & MWMO_ALERTABLE );
300         if (ret == count - 1) process_events( data->display, mask );
301     }
302     else ret = WAIT_TIMEOUT;
303
304     data->process_event_count--;
305     return ret;
306 }
307
308 /***********************************************************************
309  *           EVENT_x11_time_to_win32_time
310  *
311  * Make our timer and the X timer line up as best we can
312  *  Pass 0 to retrieve the current adjustment value (times -1)
313  */
314 DWORD EVENT_x11_time_to_win32_time(Time time)
315 {
316   static DWORD adjust = 0;
317   DWORD now = GetTickCount();
318   DWORD ret;
319
320   if (! adjust && time != 0)
321   {
322     ret = now;
323     adjust = time - now;
324   }
325   else
326   {
327       /* If we got an event in the 'future', then our clock is clearly wrong. 
328          If we got it more than 10000 ms in the future, then it's most likely
329          that the clock has wrapped.  */
330
331       ret = time - adjust;
332       if (ret > now && ((ret - now) < 10000) && time != 0)
333       {
334         adjust += ret - now;
335         ret    -= ret - now;
336       }
337   }
338
339   return ret;
340
341 }
342
343 /*******************************************************************
344  *         can_activate_window
345  *
346  * Check if we can activate the specified window.
347  */
348 static inline BOOL can_activate_window( HWND hwnd )
349 {
350     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
351     if (!(style & WS_VISIBLE)) return FALSE;
352     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
353     return !(style & WS_DISABLED);
354 }
355
356
357 /**********************************************************************
358  *              set_focus
359  */
360 static void set_focus( HWND hwnd, Time time )
361 {
362     HWND focus;
363     Window win;
364
365     TRACE( "setting foreground window to %p\n", hwnd );
366     SetForegroundWindow( hwnd );
367
368     focus = GetFocus();
369     if (focus) focus = GetAncestor( focus, GA_ROOT );
370     win = X11DRV_get_whole_window(focus);
371
372     if (win)
373     {
374         TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
375         wine_tsx11_lock();
376         XSetInputFocus( thread_display(), win, RevertToParent, time );
377         wine_tsx11_unlock();
378     }
379 }
380
381
382 /**********************************************************************
383  *              handle_wm_protocols
384  */
385 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
386 {
387     Atom protocol = (Atom)event->data.l[0];
388
389     if (!protocol) return;
390
391     if (protocol == x11drv_atom(WM_DELETE_WINDOW))
392     {
393         /* Ignore the delete window request if the window has been disabled
394          * and we are in managed mode. This is to disallow applications from
395          * being closed by the window manager while in a modal state.
396          */
397         if (IsWindowEnabled(hwnd))
398         {
399             HMENU hSysMenu;
400
401             if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
402             hSysMenu = GetSystemMenu(hwnd, FALSE);
403             if (hSysMenu)
404             {
405                 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
406                 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
407                     return;
408             }
409             PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
410         }
411     }
412     else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
413     {
414         Time event_time = (Time)event->data.l[1];
415         HWND last_focus = x11drv_thread_data()->last_focus;
416
417         TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
418                hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
419                GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
420
421         if (can_activate_window(hwnd))
422         {
423             /* simulate a mouse click on the caption to find out
424              * whether the window wants to be activated */
425             LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
426                                        (WPARAM)GetAncestor( hwnd, GA_ROOT ),
427                                        MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
428             if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
429             else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
430         }
431         else
432         {
433             hwnd = GetFocus();
434             if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
435             if (!hwnd) hwnd = GetActiveWindow();
436             if (!hwnd) hwnd = last_focus;
437             if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
438         }
439     }
440     else if (protocol == x11drv_atom(_NET_WM_PING))
441     {
442       XClientMessageEvent xev;
443       xev = *event;
444       
445       TRACE("NET_WM Ping\n");
446       wine_tsx11_lock();
447       xev.window = DefaultRootWindow(xev.display);
448       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
449       wine_tsx11_unlock();
450       /* this line is semi-stolen from gtk2 */
451       TRACE("NET_WM Pong\n");
452     }
453 }
454
455
456 static const char * const focus_details[] =
457 {
458     "NotifyAncestor",
459     "NotifyVirtual",
460     "NotifyInferior",
461     "NotifyNonlinear",
462     "NotifyNonlinearVirtual",
463     "NotifyPointer",
464     "NotifyPointerRoot",
465     "NotifyDetailNone"
466 };
467
468 /**********************************************************************
469  *              EVENT_FocusIn
470  */
471 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
472 {
473     XFocusChangeEvent *event = &xev->xfocus;
474     XIC xic;
475
476     if (!hwnd) return;
477
478     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
479
480     if (event->detail == NotifyPointer) return;
481
482     if ((xic = X11DRV_get_ic( hwnd )))
483     {
484         wine_tsx11_lock();
485         XSetICFocus( xic );
486         wine_tsx11_unlock();
487     }
488     if (use_take_focus) return;  /* ignore FocusIn if we are using take focus */
489
490     if (!can_activate_window(hwnd))
491     {
492         HWND hwnd = GetFocus();
493         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
494         if (!hwnd) hwnd = GetActiveWindow();
495         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
496         if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
497     }
498     else SetForegroundWindow( hwnd );
499 }
500
501
502 /**********************************************************************
503  *              EVENT_FocusOut
504  *
505  * Note: only top-level windows get FocusOut events.
506  */
507 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
508 {
509     XFocusChangeEvent *event = &xev->xfocus;
510     HWND hwnd_tmp;
511     Window focus_win;
512     int revert;
513     XIC xic;
514
515     if (!hwnd) return;
516
517     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
518
519     if (event->detail == NotifyPointer) return;
520     if (ximInComposeMode) return;
521
522     x11drv_thread_data()->last_focus = hwnd;
523     if ((xic = X11DRV_get_ic( hwnd )))
524     {
525         wine_tsx11_lock();
526         XUnsetICFocus( xic );
527         wine_tsx11_unlock();
528     }
529     if (hwnd != GetForegroundWindow()) return;
530     SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
531
532     /* don't reset the foreground window, if the window which is
533        getting the focus is a Wine window */
534
535     wine_tsx11_lock();
536     XGetInputFocus( thread_display(), &focus_win, &revert );
537     if (focus_win)
538     {
539         if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
540             focus_win = 0;
541     }
542     wine_tsx11_unlock();
543
544     if (!focus_win)
545     {
546         /* Abey : 6-Oct-99. Check again if the focus out window is the
547            Foreground window, because in most cases the messages sent
548            above must have already changed the foreground window, in which
549            case we don't have to change the foreground window to 0 */
550         if (hwnd == GetForegroundWindow())
551         {
552             TRACE( "lost focus, setting fg to 0\n" );
553             SetForegroundWindow( 0 );
554         }
555     }
556 }
557
558
559 /***********************************************************************
560  *           EVENT_PropertyNotify
561  *   We use this to release resources like Pixmaps when a selection
562  *   client no longer needs them.
563  */
564 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
565 {
566   XPropertyEvent *event = &xev->xproperty;
567   /* Check if we have any resources to free */
568   TRACE("Received PropertyNotify event:\n");
569
570   switch(event->state)
571   {
572     case PropertyDelete:
573     {
574       TRACE("\tPropertyDelete for atom %ld on window %ld\n",
575             event->atom, (long)event->window);
576       break;
577     }
578
579     case PropertyNewValue:
580     {
581       TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
582             event->atom, (long)event->window);
583       break;
584     }
585
586     default:
587       break;
588   }
589 }
590
591 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
592 {
593     RECT tempRect;
594
595     if (!IsWindowEnabled(hQueryWnd)) return 0;
596     
597     GetWindowRect(hQueryWnd, &tempRect);
598
599     if(!PtInRect(&tempRect, *lpPt)) return 0;
600
601     if (!IsIconic( hQueryWnd ))
602     {
603         POINT pt = *lpPt;
604         ScreenToClient( hQueryWnd, &pt );
605         GetClientRect( hQueryWnd, &tempRect );
606
607         if (PtInRect( &tempRect, pt))
608         {
609             HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
610             if (ret && ret != hQueryWnd)
611             {
612                 ret = find_drop_window( ret, lpPt );
613                 if (ret) return ret;
614             }
615         }
616     }
617
618     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
619     
620     ScreenToClient(hQueryWnd, lpPt);
621
622     return hQueryWnd;
623 }
624
625 /**********************************************************************
626  *           EVENT_DropFromOffix
627  *
628  * don't know if it still works (last Changlog is from 96/11/04)
629  */
630 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
631 {
632     unsigned long       data_length;
633     unsigned long       aux_long;
634     unsigned char*      p_data = NULL;
635     Atom atom_aux;
636     int                 x, y, dummy;
637     BOOL                bAccept;
638     Window              win, w_aux_root, w_aux_child;
639     WND*                pWnd;
640     HWND                hScope = hWnd;
641
642     win = X11DRV_get_whole_window(hWnd);
643     wine_tsx11_lock();
644     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
645                    &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
646     x += virtual_screen_rect.left;
647     y += virtual_screen_rect.top;
648     wine_tsx11_unlock();
649
650     pWnd = WIN_GetPtr(hWnd);
651
652     /* find out drop point and drop window */
653     if( x < 0 || y < 0 ||
654         x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
655         y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
656     {   
657         bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; 
658         x = 0;
659         y = 0; 
660     }
661     else
662     {
663         POINT   pt = { x, y };
664         HWND    hwndDrop = find_drop_window( hWnd, &pt );
665         if (hwndDrop)
666         {
667             x = pt.x;
668             y = pt.y;
669             hScope = hwndDrop;
670             bAccept = TRUE;
671         }
672         else
673         {
674             bAccept = FALSE;
675         }
676     }
677     WIN_ReleasePtr(pWnd);
678
679     if (!bAccept) return;
680
681     wine_tsx11_lock();
682     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
683                         x11drv_atom(DndSelection), 0, 65535, FALSE,
684                         AnyPropertyType, &atom_aux, &dummy,
685                         &data_length, &aux_long, &p_data);
686     wine_tsx11_unlock();
687
688     if( !aux_long && p_data)  /* don't bother if > 64K */
689     {
690         char *p = (char *)p_data;
691         char *p_drop;
692
693         aux_long = 0;
694         while( *p )  /* calculate buffer size */
695         {
696             INT len = GetShortPathNameA( p, NULL, 0 );
697             if (len) aux_long += len + 1;
698             p += strlen(p) + 1;
699         }
700         if( aux_long && aux_long < 65535 )
701         {
702             HDROP                 hDrop;
703             DROPFILES *lpDrop;
704
705             aux_long += sizeof(DROPFILES) + 1;
706             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
707             lpDrop = (DROPFILES*)GlobalLock( hDrop );
708
709             if( lpDrop )
710             {
711                 WND *pDropWnd = WIN_GetPtr( hScope );
712                 lpDrop->pFiles = sizeof(DROPFILES);
713                 lpDrop->pt.x = x;
714                 lpDrop->pt.y = y;
715                 lpDrop->fNC =
716                     ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
717                       y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
718                       x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
719                       y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
720                 lpDrop->fWide = FALSE;
721                 WIN_ReleasePtr(pDropWnd);
722                 p_drop = (char *)(lpDrop + 1);
723                 p = (char *)p_data;
724                 while(*p)
725                 {
726                     if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
727                         p_drop += strlen( p_drop ) + 1;
728                     p += strlen(p) + 1;
729                 }
730                 *p_drop = '\0';
731                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
732             }
733         }
734     }
735     wine_tsx11_lock();
736     if( p_data ) XFree(p_data);
737     wine_tsx11_unlock();
738 }
739
740 /**********************************************************************
741  *           EVENT_DropURLs
742  *
743  * drop items are separated by \n
744  * each item is prefixed by its mime type
745  *
746  * event->data.l[3], event->data.l[4] contains drop x,y position
747  */
748 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
749 {
750   unsigned long data_length;
751   unsigned long aux_long, drop_len = 0;
752   unsigned char *p_data = NULL; /* property data */
753   char          *p_drop = NULL;
754   char          *p, *next;
755   int           x, y;
756   DROPFILES *lpDrop;
757   HDROP hDrop;
758   union {
759     Atom        atom_aux;
760     int         i;
761     Window      w_aux;
762     unsigned int u;
763   }             u; /* unused */
764
765   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
766
767   wine_tsx11_lock();
768   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
769                       x11drv_atom(DndSelection), 0, 65535, FALSE,
770                       AnyPropertyType, &u.atom_aux, &u.i,
771                       &data_length, &aux_long, &p_data);
772   wine_tsx11_unlock();
773   if (aux_long)
774     WARN("property too large, truncated!\n");
775   TRACE("urls=%s\n", p_data);
776
777   if( !aux_long && p_data) {    /* don't bother if > 64K */
778     /* calculate length */
779     p = (char*) p_data;
780     next = strchr(p, '\n');
781     while (p) {
782       if (next) *next=0;
783       if (strncmp(p,"file:",5) == 0 ) {
784         INT len = GetShortPathNameA( p+5, NULL, 0 );
785         if (len) drop_len += len + 1;
786       }
787       if (next) {
788         *next = '\n';
789         p = next + 1;
790         next = strchr(p, '\n');
791       } else {
792         p = NULL;
793       }
794     }
795
796     if( drop_len && drop_len < 65535 ) {
797       wine_tsx11_lock();
798       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
799                      &x, &y, &u.i, &u.i, &u.u);
800       x += virtual_screen_rect.left;
801       y += virtual_screen_rect.top;
802       wine_tsx11_unlock();
803
804       drop_len += sizeof(DROPFILES) + 1;
805       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
806       lpDrop = (DROPFILES *) GlobalLock( hDrop );
807
808       if( lpDrop ) {
809           WND *pDropWnd = WIN_GetPtr( hWnd );
810           lpDrop->pFiles = sizeof(DROPFILES);
811           lpDrop->pt.x = (INT)x;
812           lpDrop->pt.y = (INT)y;
813           lpDrop->fNC =
814             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
815               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
816               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
817               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
818           lpDrop->fWide = FALSE;
819           p_drop = (char*)(lpDrop + 1);
820           WIN_ReleasePtr(pDropWnd);
821       }
822
823       /* create message content */
824       if (p_drop) {
825         p = (char*) p_data;
826         next = strchr(p, '\n');
827         while (p) {
828           if (next) *next=0;
829           if (strncmp(p,"file:",5) == 0 ) {
830             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
831             if (len) {
832               TRACE("drop file %s as %s\n", p+5, p_drop);
833               p_drop += len+1;
834             } else {
835               WARN("can't convert file %s to dos name\n", p+5);
836             }
837           } else {
838             WARN("unknown mime type %s\n", p);
839           }
840           if (next) {
841             *next = '\n';
842             p = next + 1;
843             next = strchr(p, '\n');
844           } else {
845             p = NULL;
846           }
847           *p_drop = '\0';
848         }
849
850         GlobalUnlock(hDrop);
851         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
852       }
853     }
854     wine_tsx11_lock();
855     if( p_data ) XFree(p_data);
856     wine_tsx11_unlock();
857   }
858 }
859
860 /**********************************************************************
861  *              handle_dnd_protocol
862  */
863 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
864 {
865     Window root, child;
866     int root_x, root_y, child_x, child_y;
867     unsigned int u;
868
869     /* query window (drag&drop event contains only drag window) */
870     wine_tsx11_lock();
871     XQueryPointer( event->display, root_window, &root, &child,
872                    &root_x, &root_y, &child_x, &child_y, &u);
873     if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
874     wine_tsx11_unlock();
875     if (!hwnd) return;
876     if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
877         EVENT_DropFromOffiX(hwnd, event);
878     else if (event->data.l[0] == DndURL)
879         EVENT_DropURLs(hwnd, event);
880 }
881
882
883 struct client_message_handler
884 {
885     int    atom;                                  /* protocol atom */
886     void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
887 };
888
889 static const struct client_message_handler client_messages[] =
890 {
891     { XATOM_WM_PROTOCOLS, handle_wm_protocols },
892     { XATOM_DndProtocol,  handle_dnd_protocol },
893     { XATOM_XdndEnter,    X11DRV_XDND_EnterEvent },
894     { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
895     { XATOM_XdndDrop,     X11DRV_XDND_DropEvent },
896     { XATOM_XdndLeave,    X11DRV_XDND_LeaveEvent }
897 };
898
899
900 /**********************************************************************
901  *           EVENT_ClientMessage
902  */
903 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
904 {
905     XClientMessageEvent *event = &xev->xclient;
906     unsigned int i;
907
908     if (!hwnd) return;
909
910     if (event->format != 32)
911     {
912         WARN( "Don't know how to handle format %d\n", event->format );
913         return;
914     }
915
916     for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
917     {
918         if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
919         {
920             client_messages[i].handler( hwnd, event );
921             return;
922         }
923     }
924     TRACE( "no handler found for %ld\n", event->message_type );
925 }
926
927
928 /**********************************************************************
929  *           X11DRV_WindowMessage   (X11DRV.@)
930  */
931 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
932 {
933     switch(msg)
934     {
935     case WM_X11DRV_ACQUIRE_SELECTION:
936         return X11DRV_AcquireClipboard( hwnd );
937     case WM_X11DRV_DELETE_WINDOW:
938         return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
939     default:
940         FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
941         return 0;
942     }
943 }
944
945
946 /***********************************************************************
947  *              X11DRV_SendInput  (X11DRV.@)
948  */
949 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
950 {
951     UINT i;
952
953     for (i = 0; i < count; i++, inputs++)
954     {
955         switch(inputs->type)
956         {
957         case INPUT_MOUSE:
958             X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
959                                      inputs->u.mi.mouseData, inputs->u.mi.time,
960                                      inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
961             break;
962         case INPUT_KEYBOARD:
963             X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
964                                         inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
965             break;
966         case INPUT_HARDWARE:
967             FIXME( "INPUT_HARDWARE not supported\n" );
968             break;
969         }
970     }
971     return count;
972 }