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