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