4 * Copyright 1993 Alexandre Julliard
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.
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.
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
27 #ifdef HAVE_SYS_POLL_H
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
35 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
36 #include <X11/extensions/XInput2.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
52 /* avoid conflict with field names in included win32 headers */
54 #include "shlobj.h" /* DROPFILES */
57 #include "wine/server.h"
58 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(event);
62 extern BOOL ximInComposeMode;
64 #define DndNotDnd -1 /* OffiX drag&drop */
76 #define DndURL 128 /* KDE drag&drop */
78 #define XEMBED_EMBEDDED_NOTIFY 0
79 #define XEMBED_WINDOW_ACTIVATE 1
80 #define XEMBED_WINDOW_DEACTIVATE 2
81 #define XEMBED_REQUEST_FOCUS 3
82 #define XEMBED_FOCUS_IN 4
83 #define XEMBED_FOCUS_OUT 5
84 #define XEMBED_FOCUS_NEXT 6
85 #define XEMBED_FOCUS_PREV 7
86 #define XEMBED_MODALITY_ON 10
87 #define XEMBED_MODALITY_OFF 11
88 #define XEMBED_REGISTER_ACCELERATOR 12
89 #define XEMBED_UNREGISTER_ACCELERATOR 13
90 #define XEMBED_ACTIVATE_ACCELERATOR 14
92 Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
93 void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
96 static void X11DRV_FocusIn( HWND hwnd, XEvent *event );
97 static void X11DRV_FocusOut( HWND hwnd, XEvent *event );
98 static void X11DRV_Expose( HWND hwnd, XEvent *event );
99 static void X11DRV_MapNotify( HWND hwnd, XEvent *event );
100 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
101 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
102 static void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
103 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
104 static void X11DRV_ClientMessage( HWND hwnd, XEvent *event );
105 static void X11DRV_GravityNotify( HWND hwnd, XEvent *event );
107 #define MAX_EVENT_HANDLERS 128
109 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
111 NULL, /* 0 reserved */
112 NULL, /* 1 reserved */
113 X11DRV_KeyEvent, /* 2 KeyPress */
114 X11DRV_KeyEvent, /* 3 KeyRelease */
115 X11DRV_ButtonPress, /* 4 ButtonPress */
116 X11DRV_ButtonRelease, /* 5 ButtonRelease */
117 X11DRV_MotionNotify, /* 6 MotionNotify */
118 X11DRV_EnterNotify, /* 7 EnterNotify */
119 NULL, /* 8 LeaveNotify */
120 X11DRV_FocusIn, /* 9 FocusIn */
121 X11DRV_FocusOut, /* 10 FocusOut */
122 X11DRV_KeymapNotify, /* 11 KeymapNotify */
123 X11DRV_Expose, /* 12 Expose */
124 NULL, /* 13 GraphicsExpose */
125 NULL, /* 14 NoExpose */
126 NULL, /* 15 VisibilityNotify */
127 NULL, /* 16 CreateNotify */
128 X11DRV_DestroyNotify, /* 17 DestroyNotify */
129 X11DRV_UnmapNotify, /* 18 UnmapNotify */
130 X11DRV_MapNotify, /* 19 MapNotify */
131 NULL, /* 20 MapRequest */
132 X11DRV_ReparentNotify, /* 21 ReparentNotify */
133 X11DRV_ConfigureNotify, /* 22 ConfigureNotify */
134 NULL, /* 23 ConfigureRequest */
135 X11DRV_GravityNotify, /* 24 GravityNotify */
136 NULL, /* 25 ResizeRequest */
137 NULL, /* 26 CirculateNotify */
138 NULL, /* 27 CirculateRequest */
139 X11DRV_PropertyNotify, /* 28 PropertyNotify */
140 X11DRV_SelectionClear, /* 29 SelectionClear */
141 X11DRV_SelectionRequest, /* 30 SelectionRequest */
142 NULL, /* 31 SelectionNotify */
143 NULL, /* 32 ColormapNotify */
144 X11DRV_ClientMessage, /* 33 ClientMessage */
145 X11DRV_MappingNotify, /* 34 MappingNotify */
146 X11DRV_GenericEvent /* 35 GenericEvent */
149 static const char * event_names[MAX_EVENT_HANDLERS] =
151 NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
152 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
153 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
154 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
155 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
156 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
157 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
160 int xinput2_opcode = 0;
162 /* return the name of an X event */
163 static const char *dbgstr_event( int type )
165 if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
166 return wine_dbg_sprintf( "Unknown event %d", type );
169 static inline void get_event_data( XEvent *event )
171 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
172 if (event->xany.type != GenericEvent) return;
173 if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
177 static inline void free_event_data( XEvent *event )
179 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
180 if (event->xany.type != GenericEvent) return;
181 if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
185 /***********************************************************************
186 * X11DRV_register_event_handler
188 * Register a handler for a given event type.
189 * If already registered, overwrite the previous handler.
191 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
193 assert( type < MAX_EVENT_HANDLERS );
194 assert( !handlers[type] || handlers[type] == handler );
195 handlers[type] = handler;
196 event_names[type] = name;
197 TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
201 /***********************************************************************
204 static Bool filter_event( Display *display, XEvent *event, char *arg )
206 ULONG_PTR mask = (ULONG_PTR)arg;
208 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
216 return (mask & (QS_KEY|QS_HOTKEY)) != 0;
219 return (mask & QS_MOUSEBUTTON) != 0;
223 return (mask & QS_MOUSEMOVE) != 0;
225 return (mask & QS_PAINT) != 0;
230 case ConfigureNotify:
233 return (mask & QS_POSTMESSAGE) != 0;
235 return (mask & QS_SENDMESSAGE) != 0;
240 enum event_merge_action
242 MERGE_DISCARD, /* discard the old event */
243 MERGE_HANDLE, /* handle the old event */
244 MERGE_KEEP, /* keep the old event for future merging */
245 MERGE_IGNORE /* ignore the new event, keep the old one */
248 /***********************************************************************
249 * merge_raw_motion_events
251 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
252 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
257 if (!prev->valuators.mask_len) return MERGE_HANDLE;
258 if (!next->valuators.mask_len) return MERGE_HANDLE;
260 mask = prev->valuators.mask[0] | next->valuators.mask[0];
261 if (mask == next->valuators.mask[0]) /* keep next */
263 for (i = j = k = 0; i < 8; i++)
265 if (XIMaskIsSet( prev->valuators.mask, i ))
266 next->valuators.values[j] += prev->valuators.values[k++];
267 if (XIMaskIsSet( next->valuators.mask, i )) j++;
269 TRACE( "merging duplicate GenericEvent\n" );
270 return MERGE_DISCARD;
272 if (mask == prev->valuators.mask[0]) /* keep prev */
274 for (i = j = k = 0; i < 8; i++)
276 if (XIMaskIsSet( next->valuators.mask, i ))
277 prev->valuators.values[j] += next->valuators.values[k++];
278 if (XIMaskIsSet( prev->valuators.mask, i )) j++;
280 TRACE( "merging duplicate GenericEvent\n" );
283 /* can't merge events with disjoint masks */
288 /***********************************************************************
291 * Try to merge 2 consecutive events.
293 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
297 case ConfigureNotify:
300 case ConfigureNotify:
301 if (prev->xany.window == next->xany.window)
303 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
304 return MERGE_DISCARD;
316 if (prev->xany.window == next->xany.window)
318 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
319 return MERGE_DISCARD;
322 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
324 if (next->xcookie.extension != xinput2_opcode) break;
325 if (next->xcookie.evtype != XI_RawMotion) break;
326 if (x11drv_thread_data()->warp_serial) break;
331 if (prev->xcookie.extension != xinput2_opcode) break;
332 if (prev->xcookie.evtype != XI_RawMotion) break;
336 if (next->xcookie.extension != xinput2_opcode) break;
337 if (next->xcookie.evtype != XI_RawMotion) break;
338 if (x11drv_thread_data()->warp_serial) break;
339 return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
348 /***********************************************************************
351 static inline void call_event_handler( Display *display, XEvent *event )
355 struct x11drv_thread_data *thread_data;
357 if (!handlers[event->type])
359 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
360 return; /* no handler, ignore it */
363 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
364 hwnd = 0; /* not for a registered window */
365 if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
367 TRACE( "%lu %s for hwnd/window %p/%lx\n",
368 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
369 thread_data = x11drv_thread_data();
370 prev = thread_data->current_event;
371 thread_data->current_event = event;
372 handlers[event->type]( hwnd, event );
373 thread_data->current_event = prev;
377 /***********************************************************************
380 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
382 XEvent event, prev_event;
384 enum event_merge_action action = MERGE_DISCARD;
387 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
390 if (XFilterEvent( &event, None ))
393 * SCIM on linux filters key events strangely. It does not filter the
394 * KeyPress events for these keys however it does filter the
395 * KeyRelease events. This causes wine to become very confused as
396 * to the keyboard state.
398 * We need to let those KeyRelease events be processed so that the
399 * keyboard state is correct.
401 if (event.type == KeyRelease)
404 XKeyEvent *keyevent = &event.xkey;
406 XLookupString(keyevent, NULL, 0, &keysym, NULL);
407 if (!(keysym == XK_Shift_L ||
408 keysym == XK_Shift_R ||
409 keysym == XK_Control_L ||
410 keysym == XK_Control_R ||
411 keysym == XK_Alt_R ||
412 keysym == XK_Alt_L ||
413 keysym == XK_Meta_R ||
414 keysym == XK_Meta_L))
415 continue; /* not a key we care about, ignore it */
418 continue; /* filtered, ignore it */
420 get_event_data( &event );
421 if (prev_event.type) action = merge_events( &prev_event, &event );
424 case MERGE_HANDLE: /* handle prev, keep new */
425 call_event_handler( display, &prev_event );
427 case MERGE_DISCARD: /* discard prev, keep new */
428 free_event_data( &prev_event );
431 case MERGE_KEEP: /* handle new, keep prev for future merging */
432 call_event_handler( display, &event );
434 case MERGE_IGNORE: /* ignore new, keep prev for future merging */
435 free_event_data( &event );
439 if (prev_event.type) call_event_handler( display, &prev_event );
440 free_event_data( &prev_event );
441 XFlush( gdi_display );
442 if (count) TRACE( "processed %d events\n", count );
447 /***********************************************************************
448 * MsgWaitForMultipleObjectsEx (X11DRV.@)
450 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
451 DWORD timeout, DWORD mask, DWORD flags )
454 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
458 if (!count && !timeout) return WAIT_TIMEOUT;
459 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
460 timeout, flags & MWMO_ALERTABLE );
463 if (data->current_event) mask = 0; /* don't process nested events */
465 if (process_events( data->display, filter_event, mask )) ret = count - 1;
466 else if (count || timeout)
468 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
469 timeout, flags & MWMO_ALERTABLE );
470 if (ret == count - 1) process_events( data->display, filter_event, mask );
472 else ret = WAIT_TIMEOUT;
477 /***********************************************************************
478 * EVENT_x11_time_to_win32_time
480 * Make our timer and the X timer line up as best we can
481 * Pass 0 to retrieve the current adjustment value (times -1)
483 DWORD EVENT_x11_time_to_win32_time(Time time)
485 static DWORD adjust = 0;
486 DWORD now = GetTickCount();
489 if (! adjust && time != 0)
496 /* If we got an event in the 'future', then our clock is clearly wrong.
497 If we got it more than 10000 ms in the future, then it's most likely
498 that the clock has wrapped. */
501 if (ret > now && ((ret - now) < 10000) && time != 0)
512 /*******************************************************************
513 * can_activate_window
515 * Check if we can activate the specified window.
517 static inline BOOL can_activate_window( HWND hwnd )
519 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
522 if (!(style & WS_VISIBLE)) return FALSE;
523 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
524 if (style & WS_MINIMIZE) return FALSE;
525 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
526 if (hwnd == GetDesktopWindow()) return FALSE;
527 if (GetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE;
528 return !(style & WS_DISABLED);
532 /**********************************************************************
535 * Try to force focus for non-managed windows.
537 static void set_input_focus( Display *display, Window window )
539 XWindowChanges changes;
544 if (EVENT_x11_time_to_win32_time(0))
545 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
546 /* FIXME: this is not entirely correct */
547 timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
549 timestamp = CurrentTime;
551 /* Set X focus and install colormap */
552 changes.stack_mode = Above;
553 XConfigureWindow( display, window, CWStackMode, &changes );
554 XSetInputFocus( display, window, RevertToParent, timestamp );
557 /**********************************************************************
560 static void set_focus( Display *display, HWND hwnd, Time time )
564 GUITHREADINFO threadinfo;
566 TRACE( "setting foreground window to %p\n", hwnd );
567 SetForegroundWindow( hwnd );
569 threadinfo.cbSize = sizeof(threadinfo);
570 GetGUIThreadInfo(0, &threadinfo);
571 focus = threadinfo.hwndFocus;
572 if (!focus) focus = threadinfo.hwndActive;
573 if (focus) focus = GetAncestor( focus, GA_ROOT );
574 win = X11DRV_get_whole_window(focus);
578 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
579 XSetInputFocus( display, win, RevertToParent, time );
584 /**********************************************************************
585 * handle_manager_message
587 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
589 if (hwnd != GetDesktopWindow()) return;
590 if (systray_atom && event->data.l[1] == systray_atom)
591 change_systray_owner( event->display, event->data.l[2] );
595 /**********************************************************************
596 * handle_wm_protocols
598 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
600 Atom protocol = (Atom)event->data.l[0];
601 Time event_time = (Time)event->data.l[1];
603 if (!protocol) return;
605 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
607 update_user_time( event_time );
609 if (hwnd == GetDesktopWindow())
611 /* The desktop window does not have a close button that we can
612 * pretend to click. Therefore, we simply send it a close command. */
613 SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
617 /* Ignore the delete window request if the window has been disabled
618 * and we are in managed mode. This is to disallow applications from
619 * being closed by the window manager while in a modal state.
621 if (IsWindowEnabled(hwnd))
625 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
626 hSysMenu = GetSystemMenu(hwnd, FALSE);
629 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
630 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
633 if (GetActiveWindow() != hwnd)
635 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
636 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
637 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
640 case MA_NOACTIVATEANDEAT:
641 case MA_ACTIVATEANDEAT:
647 SetActiveWindow(hwnd);
650 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
655 PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
658 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
660 HWND last_focus = x11drv_thread_data()->last_focus;
662 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
663 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
664 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
666 if (can_activate_window(hwnd))
668 /* simulate a mouse click on the caption to find out
669 * whether the window wants to be activated */
670 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
671 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
672 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
673 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
675 set_focus( event->display, hwnd, event_time );
679 else if (hwnd == GetDesktopWindow())
681 hwnd = GetForegroundWindow();
682 if (!hwnd) hwnd = last_focus;
683 if (!hwnd) hwnd = GetDesktopWindow();
684 set_focus( event->display, hwnd, event_time );
687 /* try to find some other window to give the focus to */
689 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
690 if (!hwnd) hwnd = GetActiveWindow();
691 if (!hwnd) hwnd = last_focus;
692 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
694 else if (protocol == x11drv_atom(_NET_WM_PING))
696 XClientMessageEvent xev;
699 TRACE("NET_WM Ping\n");
700 xev.window = DefaultRootWindow(xev.display);
701 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
706 static const char * const focus_details[] =
712 "NotifyNonlinearVirtual",
718 /**********************************************************************
721 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
723 XFocusChangeEvent *event = &xev->xfocus;
728 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
730 if (event->detail == NotifyPointer) return;
731 if (hwnd == GetDesktopWindow()) return;
733 if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic );
736 if (hwnd == GetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE );
740 if (!can_activate_window(hwnd))
742 HWND hwnd = GetFocus();
743 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
744 if (!hwnd) hwnd = GetActiveWindow();
745 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
746 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
748 else SetForegroundWindow( hwnd );
752 /**********************************************************************
755 * Note: only top-level windows get FocusOut events.
757 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
759 XFocusChangeEvent *event = &xev->xfocus;
765 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
767 if (event->detail == NotifyPointer)
769 if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
773 if (ximInComposeMode) return;
775 x11drv_thread_data()->last_focus = hwnd;
776 if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
778 if (root_window != DefaultRootWindow(event->display))
780 if (hwnd == GetDesktopWindow()) reset_clipping_window();
783 if (hwnd != GetForegroundWindow()) return;
784 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
786 /* don't reset the foreground window, if the window which is
787 getting the focus is a Wine window */
789 XGetInputFocus( event->display, &focus_win, &revert );
792 if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
798 /* Abey : 6-Oct-99. Check again if the focus out window is the
799 Foreground window, because in most cases the messages sent
800 above must have already changed the foreground window, in which
801 case we don't have to change the foreground window to 0 */
802 if (hwnd == GetForegroundWindow())
804 TRACE( "lost focus, setting fg to desktop\n" );
805 SetForegroundWindow( GetDesktopWindow() );
811 /***********************************************************************
814 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
816 XExposeEvent *event = &xev->xexpose;
818 struct x11drv_win_data *data;
819 int flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME;
821 TRACE( "win %p (%lx) %d,%d %dx%d\n",
822 hwnd, event->window, event->x, event->y, event->width, event->height );
824 if (!(data = get_win_data( hwnd ))) return;
826 rect.left = event->x;
828 rect.right = event->x + event->width;
829 rect.bottom = event->y + event->height;
833 data->surface->funcs->lock( data->surface );
834 add_bounds_rect( data->surface->funcs->get_bounds( data->surface ), &rect );
835 data->surface->funcs->unlock( data->surface );
836 if (data->vis.visualid != default_visual.visualid)
837 data->surface->funcs->flush( data->surface );
840 if (event->window != root_window)
842 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
843 data->whole_rect.top - data->client_rect.top );
845 if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
846 mirror_rect( &data->client_rect, &rect );
848 SERVER_START_REQ( update_window_zorder )
850 req->window = wine_server_user_handle( hwnd );
851 req->rect.left = rect.left;
852 req->rect.top = rect.top;
853 req->rect.right = rect.right;
854 req->rect.bottom = rect.bottom;
855 wine_server_call( req );
859 flags |= RDW_ALLCHILDREN;
861 else OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
863 if (data->surface) flags = 0;
864 release_win_data( data );
866 if (flags) RedrawWindow( hwnd, &rect, 0, flags );
870 /**********************************************************************
873 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
875 struct x11drv_win_data *data;
877 if (event->xany.window == x11drv_thread_data()->clip_window)
882 if (!(data = get_win_data( hwnd ))) return;
884 if (!data->managed && !data->embedded && data->mapped)
886 HWND hwndFocus = GetFocus();
887 if (hwndFocus && IsChild( hwnd, hwndFocus ))
888 set_input_focus( data->display, data->whole_window );
890 release_win_data( data );
894 /**********************************************************************
897 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
899 if (event->xany.window == x11drv_thread_data()->clip_window) clipping_cursor = 0;
903 /***********************************************************************
904 * is_net_wm_state_maximized
906 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
910 unsigned long i, count, remaining;
912 if (!data->whole_window) return FALSE;
914 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
915 65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
916 &remaining, (unsigned char **)&state ))
918 if (type == XA_ATOM && format == 32)
920 for (i = 0; i < count; i++)
922 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
923 state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
933 /***********************************************************************
934 * X11DRV_ReparentNotify
936 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
938 XReparentEvent *event = &xev->xreparent;
939 struct x11drv_win_data *data;
940 HWND parent, old_parent;
943 if (!(data = get_win_data( hwnd ))) return;
947 release_win_data( data );
951 if (data->whole_window)
953 if (event->parent == root_window)
955 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
957 release_win_data( data );
958 SendMessageW( hwnd, WM_CLOSE, 0, 0 );
961 data->embedder = event->parent;
964 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
965 release_win_data( data );
967 style = GetWindowLongW( hwnd, GWL_STYLE );
968 if (event->parent == root_window)
970 parent = GetDesktopWindow();
971 style = (style & ~WS_CHILD) | WS_POPUP;
975 if (!(parent = create_foreign_window( event->display, event->parent ))) return;
976 style = (style & ~WS_POPUP) | WS_CHILD;
979 ShowWindow( hwnd, SW_HIDE );
980 old_parent = SetParent( hwnd, parent );
981 SetWindowLongW( hwnd, GWL_STYLE, style );
982 SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
983 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
984 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
986 /* make old parent destroy itself if it no longer has children */
987 if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
991 /***********************************************************************
992 * X11DRV_ConfigureNotify
994 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
996 XConfigureEvent *event = &xev->xconfigure;
997 struct x11drv_win_data *data;
1002 int cx, cy, x = event->x, y = event->y;
1006 if (!(data = get_win_data( hwnd ))) return;
1007 if (!data->mapped || data->iconic) goto done;
1008 if (data->whole_window && !data->managed) goto done;
1009 /* ignore synthetic events on foreign windows */
1010 if (event->send_event && !data->whole_window) goto done;
1011 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
1013 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1014 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
1015 event->serial, data->configure_serial );
1021 parent = GetAncestor( hwnd, GA_PARENT );
1022 root_coords = event->send_event; /* synthetic events are always in root coords */
1024 if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
1027 XTranslateCoordinates( event->display, event->window, root_window,
1028 0, 0, &x, &y, &child );
1033 rect.right = x + event->width;
1034 rect.bottom = y + event->height;
1035 if (root_coords) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
1036 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1037 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1038 event->x, event->y, event->width, event->height );
1040 X11DRV_X_to_window_rect( data, &rect );
1041 if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1043 /* Compare what has changed */
1047 cx = rect.right - rect.left;
1048 cy = rect.bottom - rect.top;
1049 flags = SWP_NOACTIVATE | SWP_NOZORDER;
1051 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
1053 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1055 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1056 hwnd, data->window_rect.left, data->window_rect.top, x, y );
1058 if ((data->window_rect.right - data->window_rect.left == cx &&
1059 data->window_rect.bottom - data->window_rect.top == cy) ||
1060 (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
1061 flags |= SWP_NOSIZE;
1063 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1064 hwnd, data->window_rect.right - data->window_rect.left,
1065 data->window_rect.bottom - data->window_rect.top, cx, cy );
1067 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1068 if ((style & WS_CAPTION) == WS_CAPTION)
1070 if (is_net_wm_state_maximized( event->display, data ))
1072 if (!(style & WS_MAXIMIZE))
1074 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1075 release_win_data( data );
1076 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1080 else if (style & WS_MAXIMIZE)
1082 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1083 release_win_data( data );
1084 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1089 if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
1091 release_win_data( data );
1092 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1097 release_win_data( data );
1101 /**********************************************************************
1102 * X11DRV_GravityNotify
1104 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1106 XGravityEvent *event = &xev->xgravity;
1107 struct x11drv_win_data *data = get_win_data( hwnd );
1108 RECT rect, window_rect;
1112 if (data->whole_window) /* only handle this for foreign windows */
1114 release_win_data( data );
1118 rect.left = event->x;
1119 rect.top = event->y;
1120 rect.right = rect.left + data->whole_rect.right - data->whole_rect.left;
1121 rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1123 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1124 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1125 event->x, event->y );
1127 X11DRV_X_to_window_rect( data, &rect );
1128 window_rect = data->window_rect;
1129 release_win_data( data );
1131 if (window_rect.left != rect.left || window_rect.top != rect.top)
1132 SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1133 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1137 /***********************************************************************
1138 * get_window_wm_state
1140 static int get_window_wm_state( Display *display, Window window )
1148 int format, ret = -1;
1149 unsigned long count, remaining;
1151 if (!XGetWindowProperty( display, window, x11drv_atom(WM_STATE), 0,
1152 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1153 &type, &format, &count, &remaining, (unsigned char **)&state ))
1155 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1163 /***********************************************************************
1164 * handle_wm_state_notify
1166 * Handle a PropertyNotify for WM_STATE.
1168 static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
1170 struct x11drv_win_data *data = get_win_data( hwnd );
1175 switch(event->state)
1177 case PropertyDelete:
1178 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1179 data->wm_state = WithdrawnState;
1181 case PropertyNewValue:
1183 int old_state = data->wm_state;
1184 int new_state = get_window_wm_state( event->display, data->whole_window );
1185 if (new_state != -1 && new_state != data->wm_state)
1187 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1188 data->hwnd, data->whole_window, new_state, old_state );
1189 data->wm_state = new_state;
1190 /* ignore the initial state transition out of withdrawn state */
1191 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1192 if (!old_state) goto done;
1198 if (!update_window || !data->managed || !data->mapped) goto done;
1200 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1202 if (data->iconic && data->wm_state == NormalState) /* restore window */
1204 data->iconic = FALSE;
1205 if ((style & WS_CAPTION) == WS_CAPTION && is_net_wm_state_maximized( event->display, data ))
1207 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1209 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1210 release_win_data( data );
1211 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1214 TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1218 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1220 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1221 release_win_data( data );
1222 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1225 TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1228 else if (!data->iconic && data->wm_state == IconicState)
1230 data->iconic = TRUE;
1231 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1233 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1234 release_win_data( data );
1235 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1238 TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1241 release_win_data( data );
1245 /***********************************************************************
1246 * X11DRV_PropertyNotify
1248 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1250 XPropertyEvent *event = &xev->xproperty;
1253 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
1257 /* event filter to wait for a WM_STATE change notification on a window */
1258 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1260 if (event->xany.window != (Window)arg) return 0;
1261 return (event->type == DestroyNotify ||
1262 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1265 /***********************************************************************
1266 * wait_for_withdrawn_state
1268 void wait_for_withdrawn_state( HWND hwnd, BOOL set )
1270 Display *display = thread_display();
1271 struct x11drv_win_data *data;
1272 DWORD end = GetTickCount() + 2000;
1274 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
1282 if (!(data = get_win_data( hwnd ))) break;
1283 if (!data->managed || data->embedded || data->display != display) break;
1284 if (!(window = data->whole_window)) break;
1285 if (!data->mapped == !set)
1287 TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
1290 if ((data->wm_state == WithdrawnState) != !set)
1292 TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
1295 release_win_data( data );
1297 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
1300 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1301 if (event.type == DestroyNotify) call_event_handler( display, &event );
1302 else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
1308 int timeout = end - GetTickCount();
1310 pfd.fd = ConnectionNumber(display);
1311 pfd.events = POLLIN;
1312 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1314 FIXME( "window %p/%lx wait timed out\n", hwnd, window );
1319 release_win_data( data );
1323 /*****************************************************************
1324 * SetFocus (X11DRV.@)
1328 void CDECL X11DRV_SetFocus( HWND hwnd )
1330 struct x11drv_win_data *data;
1332 if (!(hwnd = GetAncestor( hwnd, GA_ROOT ))) return;
1333 if (!(data = get_win_data( hwnd ))) return;
1334 if (!data->managed) set_input_focus( data->display, data->whole_window );
1335 release_win_data( data );
1339 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1343 if (!IsWindowEnabled(hQueryWnd)) return 0;
1345 GetWindowRect(hQueryWnd, &tempRect);
1347 if(!PtInRect(&tempRect, *lpPt)) return 0;
1349 if (!IsIconic( hQueryWnd ))
1352 ScreenToClient( hQueryWnd, &pt );
1353 GetClientRect( hQueryWnd, &tempRect );
1355 if (PtInRect( &tempRect, pt))
1357 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1358 if (ret && ret != hQueryWnd)
1360 ret = find_drop_window( ret, lpPt );
1361 if (ret) return ret;
1366 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1368 ScreenToClient(hQueryWnd, lpPt);
1373 /**********************************************************************
1374 * EVENT_DropFromOffix
1376 * don't know if it still works (last Changelog is from 96/11/04)
1378 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1380 struct x11drv_win_data *data;
1381 unsigned long data_length;
1382 unsigned long aux_long;
1383 unsigned char* p_data = NULL;
1385 int x, y, cx, cy, dummy;
1387 Window win, w_aux_root, w_aux_child;
1389 if (!(data = get_win_data( hWnd ))) return;
1390 cx = data->whole_rect.right - data->whole_rect.left;
1391 cy = data->whole_rect.bottom - data->whole_rect.top;
1392 win = data->whole_window;
1393 release_win_data( data );
1395 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1396 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1397 x += virtual_screen_rect.left;
1398 y += virtual_screen_rect.top;
1400 /* find out drop point and drop window */
1401 if (x < 0 || y < 0 || x > cx || y > cy)
1403 bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1409 POINT pt = { x, y };
1410 HWND hwndDrop = find_drop_window( hWnd, &pt );
1423 if (!bAccept) return;
1425 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1426 x11drv_atom(DndSelection), 0, 65535, FALSE,
1427 AnyPropertyType, &atom_aux, &dummy,
1428 &data_length, &aux_long, &p_data);
1430 if( !aux_long && p_data) /* don't bother if > 64K */
1432 char *p = (char *)p_data;
1436 while( *p ) /* calculate buffer size */
1438 INT len = GetShortPathNameA( p, NULL, 0 );
1439 if (len) aux_long += len + 1;
1442 if( aux_long && aux_long < 65535 )
1447 aux_long += sizeof(DROPFILES) + 1;
1448 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1449 lpDrop = GlobalLock( hDrop );
1453 lpDrop->pFiles = sizeof(DROPFILES);
1456 lpDrop->fNC = FALSE;
1457 lpDrop->fWide = FALSE;
1458 p_drop = (char *)(lpDrop + 1);
1462 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1463 p_drop += strlen( p_drop ) + 1;
1467 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1471 if( p_data ) XFree(p_data);
1474 /**********************************************************************
1477 * drop items are separated by \n
1478 * each item is prefixed by its mime type
1480 * event->data.l[3], event->data.l[4] contains drop x,y position
1482 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1484 struct x11drv_win_data *win_data;
1485 unsigned long data_length;
1486 unsigned long aux_long, drop_len = 0;
1487 unsigned char *p_data = NULL; /* property data */
1488 char *p_drop = NULL;
1500 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1502 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1503 x11drv_atom(DndSelection), 0, 65535, FALSE,
1504 AnyPropertyType, &u.atom_aux, &u.i,
1505 &data_length, &aux_long, &p_data);
1507 WARN("property too large, truncated!\n");
1508 TRACE("urls=%s\n", p_data);
1510 if( !aux_long && p_data) { /* don't bother if > 64K */
1511 /* calculate length */
1513 next = strchr(p, '\n');
1516 if (strncmp(p,"file:",5) == 0 ) {
1517 INT len = GetShortPathNameA( p+5, NULL, 0 );
1518 if (len) drop_len += len + 1;
1523 next = strchr(p, '\n');
1529 if( drop_len && drop_len < 65535 ) {
1530 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1531 &x, &y, &u.i, &u.i, &u.u);
1532 x += virtual_screen_rect.left;
1533 y += virtual_screen_rect.top;
1535 drop_len += sizeof(DROPFILES) + 1;
1536 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1537 lpDrop = GlobalLock( hDrop );
1539 if( lpDrop && (win_data = get_win_data( hWnd )))
1541 lpDrop->pFiles = sizeof(DROPFILES);
1545 ( x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1546 y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1547 x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1548 y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1549 lpDrop->fWide = FALSE;
1550 p_drop = (char*)(lpDrop + 1);
1551 release_win_data( win_data );
1554 /* create message content */
1557 next = strchr(p, '\n');
1560 if (strncmp(p,"file:",5) == 0 ) {
1561 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1563 TRACE("drop file %s as %s\n", p+5, p_drop);
1566 WARN("can't convert file %s to dos name\n", p+5);
1569 WARN("unknown mime type %s\n", p);
1574 next = strchr(p, '\n');
1581 GlobalUnlock(hDrop);
1582 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1585 if( p_data ) XFree(p_data);
1590 /**********************************************************************
1591 * handle_xembed_protocol
1593 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1595 struct x11drv_win_data *data = get_win_data( hwnd );
1599 switch (event->data.l[1])
1601 case XEMBED_EMBEDDED_NOTIFY:
1602 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1603 data->embedder = event->data.l[3];
1606 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1607 hwnd, event->window, event->data.l[1], event->data.l[2] );
1610 release_win_data( data );
1614 /**********************************************************************
1615 * handle_dnd_protocol
1617 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1620 int root_x, root_y, child_x, child_y;
1623 /* query window (drag&drop event contains only drag window) */
1624 XQueryPointer( event->display, root_window, &root, &child,
1625 &root_x, &root_y, &child_x, &child_y, &u);
1626 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1628 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1629 EVENT_DropFromOffiX(hwnd, event);
1630 else if (event->data.l[0] == DndURL)
1631 EVENT_DropURLs(hwnd, event);
1635 struct client_message_handler
1637 int atom; /* protocol atom */
1638 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1641 static const struct client_message_handler client_messages[] =
1643 { XATOM_MANAGER, handle_manager_message },
1644 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1645 { XATOM__XEMBED, handle_xembed_protocol },
1646 { XATOM_DndProtocol, handle_dnd_protocol },
1647 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1648 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1649 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1650 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1654 /**********************************************************************
1655 * X11DRV_ClientMessage
1657 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1659 XClientMessageEvent *event = &xev->xclient;
1664 if (event->format != 32)
1666 WARN( "Don't know how to handle format %d\n", event->format );
1670 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1672 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1674 client_messages[i].handler( hwnd, event );
1678 TRACE( "no handler found for %ld\n", event->message_type );