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