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