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