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