mshtml: Added element blur, focus, paste and drag event implementation.
[wine] / dlls / winex11.drv / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #ifdef HAVE_POLL_H
25 #include <poll.h>
26 #endif
27 #ifdef HAVE_SYS_POLL_H
28 #include <sys/poll.h>
29 #endif
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
35
36 #include <assert.h>
37 #include <stdarg.h>
38 #include <string.h>
39
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winuser.h"
45 #include "wingdi.h"
46
47 #include "x11drv.h"
48
49 /* avoid conflict with field names in included win32 headers */
50 #undef Status
51 #include "shlobj.h"  /* DROPFILES */
52 #include "shellapi.h"
53
54 #include "wine/server.h"
55 #include "wine/debug.h"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(event);
58
59 extern BOOL ximInComposeMode;
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   /* Event handlers */
76 static void X11DRV_FocusIn( HWND hwnd, XEvent *event );
77 static void X11DRV_FocusOut( HWND hwnd, XEvent *event );
78 static void X11DRV_Expose( HWND hwnd, XEvent *event );
79 static void X11DRV_MapNotify( HWND hwnd, XEvent *event );
80 static void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
81 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
82 static void X11DRV_ClientMessage( HWND hwnd, XEvent *event );
83
84 struct event_handler
85 {
86     int                  type;    /* event type */
87     x11drv_event_handler handler; /* corresponding handler function */
88 };
89
90 #define MAX_EVENT_HANDLERS 64
91
92 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
93 {
94     /* list must be sorted by event type */
95     { KeyPress,         X11DRV_KeyEvent },
96     { KeyRelease,       X11DRV_KeyEvent },
97     { ButtonPress,      X11DRV_ButtonPress },
98     { ButtonRelease,    X11DRV_ButtonRelease },
99     { MotionNotify,     X11DRV_MotionNotify },
100     { EnterNotify,      X11DRV_EnterNotify },
101     /* LeaveNotify */
102     { FocusIn,          X11DRV_FocusIn },
103     { FocusOut,         X11DRV_FocusOut },
104     { KeymapNotify,     X11DRV_KeymapNotify },
105     { Expose,           X11DRV_Expose },
106     /* GraphicsExpose */
107     /* NoExpose */
108     /* VisibilityNotify */
109     /* CreateNotify */
110     { DestroyNotify,    X11DRV_DestroyNotify },
111     /* UnmapNotify */
112     { MapNotify,        X11DRV_MapNotify },
113     /* MapRequest */
114     /* ReparentNotify */
115     { ConfigureNotify,  X11DRV_ConfigureNotify },
116     /* ConfigureRequest */
117     /* GravityNotify */
118     /* ResizeRequest */
119     /* CirculateNotify */
120     /* CirculateRequest */
121     { PropertyNotify,   X11DRV_PropertyNotify },
122     { SelectionClear,   X11DRV_SelectionClear },
123     { SelectionRequest, X11DRV_SelectionRequest },
124     /* SelectionNotify */
125     /* ColormapNotify */
126     { ClientMessage,    X11DRV_ClientMessage },
127     { MappingNotify,    X11DRV_MappingNotify },
128 };
129
130 static int nb_event_handlers = 18;  /* change this if you add handlers above */
131
132
133 /* return the name of an X event */
134 static const char *dbgstr_event( int type )
135 {
136     static const char * const event_names[] =
137     {
138         "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
139         "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
140         "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
141         "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
142         "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
143         "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
144         "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
145         "ClientMessage", "MappingNotify"
146     };
147
148     if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
149     return wine_dbg_sprintf( "Extension event %d", type );
150 }
151
152
153 /***********************************************************************
154  *           find_handler
155  *
156  * Find the handler for a given event type. Caller must hold the x11 lock.
157  */
158 static inline x11drv_event_handler find_handler( int type )
159 {
160     int min = 0, max = nb_event_handlers - 1;
161
162     while (min <= max)
163     {
164         int pos = (min + max) / 2;
165         if (handlers[pos].type == type) return handlers[pos].handler;
166         if (handlers[pos].type > type) max = pos - 1;
167         else min = pos + 1;
168     }
169     return NULL;
170 }
171
172
173 /***********************************************************************
174  *           X11DRV_register_event_handler
175  *
176  * Register a handler for a given event type.
177  * If already registered, overwrite the previous handler.
178  */
179 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
180 {
181     int min, max;
182
183     wine_tsx11_lock();
184     min = 0;
185     max = nb_event_handlers - 1;
186     while (min <= max)
187     {
188         int pos = (min + max) / 2;
189         if (handlers[pos].type == type)
190         {
191             handlers[pos].handler = handler;
192             goto done;
193         }
194         if (handlers[pos].type > type) max = pos - 1;
195         else min = pos + 1;
196     }
197     /* insert it between max and min */
198     memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
199     handlers[min].type = type;
200     handlers[min].handler = handler;
201     nb_event_handlers++;
202     assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
203 done:
204     wine_tsx11_unlock();
205     TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
206 }
207
208
209 /***********************************************************************
210  *           filter_event
211  */
212 static Bool filter_event( Display *display, XEvent *event, char *arg )
213 {
214     ULONG_PTR mask = (ULONG_PTR)arg;
215
216     if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
217
218     switch(event->type)
219     {
220     case KeyPress:
221     case KeyRelease:
222     case KeymapNotify:
223     case MappingNotify:
224         return (mask & QS_KEY) != 0;
225     case ButtonPress:
226     case ButtonRelease:
227         return (mask & QS_MOUSEBUTTON) != 0;
228     case MotionNotify:
229     case EnterNotify:
230     case LeaveNotify:
231         return (mask & QS_MOUSEMOVE) != 0;
232     case Expose:
233         return (mask & QS_PAINT) != 0;
234     case FocusIn:
235     case FocusOut:
236     case MapNotify:
237     case UnmapNotify:
238     case ConfigureNotify:
239     case PropertyNotify:
240     case ClientMessage:
241         return (mask & QS_POSTMESSAGE) != 0;
242     default:
243         return (mask & QS_SENDMESSAGE) != 0;
244     }
245 }
246
247
248 enum event_merge_action
249 {
250     MERGE_DISCARD,  /* discard the old event */
251     MERGE_HANDLE,   /* handle the old event */
252     MERGE_KEEP      /* keep the old event for future merging */
253 };
254
255 /***********************************************************************
256  *           merge_events
257  *
258  * Try to merge 2 consecutive events.
259  */
260 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
261 {
262     switch (prev->type)
263     {
264     case ConfigureNotify:
265         switch (next->type)
266         {
267         case ConfigureNotify:
268             if (prev->xany.window == next->xany.window)
269             {
270                 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
271                 return MERGE_DISCARD;
272             }
273             break;
274         case Expose:
275         case PropertyNotify:
276             return MERGE_KEEP;
277         }
278         break;
279     case MotionNotify:
280         if (prev->xany.window == next->xany.window && next->type == MotionNotify)
281         {
282             TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
283             return MERGE_DISCARD;
284         }
285         break;
286     }
287     return MERGE_HANDLE;
288 }
289
290
291 /***********************************************************************
292  *           call_event_handler
293  */
294 static inline void call_event_handler( Display *display, XEvent *event )
295 {
296     HWND hwnd;
297     x11drv_event_handler handler;
298     XEvent *prev;
299     struct x11drv_thread_data *thread_data;
300
301     if (!(handler = find_handler( event->type )))
302     {
303         TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
304         return;  /* no handler, ignore it */
305     }
306
307     if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
308         hwnd = 0;  /* not for a registered window */
309     if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
310
311     TRACE( "%s for hwnd/window %p/%lx\n",
312            dbgstr_event( event->type ), hwnd, event->xany.window );
313     wine_tsx11_unlock();
314     thread_data = x11drv_thread_data();
315     prev = thread_data->current_event;
316     thread_data->current_event = event;
317     handler( hwnd, event );
318     thread_data->current_event = prev;
319     wine_tsx11_lock();
320 }
321
322
323 /***********************************************************************
324  *           process_events
325  */
326 static int process_events( Display *display, Bool (*filter)(), ULONG_PTR arg )
327 {
328     XEvent event, prev_event;
329     int count = 0;
330     enum event_merge_action action = MERGE_DISCARD;
331
332     prev_event.type = 0;
333     wine_tsx11_lock();
334     while (XCheckIfEvent( display, &event, filter, (char *)arg ))
335     {
336         count++;
337         if (XFilterEvent( &event, None ))
338         {
339             /*
340              * SCIM on linux filters key events strangely. It does not filter the
341              * KeyPress events for these keys however it does filter the
342              * KeyRelease events. This causes wine to become very confused as
343              * to the keyboard state.
344              *
345              * We need to let those KeyRelease events be processed so that the
346              * keyboard state is correct.
347              */
348             if (event.type == KeyRelease)
349             {
350                 KeySym keysym = 0;
351                 XKeyEvent *keyevent = &event.xkey;
352
353                 XLookupString(keyevent, NULL, 0, &keysym, NULL);
354                 if (!(keysym == XK_Shift_L ||
355                     keysym == XK_Shift_R ||
356                     keysym == XK_Control_L ||
357                     keysym == XK_Control_R ||
358                     keysym == XK_Alt_R ||
359                     keysym == XK_Alt_L ||
360                     keysym == XK_Meta_R ||
361                     keysym == XK_Meta_L))
362                         continue; /* not a key we care about, ignore it */
363             }
364             else
365                 continue;  /* filtered, ignore it */
366         }
367         if (prev_event.type) action = merge_events( &prev_event, &event );
368         switch( action )
369         {
370         case MERGE_DISCARD:  /* discard prev, keep new */
371             prev_event = event;
372             break;
373         case MERGE_HANDLE:  /* handle prev, keep new */
374             call_event_handler( display, &prev_event );
375             prev_event = event;
376             break;
377         case MERGE_KEEP:  /* handle new, keep prev for future merging */
378             call_event_handler( display, &event );
379             break;
380         }
381     }
382     XFlush( gdi_display );
383     if (prev_event.type) call_event_handler( display, &prev_event );
384     wine_tsx11_unlock();
385     if (count) TRACE( "processed %d events\n", count );
386     return count;
387 }
388
389
390 /***********************************************************************
391  *           MsgWaitForMultipleObjectsEx   (X11DRV.@)
392  */
393 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
394                                           DWORD timeout, DWORD mask, DWORD flags )
395 {
396     DWORD ret;
397     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
398
399     if (!data)
400     {
401         if (!count && !timeout) return WAIT_TIMEOUT;
402         return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
403                                          timeout, flags & MWMO_ALERTABLE );
404     }
405
406     if (data->current_event) mask = 0;  /* don't process nested events */
407
408     if (process_events( data->display, filter_event, mask )) ret = count - 1;
409     else if (count || timeout)
410     {
411         ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
412                                         timeout, flags & MWMO_ALERTABLE );
413         if (ret == count - 1) process_events( data->display, filter_event, mask );
414     }
415     else ret = WAIT_TIMEOUT;
416
417     return ret;
418 }
419
420 /***********************************************************************
421  *           EVENT_x11_time_to_win32_time
422  *
423  * Make our timer and the X timer line up as best we can
424  *  Pass 0 to retrieve the current adjustment value (times -1)
425  */
426 DWORD EVENT_x11_time_to_win32_time(Time time)
427 {
428   static DWORD adjust = 0;
429   DWORD now = GetTickCount();
430   DWORD ret;
431
432   if (! adjust && time != 0)
433   {
434     ret = now;
435     adjust = time - now;
436   }
437   else
438   {
439       /* If we got an event in the 'future', then our clock is clearly wrong. 
440          If we got it more than 10000 ms in the future, then it's most likely
441          that the clock has wrapped.  */
442
443       ret = time - adjust;
444       if (ret > now && ((ret - now) < 10000) && time != 0)
445       {
446         adjust += ret - now;
447         ret    -= ret - now;
448       }
449   }
450
451   return ret;
452
453 }
454
455 /*******************************************************************
456  *         can_activate_window
457  *
458  * Check if we can activate the specified window.
459  */
460 static inline BOOL can_activate_window( HWND hwnd )
461 {
462     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
463     if (!(style & WS_VISIBLE)) return FALSE;
464     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
465     if (hwnd == GetDesktopWindow()) return FALSE;
466     return !(style & WS_DISABLED);
467 }
468
469
470 /**********************************************************************
471  *              set_focus
472  */
473 static void set_focus( Display *display, HWND hwnd, Time time )
474 {
475     HWND focus;
476     Window win;
477
478     TRACE( "setting foreground window to %p\n", hwnd );
479     SetForegroundWindow( hwnd );
480
481     focus = GetFocus();
482     if (focus) focus = GetAncestor( focus, GA_ROOT );
483     win = X11DRV_get_whole_window(focus);
484
485     if (win)
486     {
487         TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
488         wine_tsx11_lock();
489         XSetInputFocus( display, win, RevertToParent, time );
490         wine_tsx11_unlock();
491     }
492 }
493
494
495 /**********************************************************************
496  *              handle_wm_protocols
497  */
498 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
499 {
500     Atom protocol = (Atom)event->data.l[0];
501
502     if (!protocol) return;
503
504     if (protocol == x11drv_atom(WM_DELETE_WINDOW))
505     {
506         /* Ignore the delete window request if the window has been disabled
507          * and we are in managed mode. This is to disallow applications from
508          * being closed by the window manager while in a modal state.
509          */
510         if (IsWindowEnabled(hwnd))
511         {
512             HMENU hSysMenu;
513
514             if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
515             hSysMenu = GetSystemMenu(hwnd, FALSE);
516             if (hSysMenu)
517             {
518                 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
519                 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
520                     return;
521             }
522             if (GetActiveWindow() != hwnd)
523             {
524                 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
525                                            (WPARAM)GetAncestor( hwnd, GA_ROOT ),
526                                            MAKELONG(HTCLOSE,WM_LBUTTONDOWN) );
527                 switch(ma)
528                 {
529                     case MA_NOACTIVATEANDEAT:
530                     case MA_ACTIVATEANDEAT:
531                         return;
532                     case MA_NOACTIVATE:
533                         break;
534                     case MA_ACTIVATE:
535                     case 0:
536                         SetActiveWindow(hwnd);
537                         break;
538                     default:
539                         WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
540                         break;
541                 }
542             }
543             PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
544         }
545     }
546     else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
547     {
548         Time event_time = (Time)event->data.l[1];
549         HWND last_focus = x11drv_thread_data()->last_focus;
550
551         TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
552                hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
553                GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
554
555         if (can_activate_window(hwnd))
556         {
557             /* simulate a mouse click on the caption to find out
558              * whether the window wants to be activated */
559             LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
560                                        (WPARAM)GetAncestor( hwnd, GA_ROOT ),
561                                        MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
562             if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
563             {
564                 set_focus( event->display, hwnd, event_time );
565                 return;
566             }
567         }
568         /* try to find some other window to give the focus to */
569         hwnd = GetFocus();
570         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
571         if (!hwnd) hwnd = GetActiveWindow();
572         if (!hwnd) hwnd = last_focus;
573         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
574     }
575     else if (protocol == x11drv_atom(_NET_WM_PING))
576     {
577       XClientMessageEvent xev;
578       xev = *event;
579       
580       TRACE("NET_WM Ping\n");
581       wine_tsx11_lock();
582       xev.window = DefaultRootWindow(xev.display);
583       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
584       wine_tsx11_unlock();
585       /* this line is semi-stolen from gtk2 */
586       TRACE("NET_WM Pong\n");
587     }
588 }
589
590
591 static const char * const focus_details[] =
592 {
593     "NotifyAncestor",
594     "NotifyVirtual",
595     "NotifyInferior",
596     "NotifyNonlinear",
597     "NotifyNonlinearVirtual",
598     "NotifyPointer",
599     "NotifyPointerRoot",
600     "NotifyDetailNone"
601 };
602
603 /**********************************************************************
604  *              X11DRV_FocusIn
605  */
606 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
607 {
608     XFocusChangeEvent *event = &xev->xfocus;
609     XIC xic;
610
611     if (!hwnd) return;
612
613     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
614
615     if (event->detail == NotifyPointer) return;
616
617     if ((xic = X11DRV_get_ic( hwnd )))
618     {
619         wine_tsx11_lock();
620         XSetICFocus( xic );
621         wine_tsx11_unlock();
622     }
623     if (use_take_focus) return;  /* ignore FocusIn if we are using take focus */
624
625     if (!can_activate_window(hwnd))
626     {
627         HWND hwnd = GetFocus();
628         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
629         if (!hwnd) hwnd = GetActiveWindow();
630         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
631         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
632     }
633     else SetForegroundWindow( hwnd );
634 }
635
636
637 /**********************************************************************
638  *              X11DRV_FocusOut
639  *
640  * Note: only top-level windows get FocusOut events.
641  */
642 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
643 {
644     XFocusChangeEvent *event = &xev->xfocus;
645     HWND hwnd_tmp;
646     Window focus_win;
647     int revert;
648     XIC xic;
649
650     if (!hwnd) return;
651
652     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
653
654     if (event->detail == NotifyPointer) return;
655     if (ximInComposeMode) return;
656
657     x11drv_thread_data()->last_focus = hwnd;
658     if ((xic = X11DRV_get_ic( hwnd )))
659     {
660         wine_tsx11_lock();
661         XUnsetICFocus( xic );
662         wine_tsx11_unlock();
663     }
664     if (hwnd != GetForegroundWindow()) return;
665     SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
666
667     /* don't reset the foreground window, if the window which is
668        getting the focus is a Wine window */
669
670     wine_tsx11_lock();
671     XGetInputFocus( event->display, &focus_win, &revert );
672     if (focus_win)
673     {
674         if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
675             focus_win = 0;
676     }
677     wine_tsx11_unlock();
678
679     if (!focus_win)
680     {
681         /* Abey : 6-Oct-99. Check again if the focus out window is the
682            Foreground window, because in most cases the messages sent
683            above must have already changed the foreground window, in which
684            case we don't have to change the foreground window to 0 */
685         if (hwnd == GetForegroundWindow())
686         {
687             TRACE( "lost focus, setting fg to desktop\n" );
688             SetForegroundWindow( GetDesktopWindow() );
689         }
690     }
691 }
692
693
694 /***********************************************************************
695  *           X11DRV_Expose
696  */
697 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
698 {
699     XExposeEvent *event = &xev->xexpose;
700     RECT rect;
701     struct x11drv_win_data *data;
702     int flags = RDW_INVALIDATE | RDW_ERASE;
703
704     TRACE( "win %p (%lx) %d,%d %dx%d\n",
705            hwnd, event->window, event->x, event->y, event->width, event->height );
706
707     if (!(data = X11DRV_get_win_data( hwnd ))) return;
708
709     if (event->window == data->whole_window)
710     {
711         rect.left = data->whole_rect.left + event->x;
712         rect.top  = data->whole_rect.top + event->y;
713         flags |= RDW_FRAME;
714     }
715     else
716     {
717         rect.left = data->client_rect.left + event->x;
718         rect.top  = data->client_rect.top + event->y;
719     }
720     rect.right  = rect.left + event->width;
721     rect.bottom = rect.top + event->height;
722
723     if (event->window != root_window)
724     {
725         SERVER_START_REQ( update_window_zorder )
726         {
727             req->window      = hwnd;
728             req->rect.left   = rect.left;
729             req->rect.top    = rect.top;
730             req->rect.right  = rect.right;
731             req->rect.bottom = rect.bottom;
732             wine_server_call( req );
733         }
734         SERVER_END_REQ;
735
736         /* make position relative to client area instead of parent */
737         OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top );
738         flags |= RDW_ALLCHILDREN;
739     }
740
741     RedrawWindow( hwnd, &rect, 0, flags );
742 }
743
744
745 /**********************************************************************
746  *              X11DRV_MapNotify
747  */
748 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
749 {
750     struct x11drv_win_data *data;
751
752     if (!(data = X11DRV_get_win_data( hwnd ))) return;
753     if (!data->mapped) return;
754
755     if (!data->managed)
756     {
757         HWND hwndFocus = GetFocus();
758         if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
759     }
760 }
761
762
763 /***********************************************************************
764  *     is_net_wm_state_maximized
765  */
766 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
767 {
768     Atom type, *state;
769     int format, ret = 0;
770     unsigned long i, count, remaining;
771
772     wine_tsx11_lock();
773     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
774                              65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
775                              &remaining, (unsigned char **)&state ))
776     {
777         if (type == XA_ATOM && format == 32)
778         {
779             for (i = 0; i < count; i++)
780             {
781                 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
782                     state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
783                     ret++;
784             }
785         }
786         XFree( state );
787     }
788     wine_tsx11_unlock();
789     return (ret == 2);
790 }
791
792
793 /***********************************************************************
794  *              X11DRV_ConfigureNotify
795  */
796 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
797 {
798     XConfigureEvent *event = &xev->xconfigure;
799     struct x11drv_win_data *data;
800     RECT rect;
801     UINT flags;
802     int cx, cy, x = event->x, y = event->y;
803
804     if (!hwnd) return;
805     if (!(data = X11DRV_get_win_data( hwnd ))) return;
806     if (!data->mapped || data->iconic) return;
807
808     /* Get geometry */
809
810     if (!event->send_event)  /* normal event, need to map coordinates to the root */
811     {
812         Window child;
813         wine_tsx11_lock();
814         XTranslateCoordinates( event->display, data->whole_window, root_window,
815                                0, 0, &x, &y, &child );
816         wine_tsx11_unlock();
817     }
818     rect.left   = x;
819     rect.top    = y;
820     rect.right  = x + event->width;
821     rect.bottom = y + event->height;
822     OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
823     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
824            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
825            event->x, event->y, event->width, event->height );
826     X11DRV_X_to_window_rect( data, &rect );
827
828     if (is_net_wm_state_maximized( event->display, data ))
829     {
830         if (!IsZoomed( data->hwnd ))
831         {
832             TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
833             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
834             return;
835         }
836     }
837     else
838     {
839         if (IsZoomed( data->hwnd ))
840         {
841             TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
842             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
843             return;
844         }
845     }
846
847     /* Compare what has changed */
848
849     x     = rect.left;
850     y     = rect.top;
851     cx    = rect.right - rect.left;
852     cy    = rect.bottom - rect.top;
853     flags = SWP_NOACTIVATE | SWP_NOZORDER;
854
855     if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
856     else
857         TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
858                hwnd, data->window_rect.left, data->window_rect.top, x, y );
859
860     if ((data->window_rect.right - data->window_rect.left == cx &&
861          data->window_rect.bottom - data->window_rect.top == cy) ||
862         (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
863     {
864         if (flags & SWP_NOMOVE) return;  /* if nothing changed, don't do anything */
865         flags |= SWP_NOSIZE;
866     }
867     else
868         TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
869                hwnd, data->window_rect.right - data->window_rect.left,
870                data->window_rect.bottom - data->window_rect.top, cx, cy );
871
872     SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
873 }
874
875
876 /***********************************************************************
877  *           get_window_wm_state
878  */
879 static int get_window_wm_state( Display *display, struct x11drv_win_data *data )
880 {
881     struct
882     {
883         CARD32 state;
884         XID     icon;
885     } *state;
886     Atom type;
887     int format, ret = -1;
888     unsigned long count, remaining;
889
890     wine_tsx11_lock();
891     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
892                              sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
893                              &type, &format, &count, &remaining, (unsigned char **)&state ))
894     {
895         if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
896             ret = state->state;
897         XFree( state );
898     }
899     wine_tsx11_unlock();
900     return ret;
901 }
902
903
904 /***********************************************************************
905  *           handle_wm_state_notify
906  *
907  * Handle a PropertyNotify for WM_STATE.
908  */
909 static void handle_wm_state_notify( struct x11drv_win_data *data, XPropertyEvent *event,
910                                     BOOL update_window )
911 {
912     switch(event->state)
913     {
914     case PropertyDelete:
915         TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
916         data->wm_state = WithdrawnState;
917         break;
918     case PropertyNewValue:
919         {
920             int old_state = data->wm_state;
921             int new_state = get_window_wm_state( event->display, data );
922             if (new_state != -1 && new_state != data->wm_state)
923             {
924                 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
925                        data->hwnd, data->whole_window, new_state, old_state );
926                 data->wm_state = new_state;
927                 /* ignore the initial state transition out of withdrawn state */
928                 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
929                 if (!old_state) return;
930             }
931         }
932         break;
933     }
934
935     if (!update_window || !data->managed || !data->mapped) return;
936
937     if (data->iconic && data->wm_state == NormalState)  /* restore window */
938     {
939         data->iconic = FALSE;
940         if (is_net_wm_state_maximized( event->display, data ))
941         {
942             TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
943             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
944         }
945         else
946         {
947             TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
948             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
949         }
950     }
951     else if (!data->iconic && data->wm_state == IconicState)
952     {
953         TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
954         data->iconic = TRUE;
955         SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
956     }
957 }
958
959
960 /***********************************************************************
961  *           X11DRV_PropertyNotify
962  */
963 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
964 {
965     XPropertyEvent *event = &xev->xproperty;
966     struct x11drv_win_data *data;
967
968     if (!hwnd) return;
969     if (!(data = X11DRV_get_win_data( hwnd ))) return;
970
971     if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( data, event, TRUE );
972 }
973
974
975 /* event filter to wait for a WM_STATE change notification on a window */
976 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
977 {
978     if (event->xany.window != (Window)arg) return 0;
979     return (event->type == DestroyNotify ||
980             (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
981 }
982
983 /***********************************************************************
984  *           wait_for_withdrawn_state
985  */
986 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data, BOOL set )
987 {
988     DWORD end = GetTickCount() + 2000;
989
990     if (!data->managed) return;
991
992     TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
993            data->hwnd, data->whole_window, set ? "" : "not " );
994
995     while (data->whole_window && ((data->wm_state == WithdrawnState) == !set))
996     {
997         XEvent event;
998         int count = 0;
999
1000         wine_tsx11_lock();
1001         while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)data->whole_window ))
1002         {
1003             count++;
1004             if (XFilterEvent( &event, None )) continue;  /* filtered, ignore it */
1005             if (event.type == DestroyNotify) call_event_handler( display, &event );
1006             else
1007             {
1008                 wine_tsx11_unlock();
1009                 handle_wm_state_notify( data, &event.xproperty, FALSE );
1010                 wine_tsx11_lock();
1011             }
1012         }
1013         wine_tsx11_unlock();
1014
1015         if (!count)
1016         {
1017             struct pollfd pfd;
1018             int timeout = end - GetTickCount();
1019
1020             pfd.fd = ConnectionNumber(display);
1021             pfd.events = POLLIN;
1022             if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1023             {
1024                 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
1025                 break;
1026             }
1027         }
1028     }
1029     TRACE( "window %p/%lx state now %d\n", data->hwnd, data->whole_window, data->wm_state );
1030 }
1031
1032
1033 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1034 {
1035     RECT tempRect;
1036
1037     if (!IsWindowEnabled(hQueryWnd)) return 0;
1038     
1039     GetWindowRect(hQueryWnd, &tempRect);
1040
1041     if(!PtInRect(&tempRect, *lpPt)) return 0;
1042
1043     if (!IsIconic( hQueryWnd ))
1044     {
1045         POINT pt = *lpPt;
1046         ScreenToClient( hQueryWnd, &pt );
1047         GetClientRect( hQueryWnd, &tempRect );
1048
1049         if (PtInRect( &tempRect, pt))
1050         {
1051             HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1052             if (ret && ret != hQueryWnd)
1053             {
1054                 ret = find_drop_window( ret, lpPt );
1055                 if (ret) return ret;
1056             }
1057         }
1058     }
1059
1060     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1061     
1062     ScreenToClient(hQueryWnd, lpPt);
1063
1064     return hQueryWnd;
1065 }
1066
1067 /**********************************************************************
1068  *           EVENT_DropFromOffix
1069  *
1070  * don't know if it still works (last Changelog is from 96/11/04)
1071  */
1072 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1073 {
1074     struct x11drv_win_data *data;
1075     unsigned long       data_length;
1076     unsigned long       aux_long;
1077     unsigned char*      p_data = NULL;
1078     Atom atom_aux;
1079     int                 x, y, dummy;
1080     BOOL                bAccept;
1081     Window              win, w_aux_root, w_aux_child;
1082
1083     win = X11DRV_get_whole_window(hWnd);
1084     wine_tsx11_lock();
1085     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1086                    &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1087     x += virtual_screen_rect.left;
1088     y += virtual_screen_rect.top;
1089     wine_tsx11_unlock();
1090
1091     if (!(data = X11DRV_get_win_data( hWnd ))) return;
1092
1093     /* find out drop point and drop window */
1094     if( x < 0 || y < 0 ||
1095         x > (data->whole_rect.right - data->whole_rect.left) ||
1096         y > (data->whole_rect.bottom - data->whole_rect.top) )
1097     {   
1098         bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1099         x = 0;
1100         y = 0; 
1101     }
1102     else
1103     {
1104         POINT   pt = { x, y };
1105         HWND    hwndDrop = find_drop_window( hWnd, &pt );
1106         if (hwndDrop)
1107         {
1108             x = pt.x;
1109             y = pt.y;
1110             bAccept = TRUE;
1111         }
1112         else
1113         {
1114             bAccept = FALSE;
1115         }
1116     }
1117
1118     if (!bAccept) return;
1119
1120     wine_tsx11_lock();
1121     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1122                         x11drv_atom(DndSelection), 0, 65535, FALSE,
1123                         AnyPropertyType, &atom_aux, &dummy,
1124                         &data_length, &aux_long, &p_data);
1125     wine_tsx11_unlock();
1126
1127     if( !aux_long && p_data)  /* don't bother if > 64K */
1128     {
1129         char *p = (char *)p_data;
1130         char *p_drop;
1131
1132         aux_long = 0;
1133         while( *p )  /* calculate buffer size */
1134         {
1135             INT len = GetShortPathNameA( p, NULL, 0 );
1136             if (len) aux_long += len + 1;
1137             p += strlen(p) + 1;
1138         }
1139         if( aux_long && aux_long < 65535 )
1140         {
1141             HDROP                 hDrop;
1142             DROPFILES *lpDrop;
1143
1144             aux_long += sizeof(DROPFILES) + 1;
1145             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1146             lpDrop = (DROPFILES*)GlobalLock( hDrop );
1147
1148             if( lpDrop )
1149             {
1150                 lpDrop->pFiles = sizeof(DROPFILES);
1151                 lpDrop->pt.x = x;
1152                 lpDrop->pt.y = y;
1153                 lpDrop->fNC = FALSE;
1154                 lpDrop->fWide = FALSE;
1155                 p_drop = (char *)(lpDrop + 1);
1156                 p = (char *)p_data;
1157                 while(*p)
1158                 {
1159                     if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1160                         p_drop += strlen( p_drop ) + 1;
1161                     p += strlen(p) + 1;
1162                 }
1163                 *p_drop = '\0';
1164                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1165             }
1166         }
1167     }
1168     wine_tsx11_lock();
1169     if( p_data ) XFree(p_data);
1170     wine_tsx11_unlock();
1171 }
1172
1173 /**********************************************************************
1174  *           EVENT_DropURLs
1175  *
1176  * drop items are separated by \n
1177  * each item is prefixed by its mime type
1178  *
1179  * event->data.l[3], event->data.l[4] contains drop x,y position
1180  */
1181 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1182 {
1183   struct x11drv_win_data *win_data;
1184   unsigned long data_length;
1185   unsigned long aux_long, drop_len = 0;
1186   unsigned char *p_data = NULL; /* property data */
1187   char          *p_drop = NULL;
1188   char          *p, *next;
1189   int           x, y;
1190   DROPFILES *lpDrop;
1191   HDROP hDrop;
1192   union {
1193     Atom        atom_aux;
1194     int         i;
1195     Window      w_aux;
1196     unsigned int u;
1197   }             u; /* unused */
1198
1199   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1200
1201   wine_tsx11_lock();
1202   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1203                       x11drv_atom(DndSelection), 0, 65535, FALSE,
1204                       AnyPropertyType, &u.atom_aux, &u.i,
1205                       &data_length, &aux_long, &p_data);
1206   wine_tsx11_unlock();
1207   if (aux_long)
1208     WARN("property too large, truncated!\n");
1209   TRACE("urls=%s\n", p_data);
1210
1211   if( !aux_long && p_data) {    /* don't bother if > 64K */
1212     /* calculate length */
1213     p = (char*) p_data;
1214     next = strchr(p, '\n');
1215     while (p) {
1216       if (next) *next=0;
1217       if (strncmp(p,"file:",5) == 0 ) {
1218         INT len = GetShortPathNameA( p+5, NULL, 0 );
1219         if (len) drop_len += len + 1;
1220       }
1221       if (next) {
1222         *next = '\n';
1223         p = next + 1;
1224         next = strchr(p, '\n');
1225       } else {
1226         p = NULL;
1227       }
1228     }
1229
1230     if( drop_len && drop_len < 65535 ) {
1231       wine_tsx11_lock();
1232       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1233                      &x, &y, &u.i, &u.i, &u.u);
1234       x += virtual_screen_rect.left;
1235       y += virtual_screen_rect.top;
1236       wine_tsx11_unlock();
1237
1238       drop_len += sizeof(DROPFILES) + 1;
1239       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1240       lpDrop = (DROPFILES *) GlobalLock( hDrop );
1241
1242       if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
1243       {
1244           lpDrop->pFiles = sizeof(DROPFILES);
1245           lpDrop->pt.x = x;
1246           lpDrop->pt.y = y;
1247           lpDrop->fNC =
1248             ( x < (win_data->client_rect.left - win_data->whole_rect.left)  ||
1249               y < (win_data->client_rect.top - win_data->whole_rect.top)    ||
1250               x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1251               y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1252           lpDrop->fWide = FALSE;
1253           p_drop = (char*)(lpDrop + 1);
1254       }
1255
1256       /* create message content */
1257       if (p_drop) {
1258         p = (char*) p_data;
1259         next = strchr(p, '\n');
1260         while (p) {
1261           if (next) *next=0;
1262           if (strncmp(p,"file:",5) == 0 ) {
1263             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1264             if (len) {
1265               TRACE("drop file %s as %s\n", p+5, p_drop);
1266               p_drop += len+1;
1267             } else {
1268               WARN("can't convert file %s to dos name\n", p+5);
1269             }
1270           } else {
1271             WARN("unknown mime type %s\n", p);
1272           }
1273           if (next) {
1274             *next = '\n';
1275             p = next + 1;
1276             next = strchr(p, '\n');
1277           } else {
1278             p = NULL;
1279           }
1280           *p_drop = '\0';
1281         }
1282
1283         GlobalUnlock(hDrop);
1284         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1285       }
1286     }
1287     wine_tsx11_lock();
1288     if( p_data ) XFree(p_data);
1289     wine_tsx11_unlock();
1290   }
1291 }
1292
1293 /**********************************************************************
1294  *              handle_dnd_protocol
1295  */
1296 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1297 {
1298     Window root, child;
1299     int root_x, root_y, child_x, child_y;
1300     unsigned int u;
1301
1302     /* query window (drag&drop event contains only drag window) */
1303     wine_tsx11_lock();
1304     XQueryPointer( event->display, root_window, &root, &child,
1305                    &root_x, &root_y, &child_x, &child_y, &u);
1306     if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1307     wine_tsx11_unlock();
1308     if (!hwnd) return;
1309     if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1310         EVENT_DropFromOffiX(hwnd, event);
1311     else if (event->data.l[0] == DndURL)
1312         EVENT_DropURLs(hwnd, event);
1313 }
1314
1315
1316 struct client_message_handler
1317 {
1318     int    atom;                                  /* protocol atom */
1319     void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1320 };
1321
1322 static const struct client_message_handler client_messages[] =
1323 {
1324     { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1325     { XATOM_DndProtocol,  handle_dnd_protocol },
1326     { XATOM_XdndEnter,    X11DRV_XDND_EnterEvent },
1327     { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1328     { XATOM_XdndDrop,     X11DRV_XDND_DropEvent },
1329     { XATOM_XdndLeave,    X11DRV_XDND_LeaveEvent }
1330 };
1331
1332
1333 /**********************************************************************
1334  *           X11DRV_ClientMessage
1335  */
1336 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1337 {
1338     XClientMessageEvent *event = &xev->xclient;
1339     unsigned int i;
1340
1341     if (!hwnd) return;
1342
1343     if (event->format != 32)
1344     {
1345         WARN( "Don't know how to handle format %d\n", event->format );
1346         return;
1347     }
1348
1349     for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1350     {
1351         if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1352         {
1353             client_messages[i].handler( hwnd, event );
1354             return;
1355         }
1356     }
1357     TRACE( "no handler found for %ld\n", event->message_type );
1358 }
1359
1360
1361 /***********************************************************************
1362  *              X11DRV_SendInput  (X11DRV.@)
1363  */
1364 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
1365 {
1366     UINT i;
1367
1368     for (i = 0; i < count; i++, inputs++)
1369     {
1370         switch(inputs->type)
1371         {
1372         case INPUT_MOUSE:
1373             X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
1374                                      inputs->u.mi.mouseData, inputs->u.mi.time,
1375                                      inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
1376             break;
1377         case INPUT_KEYBOARD:
1378             X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
1379                                         inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
1380             break;
1381         case INPUT_HARDWARE:
1382             FIXME( "INPUT_HARDWARE not supported\n" );
1383             break;
1384         }
1385     }
1386     return count;
1387 }