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