cryptnet: Store the bytes actually read, not the bytes available to be read.
[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)(Display*, XEvent*,XPointer), 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 CDECL 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 (style & WS_MINIMIZE) return FALSE;
466     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
467     if (hwnd == GetDesktopWindow()) return FALSE;
468     return !(style & WS_DISABLED);
469 }
470
471
472 /**********************************************************************
473  *              set_focus
474  */
475 static void set_focus( Display *display, HWND hwnd, Time time )
476 {
477     HWND focus;
478     Window win;
479     GUITHREADINFO threadinfo;
480
481     TRACE( "setting foreground window to %p\n", hwnd );
482     SetForegroundWindow( hwnd );
483
484     GetGUIThreadInfo(0, &threadinfo);
485     focus = threadinfo.hwndFocus;
486     if (focus) focus = GetAncestor( focus, GA_ROOT );
487     win = X11DRV_get_whole_window(focus);
488
489     if (win)
490     {
491         TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
492         wine_tsx11_lock();
493         XSetInputFocus( display, win, RevertToParent, time );
494         wine_tsx11_unlock();
495     }
496 }
497
498
499 /**********************************************************************
500  *              handle_wm_protocols
501  */
502 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
503 {
504     Atom protocol = (Atom)event->data.l[0];
505
506     if (!protocol) return;
507
508     if (protocol == x11drv_atom(WM_DELETE_WINDOW))
509     {
510         /* Ignore the delete window request if the window has been disabled
511          * and we are in managed mode. This is to disallow applications from
512          * being closed by the window manager while in a modal state.
513          */
514         if (IsWindowEnabled(hwnd))
515         {
516             HMENU hSysMenu;
517             POINT pt;
518
519             if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
520             hSysMenu = GetSystemMenu(hwnd, FALSE);
521             if (hSysMenu)
522             {
523                 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
524                 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
525                     return;
526             }
527             if (GetActiveWindow() != hwnd)
528             {
529                 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
530                                            (WPARAM)GetAncestor( hwnd, GA_ROOT ),
531                                            MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
532                 switch(ma)
533                 {
534                     case MA_NOACTIVATEANDEAT:
535                     case MA_ACTIVATEANDEAT:
536                         return;
537                     case MA_NOACTIVATE:
538                         break;
539                     case MA_ACTIVATE:
540                     case 0:
541                         SetActiveWindow(hwnd);
542                         break;
543                     default:
544                         WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
545                         break;
546                 }
547             }
548             /* Simulate clicking the caption Close button */
549             GetCursorPos( &pt );
550             PostMessageW( hwnd, WM_NCLBUTTONDOWN, HTCLOSE, MAKELPARAM( pt.x, pt.y ) );
551             PostMessageW( hwnd, WM_LBUTTONUP, HTCLOSE, MAKELPARAM( pt.x, pt.y ) );
552         }
553     }
554     else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
555     {
556         Time event_time = (Time)event->data.l[1];
557         HWND last_focus = x11drv_thread_data()->last_focus;
558
559         TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
560                hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
561                GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
562
563         if (can_activate_window(hwnd))
564         {
565             /* simulate a mouse click on the caption to find out
566              * whether the window wants to be activated */
567             LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
568                                        (WPARAM)GetAncestor( hwnd, GA_ROOT ),
569                                        MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
570             if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
571             {
572                 set_focus( event->display, hwnd, event_time );
573                 return;
574             }
575         }
576         else if (hwnd == GetDesktopWindow())
577         {
578             hwnd = GetForegroundWindow();
579             if (!hwnd) hwnd = last_focus;
580             if (!hwnd) hwnd = GetDesktopWindow();
581             set_focus( event->display, hwnd, event_time );
582             return;
583         }
584         /* try to find some other window to give the focus to */
585         hwnd = GetFocus();
586         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
587         if (!hwnd) hwnd = GetActiveWindow();
588         if (!hwnd) hwnd = last_focus;
589         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
590     }
591     else if (protocol == x11drv_atom(_NET_WM_PING))
592     {
593       XClientMessageEvent xev;
594       xev = *event;
595       
596       TRACE("NET_WM Ping\n");
597       wine_tsx11_lock();
598       xev.window = DefaultRootWindow(xev.display);
599       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
600       wine_tsx11_unlock();
601       /* this line is semi-stolen from gtk2 */
602       TRACE("NET_WM Pong\n");
603     }
604 }
605
606
607 static const char * const focus_details[] =
608 {
609     "NotifyAncestor",
610     "NotifyVirtual",
611     "NotifyInferior",
612     "NotifyNonlinear",
613     "NotifyNonlinearVirtual",
614     "NotifyPointer",
615     "NotifyPointerRoot",
616     "NotifyDetailNone"
617 };
618
619 /**********************************************************************
620  *              X11DRV_FocusIn
621  */
622 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
623 {
624     XFocusChangeEvent *event = &xev->xfocus;
625     XIC xic;
626
627     if (!hwnd) return;
628
629     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
630
631     if (event->detail == NotifyPointer) return;
632
633     if ((xic = X11DRV_get_ic( hwnd )))
634     {
635         wine_tsx11_lock();
636         XSetICFocus( xic );
637         wine_tsx11_unlock();
638     }
639     if (use_take_focus) return;  /* ignore FocusIn if we are using take focus */
640
641     if (!can_activate_window(hwnd))
642     {
643         HWND hwnd = GetFocus();
644         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
645         if (!hwnd) hwnd = GetActiveWindow();
646         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
647         if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
648     }
649     else SetForegroundWindow( hwnd );
650 }
651
652
653 /**********************************************************************
654  *              X11DRV_FocusOut
655  *
656  * Note: only top-level windows get FocusOut events.
657  */
658 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
659 {
660     XFocusChangeEvent *event = &xev->xfocus;
661     HWND hwnd_tmp;
662     Window focus_win;
663     int revert;
664     XIC xic;
665
666     if (!hwnd) return;
667
668     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
669
670     if (event->detail == NotifyPointer) return;
671     if (ximInComposeMode) return;
672
673     x11drv_thread_data()->last_focus = hwnd;
674     if ((xic = X11DRV_get_ic( hwnd )))
675     {
676         wine_tsx11_lock();
677         XUnsetICFocus( xic );
678         wine_tsx11_unlock();
679     }
680     if (hwnd != GetForegroundWindow()) return;
681     if (root_window != DefaultRootWindow(event->display)) return;
682     SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
683
684     /* don't reset the foreground window, if the window which is
685        getting the focus is a Wine window */
686
687     wine_tsx11_lock();
688     XGetInputFocus( event->display, &focus_win, &revert );
689     if (focus_win)
690     {
691         if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
692             focus_win = 0;
693     }
694     wine_tsx11_unlock();
695
696     if (!focus_win)
697     {
698         /* Abey : 6-Oct-99. Check again if the focus out window is the
699            Foreground window, because in most cases the messages sent
700            above must have already changed the foreground window, in which
701            case we don't have to change the foreground window to 0 */
702         if (hwnd == GetForegroundWindow())
703         {
704             TRACE( "lost focus, setting fg to desktop\n" );
705             SetForegroundWindow( GetDesktopWindow() );
706         }
707     }
708 }
709
710
711 /***********************************************************************
712  *           X11DRV_Expose
713  */
714 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
715 {
716     XExposeEvent *event = &xev->xexpose;
717     RECT rect;
718     struct x11drv_win_data *data;
719     int flags = RDW_INVALIDATE | RDW_ERASE;
720
721     TRACE( "win %p (%lx) %d,%d %dx%d\n",
722            hwnd, event->window, event->x, event->y, event->width, event->height );
723
724     if (!(data = X11DRV_get_win_data( hwnd ))) return;
725
726     if (event->window == data->whole_window)
727     {
728         rect.left = data->whole_rect.left + event->x;
729         rect.top  = data->whole_rect.top + event->y;
730         flags |= RDW_FRAME;
731     }
732     else
733     {
734         rect.left = data->client_rect.left + event->x;
735         rect.top  = data->client_rect.top + event->y;
736     }
737     rect.right  = rect.left + event->width;
738     rect.bottom = rect.top + event->height;
739
740     if (event->window != root_window)
741     {
742         SERVER_START_REQ( update_window_zorder )
743         {
744             req->window      = wine_server_user_handle( hwnd );
745             req->rect.left   = rect.left;
746             req->rect.top    = rect.top;
747             req->rect.right  = rect.right;
748             req->rect.bottom = rect.bottom;
749             wine_server_call( req );
750         }
751         SERVER_END_REQ;
752
753         /* make position relative to client area instead of parent */
754         OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top );
755         flags |= RDW_ALLCHILDREN;
756     }
757
758     RedrawWindow( hwnd, &rect, 0, flags );
759 }
760
761
762 /**********************************************************************
763  *              X11DRV_MapNotify
764  */
765 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
766 {
767     struct x11drv_win_data *data;
768
769     if (!(data = X11DRV_get_win_data( hwnd ))) return;
770     if (!data->mapped) return;
771
772     if (!data->managed)
773     {
774         HWND hwndFocus = GetFocus();
775         if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
776     }
777 }
778
779
780 /***********************************************************************
781  *     is_net_wm_state_maximized
782  */
783 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
784 {
785     Atom type, *state;
786     int format, ret = 0;
787     unsigned long i, count, remaining;
788
789     wine_tsx11_lock();
790     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
791                              65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
792                              &remaining, (unsigned char **)&state ))
793     {
794         if (type == XA_ATOM && format == 32)
795         {
796             for (i = 0; i < count; i++)
797             {
798                 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
799                     state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
800                     ret++;
801             }
802         }
803         XFree( state );
804     }
805     wine_tsx11_unlock();
806     return (ret == 2);
807 }
808
809
810 /***********************************************************************
811  *              X11DRV_ConfigureNotify
812  */
813 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
814 {
815     XConfigureEvent *event = &xev->xconfigure;
816     struct x11drv_win_data *data;
817     RECT rect;
818     UINT flags;
819     int cx, cy, x = event->x, y = event->y;
820
821     if (!hwnd) return;
822     if (!(data = X11DRV_get_win_data( hwnd ))) return;
823     if (!data->mapped || data->iconic || !data->managed) return;
824
825     /* Get geometry */
826
827     if (!event->send_event)  /* normal event, need to map coordinates to the root */
828     {
829         Window child;
830         wine_tsx11_lock();
831         XTranslateCoordinates( event->display, data->whole_window, root_window,
832                                0, 0, &x, &y, &child );
833         wine_tsx11_unlock();
834     }
835     rect.left   = x;
836     rect.top    = y;
837     rect.right  = x + event->width;
838     rect.bottom = y + event->height;
839     OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
840     TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
841            hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
842            event->x, event->y, event->width, event->height );
843     X11DRV_X_to_window_rect( data, &rect );
844
845     if (is_net_wm_state_maximized( event->display, data ))
846     {
847         if (!IsZoomed( data->hwnd ))
848         {
849             TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
850             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
851             return;
852         }
853     }
854     else
855     {
856         if (IsZoomed( data->hwnd ))
857         {
858             TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
859             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
860             return;
861         }
862     }
863
864     /* Compare what has changed */
865
866     x     = rect.left;
867     y     = rect.top;
868     cx    = rect.right - rect.left;
869     cy    = rect.bottom - rect.top;
870     flags = SWP_NOACTIVATE | SWP_NOZORDER;
871
872     if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
873     else
874         TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
875                hwnd, data->window_rect.left, data->window_rect.top, x, y );
876
877     if ((data->window_rect.right - data->window_rect.left == cx &&
878          data->window_rect.bottom - data->window_rect.top == cy) ||
879         (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
880     {
881         if (flags & SWP_NOMOVE) return;  /* if nothing changed, don't do anything */
882         flags |= SWP_NOSIZE;
883     }
884     else
885         TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
886                hwnd, data->window_rect.right - data->window_rect.left,
887                data->window_rect.bottom - data->window_rect.top, cx, cy );
888
889     SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
890 }
891
892
893 /***********************************************************************
894  *           get_window_wm_state
895  */
896 static int get_window_wm_state( Display *display, struct x11drv_win_data *data )
897 {
898     struct
899     {
900         CARD32 state;
901         XID     icon;
902     } *state;
903     Atom type;
904     int format, ret = -1;
905     unsigned long count, remaining;
906
907     wine_tsx11_lock();
908     if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
909                              sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
910                              &type, &format, &count, &remaining, (unsigned char **)&state ))
911     {
912         if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
913             ret = state->state;
914         XFree( state );
915     }
916     wine_tsx11_unlock();
917     return ret;
918 }
919
920
921 /***********************************************************************
922  *           handle_wm_state_notify
923  *
924  * Handle a PropertyNotify for WM_STATE.
925  */
926 static void handle_wm_state_notify( struct x11drv_win_data *data, XPropertyEvent *event,
927                                     BOOL update_window )
928 {
929     switch(event->state)
930     {
931     case PropertyDelete:
932         TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
933         data->wm_state = WithdrawnState;
934         break;
935     case PropertyNewValue:
936         {
937             int old_state = data->wm_state;
938             int new_state = get_window_wm_state( event->display, data );
939             if (new_state != -1 && new_state != data->wm_state)
940             {
941                 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
942                        data->hwnd, data->whole_window, new_state, old_state );
943                 data->wm_state = new_state;
944                 /* ignore the initial state transition out of withdrawn state */
945                 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
946                 if (!old_state) return;
947             }
948         }
949         break;
950     }
951
952     if (!update_window || !data->managed || !data->mapped) return;
953
954     if (data->iconic && data->wm_state == NormalState)  /* restore window */
955     {
956         data->iconic = FALSE;
957         if (is_net_wm_state_maximized( event->display, data ))
958         {
959             TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
960             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
961         }
962         else
963         {
964             TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
965             SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
966         }
967     }
968     else if (!data->iconic && data->wm_state == IconicState)
969     {
970         TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
971         data->iconic = TRUE;
972         SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
973     }
974 }
975
976
977 /***********************************************************************
978  *           X11DRV_PropertyNotify
979  */
980 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
981 {
982     XPropertyEvent *event = &xev->xproperty;
983     struct x11drv_win_data *data;
984
985     if (!hwnd) return;
986     if (!(data = X11DRV_get_win_data( hwnd ))) return;
987
988     if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( data, event, TRUE );
989 }
990
991
992 /* event filter to wait for a WM_STATE change notification on a window */
993 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
994 {
995     if (event->xany.window != (Window)arg) return 0;
996     return (event->type == DestroyNotify ||
997             (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
998 }
999
1000 /***********************************************************************
1001  *           wait_for_withdrawn_state
1002  */
1003 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data, BOOL set )
1004 {
1005     DWORD end = GetTickCount() + 2000;
1006
1007     if (!data->managed) return;
1008
1009     TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
1010            data->hwnd, data->whole_window, set ? "" : "not " );
1011
1012     while (data->whole_window && ((data->wm_state == WithdrawnState) == !set))
1013     {
1014         XEvent event;
1015         int count = 0;
1016
1017         wine_tsx11_lock();
1018         while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)data->whole_window ))
1019         {
1020             count++;
1021             if (XFilterEvent( &event, None )) continue;  /* filtered, ignore it */
1022             if (event.type == DestroyNotify) call_event_handler( display, &event );
1023             else
1024             {
1025                 wine_tsx11_unlock();
1026                 handle_wm_state_notify( data, &event.xproperty, FALSE );
1027                 wine_tsx11_lock();
1028             }
1029         }
1030         wine_tsx11_unlock();
1031
1032         if (!count)
1033         {
1034             struct pollfd pfd;
1035             int timeout = end - GetTickCount();
1036
1037             pfd.fd = ConnectionNumber(display);
1038             pfd.events = POLLIN;
1039             if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1040             {
1041                 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
1042                 break;
1043             }
1044         }
1045     }
1046     TRACE( "window %p/%lx state now %d\n", data->hwnd, data->whole_window, data->wm_state );
1047 }
1048
1049
1050 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1051 {
1052     RECT tempRect;
1053
1054     if (!IsWindowEnabled(hQueryWnd)) return 0;
1055     
1056     GetWindowRect(hQueryWnd, &tempRect);
1057
1058     if(!PtInRect(&tempRect, *lpPt)) return 0;
1059
1060     if (!IsIconic( hQueryWnd ))
1061     {
1062         POINT pt = *lpPt;
1063         ScreenToClient( hQueryWnd, &pt );
1064         GetClientRect( hQueryWnd, &tempRect );
1065
1066         if (PtInRect( &tempRect, pt))
1067         {
1068             HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1069             if (ret && ret != hQueryWnd)
1070             {
1071                 ret = find_drop_window( ret, lpPt );
1072                 if (ret) return ret;
1073             }
1074         }
1075     }
1076
1077     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1078     
1079     ScreenToClient(hQueryWnd, lpPt);
1080
1081     return hQueryWnd;
1082 }
1083
1084 /**********************************************************************
1085  *           EVENT_DropFromOffix
1086  *
1087  * don't know if it still works (last Changelog is from 96/11/04)
1088  */
1089 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1090 {
1091     struct x11drv_win_data *data;
1092     unsigned long       data_length;
1093     unsigned long       aux_long;
1094     unsigned char*      p_data = NULL;
1095     Atom atom_aux;
1096     int                 x, y, dummy;
1097     BOOL                bAccept;
1098     Window              win, w_aux_root, w_aux_child;
1099
1100     win = X11DRV_get_whole_window(hWnd);
1101     wine_tsx11_lock();
1102     XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1103                    &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1104     x += virtual_screen_rect.left;
1105     y += virtual_screen_rect.top;
1106     wine_tsx11_unlock();
1107
1108     if (!(data = X11DRV_get_win_data( hWnd ))) return;
1109
1110     /* find out drop point and drop window */
1111     if( x < 0 || y < 0 ||
1112         x > (data->whole_rect.right - data->whole_rect.left) ||
1113         y > (data->whole_rect.bottom - data->whole_rect.top) )
1114     {   
1115         bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1116         x = 0;
1117         y = 0; 
1118     }
1119     else
1120     {
1121         POINT   pt = { x, y };
1122         HWND    hwndDrop = find_drop_window( hWnd, &pt );
1123         if (hwndDrop)
1124         {
1125             x = pt.x;
1126             y = pt.y;
1127             bAccept = TRUE;
1128         }
1129         else
1130         {
1131             bAccept = FALSE;
1132         }
1133     }
1134
1135     if (!bAccept) return;
1136
1137     wine_tsx11_lock();
1138     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1139                         x11drv_atom(DndSelection), 0, 65535, FALSE,
1140                         AnyPropertyType, &atom_aux, &dummy,
1141                         &data_length, &aux_long, &p_data);
1142     wine_tsx11_unlock();
1143
1144     if( !aux_long && p_data)  /* don't bother if > 64K */
1145     {
1146         char *p = (char *)p_data;
1147         char *p_drop;
1148
1149         aux_long = 0;
1150         while( *p )  /* calculate buffer size */
1151         {
1152             INT len = GetShortPathNameA( p, NULL, 0 );
1153             if (len) aux_long += len + 1;
1154             p += strlen(p) + 1;
1155         }
1156         if( aux_long && aux_long < 65535 )
1157         {
1158             HDROP                 hDrop;
1159             DROPFILES *lpDrop;
1160
1161             aux_long += sizeof(DROPFILES) + 1;
1162             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1163             lpDrop = GlobalLock( hDrop );
1164
1165             if( lpDrop )
1166             {
1167                 lpDrop->pFiles = sizeof(DROPFILES);
1168                 lpDrop->pt.x = x;
1169                 lpDrop->pt.y = y;
1170                 lpDrop->fNC = FALSE;
1171                 lpDrop->fWide = FALSE;
1172                 p_drop = (char *)(lpDrop + 1);
1173                 p = (char *)p_data;
1174                 while(*p)
1175                 {
1176                     if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1177                         p_drop += strlen( p_drop ) + 1;
1178                     p += strlen(p) + 1;
1179                 }
1180                 *p_drop = '\0';
1181                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1182             }
1183         }
1184     }
1185     wine_tsx11_lock();
1186     if( p_data ) XFree(p_data);
1187     wine_tsx11_unlock();
1188 }
1189
1190 /**********************************************************************
1191  *           EVENT_DropURLs
1192  *
1193  * drop items are separated by \n
1194  * each item is prefixed by its mime type
1195  *
1196  * event->data.l[3], event->data.l[4] contains drop x,y position
1197  */
1198 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1199 {
1200   struct x11drv_win_data *win_data;
1201   unsigned long data_length;
1202   unsigned long aux_long, drop_len = 0;
1203   unsigned char *p_data = NULL; /* property data */
1204   char          *p_drop = NULL;
1205   char          *p, *next;
1206   int           x, y;
1207   DROPFILES *lpDrop;
1208   HDROP hDrop;
1209   union {
1210     Atom        atom_aux;
1211     int         i;
1212     Window      w_aux;
1213     unsigned int u;
1214   }             u; /* unused */
1215
1216   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1217
1218   wine_tsx11_lock();
1219   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1220                       x11drv_atom(DndSelection), 0, 65535, FALSE,
1221                       AnyPropertyType, &u.atom_aux, &u.i,
1222                       &data_length, &aux_long, &p_data);
1223   wine_tsx11_unlock();
1224   if (aux_long)
1225     WARN("property too large, truncated!\n");
1226   TRACE("urls=%s\n", p_data);
1227
1228   if( !aux_long && p_data) {    /* don't bother if > 64K */
1229     /* calculate length */
1230     p = (char*) p_data;
1231     next = strchr(p, '\n');
1232     while (p) {
1233       if (next) *next=0;
1234       if (strncmp(p,"file:",5) == 0 ) {
1235         INT len = GetShortPathNameA( p+5, NULL, 0 );
1236         if (len) drop_len += len + 1;
1237       }
1238       if (next) {
1239         *next = '\n';
1240         p = next + 1;
1241         next = strchr(p, '\n');
1242       } else {
1243         p = NULL;
1244       }
1245     }
1246
1247     if( drop_len && drop_len < 65535 ) {
1248       wine_tsx11_lock();
1249       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1250                      &x, &y, &u.i, &u.i, &u.u);
1251       x += virtual_screen_rect.left;
1252       y += virtual_screen_rect.top;
1253       wine_tsx11_unlock();
1254
1255       drop_len += sizeof(DROPFILES) + 1;
1256       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1257       lpDrop = GlobalLock( hDrop );
1258
1259       if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
1260       {
1261           lpDrop->pFiles = sizeof(DROPFILES);
1262           lpDrop->pt.x = x;
1263           lpDrop->pt.y = y;
1264           lpDrop->fNC =
1265             ( x < (win_data->client_rect.left - win_data->whole_rect.left)  ||
1266               y < (win_data->client_rect.top - win_data->whole_rect.top)    ||
1267               x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1268               y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1269           lpDrop->fWide = FALSE;
1270           p_drop = (char*)(lpDrop + 1);
1271       }
1272
1273       /* create message content */
1274       if (p_drop) {
1275         p = (char*) p_data;
1276         next = strchr(p, '\n');
1277         while (p) {
1278           if (next) *next=0;
1279           if (strncmp(p,"file:",5) == 0 ) {
1280             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1281             if (len) {
1282               TRACE("drop file %s as %s\n", p+5, p_drop);
1283               p_drop += len+1;
1284             } else {
1285               WARN("can't convert file %s to dos name\n", p+5);
1286             }
1287           } else {
1288             WARN("unknown mime type %s\n", p);
1289           }
1290           if (next) {
1291             *next = '\n';
1292             p = next + 1;
1293             next = strchr(p, '\n');
1294           } else {
1295             p = NULL;
1296           }
1297           *p_drop = '\0';
1298         }
1299
1300         GlobalUnlock(hDrop);
1301         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1302       }
1303     }
1304     wine_tsx11_lock();
1305     if( p_data ) XFree(p_data);
1306     wine_tsx11_unlock();
1307   }
1308 }
1309
1310 /**********************************************************************
1311  *              handle_dnd_protocol
1312  */
1313 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1314 {
1315     Window root, child;
1316     int root_x, root_y, child_x, child_y;
1317     unsigned int u;
1318
1319     /* query window (drag&drop event contains only drag window) */
1320     wine_tsx11_lock();
1321     XQueryPointer( event->display, root_window, &root, &child,
1322                    &root_x, &root_y, &child_x, &child_y, &u);
1323     if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1324     wine_tsx11_unlock();
1325     if (!hwnd) return;
1326     if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1327         EVENT_DropFromOffiX(hwnd, event);
1328     else if (event->data.l[0] == DndURL)
1329         EVENT_DropURLs(hwnd, event);
1330 }
1331
1332
1333 struct client_message_handler
1334 {
1335     int    atom;                                  /* protocol atom */
1336     void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1337 };
1338
1339 static const struct client_message_handler client_messages[] =
1340 {
1341     { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1342     { XATOM_DndProtocol,  handle_dnd_protocol },
1343     { XATOM_XdndEnter,    X11DRV_XDND_EnterEvent },
1344     { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1345     { XATOM_XdndDrop,     X11DRV_XDND_DropEvent },
1346     { XATOM_XdndLeave,    X11DRV_XDND_LeaveEvent }
1347 };
1348
1349
1350 /**********************************************************************
1351  *           X11DRV_ClientMessage
1352  */
1353 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1354 {
1355     XClientMessageEvent *event = &xev->xclient;
1356     unsigned int i;
1357
1358     if (!hwnd) return;
1359
1360     if (event->format != 32)
1361     {
1362         WARN( "Don't know how to handle format %d\n", event->format );
1363         return;
1364     }
1365
1366     for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1367     {
1368         if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1369         {
1370             client_messages[i].handler( hwnd, event );
1371             return;
1372         }
1373     }
1374     TRACE( "no handler found for %ld\n", event->message_type );
1375 }
1376
1377
1378 /***********************************************************************
1379  *              X11DRV_SendInput  (X11DRV.@)
1380  */
1381 UINT CDECL X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
1382 {
1383     UINT i;
1384
1385     for (i = 0; i < count; i++, inputs++)
1386     {
1387         switch(inputs->type)
1388         {
1389         case INPUT_MOUSE:
1390             X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
1391                                      inputs->u.mi.mouseData, inputs->u.mi.time,
1392                                      inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
1393             break;
1394         case INPUT_KEYBOARD:
1395             X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
1396                                         inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
1397             break;
1398         case INPUT_HARDWARE:
1399             FIXME( "INPUT_HARDWARE not supported\n" );
1400             break;
1401         }
1402     }
1403     return count;
1404 }