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