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