winex11: Release the clip cursor grab when the clipping window loses focus.
[wine/multimedia.git] / dlls / winex11.drv / event.c
blob0233a61e210e293cee638993ebeb761b94d555ef
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
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
22 #include "config.h"
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>
36 #include <assert.h>
37 #include <stdarg.h>
38 #include <string.h>
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winuser.h"
45 #include "wingdi.h"
47 #include "x11drv.h"
49 /* avoid conflict with field names in included win32 headers */
50 #undef Status
51 #include "shlobj.h" /* DROPFILES */
52 #include "shellapi.h"
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 */
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
71 #define DndEND 8
73 #define DndURL 128 /* KDE drag&drop */
75 #define XEMBED_EMBEDDED_NOTIFY 0
76 #define XEMBED_WINDOW_ACTIVATE 1
77 #define XEMBED_WINDOW_DEACTIVATE 2
78 #define XEMBED_REQUEST_FOCUS 3
79 #define XEMBED_FOCUS_IN 4
80 #define XEMBED_FOCUS_OUT 5
81 #define XEMBED_FOCUS_NEXT 6
82 #define XEMBED_FOCUS_PREV 7
83 #define XEMBED_MODALITY_ON 10
84 #define XEMBED_MODALITY_OFF 11
85 #define XEMBED_REGISTER_ACCELERATOR 12
86 #define XEMBED_UNREGISTER_ACCELERATOR 13
87 #define XEMBED_ACTIVATE_ACCELERATOR 14
89 Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
90 void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
92 /* Event handlers */
93 static void X11DRV_FocusIn( HWND hwnd, XEvent *event );
94 static void X11DRV_FocusOut( HWND hwnd, XEvent *event );
95 static void X11DRV_Expose( HWND hwnd, XEvent *event );
96 static void X11DRV_MapNotify( HWND hwnd, XEvent *event );
97 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
98 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
99 static void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
100 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
101 static void X11DRV_ClientMessage( HWND hwnd, XEvent *event );
102 static void X11DRV_GravityNotify( HWND hwnd, XEvent *event );
104 #define MAX_EVENT_HANDLERS 128
106 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
108 NULL, /* 0 reserved */
109 NULL, /* 1 reserved */
110 X11DRV_KeyEvent, /* 2 KeyPress */
111 X11DRV_KeyEvent, /* 3 KeyRelease */
112 X11DRV_ButtonPress, /* 4 ButtonPress */
113 X11DRV_ButtonRelease, /* 5 ButtonRelease */
114 X11DRV_MotionNotify, /* 6 MotionNotify */
115 X11DRV_EnterNotify, /* 7 EnterNotify */
116 NULL, /* 8 LeaveNotify */
117 X11DRV_FocusIn, /* 9 FocusIn */
118 X11DRV_FocusOut, /* 10 FocusOut */
119 X11DRV_KeymapNotify, /* 11 KeymapNotify */
120 X11DRV_Expose, /* 12 Expose */
121 NULL, /* 13 GraphicsExpose */
122 NULL, /* 14 NoExpose */
123 NULL, /* 15 VisibilityNotify */
124 NULL, /* 16 CreateNotify */
125 X11DRV_DestroyNotify, /* 17 DestroyNotify */
126 X11DRV_UnmapNotify, /* 18 UnmapNotify */
127 X11DRV_MapNotify, /* 19 MapNotify */
128 NULL, /* 20 MapRequest */
129 X11DRV_ReparentNotify, /* 21 ReparentNotify */
130 X11DRV_ConfigureNotify, /* 22 ConfigureNotify */
131 NULL, /* 23 ConfigureRequest */
132 X11DRV_GravityNotify, /* 24 GravityNotify */
133 NULL, /* 25 ResizeRequest */
134 NULL, /* 26 CirculateNotify */
135 NULL, /* 27 CirculateRequest */
136 X11DRV_PropertyNotify, /* 28 PropertyNotify */
137 X11DRV_SelectionClear, /* 29 SelectionClear */
138 X11DRV_SelectionRequest, /* 30 SelectionRequest */
139 NULL, /* 31 SelectionNotify */
140 NULL, /* 32 ColormapNotify */
141 X11DRV_ClientMessage, /* 33 ClientMessage */
142 X11DRV_MappingNotify, /* 34 MappingNotify */
143 X11DRV_GenericEvent /* 35 GenericEvent */
146 static const char * event_names[MAX_EVENT_HANDLERS] =
148 NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
149 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
150 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
151 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
152 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
153 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
154 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
157 /* return the name of an X event */
158 static const char *dbgstr_event( int type )
160 if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
161 return wine_dbg_sprintf( "Unknown event %d", type );
164 static inline void get_event_data( XEvent *event )
166 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
167 if (event->xany.type != GenericEvent) return;
168 if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
169 #endif
172 static inline void free_event_data( XEvent *event )
174 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
175 if (event->xany.type != GenericEvent) return;
176 if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
177 #endif
180 /***********************************************************************
181 * X11DRV_register_event_handler
183 * Register a handler for a given event type.
184 * If already registered, overwrite the previous handler.
186 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
188 assert( type <= MAX_EVENT_HANDLERS );
189 assert( !handlers[type] || handlers[type] == handler );
190 handlers[type] = handler;
191 event_names[type] = name;
192 TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
196 /***********************************************************************
197 * filter_event
199 static Bool filter_event( Display *display, XEvent *event, char *arg )
201 ULONG_PTR mask = (ULONG_PTR)arg;
203 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
205 switch(event->type)
207 case KeyPress:
208 case KeyRelease:
209 case KeymapNotify:
210 case MappingNotify:
211 return (mask & QS_KEY) != 0;
212 case ButtonPress:
213 case ButtonRelease:
214 return (mask & QS_MOUSEBUTTON) != 0;
215 case MotionNotify:
216 case EnterNotify:
217 case LeaveNotify:
218 return (mask & QS_MOUSEMOVE) != 0;
219 case Expose:
220 return (mask & QS_PAINT) != 0;
221 case FocusIn:
222 case FocusOut:
223 case MapNotify:
224 case UnmapNotify:
225 case ConfigureNotify:
226 case PropertyNotify:
227 case ClientMessage:
228 return (mask & QS_POSTMESSAGE) != 0;
229 default:
230 return (mask & QS_SENDMESSAGE) != 0;
235 enum event_merge_action
237 MERGE_DISCARD, /* discard the old event */
238 MERGE_HANDLE, /* handle the old event */
239 MERGE_KEEP /* keep the old event for future merging */
242 /***********************************************************************
243 * merge_events
245 * Try to merge 2 consecutive events.
247 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
249 switch (prev->type)
251 case ConfigureNotify:
252 switch (next->type)
254 case ConfigureNotify:
255 if (prev->xany.window == next->xany.window)
257 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
258 return MERGE_DISCARD;
260 break;
261 case Expose:
262 case PropertyNotify:
263 return MERGE_KEEP;
265 break;
266 case MotionNotify:
267 if (prev->xany.window == next->xany.window && next->type == MotionNotify)
269 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
270 return MERGE_DISCARD;
272 break;
274 return MERGE_HANDLE;
278 /***********************************************************************
279 * call_event_handler
281 static inline void call_event_handler( Display *display, XEvent *event )
283 HWND hwnd;
284 XEvent *prev;
285 struct x11drv_thread_data *thread_data;
287 if (!handlers[event->type])
289 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
290 return; /* no handler, ignore it */
293 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
294 hwnd = 0; /* not for a registered window */
295 if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
297 TRACE( "%lu %s for hwnd/window %p/%lx\n",
298 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
299 wine_tsx11_unlock();
300 thread_data = x11drv_thread_data();
301 prev = thread_data->current_event;
302 thread_data->current_event = event;
303 handlers[event->type]( hwnd, event );
304 thread_data->current_event = prev;
305 wine_tsx11_lock();
309 /***********************************************************************
310 * process_events
312 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
314 XEvent event, prev_event;
315 int count = 0;
316 enum event_merge_action action = MERGE_DISCARD;
318 prev_event.type = 0;
319 wine_tsx11_lock();
320 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
322 count++;
323 if (XFilterEvent( &event, None ))
326 * SCIM on linux filters key events strangely. It does not filter the
327 * KeyPress events for these keys however it does filter the
328 * KeyRelease events. This causes wine to become very confused as
329 * to the keyboard state.
331 * We need to let those KeyRelease events be processed so that the
332 * keyboard state is correct.
334 if (event.type == KeyRelease)
336 KeySym keysym = 0;
337 XKeyEvent *keyevent = &event.xkey;
339 XLookupString(keyevent, NULL, 0, &keysym, NULL);
340 if (!(keysym == XK_Shift_L ||
341 keysym == XK_Shift_R ||
342 keysym == XK_Control_L ||
343 keysym == XK_Control_R ||
344 keysym == XK_Alt_R ||
345 keysym == XK_Alt_L ||
346 keysym == XK_Meta_R ||
347 keysym == XK_Meta_L))
348 continue; /* not a key we care about, ignore it */
350 else
351 continue; /* filtered, ignore it */
353 get_event_data( &event );
354 if (prev_event.type) action = merge_events( &prev_event, &event );
355 switch( action )
357 case MERGE_HANDLE: /* handle prev, keep new */
358 call_event_handler( display, &prev_event );
359 /* fall through */
360 case MERGE_DISCARD: /* discard prev, keep new */
361 free_event_data( &prev_event );
362 prev_event = event;
363 break;
364 case MERGE_KEEP: /* handle new, keep prev for future merging */
365 call_event_handler( display, &event );
366 free_event_data( &event );
367 break;
370 if (prev_event.type) call_event_handler( display, &prev_event );
371 free_event_data( &prev_event );
372 XFlush( gdi_display );
373 wine_tsx11_unlock();
374 if (count) TRACE( "processed %d events\n", count );
375 return count;
379 /***********************************************************************
380 * MsgWaitForMultipleObjectsEx (X11DRV.@)
382 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
383 DWORD timeout, DWORD mask, DWORD flags )
385 DWORD ret;
386 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
388 if (!data)
390 if (!count && !timeout) return WAIT_TIMEOUT;
391 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
392 timeout, flags & MWMO_ALERTABLE );
395 if (data->current_event) mask = 0; /* don't process nested events */
397 if (process_events( data->display, filter_event, mask )) ret = count - 1;
398 else if (count || timeout)
400 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
401 timeout, flags & MWMO_ALERTABLE );
402 if (ret == count - 1) process_events( data->display, filter_event, mask );
404 else ret = WAIT_TIMEOUT;
406 return ret;
409 /***********************************************************************
410 * EVENT_x11_time_to_win32_time
412 * Make our timer and the X timer line up as best we can
413 * Pass 0 to retrieve the current adjustment value (times -1)
415 DWORD EVENT_x11_time_to_win32_time(Time time)
417 static DWORD adjust = 0;
418 DWORD now = GetTickCount();
419 DWORD ret;
421 if (! adjust && time != 0)
423 ret = now;
424 adjust = time - now;
426 else
428 /* If we got an event in the 'future', then our clock is clearly wrong.
429 If we got it more than 10000 ms in the future, then it's most likely
430 that the clock has wrapped. */
432 ret = time - adjust;
433 if (ret > now && ((ret - now) < 10000) && time != 0)
435 adjust += ret - now;
436 ret -= ret - now;
440 return ret;
444 /*******************************************************************
445 * can_activate_window
447 * Check if we can activate the specified window.
449 static inline BOOL can_activate_window( HWND hwnd )
451 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
452 if (!(style & WS_VISIBLE)) return FALSE;
453 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
454 if (style & WS_MINIMIZE) return FALSE;
455 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
456 if (hwnd == GetDesktopWindow()) return FALSE;
457 return !(style & WS_DISABLED);
461 /**********************************************************************
462 * set_focus
464 static void set_focus( Display *display, HWND hwnd, Time time )
466 HWND focus;
467 Window win;
468 GUITHREADINFO threadinfo;
470 TRACE( "setting foreground window to %p\n", hwnd );
471 SetForegroundWindow( hwnd );
473 threadinfo.cbSize = sizeof(threadinfo);
474 GetGUIThreadInfo(0, &threadinfo);
475 focus = threadinfo.hwndFocus;
476 if (!focus) focus = threadinfo.hwndActive;
477 if (focus) focus = GetAncestor( focus, GA_ROOT );
478 win = X11DRV_get_whole_window(focus);
480 if (win)
482 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
483 wine_tsx11_lock();
484 XSetInputFocus( display, win, RevertToParent, time );
485 wine_tsx11_unlock();
490 /**********************************************************************
491 * handle_manager_message
493 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
495 if (hwnd != GetDesktopWindow()) return;
496 if (systray_atom && event->data.l[1] == systray_atom)
497 change_systray_owner( event->display, event->data.l[2] );
501 /**********************************************************************
502 * handle_wm_protocols
504 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
506 Atom protocol = (Atom)event->data.l[0];
507 Time event_time = (Time)event->data.l[1];
509 if (!protocol) return;
511 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
513 update_user_time( event_time );
515 if (hwnd == GetDesktopWindow())
517 /* The desktop window does not have a close button that we can
518 * pretend to click. Therefore, we simply send it a close command. */
519 SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
520 return;
523 /* Ignore the delete window request if the window has been disabled
524 * and we are in managed mode. This is to disallow applications from
525 * being closed by the window manager while in a modal state.
527 if (IsWindowEnabled(hwnd))
529 HMENU hSysMenu;
531 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
532 hSysMenu = GetSystemMenu(hwnd, FALSE);
533 if (hSysMenu)
535 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
536 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
537 return;
539 if (GetActiveWindow() != hwnd)
541 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
542 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
543 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
544 switch(ma)
546 case MA_NOACTIVATEANDEAT:
547 case MA_ACTIVATEANDEAT:
548 return;
549 case MA_NOACTIVATE:
550 break;
551 case MA_ACTIVATE:
552 case 0:
553 SetActiveWindow(hwnd);
554 break;
555 default:
556 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
557 break;
561 PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
564 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
566 HWND last_focus = x11drv_thread_data()->last_focus;
568 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
569 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
570 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
572 if (can_activate_window(hwnd))
574 /* simulate a mouse click on the caption to find out
575 * whether the window wants to be activated */
576 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
577 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
578 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
579 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
581 set_focus( event->display, hwnd, event_time );
582 return;
585 else if (hwnd == GetDesktopWindow())
587 hwnd = GetForegroundWindow();
588 if (!hwnd) hwnd = last_focus;
589 if (!hwnd) hwnd = GetDesktopWindow();
590 set_focus( event->display, hwnd, event_time );
591 return;
593 /* try to find some other window to give the focus to */
594 hwnd = GetFocus();
595 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
596 if (!hwnd) hwnd = GetActiveWindow();
597 if (!hwnd) hwnd = last_focus;
598 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
600 else if (protocol == x11drv_atom(_NET_WM_PING))
602 XClientMessageEvent xev;
603 xev = *event;
605 TRACE("NET_WM Ping\n");
606 wine_tsx11_lock();
607 xev.window = DefaultRootWindow(xev.display);
608 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
609 wine_tsx11_unlock();
610 /* this line is semi-stolen from gtk2 */
611 TRACE("NET_WM Pong\n");
616 static const char * const focus_details[] =
618 "NotifyAncestor",
619 "NotifyVirtual",
620 "NotifyInferior",
621 "NotifyNonlinear",
622 "NotifyNonlinearVirtual",
623 "NotifyPointer",
624 "NotifyPointerRoot",
625 "NotifyDetailNone"
628 /**********************************************************************
629 * X11DRV_FocusIn
631 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
633 XFocusChangeEvent *event = &xev->xfocus;
634 XIC xic;
636 if (!hwnd) return;
638 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
640 if (event->detail == NotifyPointer) return;
642 if ((xic = X11DRV_get_ic( hwnd )))
644 wine_tsx11_lock();
645 XSetICFocus( xic );
646 wine_tsx11_unlock();
648 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
650 if (!can_activate_window(hwnd))
652 HWND hwnd = GetFocus();
653 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
654 if (!hwnd) hwnd = GetActiveWindow();
655 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
656 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
658 else SetForegroundWindow( hwnd );
662 /**********************************************************************
663 * X11DRV_FocusOut
665 * Note: only top-level windows get FocusOut events.
667 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
669 XFocusChangeEvent *event = &xev->xfocus;
670 HWND hwnd_tmp;
671 Window focus_win;
672 int revert;
673 XIC xic;
675 if (!hwnd)
677 if (event->detail == NotifyPointer && event->window == x11drv_thread_data()->clip_window)
679 TRACE( "clip window lost focus\n" );
680 ungrab_clipping_window();
681 ClipCursor( NULL ); /* make sure the clip rectangle is reset too */
683 return;
686 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
688 if (event->detail == NotifyPointer) return;
689 if (ximInComposeMode) return;
691 x11drv_thread_data()->last_focus = hwnd;
692 if ((xic = X11DRV_get_ic( hwnd )))
694 wine_tsx11_lock();
695 XUnsetICFocus( xic );
696 wine_tsx11_unlock();
698 if (hwnd != GetForegroundWindow()) return;
699 if (root_window != DefaultRootWindow(event->display)) return;
700 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
702 /* don't reset the foreground window, if the window which is
703 getting the focus is a Wine window */
705 wine_tsx11_lock();
706 XGetInputFocus( event->display, &focus_win, &revert );
707 if (focus_win)
709 if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
710 focus_win = 0;
712 wine_tsx11_unlock();
714 if (!focus_win)
716 /* Abey : 6-Oct-99. Check again if the focus out window is the
717 Foreground window, because in most cases the messages sent
718 above must have already changed the foreground window, in which
719 case we don't have to change the foreground window to 0 */
720 if (hwnd == GetForegroundWindow())
722 TRACE( "lost focus, setting fg to desktop\n" );
723 SetForegroundWindow( GetDesktopWindow() );
729 /***********************************************************************
730 * X11DRV_Expose
732 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
734 XExposeEvent *event = &xev->xexpose;
735 RECT rect;
736 struct x11drv_win_data *data;
737 int flags = RDW_INVALIDATE | RDW_ERASE;
739 TRACE( "win %p (%lx) %d,%d %dx%d\n",
740 hwnd, event->window, event->x, event->y, event->width, event->height );
742 if (!(data = X11DRV_get_win_data( hwnd ))) return;
744 rect.left = event->x;
745 rect.top = event->y;
746 rect.right = event->x + event->width;
747 rect.bottom = event->y + event->height;
748 if (event->window == data->whole_window)
750 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
751 data->whole_rect.top - data->client_rect.top );
752 flags |= RDW_FRAME;
755 if (event->window != root_window)
757 if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
758 mirror_rect( &data->client_rect, &rect );
760 SERVER_START_REQ( update_window_zorder )
762 req->window = wine_server_user_handle( hwnd );
763 req->rect.left = rect.left;
764 req->rect.top = rect.top;
765 req->rect.right = rect.right;
766 req->rect.bottom = rect.bottom;
767 wine_server_call( req );
769 SERVER_END_REQ;
771 flags |= RDW_ALLCHILDREN;
773 else OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
775 RedrawWindow( hwnd, &rect, 0, flags );
779 /**********************************************************************
780 * X11DRV_MapNotify
782 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
784 struct x11drv_win_data *data;
786 if (event->xany.window == x11drv_thread_data()->clip_window)
788 clipping_cursor = 1;
789 return;
791 if (!(data = X11DRV_get_win_data( hwnd ))) return;
792 if (!data->mapped || data->embedded) return;
794 if (!data->managed)
796 HWND hwndFocus = GetFocus();
797 if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus); /* FIXME */
802 /**********************************************************************
803 * X11DRV_UnmapNotify
805 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
807 if (event->xany.window == x11drv_thread_data()->clip_window) clipping_cursor = 0;
811 /***********************************************************************
812 * is_net_wm_state_maximized
814 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
816 Atom type, *state;
817 int format, ret = 0;
818 unsigned long i, count, remaining;
820 if (!data->whole_window) return FALSE;
822 wine_tsx11_lock();
823 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
824 65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
825 &remaining, (unsigned char **)&state ))
827 if (type == XA_ATOM && format == 32)
829 for (i = 0; i < count; i++)
831 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
832 state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
833 ret++;
836 XFree( state );
838 wine_tsx11_unlock();
839 return (ret == 2);
843 /***********************************************************************
844 * X11DRV_ReparentNotify
846 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
848 XReparentEvent *event = &xev->xreparent;
849 struct x11drv_win_data *data;
850 HWND parent, old_parent;
851 DWORD style;
853 if (!(data = X11DRV_get_win_data( hwnd ))) return;
854 if (!data->embedded) return;
856 if (data->whole_window)
858 if (event->parent == root_window)
860 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
861 data->embedder = 0;
862 SendMessageW( hwnd, WM_CLOSE, 0, 0 );
863 return;
865 data->embedder = event->parent;
868 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
870 style = GetWindowLongW( hwnd, GWL_STYLE );
871 if (event->parent == root_window)
873 parent = GetDesktopWindow();
874 style = (style & ~WS_CHILD) | WS_POPUP;
876 else
878 if (!(parent = create_foreign_window( event->display, event->parent ))) return;
879 style = (style & ~WS_POPUP) | WS_CHILD;
882 ShowWindow( hwnd, SW_HIDE );
883 old_parent = SetParent( hwnd, parent );
884 SetWindowLongW( hwnd, GWL_STYLE, style );
885 SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
886 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
887 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
889 /* make old parent destroy itself if it no longer has children */
890 if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
894 /***********************************************************************
895 * X11DRV_ConfigureNotify
897 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
899 XConfigureEvent *event = &xev->xconfigure;
900 struct x11drv_win_data *data;
901 RECT rect;
902 UINT flags;
903 HWND parent;
904 BOOL root_coords;
905 int cx, cy, x = event->x, y = event->y;
907 if (!hwnd) return;
908 if (!(data = X11DRV_get_win_data( hwnd ))) return;
909 if (!data->mapped || data->iconic) return;
910 if (data->whole_window && !data->managed) return;
911 /* ignore synthetic events on foreign windows */
912 if (event->send_event && !data->whole_window) return;
913 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
915 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
916 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
917 event->serial, data->configure_serial );
918 return;
921 /* Get geometry */
923 parent = GetAncestor( hwnd, GA_PARENT );
924 root_coords = event->send_event; /* synthetic events are always in root coords */
926 if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
928 Window child;
929 wine_tsx11_lock();
930 XTranslateCoordinates( event->display, event->window, root_window,
931 0, 0, &x, &y, &child );
932 wine_tsx11_unlock();
933 root_coords = TRUE;
935 rect.left = x;
936 rect.top = y;
937 rect.right = x + event->width;
938 rect.bottom = y + event->height;
939 if (root_coords) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
940 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
941 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
942 event->x, event->y, event->width, event->height );
944 X11DRV_X_to_window_rect( data, &rect );
945 if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
947 /* Compare what has changed */
949 x = rect.left;
950 y = rect.top;
951 cx = rect.right - rect.left;
952 cy = rect.bottom - rect.top;
953 flags = SWP_NOACTIVATE | SWP_NOZORDER;
955 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
957 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
958 else
959 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
960 hwnd, data->window_rect.left, data->window_rect.top, x, y );
962 if ((data->window_rect.right - data->window_rect.left == cx &&
963 data->window_rect.bottom - data->window_rect.top == cy) ||
964 (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
966 if (flags & SWP_NOMOVE) /* if nothing changed, don't do anything */
968 TRACE( "Nothing has changed, ignoring event\n" );
969 return;
971 flags |= SWP_NOSIZE;
973 else
974 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
975 hwnd, data->window_rect.right - data->window_rect.left,
976 data->window_rect.bottom - data->window_rect.top, cx, cy );
978 if (is_net_wm_state_maximized( event->display, data ))
980 if (!IsZoomed( data->hwnd ))
982 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
983 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
984 return;
987 else
989 if (IsZoomed( data->hwnd ))
991 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
992 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
993 return;
997 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1001 /**********************************************************************
1002 * X11DRV_GravityNotify
1004 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1006 XGravityEvent *event = &xev->xgravity;
1007 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1008 RECT rect;
1010 if (!data || data->whole_window) return; /* only handle this for foreign windows */
1012 rect.left = event->x;
1013 rect.top = event->y;
1014 rect.right = rect.left + data->whole_rect.right - data->whole_rect.left;
1015 rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1017 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1018 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1019 event->x, event->y );
1021 X11DRV_X_to_window_rect( data, &rect );
1023 if (data->window_rect.left != rect.left || data ->window_rect.top != rect.top)
1024 SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1025 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1029 /***********************************************************************
1030 * get_window_wm_state
1032 static int get_window_wm_state( Display *display, struct x11drv_win_data *data )
1034 struct
1036 CARD32 state;
1037 XID icon;
1038 } *state;
1039 Atom type;
1040 int format, ret = -1;
1041 unsigned long count, remaining;
1043 wine_tsx11_lock();
1044 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
1045 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1046 &type, &format, &count, &remaining, (unsigned char **)&state ))
1048 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1049 ret = state->state;
1050 XFree( state );
1052 wine_tsx11_unlock();
1053 return ret;
1057 /***********************************************************************
1058 * handle_wm_state_notify
1060 * Handle a PropertyNotify for WM_STATE.
1062 static void handle_wm_state_notify( struct x11drv_win_data *data, XPropertyEvent *event,
1063 BOOL update_window )
1065 DWORD style;
1067 switch(event->state)
1069 case PropertyDelete:
1070 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1071 data->wm_state = WithdrawnState;
1072 break;
1073 case PropertyNewValue:
1075 int old_state = data->wm_state;
1076 int new_state = get_window_wm_state( event->display, data );
1077 if (new_state != -1 && new_state != data->wm_state)
1079 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1080 data->hwnd, data->whole_window, new_state, old_state );
1081 data->wm_state = new_state;
1082 /* ignore the initial state transition out of withdrawn state */
1083 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1084 if (!old_state) return;
1087 break;
1090 if (!update_window || !data->managed || !data->mapped) return;
1092 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1094 if (data->iconic && data->wm_state == NormalState) /* restore window */
1096 data->iconic = FALSE;
1097 if (is_net_wm_state_maximized( event->display, data ))
1099 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1101 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1102 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1104 else TRACE( "not restoring to max win %p/%lx style %08x\n",
1105 data->hwnd, data->whole_window, style );
1107 else if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1109 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1110 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1112 else TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1114 else if (!data->iconic && data->wm_state == IconicState)
1116 data->iconic = TRUE;
1117 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1119 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1120 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1122 else TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1127 /***********************************************************************
1128 * X11DRV_PropertyNotify
1130 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1132 XPropertyEvent *event = &xev->xproperty;
1133 struct x11drv_win_data *data;
1135 if (!hwnd) return;
1136 if (!(data = X11DRV_get_win_data( hwnd ))) return;
1138 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( data, event, TRUE );
1142 /* event filter to wait for a WM_STATE change notification on a window */
1143 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1145 if (event->xany.window != (Window)arg) return 0;
1146 return (event->type == DestroyNotify ||
1147 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1150 /***********************************************************************
1151 * wait_for_withdrawn_state
1153 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data, BOOL set )
1155 DWORD end = GetTickCount() + 2000;
1157 if (!data->managed) return;
1159 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
1160 data->hwnd, data->whole_window, set ? "" : "not " );
1162 while (data->whole_window && ((data->wm_state == WithdrawnState) == !set))
1164 XEvent event;
1165 int count = 0;
1167 wine_tsx11_lock();
1168 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)data->whole_window ))
1170 count++;
1171 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1172 if (event.type == DestroyNotify) call_event_handler( display, &event );
1173 else
1175 wine_tsx11_unlock();
1176 handle_wm_state_notify( data, &event.xproperty, FALSE );
1177 wine_tsx11_lock();
1180 wine_tsx11_unlock();
1182 if (!count)
1184 struct pollfd pfd;
1185 int timeout = end - GetTickCount();
1187 pfd.fd = ConnectionNumber(display);
1188 pfd.events = POLLIN;
1189 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1191 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
1192 break;
1196 TRACE( "window %p/%lx state now %d\n", data->hwnd, data->whole_window, data->wm_state );
1200 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1202 RECT tempRect;
1204 if (!IsWindowEnabled(hQueryWnd)) return 0;
1206 GetWindowRect(hQueryWnd, &tempRect);
1208 if(!PtInRect(&tempRect, *lpPt)) return 0;
1210 if (!IsIconic( hQueryWnd ))
1212 POINT pt = *lpPt;
1213 ScreenToClient( hQueryWnd, &pt );
1214 GetClientRect( hQueryWnd, &tempRect );
1216 if (PtInRect( &tempRect, pt))
1218 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1219 if (ret && ret != hQueryWnd)
1221 ret = find_drop_window( ret, lpPt );
1222 if (ret) return ret;
1227 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1229 ScreenToClient(hQueryWnd, lpPt);
1231 return hQueryWnd;
1234 /**********************************************************************
1235 * EVENT_DropFromOffix
1237 * don't know if it still works (last Changelog is from 96/11/04)
1239 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1241 struct x11drv_win_data *data;
1242 unsigned long data_length;
1243 unsigned long aux_long;
1244 unsigned char* p_data = NULL;
1245 Atom atom_aux;
1246 int x, y, dummy;
1247 BOOL bAccept;
1248 Window win, w_aux_root, w_aux_child;
1250 win = X11DRV_get_whole_window(hWnd);
1251 wine_tsx11_lock();
1252 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1253 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1254 x += virtual_screen_rect.left;
1255 y += virtual_screen_rect.top;
1256 wine_tsx11_unlock();
1258 if (!(data = X11DRV_get_win_data( hWnd ))) return;
1260 /* find out drop point and drop window */
1261 if( x < 0 || y < 0 ||
1262 x > (data->whole_rect.right - data->whole_rect.left) ||
1263 y > (data->whole_rect.bottom - data->whole_rect.top) )
1265 bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1266 x = 0;
1267 y = 0;
1269 else
1271 POINT pt = { x, y };
1272 HWND hwndDrop = find_drop_window( hWnd, &pt );
1273 if (hwndDrop)
1275 x = pt.x;
1276 y = pt.y;
1277 bAccept = TRUE;
1279 else
1281 bAccept = FALSE;
1285 if (!bAccept) return;
1287 wine_tsx11_lock();
1288 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1289 x11drv_atom(DndSelection), 0, 65535, FALSE,
1290 AnyPropertyType, &atom_aux, &dummy,
1291 &data_length, &aux_long, &p_data);
1292 wine_tsx11_unlock();
1294 if( !aux_long && p_data) /* don't bother if > 64K */
1296 char *p = (char *)p_data;
1297 char *p_drop;
1299 aux_long = 0;
1300 while( *p ) /* calculate buffer size */
1302 INT len = GetShortPathNameA( p, NULL, 0 );
1303 if (len) aux_long += len + 1;
1304 p += strlen(p) + 1;
1306 if( aux_long && aux_long < 65535 )
1308 HDROP hDrop;
1309 DROPFILES *lpDrop;
1311 aux_long += sizeof(DROPFILES) + 1;
1312 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1313 lpDrop = GlobalLock( hDrop );
1315 if( lpDrop )
1317 lpDrop->pFiles = sizeof(DROPFILES);
1318 lpDrop->pt.x = x;
1319 lpDrop->pt.y = y;
1320 lpDrop->fNC = FALSE;
1321 lpDrop->fWide = FALSE;
1322 p_drop = (char *)(lpDrop + 1);
1323 p = (char *)p_data;
1324 while(*p)
1326 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1327 p_drop += strlen( p_drop ) + 1;
1328 p += strlen(p) + 1;
1330 *p_drop = '\0';
1331 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1335 wine_tsx11_lock();
1336 if( p_data ) XFree(p_data);
1337 wine_tsx11_unlock();
1340 /**********************************************************************
1341 * EVENT_DropURLs
1343 * drop items are separated by \n
1344 * each item is prefixed by its mime type
1346 * event->data.l[3], event->data.l[4] contains drop x,y position
1348 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1350 struct x11drv_win_data *win_data;
1351 unsigned long data_length;
1352 unsigned long aux_long, drop_len = 0;
1353 unsigned char *p_data = NULL; /* property data */
1354 char *p_drop = NULL;
1355 char *p, *next;
1356 int x, y;
1357 DROPFILES *lpDrop;
1358 HDROP hDrop;
1359 union {
1360 Atom atom_aux;
1361 int i;
1362 Window w_aux;
1363 unsigned int u;
1364 } u; /* unused */
1366 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1368 wine_tsx11_lock();
1369 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1370 x11drv_atom(DndSelection), 0, 65535, FALSE,
1371 AnyPropertyType, &u.atom_aux, &u.i,
1372 &data_length, &aux_long, &p_data);
1373 wine_tsx11_unlock();
1374 if (aux_long)
1375 WARN("property too large, truncated!\n");
1376 TRACE("urls=%s\n", p_data);
1378 if( !aux_long && p_data) { /* don't bother if > 64K */
1379 /* calculate length */
1380 p = (char*) p_data;
1381 next = strchr(p, '\n');
1382 while (p) {
1383 if (next) *next=0;
1384 if (strncmp(p,"file:",5) == 0 ) {
1385 INT len = GetShortPathNameA( p+5, NULL, 0 );
1386 if (len) drop_len += len + 1;
1388 if (next) {
1389 *next = '\n';
1390 p = next + 1;
1391 next = strchr(p, '\n');
1392 } else {
1393 p = NULL;
1397 if( drop_len && drop_len < 65535 ) {
1398 wine_tsx11_lock();
1399 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1400 &x, &y, &u.i, &u.i, &u.u);
1401 x += virtual_screen_rect.left;
1402 y += virtual_screen_rect.top;
1403 wine_tsx11_unlock();
1405 drop_len += sizeof(DROPFILES) + 1;
1406 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1407 lpDrop = GlobalLock( hDrop );
1409 if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
1411 lpDrop->pFiles = sizeof(DROPFILES);
1412 lpDrop->pt.x = x;
1413 lpDrop->pt.y = y;
1414 lpDrop->fNC =
1415 ( x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1416 y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1417 x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1418 y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1419 lpDrop->fWide = FALSE;
1420 p_drop = (char*)(lpDrop + 1);
1423 /* create message content */
1424 if (p_drop) {
1425 p = (char*) p_data;
1426 next = strchr(p, '\n');
1427 while (p) {
1428 if (next) *next=0;
1429 if (strncmp(p,"file:",5) == 0 ) {
1430 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1431 if (len) {
1432 TRACE("drop file %s as %s\n", p+5, p_drop);
1433 p_drop += len+1;
1434 } else {
1435 WARN("can't convert file %s to dos name\n", p+5);
1437 } else {
1438 WARN("unknown mime type %s\n", p);
1440 if (next) {
1441 *next = '\n';
1442 p = next + 1;
1443 next = strchr(p, '\n');
1444 } else {
1445 p = NULL;
1447 *p_drop = '\0';
1450 GlobalUnlock(hDrop);
1451 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1454 wine_tsx11_lock();
1455 if( p_data ) XFree(p_data);
1456 wine_tsx11_unlock();
1461 /**********************************************************************
1462 * handle_xembed_protocol
1464 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1466 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1468 if (!data) return;
1470 switch (event->data.l[1])
1472 case XEMBED_EMBEDDED_NOTIFY:
1473 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1474 data->embedder = event->data.l[3];
1475 break;
1476 default:
1477 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1478 hwnd, event->window, event->data.l[1], event->data.l[2] );
1479 break;
1484 /**********************************************************************
1485 * handle_dnd_protocol
1487 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1489 Window root, child;
1490 int root_x, root_y, child_x, child_y;
1491 unsigned int u;
1493 /* query window (drag&drop event contains only drag window) */
1494 wine_tsx11_lock();
1495 XQueryPointer( event->display, root_window, &root, &child,
1496 &root_x, &root_y, &child_x, &child_y, &u);
1497 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1498 wine_tsx11_unlock();
1499 if (!hwnd) return;
1500 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1501 EVENT_DropFromOffiX(hwnd, event);
1502 else if (event->data.l[0] == DndURL)
1503 EVENT_DropURLs(hwnd, event);
1507 struct client_message_handler
1509 int atom; /* protocol atom */
1510 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1513 static const struct client_message_handler client_messages[] =
1515 { XATOM_MANAGER, handle_manager_message },
1516 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1517 { XATOM__XEMBED, handle_xembed_protocol },
1518 { XATOM_DndProtocol, handle_dnd_protocol },
1519 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1520 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1521 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1522 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1526 /**********************************************************************
1527 * X11DRV_ClientMessage
1529 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1531 XClientMessageEvent *event = &xev->xclient;
1532 unsigned int i;
1534 if (!hwnd) return;
1536 if (event->format != 32)
1538 WARN( "Don't know how to handle format %d\n", event->format );
1539 return;
1542 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1544 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1546 client_messages[i].handler( hwnd, event );
1547 return;
1550 TRACE( "no handler found for %ld\n", event->message_type );