EnumThemeColors() and EnumThemeSizes() actually do not return a single
[wine] / dlls / x11drv / event.c
1 /*
2  * X11 event driver
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1999 Noel Borthwick
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #define COM_NO_WINDOWS_H
23 #include "config.h"
24
25 #include <X11/Xatom.h>
26 #include <X11/keysym.h>
27 #include <X11/Xlib.h>
28 #include <X11/Xresource.h>
29 #include <X11/Xutil.h>
30 #ifdef HAVE_LIBXXF86DGA2
31 #include <X11/extensions/xf86dga.h>
32 #endif
33
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <string.h>
37
38 #define NONAMELESSUNION
39 #define NONAMELESSSTRUCT
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winuser.h"
43 #include "wingdi.h"
44 #include "shlobj.h"  /* DROPFILES */
45
46 #include "win.h"
47 #include "winreg.h"
48 #include "x11drv.h"
49 #include "shellapi.h"
50 #include "wine/debug.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(event);
53
54 extern BOOL ximInComposeMode;
55
56 #define DndNotDnd       -1    /* OffiX drag&drop */
57 #define DndUnknown      0
58 #define DndRawData      1
59 #define DndFile         2
60 #define DndFiles        3
61 #define DndText         4
62 #define DndDir          5
63 #define DndLink         6
64 #define DndExe          7
65
66 #define DndEND          8
67
68 #define DndURL          128   /* KDE drag&drop */
69
70   /* Event handlers */
71 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
72 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
73 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
74 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
75
76 struct event_handler
77 {
78     int                  type;    /* event type */
79     x11drv_event_handler handler; /* corresponding handler function */
80 };
81
82 #define MAX_EVENT_HANDLERS 64
83
84 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
85 {
86     /* list must be sorted by event type */
87     { KeyPress,         X11DRV_KeyEvent },
88     { KeyRelease,       X11DRV_KeyEvent },
89     { ButtonPress,      X11DRV_ButtonPress },
90     { ButtonRelease,    X11DRV_ButtonRelease },
91     { MotionNotify,     X11DRV_MotionNotify },
92     { EnterNotify,      X11DRV_EnterNotify },
93     /* LeaveNotify */
94     { FocusIn,          EVENT_FocusIn },
95     { FocusOut,         EVENT_FocusOut },
96     { KeymapNotify,     X11DRV_KeymapNotify },
97     { Expose,           X11DRV_Expose },
98     /* GraphicsExpose */
99     /* NoExpose */
100     /* VisibilityNotify */
101     /* CreateNotify */
102     /* DestroyNotify */
103     { UnmapNotify,      X11DRV_UnmapNotify },
104     { MapNotify,        X11DRV_MapNotify },
105     /* MapRequest */
106     /* ReparentNotify */
107     { ConfigureNotify,  X11DRV_ConfigureNotify },
108     /* ConfigureRequest */
109     /* GravityNotify */
110     /* ResizeRequest */
111     /* CirculateNotify */
112     /* CirculateRequest */
113     { PropertyNotify,   EVENT_PropertyNotify },
114     { SelectionClear,   X11DRV_SelectionClear },
115     { SelectionRequest, X11DRV_SelectionRequest },
116     /* SelectionNotify */
117     /* ColormapNotify */
118     { ClientMessage,    EVENT_ClientMessage },
119     { MappingNotify,    X11DRV_MappingNotify },
120 };
121
122 static int nb_event_handlers = 18;  /* change this if you add handlers above */
123
124
125 /* return the name of an X event */
126 static const char *dbgstr_event( int type )
127 {
128     static const char * const event_names[] =
129     {
130         "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
131         "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
132         "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
133         "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
134         "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
135         "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
136         "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
137         "ClientMessage", "MappingNotify"
138     };
139
140     if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
141     return wine_dbg_sprintf( "Extension event %d", type );
142 }
143
144
145 /***********************************************************************
146  *           find_handler
147  *
148  * Find the handler for a given event type. Caller must hold the x11 lock.
149  */
150 static inline x11drv_event_handler find_handler( int type )
151 {
152     int min = 0, max = nb_event_handlers - 1;
153
154     while (min <= max)
155     {
156         int pos = (min + max) / 2;
157         if (handlers[pos].type == type) return handlers[pos].handler;
158         if (handlers[pos].type > type) max = pos - 1;
159         else min = pos + 1;
160     }
161     return NULL;
162 }
163
164
165 /***********************************************************************
166  *           X11DRV_register_event_handler
167  *
168  * Register a handler for a given event type.
169  * If already registered, overwrite the previous handler.
170  */
171 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
172 {
173     int min, max;
174
175     wine_tsx11_lock();
176     min = 0;
177     max = nb_event_handlers - 1;
178     while (min <= max)
179     {
180         int pos = (min + max) / 2;
181         if (handlers[pos].type == type)
182         {
183             handlers[pos].handler = handler;
184             goto done;
185         }
186         if (handlers[pos].type > type) max = pos - 1;
187         else min = pos + 1;
188     }
189     /* insert it between max and min */
190     memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
191     handlers[min].type = type;
192     handlers[min].handler = handler;
193     nb_event_handlers++;
194     assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
195 done:
196     wine_tsx11_unlock();
197     TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
198 }
199
200
201 /***********************************************************************
202  *           filter_event
203  */
204 static Bool filter_event( Display *display, XEvent *event, char *arg )
205 {
206     DWORD mask = (ULONG_PTR)arg;
207
208     if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
209
210     switch(event->type)
211     {
212     case KeyPress:
213     case KeyRelease:
214     case KeymapNotify:
215         return (mask & QS_KEY) != 0;
216     case ButtonPress:
217     case ButtonRelease:
218         return (mask & QS_MOUSEBUTTON) != 0;
219     case MotionNotify:
220     case EnterNotify:
221     case LeaveNotify:
222         return (mask & QS_MOUSEMOVE) != 0;
223     case Expose:
224         return (mask & QS_PAINT) != 0;
225     case ClientMessage:
226         return (mask & QS_POSTMESSAGE) != 0;
227     default:
228         return (mask & QS_SENDMESSAGE) != 0;
229     }
230 }
231
232
233 /***********************************************************************
234  *           process_events
235  */
236 static int process_events( Display *display, DWORD mask )
237 {
238     XEvent event;
239     HWND hwnd;
240     int count = 0;
241     x11drv_event_handler handler;
242
243     wine_tsx11_lock();
244     while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
245     {
246         count++;
247         if (XFilterEvent( &event, None )) continue;  /* filtered, ignore it */
248
249         if (!(handler = find_handler( event.type )))
250         {
251             TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
252             continue;  /* no handler, ignore it */
253         }
254
255         if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
256             hwnd = 0;  /* not for a registered window */
257         if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
258
259         wine_tsx11_unlock();
260         TRACE( "%s for hwnd/window %p/%lx\n",
261                dbgstr_event( event.type ), hwnd, event.xany.window );
262         handler( hwnd, &event );
263         wine_tsx11_lock();
264     }
265     wine_tsx11_unlock();
266     if (count) TRACE( "processed %d events\n", count );
267     return count;
268 }
269
270
271 /***********************************************************************
272  *           MsgWaitForMultipleObjectsEx   (X11DRV.@)
273  */
274 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
275                                           DWORD timeout, DWORD mask, DWORD flags )
276 {
277     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     union {
641         Atom    atom_aux;
642         struct {
643             int x;
644             int y;
645         }       pt_aux;
646         int     i;
647     }                   u;
648     int                 x, y;
649     BOOL                bAccept;
650     Window              win, w_aux_root, w_aux_child;
651     WND*                pWnd;
652     HWND                hScope = hWnd;
653
654     win = X11DRV_get_whole_window(hWnd);
655     wine_tsx11_lock();
656     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
657                    &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
658                    (unsigned int*)&aux_long);
659     wine_tsx11_unlock();
660
661     pWnd = WIN_GetPtr(hWnd);
662
663     /* find out drop point and drop window */
664     if( x < 0 || y < 0 ||
665         x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
666         y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
667     {   
668         bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; 
669         x = 0;
670         y = 0; 
671     }
672     else
673     {
674         POINT   pt = { x, y };
675         HWND    hwndDrop = find_drop_window( hWnd, &pt );
676         if (hwndDrop)
677         {
678             x = pt.x;
679             y = pt.y;
680             hScope = hwndDrop;
681             bAccept = TRUE;
682         }
683         else
684         {
685             bAccept = FALSE;
686         }
687     }
688     WIN_ReleasePtr(pWnd);
689
690     if (!bAccept) return;
691
692     wine_tsx11_lock();
693     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
694                         x11drv_atom(DndSelection), 0, 65535, FALSE,
695                         AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
696                         &data_length, &aux_long, &p_data);
697     wine_tsx11_unlock();
698
699     if( !aux_long && p_data)  /* don't bother if > 64K */
700     {
701         signed char *p = (signed char*) p_data;
702         char *p_drop;
703
704         aux_long = 0;
705         while( *p )  /* calculate buffer size */
706         {
707             p_drop = p;
708             if((u.i = *p) != -1 )
709             {
710                 INT len = GetShortPathNameA( p, NULL, 0 );
711                 if (len) aux_long += len + 1;
712                 else *p = -1;
713             }
714             p += strlen(p) + 1;
715         }
716         if( aux_long && aux_long < 65535 )
717         {
718             HDROP                 hDrop;
719             DROPFILES *lpDrop;
720
721             aux_long += sizeof(DROPFILES) + 1;
722             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
723             lpDrop = (DROPFILES*)GlobalLock( hDrop );
724
725             if( lpDrop )
726             {
727                 WND *pDropWnd = WIN_GetPtr( hScope );
728                 lpDrop->pFiles = sizeof(DROPFILES);
729                 lpDrop->pt.x = x;
730                 lpDrop->pt.y = y;
731                 lpDrop->fNC =
732                     ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
733                       y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
734                       x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
735                       y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
736                 lpDrop->fWide = FALSE;
737                 WIN_ReleasePtr(pDropWnd);
738                 p_drop = (char *)(lpDrop + 1);
739                 p = p_data;
740                 while(*p)
741                 {
742                     if( *p != -1 ) /* use only "good" entries */
743                     {
744                         GetShortPathNameA( p, p_drop, 65535 );
745                         p_drop += strlen( p_drop ) + 1;
746                     }
747                     p += strlen(p) + 1;
748                 }
749                 *p_drop = '\0';
750                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
751             }
752         }
753     }
754     wine_tsx11_lock();
755     if( p_data ) XFree(p_data);
756     wine_tsx11_unlock();
757 }
758
759 /**********************************************************************
760  *           EVENT_DropURLs
761  *
762  * drop items are separated by \n
763  * each item is prefixed by its mime type
764  *
765  * event->data.l[3], event->data.l[4] contains drop x,y position
766  */
767 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
768 {
769   unsigned long data_length;
770   unsigned long aux_long, drop_len = 0;
771   unsigned char *p_data = NULL; /* property data */
772   char          *p_drop = NULL;
773   char          *p, *next;
774   int           x, y;
775   DROPFILES *lpDrop;
776   HDROP hDrop;
777   union {
778     Atom        atom_aux;
779     int         i;
780     Window      w_aux;
781     unsigned int u;
782   }             u; /* unused */
783
784   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
785
786   wine_tsx11_lock();
787   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
788                       x11drv_atom(DndSelection), 0, 65535, FALSE,
789                       AnyPropertyType, &u.atom_aux, &u.i,
790                       &data_length, &aux_long, &p_data);
791   wine_tsx11_unlock();
792   if (aux_long)
793     WARN("property too large, truncated!\n");
794   TRACE("urls=%s\n", p_data);
795
796   if( !aux_long && p_data) {    /* don't bother if > 64K */
797     /* calculate length */
798     p = (char*) p_data;
799     next = strchr(p, '\n');
800     while (p) {
801       if (next) *next=0;
802       if (strncmp(p,"file:",5) == 0 ) {
803         INT len = GetShortPathNameA( p+5, NULL, 0 );
804         if (len) drop_len += len + 1;
805       }
806       if (next) {
807         *next = '\n';
808         p = next + 1;
809         next = strchr(p, '\n');
810       } else {
811         p = NULL;
812       }
813     }
814
815     if( drop_len && drop_len < 65535 ) {
816       wine_tsx11_lock();
817       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
818                      &x, &y, &u.i, &u.i, &u.u);
819       wine_tsx11_unlock();
820
821       drop_len += sizeof(DROPFILES) + 1;
822       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
823       lpDrop = (DROPFILES *) GlobalLock( hDrop );
824
825       if( lpDrop ) {
826           WND *pDropWnd = WIN_GetPtr( hWnd );
827           lpDrop->pFiles = sizeof(DROPFILES);
828           lpDrop->pt.x = (INT)x;
829           lpDrop->pt.y = (INT)y;
830           lpDrop->fNC =
831             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
832               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
833               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
834               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
835           lpDrop->fWide = FALSE;
836           p_drop = (char*)(lpDrop + 1);
837           WIN_ReleasePtr(pDropWnd);
838       }
839
840       /* create message content */
841       if (p_drop) {
842         p = (char*) p_data;
843         next = strchr(p, '\n');
844         while (p) {
845           if (next) *next=0;
846           if (strncmp(p,"file:",5) == 0 ) {
847             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
848             if (len) {
849               TRACE("drop file %s as %s\n", p+5, p_drop);
850               p_drop += len+1;
851             } else {
852               WARN("can't convert file %s to dos name \n", p+5);
853             }
854           } else {
855             WARN("unknown mime type %s\n", p);
856           }
857           if (next) {
858             *next = '\n';
859             p = next + 1;
860             next = strchr(p, '\n');
861           } else {
862             p = NULL;
863           }
864           *p_drop = '\0';
865         }
866
867         GlobalUnlock(hDrop);
868         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
869       }
870     }
871     wine_tsx11_lock();
872     if( p_data ) XFree(p_data);
873     wine_tsx11_unlock();
874   }
875 }
876
877 /**********************************************************************
878  *              handle_dnd_protocol
879  */
880 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
881 {
882     Window root, child;
883     int root_x, root_y, child_x, child_y;
884     unsigned int u;
885
886     /* query window (drag&drop event contains only drag window) */
887     wine_tsx11_lock();
888     XQueryPointer( event->display, root_window, &root, &child,
889                    &root_x, &root_y, &child_x, &child_y, &u);
890     if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
891     wine_tsx11_unlock();
892     if (!hwnd) return;
893     if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
894         EVENT_DropFromOffiX(hwnd, event);
895     else if (event->data.l[0] == DndURL)
896         EVENT_DropURLs(hwnd, event);
897 }
898
899
900 struct client_message_handler
901 {
902     int    atom;                                  /* protocol atom */
903     void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
904 };
905
906 static const struct client_message_handler client_messages[] =
907 {
908     { XATOM_WM_PROTOCOLS, handle_wm_protocols },
909     { XATOM_DndProtocol,  handle_dnd_protocol },
910     { XATOM_XdndEnter,    X11DRV_XDND_EnterEvent },
911     { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
912     { XATOM_XdndDrop,     X11DRV_XDND_DropEvent },
913     { XATOM_XdndLeave,    X11DRV_XDND_LeaveEvent }
914 };
915
916
917 /**********************************************************************
918  *           EVENT_ClientMessage
919  */
920 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
921 {
922     XClientMessageEvent *event = &xev->xclient;
923     unsigned int i;
924
925     if (!hwnd) return;
926
927     if (event->format != 32)
928     {
929         WARN( "Don't know how to handle format %d\n", event->format );
930         return;
931     }
932
933     for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
934     {
935         if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
936         {
937             client_messages[i].handler( hwnd, event );
938             return;
939         }
940     }
941     TRACE( "no handler found for %ld\n", event->message_type );
942 }
943
944
945 /**********************************************************************
946  *           X11DRV_WindowMessage   (X11DRV.@)
947  */
948 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
949 {
950     switch(msg)
951     {
952     case WM_X11DRV_ACQUIRE_SELECTION:
953         X11DRV_AcquireClipboard( hwnd );
954         return 0;
955     case WM_X11DRV_DELETE_WINDOW:
956         return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
957     default:
958         FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
959         return 0;
960     }
961 }
962
963
964 /***********************************************************************
965  *              X11DRV_SendInput  (X11DRV.@)
966  */
967 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
968 {
969     UINT i;
970
971     for (i = 0; i < count; i++, inputs++)
972     {
973         switch(inputs->type)
974         {
975         case INPUT_MOUSE:
976             X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
977                                      inputs->u.mi.mouseData, inputs->u.mi.time,
978                                      inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
979             break;
980         case INPUT_KEYBOARD:
981             X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
982                                         inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
983             break;
984         case INPUT_HARDWARE:
985             FIXME( "INPUT_HARDWARE not supported\n" );
986             break;
987         }
988     }
989     return count;
990 }