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