mshtml: Create nsWineURI even if we don't have valid nsIURI.
[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       xev.window = DefaultRootWindow(xev.display);
457       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
458       /* this line is semi-stolen from gtk2 */
459       TRACE("NET_WM Pong\n");
460     }
461 }
462
463
464 static const char * const focus_details[] =
465 {
466     "NotifyAncestor",
467     "NotifyVirtual",
468     "NotifyInferior",
469     "NotifyNonlinear",
470     "NotifyNonlinearVirtual",
471     "NotifyPointer",
472     "NotifyPointerRoot",
473     "NotifyDetailNone"
474 };
475
476 /**********************************************************************
477  *              EVENT_FocusIn
478  */
479 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
480 {
481     XFocusChangeEvent *event = &xev->xfocus;
482     XIC xic;
483
484     if (!hwnd) return;
485
486     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
487
488     if (event->detail == NotifyPointer) return;
489
490     if ((xic = X11DRV_get_ic( hwnd )))
491     {
492         wine_tsx11_lock();
493         XSetICFocus( xic );
494         wine_tsx11_unlock();
495     }
496     if (use_take_focus) return;  /* ignore FocusIn if we are using take focus */
497
498     if (!can_activate_window(hwnd))
499     {
500         HWND hwnd = GetFocus();
501         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
502         if (!hwnd) hwnd = GetActiveWindow();
503         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
504         if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
505     }
506     else SetForegroundWindow( hwnd );
507 }
508
509
510 /**********************************************************************
511  *              EVENT_FocusOut
512  *
513  * Note: only top-level windows get FocusOut events.
514  */
515 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
516 {
517     XFocusChangeEvent *event = &xev->xfocus;
518     HWND hwnd_tmp;
519     Window focus_win;
520     int revert;
521     XIC xic;
522
523     if (!hwnd) return;
524
525     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
526
527     if (event->detail == NotifyPointer) return;
528     if (ximInComposeMode) return;
529
530     x11drv_thread_data()->last_focus = hwnd;
531     if ((xic = X11DRV_get_ic( hwnd )))
532     {
533         wine_tsx11_lock();
534         XUnsetICFocus( xic );
535         wine_tsx11_unlock();
536     }
537     if (hwnd != GetForegroundWindow()) return;
538     SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
539
540     /* don't reset the foreground window, if the window which is
541        getting the focus is a Wine window */
542
543     wine_tsx11_lock();
544     XGetInputFocus( thread_display(), &focus_win, &revert );
545     if (focus_win)
546     {
547         if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
548             focus_win = 0;
549     }
550     wine_tsx11_unlock();
551
552     if (!focus_win)
553     {
554         /* Abey : 6-Oct-99. Check again if the focus out window is the
555            Foreground window, because in most cases the messages sent
556            above must have already changed the foreground window, in which
557            case we don't have to change the foreground window to 0 */
558         if (hwnd == GetForegroundWindow())
559         {
560             TRACE( "lost focus, setting fg to 0\n" );
561             SetForegroundWindow( 0 );
562         }
563     }
564 }
565
566
567 /***********************************************************************
568  *           EVENT_PropertyNotify
569  *   We use this to release resources like Pixmaps when a selection
570  *   client no longer needs them.
571  */
572 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
573 {
574   XPropertyEvent *event = &xev->xproperty;
575   /* Check if we have any resources to free */
576   TRACE("Received PropertyNotify event:\n");
577
578   switch(event->state)
579   {
580     case PropertyDelete:
581     {
582       TRACE("\tPropertyDelete for atom %ld on window %ld\n",
583             event->atom, (long)event->window);
584       break;
585     }
586
587     case PropertyNewValue:
588     {
589       TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
590             event->atom, (long)event->window);
591       break;
592     }
593
594     default:
595       break;
596   }
597 }
598
599 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
600 {
601     RECT tempRect;
602
603     if (!IsWindowEnabled(hQueryWnd)) return 0;
604     
605     GetWindowRect(hQueryWnd, &tempRect);
606
607     if(!PtInRect(&tempRect, *lpPt)) return 0;
608
609     if (!IsIconic( hQueryWnd ))
610     {
611         POINT pt = *lpPt;
612         ScreenToClient( hQueryWnd, &pt );
613         GetClientRect( hQueryWnd, &tempRect );
614
615         if (PtInRect( &tempRect, pt))
616         {
617             HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
618             if (ret && ret != hQueryWnd)
619             {
620                 ret = find_drop_window( ret, lpPt );
621                 if (ret) return ret;
622             }
623         }
624     }
625
626     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
627     
628     ScreenToClient(hQueryWnd, lpPt);
629
630     return hQueryWnd;
631 }
632
633 /**********************************************************************
634  *           EVENT_DropFromOffix
635  *
636  * don't know if it still works (last Changlog is from 96/11/04)
637  */
638 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
639 {
640     unsigned long       data_length;
641     unsigned long       aux_long;
642     unsigned char*      p_data = NULL;
643     Atom atom_aux;
644     int                 x, y, dummy;
645     BOOL                bAccept;
646     Window              win, w_aux_root, w_aux_child;
647     WND*                pWnd;
648     HWND                hScope = hWnd;
649
650     win = X11DRV_get_whole_window(hWnd);
651     wine_tsx11_lock();
652     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
653                    &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
654     wine_tsx11_unlock();
655
656     pWnd = WIN_GetPtr(hWnd);
657
658     /* find out drop point and drop window */
659     if( x < 0 || y < 0 ||
660         x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
661         y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
662     {   
663         bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; 
664         x = 0;
665         y = 0; 
666     }
667     else
668     {
669         POINT   pt = { x, y };
670         HWND    hwndDrop = find_drop_window( hWnd, &pt );
671         if (hwndDrop)
672         {
673             x = pt.x;
674             y = pt.y;
675             hScope = hwndDrop;
676             bAccept = TRUE;
677         }
678         else
679         {
680             bAccept = FALSE;
681         }
682     }
683     WIN_ReleasePtr(pWnd);
684
685     if (!bAccept) return;
686
687     wine_tsx11_lock();
688     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
689                         x11drv_atom(DndSelection), 0, 65535, FALSE,
690                         AnyPropertyType, &atom_aux, &dummy,
691                         &data_length, &aux_long, &p_data);
692     wine_tsx11_unlock();
693
694     if( !aux_long && p_data)  /* don't bother if > 64K */
695     {
696         char *p = (char *)p_data;
697         char *p_drop;
698
699         aux_long = 0;
700         while( *p )  /* calculate buffer size */
701         {
702             INT len = GetShortPathNameA( p, NULL, 0 );
703             if (len) aux_long += len + 1;
704             p += strlen(p) + 1;
705         }
706         if( aux_long && aux_long < 65535 )
707         {
708             HDROP                 hDrop;
709             DROPFILES *lpDrop;
710
711             aux_long += sizeof(DROPFILES) + 1;
712             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
713             lpDrop = (DROPFILES*)GlobalLock( hDrop );
714
715             if( lpDrop )
716             {
717                 WND *pDropWnd = WIN_GetPtr( hScope );
718                 lpDrop->pFiles = sizeof(DROPFILES);
719                 lpDrop->pt.x = x;
720                 lpDrop->pt.y = y;
721                 lpDrop->fNC =
722                     ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
723                       y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
724                       x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
725                       y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
726                 lpDrop->fWide = FALSE;
727                 WIN_ReleasePtr(pDropWnd);
728                 p_drop = (char *)(lpDrop + 1);
729                 p = (char *)p_data;
730                 while(*p)
731                 {
732                     if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
733                         p_drop += strlen( p_drop ) + 1;
734                     p += strlen(p) + 1;
735                 }
736                 *p_drop = '\0';
737                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
738             }
739         }
740     }
741     wine_tsx11_lock();
742     if( p_data ) XFree(p_data);
743     wine_tsx11_unlock();
744 }
745
746 /**********************************************************************
747  *           EVENT_DropURLs
748  *
749  * drop items are separated by \n
750  * each item is prefixed by its mime type
751  *
752  * event->data.l[3], event->data.l[4] contains drop x,y position
753  */
754 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
755 {
756   unsigned long data_length;
757   unsigned long aux_long, drop_len = 0;
758   unsigned char *p_data = NULL; /* property data */
759   char          *p_drop = NULL;
760   char          *p, *next;
761   int           x, y;
762   DROPFILES *lpDrop;
763   HDROP hDrop;
764   union {
765     Atom        atom_aux;
766     int         i;
767     Window      w_aux;
768     unsigned int u;
769   }             u; /* unused */
770
771   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
772
773   wine_tsx11_lock();
774   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
775                       x11drv_atom(DndSelection), 0, 65535, FALSE,
776                       AnyPropertyType, &u.atom_aux, &u.i,
777                       &data_length, &aux_long, &p_data);
778   wine_tsx11_unlock();
779   if (aux_long)
780     WARN("property too large, truncated!\n");
781   TRACE("urls=%s\n", p_data);
782
783   if( !aux_long && p_data) {    /* don't bother if > 64K */
784     /* calculate length */
785     p = (char*) p_data;
786     next = strchr(p, '\n');
787     while (p) {
788       if (next) *next=0;
789       if (strncmp(p,"file:",5) == 0 ) {
790         INT len = GetShortPathNameA( p+5, NULL, 0 );
791         if (len) drop_len += len + 1;
792       }
793       if (next) {
794         *next = '\n';
795         p = next + 1;
796         next = strchr(p, '\n');
797       } else {
798         p = NULL;
799       }
800     }
801
802     if( drop_len && drop_len < 65535 ) {
803       wine_tsx11_lock();
804       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
805                      &x, &y, &u.i, &u.i, &u.u);
806       wine_tsx11_unlock();
807
808       drop_len += sizeof(DROPFILES) + 1;
809       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
810       lpDrop = (DROPFILES *) GlobalLock( hDrop );
811
812       if( lpDrop ) {
813           WND *pDropWnd = WIN_GetPtr( hWnd );
814           lpDrop->pFiles = sizeof(DROPFILES);
815           lpDrop->pt.x = (INT)x;
816           lpDrop->pt.y = (INT)y;
817           lpDrop->fNC =
818             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
819               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
820               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
821               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
822           lpDrop->fWide = FALSE;
823           p_drop = (char*)(lpDrop + 1);
824           WIN_ReleasePtr(pDropWnd);
825       }
826
827       /* create message content */
828       if (p_drop) {
829         p = (char*) p_data;
830         next = strchr(p, '\n');
831         while (p) {
832           if (next) *next=0;
833           if (strncmp(p,"file:",5) == 0 ) {
834             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
835             if (len) {
836               TRACE("drop file %s as %s\n", p+5, p_drop);
837               p_drop += len+1;
838             } else {
839               WARN("can't convert file %s to dos name\n", p+5);
840             }
841           } else {
842             WARN("unknown mime type %s\n", p);
843           }
844           if (next) {
845             *next = '\n';
846             p = next + 1;
847             next = strchr(p, '\n');
848           } else {
849             p = NULL;
850           }
851           *p_drop = '\0';
852         }
853
854         GlobalUnlock(hDrop);
855         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
856       }
857     }
858     wine_tsx11_lock();
859     if( p_data ) XFree(p_data);
860     wine_tsx11_unlock();
861   }
862 }
863
864 /**********************************************************************
865  *              handle_dnd_protocol
866  */
867 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
868 {
869     Window root, child;
870     int root_x, root_y, child_x, child_y;
871     unsigned int u;
872
873     /* query window (drag&drop event contains only drag window) */
874     wine_tsx11_lock();
875     XQueryPointer( event->display, root_window, &root, &child,
876                    &root_x, &root_y, &child_x, &child_y, &u);
877     if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
878     wine_tsx11_unlock();
879     if (!hwnd) return;
880     if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
881         EVENT_DropFromOffiX(hwnd, event);
882     else if (event->data.l[0] == DndURL)
883         EVENT_DropURLs(hwnd, event);
884 }
885
886
887 struct client_message_handler
888 {
889     int    atom;                                  /* protocol atom */
890     void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
891 };
892
893 static const struct client_message_handler client_messages[] =
894 {
895     { XATOM_WM_PROTOCOLS, handle_wm_protocols },
896     { XATOM_DndProtocol,  handle_dnd_protocol },
897     { XATOM_XdndEnter,    X11DRV_XDND_EnterEvent },
898     { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
899     { XATOM_XdndDrop,     X11DRV_XDND_DropEvent },
900     { XATOM_XdndLeave,    X11DRV_XDND_LeaveEvent }
901 };
902
903
904 /**********************************************************************
905  *           EVENT_ClientMessage
906  */
907 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
908 {
909     XClientMessageEvent *event = &xev->xclient;
910     unsigned int i;
911
912     if (!hwnd) return;
913
914     if (event->format != 32)
915     {
916         WARN( "Don't know how to handle format %d\n", event->format );
917         return;
918     }
919
920     for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
921     {
922         if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
923         {
924             client_messages[i].handler( hwnd, event );
925             return;
926         }
927     }
928     TRACE( "no handler found for %ld\n", event->message_type );
929 }
930
931
932 /**********************************************************************
933  *           X11DRV_WindowMessage   (X11DRV.@)
934  */
935 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
936 {
937     switch(msg)
938     {
939     case WM_X11DRV_ACQUIRE_SELECTION:
940         return X11DRV_AcquireClipboard( hwnd );
941     case WM_X11DRV_DELETE_WINDOW:
942         return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
943     default:
944         FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
945         return 0;
946     }
947 }
948
949
950 /***********************************************************************
951  *              X11DRV_SendInput  (X11DRV.@)
952  */
953 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
954 {
955     UINT i;
956
957     for (i = 0; i < count; i++, inputs++)
958     {
959         switch(inputs->type)
960         {
961         case INPUT_MOUSE:
962             X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
963                                      inputs->u.mi.mouseData, inputs->u.mi.time,
964                                      inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
965             break;
966         case INPUT_KEYBOARD:
967             X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
968                                         inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
969             break;
970         case INPUT_HARDWARE:
971             FIXME( "INPUT_HARDWARE not supported\n" );
972             break;
973         }
974     }
975     return count;
976 }