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>
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
49 /* avoid conflict with field names in included win32 headers */
51 #include "shlobj.h" /* DROPFILES */
54 #include "wine/server.h"
55 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(event);
59 extern BOOL ximInComposeMode;
61 #define DndNotDnd -1 /* OffiX drag&drop */
73 #define DndURL 128 /* KDE drag&drop */
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 );
86 int type; /* event type */
87 x11drv_event_handler handler; /* corresponding handler function */
90 #define MAX_EVENT_HANDLERS 64
92 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
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 },
102 { FocusIn, X11DRV_FocusIn },
103 { FocusOut, X11DRV_FocusOut },
104 { KeymapNotify, X11DRV_KeymapNotify },
105 { Expose, X11DRV_Expose },
108 /* VisibilityNotify */
110 { DestroyNotify, X11DRV_DestroyNotify },
112 { MapNotify, X11DRV_MapNotify },
115 { ConfigureNotify, X11DRV_ConfigureNotify },
116 /* ConfigureRequest */
119 /* CirculateNotify */
120 /* CirculateRequest */
121 { PropertyNotify, X11DRV_PropertyNotify },
122 { SelectionClear, X11DRV_SelectionClear },
123 { SelectionRequest, X11DRV_SelectionRequest },
124 /* SelectionNotify */
126 { ClientMessage, X11DRV_ClientMessage },
127 { MappingNotify, X11DRV_MappingNotify },
130 static int nb_event_handlers = 18; /* change this if you add handlers above */
133 /* return the name of an X event */
134 static const char *dbgstr_event( int type )
136 static const char * const event_names[] =
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"
148 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
149 return wine_dbg_sprintf( "Extension event %d", type );
153 /***********************************************************************
156 * Find the handler for a given event type. Caller must hold the x11 lock.
158 static inline x11drv_event_handler find_handler( int type )
160 int min = 0, max = nb_event_handlers - 1;
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;
173 /***********************************************************************
174 * X11DRV_register_event_handler
176 * Register a handler for a given event type.
177 * If already registered, overwrite the previous handler.
179 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
185 max = nb_event_handlers - 1;
188 int pos = (min + max) / 2;
189 if (handlers[pos].type == type)
191 handlers[pos].handler = handler;
194 if (handlers[pos].type > type) max = pos - 1;
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;
202 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
205 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
209 /***********************************************************************
212 static Bool filter_event( Display *display, XEvent *event, char *arg )
214 ULONG_PTR mask = (ULONG_PTR)arg;
216 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
224 return (mask & QS_KEY) != 0;
227 return (mask & QS_MOUSEBUTTON) != 0;
231 return (mask & QS_MOUSEMOVE) != 0;
233 return (mask & QS_PAINT) != 0;
238 case ConfigureNotify:
241 return (mask & QS_POSTMESSAGE) != 0;
243 return (mask & QS_SENDMESSAGE) != 0;
248 enum event_merge_action
250 MERGE_DISCARD, /* discard the old event */
251 MERGE_HANDLE, /* handle the old event */
252 MERGE_KEEP /* keep the old event for future merging */
255 /***********************************************************************
258 * Try to merge 2 consecutive events.
260 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
264 case ConfigureNotify:
267 case ConfigureNotify:
268 if (prev->xany.window == next->xany.window)
270 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
271 return MERGE_DISCARD;
280 if (prev->xany.window == next->xany.window && next->type == MotionNotify)
282 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
283 return MERGE_DISCARD;
291 /***********************************************************************
294 static inline void call_event_handler( Display *display, XEvent *event )
297 x11drv_event_handler handler;
299 struct x11drv_thread_data *thread_data;
301 if (!(handler = find_handler( event->type )))
303 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
304 return; /* no handler, ignore it */
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();
311 TRACE( "%s for hwnd/window %p/%lx\n",
312 dbgstr_event( event->type ), hwnd, event->xany.window );
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;
323 /***********************************************************************
326 static int process_events( Display *display, Bool (*filter)(), ULONG_PTR arg )
328 XEvent event, prev_event;
330 enum event_merge_action action = MERGE_DISCARD;
334 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
337 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
338 if (prev_event.type) action = merge_events( &prev_event, &event );
341 case MERGE_DISCARD: /* discard prev, keep new */
344 case MERGE_HANDLE: /* handle prev, keep new */
345 call_event_handler( display, &prev_event );
348 case MERGE_KEEP: /* handle new, keep prev for future merging */
349 call_event_handler( display, &event );
353 XFlush( gdi_display );
354 if (prev_event.type) call_event_handler( display, &prev_event );
356 if (count) TRACE( "processed %d events\n", count );
361 /***********************************************************************
362 * MsgWaitForMultipleObjectsEx (X11DRV.@)
364 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
365 DWORD timeout, DWORD mask, DWORD flags )
368 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
372 if (!count && !timeout) return WAIT_TIMEOUT;
373 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
374 timeout, flags & MWMO_ALERTABLE );
377 if (data->current_event) mask = 0; /* don't process nested events */
379 if (process_events( data->display, filter_event, mask )) ret = count - 1;
380 else if (count || timeout)
382 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
383 timeout, flags & MWMO_ALERTABLE );
384 if (ret == count - 1) process_events( data->display, filter_event, mask );
386 else ret = WAIT_TIMEOUT;
391 /***********************************************************************
392 * EVENT_x11_time_to_win32_time
394 * Make our timer and the X timer line up as best we can
395 * Pass 0 to retrieve the current adjustment value (times -1)
397 DWORD EVENT_x11_time_to_win32_time(Time time)
399 static DWORD adjust = 0;
400 DWORD now = GetTickCount();
403 if (! adjust && time != 0)
410 /* If we got an event in the 'future', then our clock is clearly wrong.
411 If we got it more than 10000 ms in the future, then it's most likely
412 that the clock has wrapped. */
415 if (ret > now && ((ret - now) < 10000) && time != 0)
426 /*******************************************************************
427 * can_activate_window
429 * Check if we can activate the specified window.
431 static inline BOOL can_activate_window( HWND hwnd )
433 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
434 if (!(style & WS_VISIBLE)) return FALSE;
435 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
436 if (hwnd == GetDesktopWindow()) return FALSE;
437 return !(style & WS_DISABLED);
441 /**********************************************************************
444 static void set_focus( HWND hwnd, Time time )
449 TRACE( "setting foreground window to %p\n", hwnd );
450 SetForegroundWindow( hwnd );
453 if (focus) focus = GetAncestor( focus, GA_ROOT );
454 win = X11DRV_get_whole_window(focus);
458 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
460 XSetInputFocus( thread_display(), win, RevertToParent, time );
466 /**********************************************************************
467 * handle_wm_protocols
469 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
471 Atom protocol = (Atom)event->data.l[0];
473 if (!protocol) return;
475 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
477 /* Ignore the delete window request if the window has been disabled
478 * and we are in managed mode. This is to disallow applications from
479 * being closed by the window manager while in a modal state.
481 if (IsWindowEnabled(hwnd))
485 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
486 hSysMenu = GetSystemMenu(hwnd, FALSE);
489 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
490 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
493 if (GetActiveWindow() != hwnd)
495 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
496 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
497 MAKELONG(HTCLOSE,WM_LBUTTONDOWN) );
500 case MA_NOACTIVATEANDEAT:
501 case MA_ACTIVATEANDEAT:
507 SetActiveWindow(hwnd);
510 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
514 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
517 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
519 Time event_time = (Time)event->data.l[1];
520 HWND last_focus = x11drv_thread_data()->last_focus;
522 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
523 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
524 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
526 if (can_activate_window(hwnd))
528 /* simulate a mouse click on the caption to find out
529 * whether the window wants to be activated */
530 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
531 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
532 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
533 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
535 set_focus( hwnd, event_time );
539 /* try to find some other window to give the focus to */
541 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
542 if (!hwnd) hwnd = GetActiveWindow();
543 if (!hwnd) hwnd = last_focus;
544 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
546 else if (protocol == x11drv_atom(_NET_WM_PING))
548 XClientMessageEvent xev;
551 TRACE("NET_WM Ping\n");
553 xev.window = DefaultRootWindow(xev.display);
554 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
556 /* this line is semi-stolen from gtk2 */
557 TRACE("NET_WM Pong\n");
562 static const char * const focus_details[] =
568 "NotifyNonlinearVirtual",
574 /**********************************************************************
577 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
579 XFocusChangeEvent *event = &xev->xfocus;
584 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
586 if (event->detail == NotifyPointer) return;
588 if ((xic = X11DRV_get_ic( hwnd )))
594 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
596 if (!can_activate_window(hwnd))
598 HWND hwnd = GetFocus();
599 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
600 if (!hwnd) hwnd = GetActiveWindow();
601 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
602 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
604 else SetForegroundWindow( hwnd );
608 /**********************************************************************
611 * Note: only top-level windows get FocusOut events.
613 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
615 XFocusChangeEvent *event = &xev->xfocus;
623 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
625 if (event->detail == NotifyPointer) return;
626 if (ximInComposeMode) return;
628 x11drv_thread_data()->last_focus = hwnd;
629 if ((xic = X11DRV_get_ic( hwnd )))
632 XUnsetICFocus( xic );
635 if (hwnd != GetForegroundWindow()) return;
636 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
638 /* don't reset the foreground window, if the window which is
639 getting the focus is a Wine window */
642 XGetInputFocus( thread_display(), &focus_win, &revert );
645 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
652 /* Abey : 6-Oct-99. Check again if the focus out window is the
653 Foreground window, because in most cases the messages sent
654 above must have already changed the foreground window, in which
655 case we don't have to change the foreground window to 0 */
656 if (hwnd == GetForegroundWindow())
658 TRACE( "lost focus, setting fg to desktop\n" );
659 SetForegroundWindow( GetDesktopWindow() );
665 /***********************************************************************
668 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
670 XExposeEvent *event = &xev->xexpose;
672 struct x11drv_win_data *data;
673 int flags = RDW_INVALIDATE | RDW_ERASE;
675 TRACE( "win %p (%lx) %d,%d %dx%d\n",
676 hwnd, event->window, event->x, event->y, event->width, event->height );
678 if (!(data = X11DRV_get_win_data( hwnd ))) return;
680 if (event->window == data->whole_window)
682 rect.left = data->whole_rect.left + event->x;
683 rect.top = data->whole_rect.top + event->y;
688 rect.left = data->client_rect.left + event->x;
689 rect.top = data->client_rect.top + event->y;
691 rect.right = rect.left + event->width;
692 rect.bottom = rect.top + event->height;
694 if (event->window != root_window)
696 SERVER_START_REQ( update_window_zorder )
699 req->rect.left = rect.left;
700 req->rect.top = rect.top;
701 req->rect.right = rect.right;
702 req->rect.bottom = rect.bottom;
703 wine_server_call( req );
707 /* make position relative to client area instead of parent */
708 OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top );
709 flags |= RDW_ALLCHILDREN;
712 RedrawWindow( hwnd, &rect, 0, flags );
716 /**********************************************************************
719 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
721 struct x11drv_win_data *data;
723 if (!(data = X11DRV_get_win_data( hwnd ))) return;
724 if (!data->mapped) return;
728 HWND hwndFocus = GetFocus();
729 if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus); /* FIXME */
734 /***********************************************************************
735 * X11DRV_ConfigureNotify
737 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
739 XConfigureEvent *event = &xev->xconfigure;
740 struct x11drv_win_data *data;
743 int cx, cy, x = event->x, y = event->y;
746 if (!(data = X11DRV_get_win_data( hwnd ))) return;
747 if (!data->mapped || data->iconic) return;
751 if (!event->send_event) /* normal event, need to map coordinates to the root */
755 XTranslateCoordinates( event->display, data->whole_window, root_window,
756 0, 0, &x, &y, &child );
761 rect.right = x + event->width;
762 rect.bottom = y + event->height;
763 OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
764 TRACE( "win %p new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
765 hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
766 event->x, event->y, event->width, event->height );
767 X11DRV_X_to_window_rect( data, &rect );
771 cx = rect.right - rect.left;
772 cy = rect.bottom - rect.top;
773 flags = SWP_NOACTIVATE | SWP_NOZORDER;
775 /* Compare what has changed */
777 GetWindowRect( hwnd, &rect );
778 if (rect.left == x && rect.top == y) flags |= SWP_NOMOVE;
780 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
781 hwnd, rect.left, rect.top, x, y );
783 if ((rect.right - rect.left == cx && rect.bottom - rect.top == cy) ||
784 (IsRectEmpty( &rect ) && event->width == 1 && event->height == 1))
786 if (flags & SWP_NOMOVE) return; /* if nothing changed, don't do anything */
790 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
791 hwnd, rect.right - rect.left, rect.bottom - rect.top, cx, cy );
793 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
797 /***********************************************************************
798 * get_window_wm_state
800 static int get_window_wm_state( Display *display, struct x11drv_win_data *data )
808 int format, ret = -1;
809 unsigned long count, remaining;
812 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
813 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
814 &type, &format, &count, &remaining, (unsigned char **)&state ))
816 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
825 /***********************************************************************
826 * handle_wm_state_notify
828 * Handle a PropertyNotify for WM_STATE.
830 static void handle_wm_state_notify( struct x11drv_win_data *data, XPropertyEvent *event,
836 data->wm_state = WithdrawnState;
837 TRACE( "%p/%lx: WM_STATE deleted\n", data->hwnd, data->whole_window );
839 case PropertyNewValue:
841 int new_state = get_window_wm_state( event->display, data );
842 if (new_state != -1 && new_state != data->wm_state)
844 TRACE( "%p/%lx: new WM_STATE %d\n", data->hwnd, data->whole_window, new_state );
845 data->wm_state = new_state;
851 if (!update_window || !data->managed || !data->mapped) return;
853 if (data->iconic && data->wm_state == NormalState) /* restore window */
856 unsigned int width, height, border, depth;
863 XGetGeometry( event->display, data->whole_window, &root, &x, &y, &width, &height,
865 XTranslateCoordinates( event->display, data->whole_window, root, 0, 0, &x, &y, &top );
869 rect.right = x + width;
870 rect.bottom = y + height;
871 OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
872 X11DRV_X_to_window_rect( data, &rect );
874 wp.length = sizeof(wp);
875 GetWindowPlacement( data->hwnd, &wp );
877 wp.showCmd = SW_RESTORE;
878 wp.rcNormalPosition = rect;
880 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
881 data->iconic = FALSE;
882 SetWindowPlacement( data->hwnd, &wp );
884 else if (!data->iconic && data->wm_state == IconicState)
886 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
888 ShowWindow( data->hwnd, SW_MINIMIZE );
893 /***********************************************************************
894 * X11DRV_PropertyNotify
896 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
898 XPropertyEvent *event = &xev->xproperty;
899 struct x11drv_win_data *data;
902 if (!(data = X11DRV_get_win_data( hwnd ))) return;
904 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( data, event, TRUE );
908 /* event filter to wait for a WM_STATE change notification on a window */
909 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
911 if (event->xany.window != (Window)arg) return 0;
912 return (event->type == DestroyNotify ||
913 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
916 /***********************************************************************
917 * wait_for_withdrawn_state
919 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data, BOOL set )
921 DWORD end = GetTickCount() + 2000;
923 if (!data->managed) return;
925 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
926 data->hwnd, data->whole_window, set ? "" : "not " );
928 while (data->whole_window && ((data->wm_state == WithdrawnState) == !set))
934 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)data->whole_window ))
937 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
938 if (event.type == DestroyNotify) call_event_handler( display, &event );
942 handle_wm_state_notify( data, &event.xproperty, FALSE );
951 int timeout = end - GetTickCount();
953 pfd.fd = ConnectionNumber(display);
955 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
957 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
962 TRACE( "window %p/%lx state now %d\n", data->hwnd, data->whole_window, data->wm_state );
966 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
970 if (!IsWindowEnabled(hQueryWnd)) return 0;
972 GetWindowRect(hQueryWnd, &tempRect);
974 if(!PtInRect(&tempRect, *lpPt)) return 0;
976 if (!IsIconic( hQueryWnd ))
979 ScreenToClient( hQueryWnd, &pt );
980 GetClientRect( hQueryWnd, &tempRect );
982 if (PtInRect( &tempRect, pt))
984 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
985 if (ret && ret != hQueryWnd)
987 ret = find_drop_window( ret, lpPt );
993 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
995 ScreenToClient(hQueryWnd, lpPt);
1000 /**********************************************************************
1001 * EVENT_DropFromOffix
1003 * don't know if it still works (last Changelog is from 96/11/04)
1005 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1007 struct x11drv_win_data *data;
1008 unsigned long data_length;
1009 unsigned long aux_long;
1010 unsigned char* p_data = NULL;
1014 Window win, w_aux_root, w_aux_child;
1017 win = X11DRV_get_whole_window(hWnd);
1019 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1020 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1021 x += virtual_screen_rect.left;
1022 y += virtual_screen_rect.top;
1023 wine_tsx11_unlock();
1025 if (!(data = X11DRV_get_win_data( hWnd ))) return;
1027 /* find out drop point and drop window */
1028 if( x < 0 || y < 0 ||
1029 x > (data->whole_rect.right - data->whole_rect.left) ||
1030 y > (data->whole_rect.bottom - data->whole_rect.top) )
1032 bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1038 POINT pt = { x, y };
1039 HWND hwndDrop = find_drop_window( hWnd, &pt );
1053 if (!bAccept) return;
1056 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1057 x11drv_atom(DndSelection), 0, 65535, FALSE,
1058 AnyPropertyType, &atom_aux, &dummy,
1059 &data_length, &aux_long, &p_data);
1060 wine_tsx11_unlock();
1062 if( !aux_long && p_data) /* don't bother if > 64K */
1064 char *p = (char *)p_data;
1068 while( *p ) /* calculate buffer size */
1070 INT len = GetShortPathNameA( p, NULL, 0 );
1071 if (len) aux_long += len + 1;
1074 if( aux_long && aux_long < 65535 )
1079 aux_long += sizeof(DROPFILES) + 1;
1080 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1081 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1085 lpDrop->pFiles = sizeof(DROPFILES);
1088 lpDrop->fNC = FALSE;
1089 lpDrop->fWide = FALSE;
1090 p_drop = (char *)(lpDrop + 1);
1094 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1095 p_drop += strlen( p_drop ) + 1;
1099 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1104 if( p_data ) XFree(p_data);
1105 wine_tsx11_unlock();
1108 /**********************************************************************
1111 * drop items are separated by \n
1112 * each item is prefixed by its mime type
1114 * event->data.l[3], event->data.l[4] contains drop x,y position
1116 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1118 struct x11drv_win_data *win_data;
1119 unsigned long data_length;
1120 unsigned long aux_long, drop_len = 0;
1121 unsigned char *p_data = NULL; /* property data */
1122 char *p_drop = NULL;
1134 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1137 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1138 x11drv_atom(DndSelection), 0, 65535, FALSE,
1139 AnyPropertyType, &u.atom_aux, &u.i,
1140 &data_length, &aux_long, &p_data);
1141 wine_tsx11_unlock();
1143 WARN("property too large, truncated!\n");
1144 TRACE("urls=%s\n", p_data);
1146 if( !aux_long && p_data) { /* don't bother if > 64K */
1147 /* calculate length */
1149 next = strchr(p, '\n');
1152 if (strncmp(p,"file:",5) == 0 ) {
1153 INT len = GetShortPathNameA( p+5, NULL, 0 );
1154 if (len) drop_len += len + 1;
1159 next = strchr(p, '\n');
1165 if( drop_len && drop_len < 65535 ) {
1167 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1168 &x, &y, &u.i, &u.i, &u.u);
1169 x += virtual_screen_rect.left;
1170 y += virtual_screen_rect.top;
1171 wine_tsx11_unlock();
1173 drop_len += sizeof(DROPFILES) + 1;
1174 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1175 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1177 if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
1179 lpDrop->pFiles = sizeof(DROPFILES);
1183 ( x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1184 y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1185 x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1186 y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1187 lpDrop->fWide = FALSE;
1188 p_drop = (char*)(lpDrop + 1);
1191 /* create message content */
1194 next = strchr(p, '\n');
1197 if (strncmp(p,"file:",5) == 0 ) {
1198 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1200 TRACE("drop file %s as %s\n", p+5, p_drop);
1203 WARN("can't convert file %s to dos name\n", p+5);
1206 WARN("unknown mime type %s\n", p);
1211 next = strchr(p, '\n');
1218 GlobalUnlock(hDrop);
1219 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1223 if( p_data ) XFree(p_data);
1224 wine_tsx11_unlock();
1228 /**********************************************************************
1229 * handle_dnd_protocol
1231 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1234 int root_x, root_y, child_x, child_y;
1237 /* query window (drag&drop event contains only drag window) */
1239 XQueryPointer( event->display, root_window, &root, &child,
1240 &root_x, &root_y, &child_x, &child_y, &u);
1241 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1242 wine_tsx11_unlock();
1244 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1245 EVENT_DropFromOffiX(hwnd, event);
1246 else if (event->data.l[0] == DndURL)
1247 EVENT_DropURLs(hwnd, event);
1251 struct client_message_handler
1253 int atom; /* protocol atom */
1254 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1257 static const struct client_message_handler client_messages[] =
1259 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1260 { XATOM_DndProtocol, handle_dnd_protocol },
1261 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1262 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1263 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1264 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1268 /**********************************************************************
1269 * X11DRV_ClientMessage
1271 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1273 XClientMessageEvent *event = &xev->xclient;
1278 if (event->format != 32)
1280 WARN( "Don't know how to handle format %d\n", event->format );
1284 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1286 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1288 client_messages[i].handler( hwnd, event );
1292 TRACE( "no handler found for %ld\n", event->message_type );
1296 /**********************************************************************
1297 * X11DRV_WindowMessage (X11DRV.@)
1299 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1303 case WM_X11DRV_ACQUIRE_SELECTION:
1304 return X11DRV_AcquireClipboard( hwnd );
1305 case WM_X11DRV_DELETE_WINDOW:
1306 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1307 case WM_X11DRV_SET_WIN_FORMAT:
1308 return X11DRV_set_win_format( hwnd, (XID)wp );
1309 case WM_X11DRV_RESIZE_DESKTOP:
1310 X11DRV_resize_desktop( LOWORD(lp), HIWORD(lp) );
1313 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
1319 /***********************************************************************
1320 * X11DRV_SendInput (X11DRV.@)
1322 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
1326 for (i = 0; i < count; i++, inputs++)
1328 switch(inputs->type)
1331 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
1332 inputs->u.mi.mouseData, inputs->u.mi.time,
1333 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
1335 case INPUT_KEYBOARD:
1336 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
1337 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
1339 case INPUT_HARDWARE:
1340 FIXME( "INPUT_HARDWARE not supported\n" );