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