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