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