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