Moved clipboard event handling functions and some private data
[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 #include "wine/winuser16.h"
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "wingdi.h"
42 #include "shlobj.h"  /* DROPFILES */
43
44 #include "win.h"
45 #include "winreg.h"
46 #include "x11drv.h"
47 #include "shellapi.h"
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(event);
51 WINE_DECLARE_DEBUG_CHANNEL(clipboard);
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 static const char * const event_names[] =
70 {
71   "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
72   "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
73   "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
74   "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
75   "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
76   "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
77   "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
78   "ClientMessage", "MappingNotify"
79 };
80
81
82 static void EVENT_ProcessEvent( XEvent *event );
83
84   /* Event handlers */
85 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
86 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
87 static void EVENT_PropertyNotify( XPropertyEvent *event );
88 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
89
90 #ifdef HAVE_LIBXXF86DGA2
91 static int DGAMotionEventType;
92 static int DGAButtonPressEventType;
93 static int DGAButtonReleaseEventType;
94 static int DGAKeyPressEventType;
95 static int DGAKeyReleaseEventType;
96
97 static BOOL DGAUsed = FALSE;
98 static HWND DGAhwnd = 0;
99 #endif
100
101 /* Static used for the current input method */
102 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
103 static BOOL in_transition = FALSE; /* This is not used as for today */
104
105
106 /***********************************************************************
107  *           process_events
108  */
109 static int process_events( struct x11drv_thread_data *data )
110 {
111     XEvent event;
112     int count = 0;
113
114     wine_tsx11_lock();
115     while ( XPending( data->display ) )
116     {
117         Bool ignore;
118
119         XNextEvent( data->display, &event );
120         ignore = XFilterEvent( &event, None );
121         wine_tsx11_unlock();
122         if (!ignore) EVENT_ProcessEvent( &event );
123         count++;
124         wine_tsx11_lock();
125     }
126     wine_tsx11_unlock();
127     return count;
128 }
129
130
131 /***********************************************************************
132  *           MsgWaitForMultipleObjectsEx   (X11DRV.@)
133  */
134 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
135                                           DWORD timeout, DWORD mask, DWORD flags )
136 {
137     HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1];  /* FIXME! */
138     DWORD i, ret;
139     struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
140
141     if (!data || data->process_event_count)
142         return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
143                                          timeout, flags & MWMO_ALERTABLE );
144
145     /* check whether only server queue handle was passed in */
146     if (count < 2) flags &= ~MWMO_WAITALL;
147
148     for (i = 0; i < count; i++) new_handles[i] = handles[i];
149     new_handles[count] = data->display_fd;
150
151     wine_tsx11_lock();
152     XFlush( gdi_display );
153     XFlush( data->display );
154     wine_tsx11_unlock();
155
156     data->process_event_count++;
157     if (process_events( data )) ret = count;
158     else
159     {
160         ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
161                                         timeout, flags & MWMO_ALERTABLE );
162         if (ret == count) process_events( data );
163     }
164     data->process_event_count--;
165     return ret;
166 }
167
168 /***********************************************************************
169  *           EVENT_x11_time_to_win32_time
170  *
171  * Make our timer and the X timer line up as best we can
172  *  Pass 0 to retrieve the current adjustment value (times -1)
173  */
174 DWORD EVENT_x11_time_to_win32_time(Time time)
175 {
176   static DWORD adjust = 0;
177   DWORD now = GetTickCount();
178   DWORD ret;
179
180   if (! adjust && time != 0)
181   {
182     ret = now;
183     adjust = time - now;
184   }
185   else
186   {
187       /* If we got an event in the 'future', then our clock is clearly wrong. 
188          If we got it more than 10000 ms in the future, then it's most likely
189          that the clock has wrapped.  */
190
191       ret = time - adjust;
192       if (ret > now && ((ret - now) < 10000) && time != 0)
193       {
194         adjust += ret - now;
195         ret    -= ret - now;
196       }
197   }
198
199   return ret;
200
201 }
202
203 /***********************************************************************
204  *           EVENT_ProcessEvent
205  *
206  * Process an X event.
207  */
208 static void EVENT_ProcessEvent( XEvent *event )
209 {
210   HWND hWnd;
211   Display *display = event->xany.display;
212
213   TRACE( "called.\n" );
214
215   switch (event->type)
216   {
217     case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
218          FIXME("Got SelectionNotify - must not happen!\n");
219          /* fall through */
220
221       /* We get all these because of StructureNotifyMask.
222          This check is placed here to avoid getting error messages below,
223          as X might send some of these even for windows that have already
224          been deleted ... */
225     case CirculateNotify:
226     case CreateNotify:
227     case DestroyNotify:
228     case GravityNotify:
229     case ReparentNotify:
230       return;
231   }
232
233 #ifdef HAVE_LIBXXF86DGA2
234   if (DGAUsed) {
235     if (event->type == DGAMotionEventType) {
236       TRACE("DGAMotionEvent received.\n");
237       X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
238       return;
239     }
240     if (event->type == DGAButtonPressEventType) {
241       TRACE("DGAButtonPressEvent received.\n");
242       X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
243       return;
244     }
245     if (event->type == DGAButtonReleaseEventType) {
246       TRACE("DGAButtonReleaseEvent received.\n");
247       X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
248       return;
249     }
250     if ((event->type == DGAKeyPressEventType) ||
251         (event->type == DGAKeyReleaseEventType)) {
252       /* Fill a XKeyEvent to send to EVENT_Key */
253       XKeyEvent ke;
254       XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
255
256       TRACE("DGAKeyPress/ReleaseEvent received.\n");
257
258       if (evt->type == DGAKeyReleaseEventType)
259         ke.type = KeyRelease;
260       else
261         ke.type = KeyPress;
262       ke.serial = evt->serial;
263       ke.send_event = FALSE;
264       ke.display = evt->display;
265       ke.window = 0;
266       ke.root = 0;
267       ke.subwindow = 0;
268       ke.time = evt->time;
269       ke.x = -1;
270       ke.y = -1;
271       ke.x_root = -1;
272       ke.y_root = -1;
273       ke.state = evt->state;
274       ke.keycode = evt->keycode;
275       ke.same_screen = TRUE;
276       X11DRV_KeyEvent( 0, &ke );
277       return;
278     }
279   }
280 #endif
281
282   wine_tsx11_lock();
283   if (XFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
284       hWnd = 0;  /* Not for a registered window */
285   wine_tsx11_unlock();
286   if (!hWnd && event->xany.window == root_window) hWnd = GetDesktopWindow();
287
288   if (!hWnd && event->type != PropertyNotify &&
289       event->type != MappingNotify && event->type != KeymapNotify)
290       WARN( "Got event %s for unknown Window %08lx\n",
291             event_names[event->type], event->xany.window );
292   else if (event->type <= MappingNotify)
293       TRACE("Got event %s for hwnd/window %p/%lx, GetFocus()=%p\n",
294             event_names[event->type], hWnd, event->xany.window, GetFocus() );
295   else
296       TRACE("Got extension event for hwnd/window %p/%lx, GetFocus()=%p\n",
297             hWnd, event->xany.window, GetFocus() );
298
299   if (X11DRV_ProcessTabletEvent(hWnd, event))
300   {
301         TRACE("Return: filtered by tablet\n");
302         return;
303   }
304
305   switch(event->type)
306     {
307     case KeyPress:
308     case KeyRelease:
309       /* FIXME: should generate a motion event if event point is different from current pos */
310       X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
311       break;
312
313     case ButtonPress:
314       X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
315       break;
316
317     case ButtonRelease:
318       X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
319       break;
320
321     case MotionNotify:
322       X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
323       break;
324
325     case EnterNotify:
326       X11DRV_EnterNotify( hWnd, (XCrossingEvent*)event );
327       break;
328
329     case FocusIn:
330       EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
331       break;
332
333     case FocusOut:
334       EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
335       break;
336
337     case Expose:
338       X11DRV_Expose( hWnd, &event->xexpose );
339       break;
340
341     case ConfigureNotify:
342       if (!hWnd) return;
343       X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
344       break;
345
346     case SelectionRequest:
347       X11DRV_SelectionRequest( hWnd, (XSelectionRequestEvent *)event );
348       break;
349
350     case SelectionClear:
351       X11DRV_SelectionClear( hWnd, (XSelectionClearEvent*) event );
352       break;
353
354     case PropertyNotify:
355       EVENT_PropertyNotify( (XPropertyEvent *)event );
356       break;
357
358     case ClientMessage:
359       if (!hWnd) return;
360       EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
361       break;
362
363     case NoExpose:
364       break;
365
366     case MapNotify:
367       X11DRV_MapNotify( hWnd, (XMapEvent *)event );
368       break;
369
370     case UnmapNotify:
371       X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
372       break;
373
374     case KeymapNotify:
375       X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
376       break;
377
378     case MappingNotify:
379       X11DRV_MappingNotify( (XMappingEvent *) event );
380       break;
381
382     default:
383       WARN("Unprocessed event %s for hwnd %p\n", event_names[event->type], hWnd );
384       break;
385     }
386     TRACE( "returns.\n" );
387 }
388
389
390 /*******************************************************************
391  *         can_activate_window
392  *
393  * Check if we can activate the specified window.
394  */
395 inline static BOOL can_activate_window( HWND hwnd )
396 {
397     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
398     if (!(style & WS_VISIBLE)) return FALSE;
399     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
400     return !(style & WS_DISABLED);
401 }
402
403
404 /**********************************************************************
405  *              set_focus
406  */
407 static void set_focus( HWND hwnd, Time time )
408 {
409     HWND focus;
410     Window win;
411
412     TRACE( "setting foreground window to %p\n", hwnd );
413     SetForegroundWindow( hwnd );
414
415     focus = GetFocus();
416     if (focus) focus = GetAncestor( focus, GA_ROOT );
417     win = X11DRV_get_whole_window(focus);
418
419     if (win)
420     {
421         TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
422         wine_tsx11_lock();
423         XSetInputFocus( thread_display(), win, RevertToParent, time );
424         wine_tsx11_unlock();
425     }
426 }
427
428
429 /**********************************************************************
430  *              handle_wm_protocols_message
431  */
432 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
433 {
434     Atom protocol = (Atom)event->data.l[0];
435
436     if (!protocol) return;
437
438     if (protocol == x11drv_atom(WM_DELETE_WINDOW))
439     {
440         /* Ignore the delete window request if the window has been disabled
441          * and we are in managed mode. This is to disallow applications from
442          * being closed by the window manager while in a modal state.
443          */
444         if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
445     }
446     else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
447     {
448         Time event_time = (Time)event->data.l[1];
449         HWND last_focus = x11drv_thread_data()->last_focus;
450
451         TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
452                hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
453                GetForegroundWindow(), last_focus );
454
455         if (can_activate_window(hwnd))
456         {
457             /* simulate a mouse click on the caption to find out
458              * whether the window wants to be activated */
459             LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
460                                        (WPARAM)GetAncestor( hwnd, GA_ROOT ),
461                                        MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
462             if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
463             else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
464         }
465         else
466         {
467             hwnd = GetFocus();
468             if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
469             if (!hwnd) hwnd = GetActiveWindow();
470             if (!hwnd) hwnd = last_focus;
471             if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
472         }
473     }
474     else if (protocol == x11drv_atom(_NET_WM_PING))
475     {
476       XClientMessageEvent xev;
477       xev = *event;
478       
479       TRACE("NET_WM Ping\n");
480       xev.window = DefaultRootWindow(xev.display);
481       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
482       /* this line is semi-stolen from gtk2 */
483       TRACE("NET_WM Pong\n");
484     }
485 }
486
487
488 static const char * const focus_details[] =
489 {
490     "NotifyAncestor",
491     "NotifyVirtual",
492     "NotifyInferior",
493     "NotifyNonlinear",
494     "NotifyNonlinearVirtual",
495     "NotifyPointer",
496     "NotifyPointerRoot",
497     "NotifyDetailNone"
498 };
499
500 /**********************************************************************
501  *              EVENT_FocusIn
502  */
503 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
504 {
505     XIC xic;
506
507     if (!hwnd) return;
508
509     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
510
511     if (event->detail == NotifyPointer) return;
512
513     if ((xic = X11DRV_get_ic( hwnd )))
514     {
515         wine_tsx11_lock();
516         XSetICFocus( xic );
517         wine_tsx11_unlock();
518     }
519     if (use_take_focus) return;  /* ignore FocusIn if we are using take focus */
520
521     if (!can_activate_window(hwnd))
522     {
523         HWND hwnd = GetFocus();
524         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
525         if (!hwnd) hwnd = GetActiveWindow();
526         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
527         if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
528     }
529     else SetForegroundWindow( hwnd );
530 }
531
532
533 /**********************************************************************
534  *              EVENT_FocusOut
535  *
536  * Note: only top-level windows get FocusOut events.
537  */
538 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
539 {
540     HWND hwnd_tmp;
541     Window focus_win;
542     int revert;
543     XIC xic;
544
545     if (!hwnd) return;
546
547     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
548
549     if (event->detail == NotifyPointer) return;
550     if (ximInComposeMode) return;
551
552     x11drv_thread_data()->last_focus = hwnd;
553     if ((xic = X11DRV_get_ic( hwnd )))
554     {
555         wine_tsx11_lock();
556         XUnsetICFocus( xic );
557         wine_tsx11_unlock();
558     }
559     if (hwnd != GetForegroundWindow()) return;
560     SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
561
562     /* don't reset the foreground window, if the window which is
563        getting the focus is a Wine window */
564
565     wine_tsx11_lock();
566     XGetInputFocus( thread_display(), &focus_win, &revert );
567     if (focus_win)
568     {
569         if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
570             focus_win = 0;
571     }
572     wine_tsx11_unlock();
573
574     if (!focus_win)
575     {
576         /* Abey : 6-Oct-99. Check again if the focus out window is the
577            Foreground window, because in most cases the messages sent
578            above must have already changed the foreground window, in which
579            case we don't have to change the foreground window to 0 */
580         if (hwnd == GetForegroundWindow())
581         {
582             TRACE( "lost focus, setting fg to 0\n" );
583             SetForegroundWindow( 0 );
584         }
585     }
586 }
587
588
589 /***********************************************************************
590  *           EVENT_PropertyNotify
591  *   We use this to release resources like Pixmaps when a selection
592  *   client no longer needs them.
593  */
594 static void EVENT_PropertyNotify( XPropertyEvent *event )
595 {
596   /* Check if we have any resources to free */
597   TRACE("Received PropertyNotify event: \n");
598
599   switch(event->state)
600   {
601     case PropertyDelete:
602     {
603       TRACE("\tPropertyDelete for atom %ld on window %ld\n",
604             event->atom, (long)event->window);
605       break;
606     }
607
608     case PropertyNewValue:
609     {
610       TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
611             event->atom, (long)event->window);
612       break;
613     }
614
615     default:
616       break;
617   }
618 }
619
620 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
621 {
622     RECT tempRect;
623
624     if (!IsWindowEnabled(hQueryWnd)) return 0;
625     
626     GetWindowRect(hQueryWnd, &tempRect);
627
628     if(!PtInRect(&tempRect, *lpPt)) return 0;
629
630     if (!IsIconic( hQueryWnd ))
631     {
632         GetClientRect( hQueryWnd, &tempRect );
633         MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
634
635         if (PtInRect( &tempRect, *lpPt))
636         {
637             HWND *list = WIN_ListChildren( hQueryWnd );
638             HWND bResult = 0;
639
640             if (list)
641             {
642                 int i;
643                 
644                 for (i = 0; list[i]; i++)
645                 {
646                     if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
647                     {
648                         GetWindowRect( list[i], &tempRect );
649                         if (PtInRect( &tempRect, *lpPt )) break;
650                     }
651                 }
652                 if (list[i])
653                 {
654                     if (IsWindowEnabled( list[i] ))
655                         bResult = find_drop_window( list[i], lpPt );
656                 }
657                 HeapFree( GetProcessHeap(), 0, list );
658             }
659             if(bResult) return bResult;
660         }
661     }
662
663     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
664     
665     ScreenToClient(hQueryWnd, lpPt);
666
667     return hQueryWnd;
668 }
669
670 /**********************************************************************
671  *           EVENT_DropFromOffix
672  *
673  * don't know if it still works (last Changlog is from 96/11/04)
674  */
675 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
676 {
677     unsigned long       data_length;
678     unsigned long       aux_long;
679     unsigned char*      p_data = NULL;
680     union {
681         Atom    atom_aux;
682         struct {
683             int x;
684             int y;
685         }       pt_aux;
686         int     i;
687     }                   u;
688     int                 x, y;
689     BOOL                bAccept;
690     Window              win, w_aux_root, w_aux_child;
691     WND*                pWnd;
692     HWND                hScope = hWnd;
693
694     win = X11DRV_get_whole_window(hWnd);
695     wine_tsx11_lock();
696     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
697                    &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
698                    (unsigned int*)&aux_long);
699     wine_tsx11_unlock();
700
701     pWnd = WIN_GetPtr(hWnd);
702
703     /* find out drop point and drop window */
704     if( x < 0 || y < 0 ||
705         x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
706         y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
707     {   
708         bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; 
709         x = 0;
710         y = 0; 
711     }
712     else
713     {
714         POINT   pt = { x, y };
715         HWND    hwndDrop = find_drop_window( hWnd, &pt );
716         if (hwndDrop)
717         {
718             x = pt.x;
719             y = pt.y;
720             hScope = hwndDrop;
721             bAccept = TRUE;
722         }
723         else
724         {
725             bAccept = FALSE;
726         }
727     }
728     WIN_ReleasePtr(pWnd);
729
730     if (!bAccept) return;
731
732     wine_tsx11_lock();
733     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
734                         x11drv_atom(DndSelection), 0, 65535, FALSE,
735                         AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
736                         &data_length, &aux_long, &p_data);
737     wine_tsx11_unlock();
738
739     if( !aux_long && p_data)  /* don't bother if > 64K */
740     {
741         signed char *p = (signed char*) p_data;
742         char *p_drop;
743
744         aux_long = 0;
745         while( *p )  /* calculate buffer size */
746         {
747             p_drop = p;
748             if((u.i = *p) != -1 )
749             {
750                 INT len = GetShortPathNameA( p, NULL, 0 );
751                 if (len) aux_long += len + 1;
752                 else *p = -1;
753             }
754             p += strlen(p) + 1;
755         }
756         if( aux_long && aux_long < 65535 )
757         {
758             HDROP                 hDrop;
759             DROPFILES *lpDrop;
760
761             aux_long += sizeof(DROPFILES) + 1;
762             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
763             lpDrop = (DROPFILES*)GlobalLock( hDrop );
764
765             if( lpDrop )
766             {
767                 WND *pDropWnd = WIN_GetPtr( hScope );
768                 lpDrop->pFiles = sizeof(DROPFILES);
769                 lpDrop->pt.x = x;
770                 lpDrop->pt.y = y;
771                 lpDrop->fNC =
772                     ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
773                       y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
774                       x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
775                       y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
776                 lpDrop->fWide = FALSE;
777                 WIN_ReleasePtr(pDropWnd);
778                 p_drop = (char *)(lpDrop + 1);
779                 p = p_data;
780                 while(*p)
781                 {
782                     if( *p != -1 ) /* use only "good" entries */
783                     {
784                         GetShortPathNameA( p, p_drop, 65535 );
785                         p_drop += strlen( p_drop ) + 1;
786                     }
787                     p += strlen(p) + 1;
788                 }
789                 *p_drop = '\0';
790                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
791             }
792         }
793     }
794     wine_tsx11_lock();
795     if( p_data ) XFree(p_data);
796     wine_tsx11_unlock();
797 }
798
799 /**********************************************************************
800  *           EVENT_DropURLs
801  *
802  * drop items are separated by \n
803  * each item is prefixed by its mime type
804  *
805  * event->data.l[3], event->data.l[4] contains drop x,y position
806  */
807 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
808 {
809   unsigned long data_length;
810   unsigned long aux_long, drop_len = 0;
811   unsigned char *p_data = NULL; /* property data */
812   char          *p_drop = NULL;
813   char          *p, *next;
814   int           x, y;
815   DROPFILES *lpDrop;
816   HDROP hDrop;
817   union {
818     Atom        atom_aux;
819     int         i;
820     Window      w_aux;
821   }             u; /* unused */
822
823   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
824
825   wine_tsx11_lock();
826   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
827                       x11drv_atom(DndSelection), 0, 65535, FALSE,
828                       AnyPropertyType, &u.atom_aux, &u.i,
829                       &data_length, &aux_long, &p_data);
830   wine_tsx11_unlock();
831   if (aux_long)
832     WARN("property too large, truncated!\n");
833   TRACE("urls=%s\n", p_data);
834
835   if( !aux_long && p_data) {    /* don't bother if > 64K */
836     /* calculate length */
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, NULL, 0 );
843         if (len) drop_len += len + 1;
844       }
845       if (next) {
846         *next = '\n';
847         p = next + 1;
848         next = strchr(p, '\n');
849       } else {
850         p = NULL;
851       }
852     }
853
854     if( drop_len && drop_len < 65535 ) {
855       wine_tsx11_lock();
856       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
857                      &x, &y, &u.i, &u.i, &u.i);
858       wine_tsx11_unlock();
859
860       drop_len += sizeof(DROPFILES) + 1;
861       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
862       lpDrop = (DROPFILES *) GlobalLock( hDrop );
863
864       if( lpDrop ) {
865           WND *pDropWnd = WIN_GetPtr( hWnd );
866           lpDrop->pFiles = sizeof(DROPFILES);
867           lpDrop->pt.x = (INT)x;
868           lpDrop->pt.y = (INT)y;
869           lpDrop->fNC =
870             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
871               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
872               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
873               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
874           lpDrop->fWide = FALSE;
875           p_drop = (char*)(lpDrop + 1);
876           WIN_ReleasePtr(pDropWnd);
877       }
878
879       /* create message content */
880       if (p_drop) {
881         p = p_data;
882         next = strchr(p, '\n');
883         while (p) {
884           if (next) *next=0;
885           if (strncmp(p,"file:",5) == 0 ) {
886             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
887             if (len) {
888               TRACE("drop file %s as %s\n", p+5, p_drop);
889               p_drop += len+1;
890             } else {
891               WARN("can't convert file %s to dos name \n", p+5);
892             }
893           } else {
894             WARN("unknown mime type %s\n", p);
895           }
896           if (next) {
897             *next = '\n';
898             p = next + 1;
899             next = strchr(p, '\n');
900           } else {
901             p = NULL;
902           }
903           *p_drop = '\0';
904         }
905
906         GlobalUnlock(hDrop);
907         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
908       }
909     }
910     wine_tsx11_lock();
911     if( p_data ) XFree(p_data);
912     wine_tsx11_unlock();
913   }
914 }
915
916 /**********************************************************************
917  *           EVENT_ClientMessage
918  */
919 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
920 {
921   if (event->message_type != None && event->format == 32) {
922     if (event->message_type == x11drv_atom(WM_PROTOCOLS))
923         handle_wm_protocols_message( hWnd, event );
924     else if (event->message_type == x11drv_atom(DndProtocol))
925     {
926         /* query window (drag&drop event contains only drag window) */
927         Window root, child;
928         int root_x, root_y, child_x, child_y;
929         unsigned int u;
930
931         wine_tsx11_lock();
932         XQueryPointer( event->display, root_window, &root, &child,
933                        &root_x, &root_y, &child_x, &child_y, &u);
934         if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
935         wine_tsx11_unlock();
936         if (!hWnd) return;
937         if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
938             EVENT_DropFromOffiX(hWnd, event);
939         else if (event->data.l[0] == DndURL)
940             EVENT_DropURLs(hWnd, event);
941     }
942     else if (!X11DRV_XDND_Event(hWnd, event))
943     {
944 #if 0
945       /* enable this if you want to see the message */
946       unsigned char* p_data = NULL;
947       union {
948         unsigned long   l;
949         int             i;
950         Atom            atom;
951       } u; /* unused */
952       wine_tsx11_lock();
953       XGetWindowProperty( event->display, DefaultRootWindow(event->display),
954                             dndSelection, 0, 65535, FALSE,
955                             AnyPropertyType, &u.atom, &u.i,
956                             &u.l, &u.l, &p_data);
957       wine_tsx11_unlock();
958       TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
959             event->message_type, event->data.l[0], event->data.l[1],
960             event->data.l[2], event->data.l[3], event->data.l[4],
961             p_data);
962 #endif
963       TRACE("unrecognized ClientMessage\n" );
964     }
965   }
966 }
967
968
969 /**********************************************************************
970  *              X11DRV_EVENT_SetInputMethod
971  */
972 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
973 {
974   INPUT_TYPE prev = current_input_type;
975
976   /* Flag not used yet */
977   in_transition = FALSE;
978   current_input_type = type;
979
980   return prev;
981 }
982
983 #ifdef HAVE_LIBXXF86DGA2
984 /**********************************************************************
985  *              X11DRV_EVENT_SetDGAStatus
986  */
987 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
988 {
989   if (event_base < 0) {
990     DGAUsed = FALSE;
991     DGAhwnd = 0;
992   } else {
993     DGAUsed = TRUE;
994     DGAhwnd = hwnd;
995     DGAMotionEventType = event_base + MotionNotify;
996     DGAButtonPressEventType = event_base + ButtonPress;
997     DGAButtonReleaseEventType = event_base + ButtonRelease;
998     DGAKeyPressEventType = event_base + KeyPress;
999     DGAKeyReleaseEventType = event_base + KeyRelease;
1000   }
1001 }
1002 #endif