Added version information.
[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
28 #include "ts_xlib.h"
29 #include <X11/Xresource.h>
30 #include <X11/Xutil.h>
31 #ifdef HAVE_LIBXXF86DGA2
32 #include <X11/extensions/xf86dga.h>
33 #endif
34
35 #include <assert.h>
36 #include <string.h>
37 #include "wine/winuser16.h"
38 #include "shlobj.h"  /* DROPFILES */
39
40 #include "clipboard.h"
41 #include "win.h"
42 #include "winpos.h"
43 #include "windef.h"
44 #include "winreg.h"
45 #include "x11drv.h"
46 #include "shellapi.h"
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(event);
50
51 /* X context to associate a hwnd to an X window */
52 extern XContext winContext;
53
54 extern Atom wmProtocols;
55 extern Atom wmDeleteWindow;
56 extern Atom dndProtocol;
57 extern Atom dndSelection;
58 extern Atom netwmPing;
59
60 #define DndNotDnd       -1    /* OffiX drag&drop */
61 #define DndUnknown      0
62 #define DndRawData      1
63 #define DndFile         2
64 #define DndFiles        3
65 #define DndText         4
66 #define DndDir          5
67 #define DndLink         6
68 #define DndExe          7
69
70 #define DndEND          8
71
72 #define DndURL          128   /* KDE drag&drop */
73
74 static const char * const event_names[] =
75 {
76   "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
77   "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
78   "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
79   "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
80   "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
81   "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
82   "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
83   "ClientMessage", "MappingNotify"
84 };
85
86
87 static void EVENT_ProcessEvent( XEvent *event );
88
89   /* Event handlers */
90 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
91 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
92 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
93 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
94 static void EVENT_PropertyNotify( XPropertyEvent *event );
95 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
96
97 extern void X11DRV_ButtonPress( HWND hwnd, XButtonEvent *event );
98 extern void X11DRV_ButtonRelease( HWND hwnd, XButtonEvent *event );
99 extern void X11DRV_MotionNotify( HWND hwnd, XMotionEvent *event );
100 extern void X11DRV_EnterNotify( HWND hwnd, XCrossingEvent *event );
101 extern void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event );
102 extern void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event );
103 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
104 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
105 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
106 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
107 extern void X11DRV_MappingNotify( XMappingEvent *event );
108
109 #ifdef HAVE_LIBXXF86DGA2
110 static int DGAMotionEventType;
111 static int DGAButtonPressEventType;
112 static int DGAButtonReleaseEventType;
113 static int DGAKeyPressEventType;
114 static int DGAKeyReleaseEventType;
115
116 static BOOL DGAUsed = FALSE;
117 static HWND DGAhwnd = 0;
118
119 extern void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event );
120 extern void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event );
121 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event );
122 #endif
123
124 /* Static used for the current input method */
125 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
126 static BOOL in_transition = FALSE; /* This is not used as for today */
127
128
129 /***********************************************************************
130  *           process_events
131  */
132 static int process_events( struct x11drv_thread_data *data )
133 {
134     XEvent event;
135     int count = 0;
136
137     wine_tsx11_lock();
138     while ( XPending( data->display ) )
139     {
140         Bool ignore;
141
142         XNextEvent( data->display, &event );
143         ignore = XFilterEvent( &event, None );
144         wine_tsx11_unlock();
145         if (!ignore) EVENT_ProcessEvent( &event );
146         count++;
147         wine_tsx11_lock();
148     }
149     wine_tsx11_unlock();
150     return count;
151 }
152
153
154 /***********************************************************************
155  *           MsgWaitForMultipleObjectsEx   (X11DRV.@)
156  */
157 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
158                                           DWORD timeout, DWORD mask, DWORD flags )
159 {
160     HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1];  /* FIXME! */
161     DWORD i, ret;
162     struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
163
164     if (!data || data->process_event_count)
165         return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
166                                          timeout, flags & MWMO_ALERTABLE );
167
168     for (i = 0; i < count; i++) new_handles[i] = handles[i];
169     new_handles[count] = data->display_fd;
170
171     wine_tsx11_lock();
172     XFlush( gdi_display );
173     XFlush( data->display );
174     wine_tsx11_unlock();
175
176     data->process_event_count++;
177     if (process_events( data )) ret = count;
178     else
179     {
180         ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
181                                         timeout, flags & MWMO_ALERTABLE );
182         if (ret == count) process_events( data );
183     }
184     data->process_event_count--;
185     return ret;
186 }
187
188
189 /***********************************************************************
190  *           EVENT_ProcessEvent
191  *
192  * Process an X event.
193  */
194 static void EVENT_ProcessEvent( XEvent *event )
195 {
196   HWND hWnd;
197   Display *display = event->xany.display;
198
199   TRACE( "called.\n" );
200
201   switch (event->type)
202   {
203     case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
204          FIXME("Got SelectionNotify - must not happen!\n");
205          /* fall through */
206
207       /* We get all these because of StructureNotifyMask.
208          This check is placed here to avoid getting error messages below,
209          as X might send some of these even for windows that have already
210          been deleted ... */
211     case CirculateNotify:
212     case CreateNotify:
213     case DestroyNotify:
214     case GravityNotify:
215     case ReparentNotify:
216       return;
217   }
218
219 #ifdef HAVE_LIBXXF86DGA2
220   if (DGAUsed) {
221     if (event->type == DGAMotionEventType) {
222       TRACE("DGAMotionEvent received.\n");
223       X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
224       return;
225     }
226     if (event->type == DGAButtonPressEventType) {
227       TRACE("DGAButtonPressEvent received.\n");
228       X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
229       return;
230     }
231     if (event->type == DGAButtonReleaseEventType) {
232       TRACE("DGAButtonReleaseEvent received.\n");
233       X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
234       return;
235     }
236     if ((event->type == DGAKeyPressEventType) ||
237         (event->type == DGAKeyReleaseEventType)) {
238       /* Fill a XKeyEvent to send to EVENT_Key */
239       XKeyEvent ke;
240       XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
241
242       TRACE("DGAKeyPress/ReleaseEvent received.\n");
243
244       if (evt->type == DGAKeyReleaseEventType)
245         ke.type = KeyRelease;
246       else
247         ke.type = KeyPress;
248       ke.serial = evt->serial;
249       ke.send_event = FALSE;
250       ke.display = evt->display;
251       ke.window = 0;
252       ke.root = 0;
253       ke.subwindow = 0;
254       ke.time = evt->time;
255       ke.x = -1;
256       ke.y = -1;
257       ke.x_root = -1;
258       ke.y_root = -1;
259       ke.state = evt->state;
260       ke.keycode = evt->keycode;
261       ke.same_screen = TRUE;
262       X11DRV_KeyEvent( 0, &ke );
263       return;
264     }
265   }
266 #endif
267
268   wine_tsx11_lock();
269   if (XFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
270       hWnd = 0;  /* Not for a registered window */
271   wine_tsx11_unlock();
272
273   if ( !hWnd && event->xany.window != root_window
274              && event->type != PropertyNotify
275              && event->type != MappingNotify)
276       WARN( "Got event %s for unknown Window %08lx\n",
277             event_names[event->type], event->xany.window );
278   else
279       TRACE("Got event %s for hwnd %p\n",
280             event_names[event->type], hWnd );
281
282   switch(event->type)
283     {
284     case KeyPress:
285     case KeyRelease:
286       /* FIXME: should generate a motion event if event point is different from current pos */
287       X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
288       break;
289
290     case ButtonPress:
291       X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
292       break;
293
294     case ButtonRelease:
295       X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
296       break;
297
298     case MotionNotify:
299       X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
300       break;
301
302     case EnterNotify:
303       X11DRV_EnterNotify( hWnd, (XCrossingEvent*)event );
304       break;
305
306     case FocusIn:
307       EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
308       break;
309
310     case FocusOut:
311       EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
312       break;
313
314     case Expose:
315       X11DRV_Expose( hWnd, &event->xexpose );
316       break;
317
318     case ConfigureNotify:
319       if (!hWnd) return;
320       X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
321       break;
322
323     case SelectionRequest:
324       if (!hWnd) return;
325       EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
326       break;
327
328     case SelectionClear:
329       if (!hWnd) return;
330       EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
331       break;
332
333     case PropertyNotify:
334       EVENT_PropertyNotify( (XPropertyEvent *)event );
335       break;
336
337     case ClientMessage:
338       if (!hWnd) return;
339       EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
340       break;
341
342     case NoExpose:
343       break;
344
345     case MapNotify:
346       X11DRV_MapNotify( hWnd, (XMapEvent *)event );
347       break;
348
349     case UnmapNotify:
350       X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
351       break;
352
353     case KeymapNotify:
354       X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
355       break;
356
357     case MappingNotify:
358       X11DRV_MappingNotify( (XMappingEvent *) event );
359       break;
360
361     default:
362       WARN("Unprocessed event %s for hwnd %p\n", event_names[event->type], hWnd );
363       break;
364     }
365     TRACE( "returns.\n" );
366 }
367
368
369 /*******************************************************************
370  *         can_activate_window
371  *
372  * Check if we can activate the specified window.
373  */
374 inline static BOOL can_activate_window( HWND hwnd )
375 {
376     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
377     if (!(style & WS_VISIBLE)) return FALSE;
378     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
379     return !(style & WS_DISABLED);
380 }
381
382
383 /**********************************************************************
384  *              set_focus_error_handler
385  *
386  * Handler for X errors happening during XSetInputFocus call.
387  */
388 static int set_focus_error_handler( Display *display, XErrorEvent *event, void *arg )
389 {
390     return (event->error_code == BadMatch);
391 }
392
393
394 /**********************************************************************
395  *              set_focus
396  */
397 static void set_focus( HWND hwnd, Time time )
398 {
399     HWND focus;
400     Window win;
401
402     TRACE( "setting foreground window to %p\n", hwnd );
403     SetForegroundWindow( hwnd );
404
405     focus = GetFocus();
406     if (focus) focus = GetAncestor( focus, GA_ROOT );
407     win = X11DRV_get_whole_window(focus);
408
409     if (win)
410     {
411         Display *display = thread_display();
412         TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
413         X11DRV_expect_error( display, set_focus_error_handler, NULL );
414         XSetInputFocus( display, win, RevertToParent, time );
415         if (X11DRV_check_error()) TRACE("got BadMatch, ignoring\n" );
416     }
417 }
418
419
420 /**********************************************************************
421  *              handle_wm_protocols_message
422  */
423 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
424 {
425     Atom protocol = (Atom)event->data.l[0];
426
427     if (!protocol) return;
428
429     if (protocol == wmDeleteWindow)
430     {
431         /* Ignore the delete window request if the window has been disabled
432          * and we are in managed mode. This is to disallow applications from
433          * being closed by the window manager while in a modal state.
434          */
435         if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
436     }
437     else if (protocol == wmTakeFocus)
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, focus=%p, active=%p, fg=%p, last=%p\n",
443                hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
444                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) set_focus( hwnd, event_time );
454             else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
455         }
456         else
457         {
458             hwnd = GetFocus();
459             if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
460             if (!hwnd) hwnd = GetActiveWindow();
461             if (!hwnd) hwnd = last_focus;
462             if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
463         }
464     } else if (protocol == netwmPing) {
465       XClientMessageEvent xev;
466       xev = *event;
467       
468       TRACE("NET_WM Ping\n");
469       xev.window = DefaultRootWindow(xev.display);
470       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
471       /* this line is semi-stolen from gtk2 */
472       TRACE("NET_WM Pong\n");
473     }
474 }
475
476
477 static const char * const focus_details[] =
478 {
479     "NotifyAncestor",
480     "NotifyVirtual",
481     "NotifyInferior",
482     "NotifyNonlinear",
483     "NotifyNonlinearVirtual",
484     "NotifyPointer",
485     "NotifyPointerRoot",
486     "NotifyDetailNone"
487 };
488
489 /**********************************************************************
490  *              EVENT_FocusIn
491  */
492 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
493 {
494     XIC xic;
495
496     if (!hwnd) return;
497
498     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
499
500     if (event->detail == NotifyPointer) return;
501
502     if ((xic = X11DRV_get_ic( hwnd )))
503     {
504         wine_tsx11_lock();
505         XSetICFocus( xic );
506         wine_tsx11_unlock();
507     }
508     if (wmTakeFocus) return;  /* ignore FocusIn if we are using take focus */
509
510     if (!can_activate_window(hwnd))
511     {
512         HWND hwnd = GetFocus();
513         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
514         if (!hwnd) hwnd = GetActiveWindow();
515         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
516         if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
517     }
518     else SetForegroundWindow( hwnd );
519 }
520
521
522 /**********************************************************************
523  *              EVENT_FocusOut
524  *
525  * Note: only top-level windows get FocusOut events.
526  */
527 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
528 {
529     HWND hwnd_tmp;
530     Window focus_win;
531     int revert;
532     XIC xic;
533
534     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
535
536     if (event->detail == NotifyPointer) return;
537     x11drv_thread_data()->last_focus = hwnd;
538     if ((xic = X11DRV_get_ic( hwnd )))
539     {
540         wine_tsx11_lock();
541         XUnsetICFocus( xic );
542         wine_tsx11_unlock();
543     }
544     if (hwnd != GetForegroundWindow()) return;
545     SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
546
547     /* don't reset the foreground window, if the window which is
548        getting the focus is a Wine window */
549
550     wine_tsx11_lock();
551     XGetInputFocus( thread_display(), &focus_win, &revert );
552     if (focus_win)
553     {
554         if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
555             focus_win = 0;
556     }
557     wine_tsx11_unlock();
558
559     if (!focus_win)
560     {
561         /* Abey : 6-Oct-99. Check again if the focus out window is the
562            Foreground window, because in most cases the messages sent
563            above must have already changed the foreground window, in which
564            case we don't have to change the foreground window to 0 */
565         if (hwnd == GetForegroundWindow())
566         {
567             TRACE( "lost focus, setting fg to 0\n" );
568             SetForegroundWindow( 0 );
569         }
570     }
571 }
572
573
574 /***********************************************************************
575  *           EVENT_SelectionRequest_TARGETS
576  *  Service a TARGETS selection request event
577  */
578 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
579                                             Atom target, Atom rprop )
580 {
581     Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
582     Atom* targets;
583     Atom prop;
584     UINT wFormat;
585     unsigned long cTargets;
586     BOOL bHavePixmap;
587     int xRc;
588
589     TRACE("Request for %s\n", TSXGetAtomName(display, target));
590
591     /*
592      * Count the number of items we wish to expose as selection targets.
593      * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
594      */
595     cTargets = CountClipboardFormats() + 1;
596     if ( CLIPBOARD_IsPresent(CF_DIB) ||  CLIPBOARD_IsPresent(CF_BITMAP) )
597        cTargets++;
598
599     /* Allocate temp buffer */
600     targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
601     if(targets == NULL) return None;
602
603     /* Create TARGETS property list (First item in list is TARGETS itself) */
604
605     for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
606           (wFormat = EnumClipboardFormats( wFormat )); )
607     {
608         if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
609         {
610             /* Scan through what we have so far to avoid duplicates */
611             int i;
612             BOOL bExists;
613             for (i = 0, bExists = FALSE; i < cTargets; i++)
614             {
615                 if (targets[i] == prop)
616                 {
617                     bExists = TRUE;
618                     break;
619                 }
620             }
621             if (!bExists)
622             {
623                 targets[cTargets++] = prop;
624
625                 /* Add PIXMAP prop for bitmaps additionally */
626                 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
627                      && !bHavePixmap )
628                 {
629                     targets[cTargets++] = XA_PIXMAP;
630                     bHavePixmap = TRUE;
631                 }
632             }
633         }
634     }
635
636     if (TRACE_ON(event))
637     {
638         int i;
639         for ( i = 0; i < cTargets; i++)
640         {
641             if (targets[i])
642             {
643                 char *itemFmtName = TSXGetAtomName(display, targets[i]);
644                 TRACE("\tAtom# %d:  Type %s\n", i, itemFmtName);
645                 TSXFree(itemFmtName);
646             }
647         }
648     }
649
650     /* Update the X property */
651     TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
652
653     /* We may want to consider setting the type to xaTargets instead,
654      * in case some apps expect this instead of XA_ATOM */
655     xRc = TSXChangeProperty(display, requestor, rprop,
656                             XA_ATOM, 32, PropModeReplace,
657                             (unsigned char *)targets, cTargets);
658     TRACE("(Rc=%d)\n", xRc);
659
660     HeapFree( GetProcessHeap(), 0, targets );
661
662     return rprop;
663 }
664
665
666 /***********************************************************************
667  *           EVENT_SelectionRequest_STRING
668  *  Service a STRING selection request event
669  */
670 static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
671                                            Atom target, Atom rprop )
672 {
673     static UINT text_cp = (UINT)-1;
674     HANDLE hUnicodeText;
675     LPWSTR uni_text;
676     LPSTR  text;
677     int    size,i,j;
678     char* lpstr = 0;
679     char *itemFmtName;
680     int xRc;
681
682     if(text_cp == (UINT)-1)
683     {
684         HKEY hkey;
685         /* default value */
686         text_cp = CP_ACP;
687         if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
688         {
689             char buf[20];
690             DWORD type, count = sizeof(buf);
691             if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
692                 text_cp = atoi(buf);
693             RegCloseKey(hkey);
694           }
695     }
696
697     /*
698      * Map the requested X selection property type atom name to a
699      * windows clipboard format ID.
700      */
701     itemFmtName = TSXGetAtomName(display, target);
702     TRACE("Request for %s (wFormat=%x %s)\n",
703         itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT, NULL, 0));
704     TSXFree(itemFmtName);
705
706     hUnicodeText = GetClipboardData(CF_UNICODETEXT);
707     if(!hUnicodeText)
708        return None;
709     uni_text = GlobalLock(hUnicodeText);
710     if(!uni_text)
711        return None;
712
713     size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
714     text = HeapAlloc(GetProcessHeap(), 0, size);
715     if (!text)
716        return None;
717     WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
718
719     /* remove carriage returns */
720
721     lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
722     if(lpstr == NULL) return None;
723     for(i=0,j=0; i < size && text[i]; i++ )
724     {
725         if( text[i] == '\r' &&
726             (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
727         lpstr[j++] = text[i];
728     }
729     lpstr[j]='\0';
730
731     /* Update the X property */
732     TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
733     xRc = TSXChangeProperty(display, requestor, rprop,
734                             XA_STRING, 8, PropModeReplace,
735                             lpstr, j);
736     TRACE("(Rc=%d)\n", xRc);
737
738     GlobalUnlock(hUnicodeText);
739     HeapFree(GetProcessHeap(), 0, text);
740     HeapFree( GetProcessHeap(), 0, lpstr );
741
742     return rprop;
743 }
744
745 /***********************************************************************
746  *           EVENT_SelectionRequest_PIXMAP
747  *  Service a PIXMAP selection request event
748  */
749 static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
750                                            Atom target, Atom rprop )
751 {
752     HANDLE hClipData = 0;
753     Pixmap pixmap = 0;
754     UINT   wFormat;
755     char * itemFmtName;
756     int xRc;
757 #if(0)
758     XSetWindowAttributes win_attr;
759     XWindowAttributes win_attr_src;
760 #endif
761
762     /*
763      * Map the requested X selection property type atom name to a
764      * windows clipboard format ID.
765      */
766     itemFmtName = TSXGetAtomName(display, target);
767     wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
768     TRACE("Request for %s (wFormat=%x %s)\n",
769                   itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0 ));
770     TSXFree(itemFmtName);
771
772     hClipData = GetClipboardData(wFormat);
773     if ( !hClipData )
774     {
775         TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
776         rprop = None; /* Fail the request */
777         goto END;
778     }
779
780     if (wFormat == CF_DIB)
781     {
782         HWND hwnd = GetOpenClipboardWindow();
783         HDC hdc = GetDC(hwnd);
784
785         /* For convert from packed DIB to Pixmap */
786         pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
787
788         ReleaseDC(hwnd, hdc);
789     }
790     else if (wFormat == CF_BITMAP)
791     {
792         HWND hwnd = GetOpenClipboardWindow();
793         HDC hdc = GetDC(hwnd);
794
795         pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
796
797         ReleaseDC(hwnd, hdc);
798     }
799     else
800     {
801         FIXME("%s to PIXMAP conversion not yet implemented!\n",
802                       CLIPBOARD_GetFormatName(wFormat, NULL, 0));
803         rprop = None;
804         goto END;
805     }
806
807     TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
808           TSXGetAtomName(display, rprop), (long)requestor,
809           TSXGetAtomName(display, target), pixmap);
810
811     /* Store the Pixmap handle in the property */
812     xRc = TSXChangeProperty(display, requestor, rprop, target,
813                             32, PropModeReplace,
814                             (unsigned char *)&pixmap, 1);
815     TRACE("(Rc=%d)\n", xRc);
816
817     /* Enable the code below if you want to handle destroying Pixmap resources
818      * in response to property notify events. Clients like XPaint don't
819      * appear to be duplicating Pixmaps so they don't like us deleting,
820      * the resource in response to the property being deleted.
821      */
822 #if(0)
823     /* Express interest in property notify events so that we can delete the
824      * pixmap when the client deletes the property atom.
825      */
826     xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
827     TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
828           (long)requestor);
829     win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
830     TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
831
832     /* Register the Pixmap we created with the request property Atom.
833      * When this property is destroyed we also destroy the Pixmap in
834      * response to the PropertyNotify event.
835      */
836     X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
837 #endif
838
839 END:
840     return rprop;
841 }
842
843
844 /***********************************************************************
845  *           EVENT_SelectionRequest_WCF
846  *  Service a Wine Clipboard Format selection request event.
847  *  For <WCF>* data types we simply copy the data to X without conversion.
848  */
849 static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
850                                         Atom target, Atom rprop )
851 {
852     HANDLE hClipData = 0;
853     void*  lpClipData;
854     UINT   wFormat;
855     char * itemFmtName;
856     int cBytes;
857     int xRc;
858     int bemf;
859
860     /*
861      * Map the requested X selection property type atom name to a
862      * windows clipboard format ID.
863      */
864     itemFmtName = TSXGetAtomName(display, target);
865     wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
866     TRACE("Request for %s (wFormat=%x %s)\n",
867           itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0));
868     TSXFree(itemFmtName);
869
870     hClipData = GetClipboardData(wFormat);
871
872     bemf = wFormat == CF_METAFILEPICT || wFormat == CF_ENHMETAFILE;
873     if (bemf)
874         hClipData = X11DRV_CLIPBOARD_SerializeMetafile(wFormat, hClipData, sizeof(hClipData), TRUE);
875
876     if( hClipData && (lpClipData = GlobalLock(hClipData)) )
877     {
878         cBytes = GlobalSize(hClipData);
879
880         TRACE("\tUpdating property %s, %d bytes...\n",
881               TSXGetAtomName(display, rprop), cBytes);
882
883         xRc = TSXChangeProperty(display, requestor, rprop,
884                                 target, 8, PropModeReplace,
885                                 (unsigned char *)lpClipData, cBytes);
886         TRACE("(Rc=%d)\n", xRc);
887
888         GlobalUnlock(hClipData);
889     }
890     else
891     {
892         TRACE("\tCould not retrieve native format!\n");
893         rprop = None; /* Fail the request */
894     }
895
896     if (bemf) /* We must free serialized metafile data */
897         GlobalFree(hClipData);
898
899     return rprop;
900 }
901
902
903 /***********************************************************************
904  *           EVENT_SelectionRequest_MULTIPLE
905  *  Service a MULTIPLE selection request event
906  *  rprop contains a list of (target,property) atom pairs.
907  *  The first atom names a target and the second names a property.
908  *  The effect is as if we have received a sequence of SelectionRequest events
909  *  (one for each atom pair) except that:
910  *  1. We reply with a SelectionNotify only when all the requested conversions
911  *  have been performed.
912  *  2. If we fail to convert the target named by an atom in the MULTIPLE property,
913  *  we replace the atom in the property by None.
914  */
915 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
916 {
917     Display *display = pevent->display;
918     Atom           rprop;
919     Atom           atype=AnyPropertyType;
920     int            aformat;
921     unsigned long  remain;
922     Atom*          targetPropList=NULL;
923     unsigned long  cTargetPropList = 0;
924 /*  Atom           xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
925
926    /* If the specified property is None the requestor is an obsolete client.
927     * We support these by using the specified target atom as the reply property.
928     */
929     rprop = pevent->property;
930     if( rprop == None )
931         rprop = pevent->target;
932     if (!rprop)
933         goto END;
934
935     /* Read the MULTIPLE property contents. This should contain a list of
936      * (target,property) atom pairs.
937      */
938     if(TSXGetWindowProperty(display, pevent->requestor, rprop,
939                             0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
940                             &cTargetPropList, &remain,
941                             (unsigned char**)&targetPropList) != Success)
942         TRACE("\tCouldn't read MULTIPLE property\n");
943     else
944     {
945        TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
946              TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
947
948        /*
949         * Make sure we got what we expect.
950         * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
951         * in a MULTIPLE selection request should be of type ATOM_PAIR.
952         * However some X apps(such as XPaint) are not compliant with this and return
953         * a user defined atom in atype when XGetWindowProperty is called.
954         * The data *is* an atom pair but is not denoted as such.
955         */
956        if(aformat == 32 /* atype == xAtomPair */ )
957        {
958           int i;
959
960           /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
961            * for each (target,property) pair */
962
963           for (i = 0; i < cTargetPropList; i+=2)
964           {
965               char *targetName = TSXGetAtomName(display, targetPropList[i]);
966               char *propName = TSXGetAtomName(display, targetPropList[i+1]);
967               XSelectionRequestEvent event;
968
969               TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
970                     i/2, targetName, propName);
971               TSXFree(targetName);
972               TSXFree(propName);
973
974               /* We must have a non "None" property to service a MULTIPLE target atom */
975               if ( !targetPropList[i+1] )
976               {
977                   TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
978                   continue;
979               }
980
981               /* Set up an XSelectionRequestEvent for this (target,property) pair */
982               memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
983               event.target = targetPropList[i];
984               event.property = targetPropList[i+1];
985
986               /* Fire a SelectionRequest, informing the handler that we are processing
987                * a MULTIPLE selection request event.
988                */
989               EVENT_SelectionRequest( hWnd, &event, TRUE );
990           }
991        }
992
993        /* Free the list of targets/properties */
994        TSXFree(targetPropList);
995     }
996
997 END:
998     return rprop;
999 }
1000
1001
1002 /***********************************************************************
1003  *           EVENT_SelectionRequest
1004  *  Process an event selection request event.
1005  *  The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1006  *  recursively while servicing a "MULTIPLE" selection target.
1007  *
1008  *  Note: We only receive this event when WINE owns the X selection
1009  */
1010 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1011 {
1012     Display *display = event->display;
1013   XSelectionEvent result;
1014   Atom            rprop = None;
1015   Window          request = event->requestor;
1016   BOOL            couldOpen = FALSE;
1017   Atom            xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1018   Atom            xaTargets = TSXInternAtom(display, "TARGETS", False);
1019   Atom            xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1020
1021   /*
1022    * We can only handle the selection request if :
1023    * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1024    * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1025    * since this has been already done.
1026    */
1027   if ( !bIsMultiple )
1028   {
1029     if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1030         || !(couldOpen = OpenClipboard(hWnd)) )
1031        goto END;
1032   }
1033
1034   /* If the specified property is None the requestor is an obsolete client.
1035    * We support these by using the specified target atom as the reply property.
1036    */
1037   rprop = event->property;
1038   if( rprop == None )
1039       rprop = event->target;
1040
1041   if(event->target == xaTargets)  /*  Return a list of all supported targets */
1042   {
1043       /* TARGETS selection request */
1044       rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
1045   }
1046   else if(event->target == xaMultiple)  /*  rprop contains a list of (target, property) atom pairs */
1047   {
1048       /* MULTIPLE selection request */
1049       rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1050   }
1051   else if(event->target == XA_STRING)  /* treat CF_TEXT as Unix text */
1052   {
1053       /* XA_STRING selection request */
1054       rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
1055   }
1056   else if(event->target == XA_PIXMAP)  /*  Convert DIB's to Pixmaps */
1057   {
1058       /* XA_PIXMAP selection request */
1059       rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
1060   }
1061   else if(event->target == XA_BITMAP)  /*  Convert DIB's to 1-bit Pixmaps */
1062   {
1063       /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1064       rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
1065   }
1066   else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1067   {
1068       /* All <WCF> selection requests */
1069       rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
1070   }
1071   else
1072       rprop = None;  /* Don't support this format */
1073
1074 END:
1075   /* close clipboard only if we opened before */
1076   if(couldOpen) CloseClipboard();
1077
1078   if( rprop == None)
1079       TRACE("\tRequest ignored\n");
1080
1081   /* reply to sender
1082    * SelectionNotify should be sent only at the end of a MULTIPLE request
1083    */
1084   if ( !bIsMultiple )
1085   {
1086     result.type = SelectionNotify;
1087     result.display = display;
1088     result.requestor = request;
1089     result.selection = event->selection;
1090     result.property = rprop;
1091     result.target = event->target;
1092     result.time = event->time;
1093     TRACE("Sending SelectionNotify event...\n");
1094     TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1095   }
1096 }
1097
1098 /***********************************************************************
1099  *           EVENT_SelectionClear
1100  */
1101 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1102 {
1103   Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
1104
1105   if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1106       X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1107 }
1108
1109 /***********************************************************************
1110  *           EVENT_PropertyNotify
1111  *   We use this to release resources like Pixmaps when a selection
1112  *   client no longer needs them.
1113  */
1114 static void EVENT_PropertyNotify( XPropertyEvent *event )
1115 {
1116   /* Check if we have any resources to free */
1117   TRACE("Received PropertyNotify event: \n");
1118
1119   switch(event->state)
1120   {
1121     case PropertyDelete:
1122     {
1123       TRACE("\tPropertyDelete for atom %s on window %ld\n",
1124             TSXGetAtomName(event->display, event->atom), (long)event->window);
1125
1126       if (X11DRV_IsSelectionOwner())
1127           X11DRV_CLIPBOARD_FreeResources( event->atom );
1128       break;
1129     }
1130
1131     case PropertyNewValue:
1132     {
1133       TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1134             TSXGetAtomName(event->display, event->atom), (long)event->window);
1135       break;
1136     }
1137
1138     default:
1139       break;
1140   }
1141 }
1142
1143 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1144 {
1145     RECT tempRect;
1146
1147     if (!IsWindowEnabled(hQueryWnd)) return 0;
1148     
1149     GetWindowRect(hQueryWnd, &tempRect);
1150
1151     if(!PtInRect(&tempRect, *lpPt)) return 0;
1152
1153     if (!IsIconic( hQueryWnd ))
1154     {
1155         GetClientRect( hQueryWnd, &tempRect );
1156         MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
1157
1158         if (PtInRect( &tempRect, *lpPt))
1159         {
1160             HWND *list = WIN_ListChildren( hQueryWnd );
1161             HWND bResult = 0;
1162
1163             if (list)
1164             {
1165                 int i;
1166                 
1167                 for (i = 0; list[i]; i++)
1168                 {
1169                     if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
1170                     {
1171                         GetWindowRect( list[i], &tempRect );
1172                         if (PtInRect( &tempRect, *lpPt )) break;
1173                     }
1174                 }
1175                 if (list[i])
1176                 {
1177                     if (IsWindowEnabled( list[i] ))
1178                         bResult = find_drop_window( list[i], lpPt );
1179                 }
1180                 HeapFree( GetProcessHeap(), 0, list );
1181             }
1182             if(bResult) return bResult;
1183         }
1184     }
1185
1186     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1187     
1188     ScreenToClient(hQueryWnd, lpPt);
1189
1190     return hQueryWnd;
1191 }
1192
1193 /**********************************************************************
1194  *           EVENT_DropFromOffix
1195  *
1196  * don't know if it still works (last Changlog is from 96/11/04)
1197  */
1198 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1199 {
1200     unsigned long       data_length;
1201     unsigned long       aux_long;
1202     unsigned char*      p_data = NULL;
1203     union {
1204         Atom    atom_aux;
1205         struct {
1206             int x;
1207             int y;
1208         }       pt_aux;
1209         int     i;
1210     }                   u;
1211     int                 x, y;
1212     BOOL                bAccept;
1213     Window              w_aux_root, w_aux_child;
1214     WND*                pWnd;
1215     HWND                hScope = hWnd;
1216
1217     pWnd = WIN_FindWndPtr(hWnd);
1218
1219     TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1220                      &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1221                      (unsigned int*)&aux_long);
1222
1223     /* find out drop point and drop window */
1224     if( x < 0 || y < 0 ||
1225         x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1226         y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1227     {   
1228         bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; 
1229         x = 0;
1230         y = 0; 
1231     }
1232     else
1233     {
1234         POINT   pt = { x, y };
1235         HWND    hwndDrop = find_drop_window( hWnd, &pt );
1236         if (hwndDrop)
1237         {
1238             x = pt.x;
1239             y = pt.y;
1240             hScope = hwndDrop;
1241             bAccept = TRUE;
1242         }
1243         else
1244         {
1245             bAccept = FALSE;
1246         }
1247     }
1248     WIN_ReleaseWndPtr(pWnd);
1249
1250     if (!bAccept) return;
1251
1252     TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1253                           dndSelection, 0, 65535, FALSE,
1254                           AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1255                           &data_length, &aux_long, &p_data);
1256
1257     if( !aux_long && p_data)  /* don't bother if > 64K */
1258     {
1259         signed char *p = (signed char*) p_data;
1260         char *p_drop;
1261
1262         aux_long = 0;
1263         while( *p )  /* calculate buffer size */
1264         {
1265             p_drop = p;
1266             if((u.i = *p) != -1 )
1267             {
1268                 INT len = GetShortPathNameA( p, NULL, 0 );
1269                 if (len) aux_long += len + 1;
1270                 else *p = -1;
1271             }
1272             p += strlen(p) + 1;
1273         }
1274         if( aux_long && aux_long < 65535 )
1275         {
1276             HDROP                 hDrop;
1277             DROPFILES *lpDrop;
1278
1279             aux_long += sizeof(DROPFILES) + 1;
1280             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1281             lpDrop = (DROPFILES*)GlobalLock( hDrop );
1282
1283             if( lpDrop )
1284             {
1285                 WND *pDropWnd = WIN_FindWndPtr( hScope );
1286                 lpDrop->pFiles = sizeof(DROPFILES);
1287                 lpDrop->pt.x = x;
1288                 lpDrop->pt.y = y;
1289                 lpDrop->fNC =
1290                     ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1291                       y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1292                       x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1293                       y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1294                 lpDrop->fWide = FALSE;
1295                 WIN_ReleaseWndPtr(pDropWnd);
1296                 p_drop = (char *)(lpDrop + 1);
1297                 p = p_data;
1298                 while(*p)
1299                 {
1300                     if( *p != -1 ) /* use only "good" entries */
1301                     {
1302                         GetShortPathNameA( p, p_drop, 65535 );
1303                         p_drop += strlen( p_drop ) + 1;
1304                     }
1305                     p += strlen(p) + 1;
1306                 }
1307                 *p_drop = '\0';
1308                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1309             }
1310         }
1311     }
1312     if( p_data ) TSXFree(p_data);
1313 }
1314
1315 /**********************************************************************
1316  *           EVENT_DropURLs
1317  *
1318  * drop items are separated by \n
1319  * each item is prefixed by its mime type
1320  *
1321  * event->data.l[3], event->data.l[4] contains drop x,y position
1322  */
1323 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1324 {
1325   unsigned long data_length;
1326   unsigned long aux_long, drop_len = 0;
1327   unsigned char *p_data = NULL; /* property data */
1328   char          *p_drop = NULL;
1329   char          *p, *next;
1330   int           x, y;
1331   DROPFILES *lpDrop;
1332   HDROP hDrop;
1333   union {
1334     Atom        atom_aux;
1335     int         i;
1336     Window      w_aux;
1337   }             u; /* unused */
1338
1339   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1340
1341   TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1342                         dndSelection, 0, 65535, FALSE,
1343                         AnyPropertyType, &u.atom_aux, &u.i,
1344                         &data_length, &aux_long, &p_data);
1345   if (aux_long)
1346     WARN("property too large, truncated!\n");
1347   TRACE("urls=%s\n", p_data);
1348
1349   if( !aux_long && p_data) {    /* don't bother if > 64K */
1350     /* calculate length */
1351     p = p_data;
1352     next = strchr(p, '\n');
1353     while (p) {
1354       if (next) *next=0;
1355       if (strncmp(p,"file:",5) == 0 ) {
1356         INT len = GetShortPathNameA( p+5, NULL, 0 );
1357         if (len) drop_len += len + 1;
1358       }
1359       if (next) {
1360         *next = '\n';
1361         p = next + 1;
1362         next = strchr(p, '\n');
1363       } else {
1364         p = NULL;
1365       }
1366     }
1367
1368     if( drop_len && drop_len < 65535 ) {
1369       TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1370                        &x, &y, &u.i, &u.i, &u.i);
1371
1372       drop_len += sizeof(DROPFILES) + 1;
1373       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1374       lpDrop = (DROPFILES *) GlobalLock( hDrop );
1375
1376       if( lpDrop ) {
1377           WND *pDropWnd = WIN_FindWndPtr( hWnd );
1378           lpDrop->pFiles = sizeof(DROPFILES);
1379           lpDrop->pt.x = (INT)x;
1380           lpDrop->pt.y = (INT)y;
1381           lpDrop->fNC =
1382             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1383               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1384               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1385               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1386           lpDrop->fWide = FALSE;
1387           p_drop = (char*)(lpDrop + 1);
1388           WIN_ReleaseWndPtr(pDropWnd);
1389       }
1390
1391       /* create message content */
1392       if (p_drop) {
1393         p = p_data;
1394         next = strchr(p, '\n');
1395         while (p) {
1396           if (next) *next=0;
1397           if (strncmp(p,"file:",5) == 0 ) {
1398             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1399             if (len) {
1400               TRACE("drop file %s as %s\n", p+5, p_drop);
1401               p_drop += len+1;
1402             } else {
1403               WARN("can't convert file %s to dos name \n", p+5);
1404             }
1405           } else {
1406             WARN("unknown mime type %s\n", p);
1407           }
1408           if (next) {
1409             *next = '\n';
1410             p = next + 1;
1411             next = strchr(p, '\n');
1412           } else {
1413             p = NULL;
1414           }
1415           *p_drop = '\0';
1416         }
1417
1418         GlobalUnlock(hDrop);
1419         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1420       }
1421     }
1422     if( p_data ) TSXFree(p_data);
1423   }
1424 }
1425
1426 /**********************************************************************
1427  *           EVENT_ClientMessage
1428  */
1429 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1430 {
1431   if (event->message_type != None && event->format == 32) {
1432     if (event->message_type == wmProtocols)
1433         handle_wm_protocols_message( hWnd, event );
1434     else if (event->message_type == dndProtocol)
1435     {
1436         /* query window (drag&drop event contains only drag window) */
1437         Window root, child;
1438         int root_x, root_y, child_x, child_y;
1439         unsigned int u;
1440
1441         wine_tsx11_lock();
1442         XQueryPointer( event->display, root_window, &root, &child,
1443                        &root_x, &root_y, &child_x, &child_y, &u);
1444         if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1445         wine_tsx11_unlock();
1446         if (!hWnd) return;
1447         if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1448             EVENT_DropFromOffiX(hWnd, event);
1449         else if (event->data.l[0] == DndURL)
1450             EVENT_DropURLs(hWnd, event);
1451     }
1452     else {
1453 #if 0
1454       /* enable this if you want to see the message */
1455       unsigned char* p_data = NULL;
1456       union {
1457         unsigned long   l;
1458         int             i;
1459         Atom            atom;
1460       } u; /* unused */
1461       TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1462                             dndSelection, 0, 65535, FALSE,
1463                             AnyPropertyType, &u.atom, &u.i,
1464                             &u.l, &u.l, &p_data);
1465       TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1466             event->message_type, event->data.l[0], event->data.l[1],
1467             event->data.l[2], event->data.l[3], event->data.l[4],
1468             p_data);
1469 #endif
1470       TRACE("unrecognized ClientMessage\n" );
1471     }
1472   }
1473 }
1474
1475
1476 /**********************************************************************
1477  *              X11DRV_EVENT_SetInputMethod
1478  */
1479 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1480 {
1481   INPUT_TYPE prev = current_input_type;
1482
1483   /* Flag not used yet */
1484   in_transition = FALSE;
1485   current_input_type = type;
1486
1487   return prev;
1488 }
1489
1490 #ifdef HAVE_LIBXXF86DGA2
1491 /**********************************************************************
1492  *              X11DRV_EVENT_SetDGAStatus
1493  */
1494 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1495 {
1496   if (event_base < 0) {
1497     DGAUsed = FALSE;
1498     DGAhwnd = 0;
1499   } else {
1500     DGAUsed = TRUE;
1501     DGAhwnd = hwnd;
1502     DGAMotionEventType = event_base + MotionNotify;
1503     DGAButtonPressEventType = event_base + ButtonPress;
1504     DGAButtonReleaseEventType = event_base + ButtonRelease;
1505     DGAKeyPressEventType = event_base + KeyPress;
1506     DGAKeyReleaseEventType = event_base + KeyRelease;
1507   }
1508 }
1509 #endif