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