gdiplus/tests: Add tests for GdipMeasureString with StringFormatFlagsNoWrap.
[wine.git] / dlls / winex11.drv / event.c
blob07f7a1ad502b01da69adf79b2dfa4879f05f547f
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>
35 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
36 #include <X11/extensions/XInput2.h>
37 #endif
39 #include <assert.h>
40 #include <stdarg.h>
41 #include <string.h>
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winuser.h"
46 #include "wingdi.h"
48 #include "x11drv.h"
50 /* avoid conflict with field names in included win32 headers */
51 #undef Status
52 #include "shlobj.h" /* DROPFILES */
53 #include "shellapi.h"
55 #include "wine/server.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(event);
60 extern BOOL ximInComposeMode;
62 #define DndNotDnd -1 /* OffiX drag&drop */
63 #define DndUnknown 0
64 #define DndRawData 1
65 #define DndFile 2
66 #define DndFiles 3
67 #define DndText 4
68 #define DndDir 5
69 #define DndLink 6
70 #define DndExe 7
72 #define DndEND 8
74 #define DndURL 128 /* KDE drag&drop */
76 #define XEMBED_EMBEDDED_NOTIFY 0
77 #define XEMBED_WINDOW_ACTIVATE 1
78 #define XEMBED_WINDOW_DEACTIVATE 2
79 #define XEMBED_REQUEST_FOCUS 3
80 #define XEMBED_FOCUS_IN 4
81 #define XEMBED_FOCUS_OUT 5
82 #define XEMBED_FOCUS_NEXT 6
83 #define XEMBED_FOCUS_PREV 7
84 #define XEMBED_MODALITY_ON 10
85 #define XEMBED_MODALITY_OFF 11
86 #define XEMBED_REGISTER_ACCELERATOR 12
87 #define XEMBED_UNREGISTER_ACCELERATOR 13
88 #define XEMBED_ACTIVATE_ACCELERATOR 14
90 Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
91 void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
93 /* Event handlers */
94 static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *event );
95 static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *event );
96 static BOOL X11DRV_Expose( HWND hwnd, XEvent *event );
97 static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event );
98 static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
99 static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
100 static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
101 static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
102 static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *event );
103 static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *event );
105 #define MAX_EVENT_HANDLERS 128
107 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
109 NULL, /* 0 reserved */
110 NULL, /* 1 reserved */
111 X11DRV_KeyEvent, /* 2 KeyPress */
112 X11DRV_KeyEvent, /* 3 KeyRelease */
113 X11DRV_ButtonPress, /* 4 ButtonPress */
114 X11DRV_ButtonRelease, /* 5 ButtonRelease */
115 X11DRV_MotionNotify, /* 6 MotionNotify */
116 X11DRV_EnterNotify, /* 7 EnterNotify */
117 NULL, /* 8 LeaveNotify */
118 X11DRV_FocusIn, /* 9 FocusIn */
119 X11DRV_FocusOut, /* 10 FocusOut */
120 X11DRV_KeymapNotify, /* 11 KeymapNotify */
121 X11DRV_Expose, /* 12 Expose */
122 NULL, /* 13 GraphicsExpose */
123 NULL, /* 14 NoExpose */
124 NULL, /* 15 VisibilityNotify */
125 NULL, /* 16 CreateNotify */
126 X11DRV_DestroyNotify, /* 17 DestroyNotify */
127 X11DRV_UnmapNotify, /* 18 UnmapNotify */
128 X11DRV_MapNotify, /* 19 MapNotify */
129 NULL, /* 20 MapRequest */
130 X11DRV_ReparentNotify, /* 21 ReparentNotify */
131 X11DRV_ConfigureNotify, /* 22 ConfigureNotify */
132 NULL, /* 23 ConfigureRequest */
133 X11DRV_GravityNotify, /* 24 GravityNotify */
134 NULL, /* 25 ResizeRequest */
135 NULL, /* 26 CirculateNotify */
136 NULL, /* 27 CirculateRequest */
137 X11DRV_PropertyNotify, /* 28 PropertyNotify */
138 X11DRV_SelectionClear, /* 29 SelectionClear */
139 X11DRV_SelectionRequest, /* 30 SelectionRequest */
140 NULL, /* 31 SelectionNotify */
141 NULL, /* 32 ColormapNotify */
142 X11DRV_ClientMessage, /* 33 ClientMessage */
143 X11DRV_MappingNotify, /* 34 MappingNotify */
144 X11DRV_GenericEvent /* 35 GenericEvent */
147 static const char * event_names[MAX_EVENT_HANDLERS] =
149 NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
150 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
151 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
152 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
153 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
154 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
155 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
158 /* is someone else grabbing the keyboard, for example the WM, when manipulating the window */
159 BOOL keyboard_grabbed = FALSE;
161 int xinput2_opcode = 0;
163 /* return the name of an X event */
164 static const char *dbgstr_event( int type )
166 if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
167 return wine_dbg_sprintf( "Unknown event %d", type );
170 static inline void get_event_data( XEvent *event )
172 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
173 if (event->xany.type != GenericEvent) return;
174 if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
175 #endif
178 static inline void free_event_data( XEvent *event )
180 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
181 if (event->xany.type != GenericEvent) return;
182 if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
183 #endif
186 /***********************************************************************
187 * xembed_request_focus
189 static void xembed_request_focus( Display *display, Window window, DWORD timestamp )
191 XEvent xev;
193 xev.xclient.type = ClientMessage;
194 xev.xclient.window = window;
195 xev.xclient.message_type = x11drv_atom(_XEMBED);
196 xev.xclient.serial = 0;
197 xev.xclient.display = display;
198 xev.xclient.send_event = True;
199 xev.xclient.format = 32;
201 xev.xclient.data.l[0] = timestamp;
202 xev.xclient.data.l[1] = XEMBED_REQUEST_FOCUS;
203 xev.xclient.data.l[2] = 0;
204 xev.xclient.data.l[3] = 0;
205 xev.xclient.data.l[4] = 0;
207 XSendEvent(display, window, False, NoEventMask, &xev);
208 XFlush( display );
211 /***********************************************************************
212 * X11DRV_register_event_handler
214 * Register a handler for a given event type.
215 * If already registered, overwrite the previous handler.
217 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
219 assert( type < MAX_EVENT_HANDLERS );
220 assert( !handlers[type] || handlers[type] == handler );
221 handlers[type] = handler;
222 event_names[type] = name;
223 TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
227 /***********************************************************************
228 * filter_event
230 static Bool filter_event( Display *display, XEvent *event, char *arg )
232 ULONG_PTR mask = (ULONG_PTR)arg;
234 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
236 switch(event->type)
238 case KeyPress:
239 case KeyRelease:
240 case KeymapNotify:
241 case MappingNotify:
242 return (mask & (QS_KEY|QS_HOTKEY)) != 0;
243 case ButtonPress:
244 case ButtonRelease:
245 return (mask & QS_MOUSEBUTTON) != 0;
246 #ifdef GenericEvent
247 case GenericEvent:
248 #endif
249 case MotionNotify:
250 case EnterNotify:
251 case LeaveNotify:
252 return (mask & QS_MOUSEMOVE) != 0;
253 case Expose:
254 return (mask & QS_PAINT) != 0;
255 case FocusIn:
256 case FocusOut:
257 case MapNotify:
258 case UnmapNotify:
259 case ConfigureNotify:
260 case PropertyNotify:
261 case ClientMessage:
262 return (mask & QS_POSTMESSAGE) != 0;
263 default:
264 return (mask & QS_SENDMESSAGE) != 0;
269 enum event_merge_action
271 MERGE_DISCARD, /* discard the old event */
272 MERGE_HANDLE, /* handle the old event */
273 MERGE_KEEP, /* keep the old event for future merging */
274 MERGE_IGNORE /* ignore the new event, keep the old one */
277 /***********************************************************************
278 * merge_raw_motion_events
280 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
281 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
283 int i, j, k;
284 unsigned char mask;
286 if (!prev->valuators.mask_len) return MERGE_HANDLE;
287 if (!next->valuators.mask_len) return MERGE_HANDLE;
289 mask = prev->valuators.mask[0] | next->valuators.mask[0];
290 if (mask == next->valuators.mask[0]) /* keep next */
292 for (i = j = k = 0; i < 8; i++)
294 if (XIMaskIsSet( prev->valuators.mask, i ))
295 next->valuators.values[j] += prev->valuators.values[k++];
296 if (XIMaskIsSet( next->valuators.mask, i )) j++;
298 TRACE( "merging duplicate GenericEvent\n" );
299 return MERGE_DISCARD;
301 if (mask == prev->valuators.mask[0]) /* keep prev */
303 for (i = j = k = 0; i < 8; i++)
305 if (XIMaskIsSet( next->valuators.mask, i ))
306 prev->valuators.values[j] += next->valuators.values[k++];
307 if (XIMaskIsSet( prev->valuators.mask, i )) j++;
309 TRACE( "merging duplicate GenericEvent\n" );
310 return MERGE_IGNORE;
312 /* can't merge events with disjoint masks */
313 return MERGE_HANDLE;
315 #endif
317 /***********************************************************************
318 * merge_events
320 * Try to merge 2 consecutive events.
322 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
324 switch (prev->type)
326 case ConfigureNotify:
327 switch (next->type)
329 case ConfigureNotify:
330 if (prev->xany.window == next->xany.window)
332 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
333 return MERGE_DISCARD;
335 break;
336 case Expose:
337 case PropertyNotify:
338 return MERGE_KEEP;
340 break;
341 case MotionNotify:
342 switch (next->type)
344 case MotionNotify:
345 if (prev->xany.window == next->xany.window)
347 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
348 return MERGE_DISCARD;
350 break;
351 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
352 case GenericEvent:
353 if (next->xcookie.extension != xinput2_opcode) break;
354 if (next->xcookie.evtype != XI_RawMotion) break;
355 if (x11drv_thread_data()->warp_serial) break;
356 return MERGE_KEEP;
358 break;
359 case GenericEvent:
360 if (prev->xcookie.extension != xinput2_opcode) break;
361 if (prev->xcookie.evtype != XI_RawMotion) break;
362 switch (next->type)
364 case GenericEvent:
365 if (next->xcookie.extension != xinput2_opcode) break;
366 if (next->xcookie.evtype != XI_RawMotion) break;
367 if (x11drv_thread_data()->warp_serial) break;
368 return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
369 #endif
371 break;
373 return MERGE_HANDLE;
377 /***********************************************************************
378 * call_event_handler
380 static inline BOOL call_event_handler( Display *display, XEvent *event )
382 HWND hwnd;
383 XEvent *prev;
384 struct x11drv_thread_data *thread_data;
385 BOOL ret;
387 if (!handlers[event->type])
389 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
390 return FALSE; /* no handler, ignore it */
393 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
394 hwnd = 0; /* not for a registered window */
395 if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
397 TRACE( "%lu %s for hwnd/window %p/%lx\n",
398 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
399 thread_data = x11drv_thread_data();
400 prev = thread_data->current_event;
401 thread_data->current_event = event;
402 ret = handlers[event->type]( hwnd, event );
403 thread_data->current_event = prev;
404 return ret;
408 /***********************************************************************
409 * process_events
411 static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
413 XEvent event, prev_event;
414 int count = 0;
415 BOOL queued = FALSE;
416 enum event_merge_action action = MERGE_DISCARD;
418 prev_event.type = 0;
419 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
421 count++;
422 if (XFilterEvent( &event, None ))
425 * SCIM on linux filters key events strangely. It does not filter the
426 * KeyPress events for these keys however it does filter the
427 * KeyRelease events. This causes wine to become very confused as
428 * to the keyboard state.
430 * We need to let those KeyRelease events be processed so that the
431 * keyboard state is correct.
433 if (event.type == KeyRelease)
435 KeySym keysym = 0;
436 XKeyEvent *keyevent = &event.xkey;
438 XLookupString(keyevent, NULL, 0, &keysym, NULL);
439 if (!(keysym == XK_Shift_L ||
440 keysym == XK_Shift_R ||
441 keysym == XK_Control_L ||
442 keysym == XK_Control_R ||
443 keysym == XK_Alt_R ||
444 keysym == XK_Alt_L ||
445 keysym == XK_Meta_R ||
446 keysym == XK_Meta_L))
447 continue; /* not a key we care about, ignore it */
449 else
450 continue; /* filtered, ignore it */
452 get_event_data( &event );
453 if (prev_event.type) action = merge_events( &prev_event, &event );
454 switch( action )
456 case MERGE_HANDLE: /* handle prev, keep new */
457 queued |= call_event_handler( display, &prev_event );
458 /* fall through */
459 case MERGE_DISCARD: /* discard prev, keep new */
460 free_event_data( &prev_event );
461 prev_event = event;
462 break;
463 case MERGE_KEEP: /* handle new, keep prev for future merging */
464 queued |= call_event_handler( display, &event );
465 /* fall through */
466 case MERGE_IGNORE: /* ignore new, keep prev for future merging */
467 free_event_data( &event );
468 break;
471 if (prev_event.type) queued |= call_event_handler( display, &prev_event );
472 free_event_data( &prev_event );
473 XFlush( gdi_display );
474 if (count) TRACE( "processed %d events, returning %d\n", count, queued );
475 return queued;
479 /***********************************************************************
480 * MsgWaitForMultipleObjectsEx (X11DRV.@)
482 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
483 DWORD timeout, DWORD mask, DWORD flags )
485 DWORD ret;
486 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
488 if (!data)
490 if (!count && !timeout) return WAIT_TIMEOUT;
491 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
492 timeout, flags & MWMO_ALERTABLE );
495 if (data->current_event) mask = 0; /* don't process nested events */
497 if (process_events( data->display, filter_event, mask )) ret = count - 1;
498 else if (count || timeout)
500 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
501 timeout, flags & MWMO_ALERTABLE );
502 if (ret == count - 1) process_events( data->display, filter_event, mask );
504 else ret = WAIT_TIMEOUT;
506 return ret;
509 /***********************************************************************
510 * EVENT_x11_time_to_win32_time
512 * Make our timer and the X timer line up as best we can
513 * Pass 0 to retrieve the current adjustment value (times -1)
515 DWORD EVENT_x11_time_to_win32_time(Time time)
517 static DWORD adjust = 0;
518 DWORD now = GetTickCount();
519 DWORD ret;
521 if (! adjust && time != 0)
523 ret = now;
524 adjust = time - now;
526 else
528 /* If we got an event in the 'future', then our clock is clearly wrong.
529 If we got it more than 10000 ms in the future, then it's most likely
530 that the clock has wrapped. */
532 ret = time - adjust;
533 if (ret > now && ((ret - now) < 10000) && time != 0)
535 adjust += ret - now;
536 ret -= ret - now;
540 return ret;
544 /*******************************************************************
545 * can_activate_window
547 * Check if we can activate the specified window.
549 static inline BOOL can_activate_window( HWND hwnd )
551 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
552 RECT rect;
554 if (!(style & WS_VISIBLE)) return FALSE;
555 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
556 if (style & WS_MINIMIZE) return FALSE;
557 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
558 if (hwnd == GetDesktopWindow()) return FALSE;
559 if (GetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE;
560 return !(style & WS_DISABLED);
564 /**********************************************************************
565 * set_input_focus
567 * Try to force focus for embedded or non-managed windows.
569 static void set_input_focus( struct x11drv_win_data *data )
571 XWindowChanges changes;
572 DWORD timestamp;
574 if (!data->whole_window) return;
576 if (EVENT_x11_time_to_win32_time(0))
577 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
578 /* FIXME: this is not entirely correct */
579 timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
580 else
581 timestamp = CurrentTime;
583 /* Set X focus and install colormap */
584 changes.stack_mode = Above;
585 XConfigureWindow( data->display, data->whole_window, CWStackMode, &changes );
587 if (data->embedder)
588 xembed_request_focus( data->display, data->embedder, timestamp );
589 else
590 XSetInputFocus( data->display, data->whole_window, RevertToParent, timestamp );
594 /**********************************************************************
595 * set_focus
597 static void set_focus( Display *display, HWND hwnd, Time time )
599 HWND focus;
600 Window win;
601 GUITHREADINFO threadinfo;
603 TRACE( "setting foreground window to %p\n", hwnd );
604 SetForegroundWindow( hwnd );
606 threadinfo.cbSize = sizeof(threadinfo);
607 GetGUIThreadInfo(0, &threadinfo);
608 focus = threadinfo.hwndFocus;
609 if (!focus) focus = threadinfo.hwndActive;
610 if (focus) focus = GetAncestor( focus, GA_ROOT );
611 win = X11DRV_get_whole_window(focus);
613 if (win)
615 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
616 XSetInputFocus( display, win, RevertToParent, time );
621 /**********************************************************************
622 * handle_manager_message
624 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
626 if (hwnd != GetDesktopWindow()) return;
627 if (systray_atom && event->data.l[1] == systray_atom)
628 change_systray_owner( event->display, event->data.l[2] );
632 /**********************************************************************
633 * handle_wm_protocols
635 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
637 Atom protocol = (Atom)event->data.l[0];
638 Time event_time = (Time)event->data.l[1];
640 if (!protocol) return;
642 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
644 update_user_time( event_time );
646 if (hwnd == GetDesktopWindow())
648 /* The desktop window does not have a close button that we can
649 * pretend to click. Therefore, we simply send it a close command. */
650 SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
651 return;
654 /* Ignore the delete window request if the window has been disabled
655 * and we are in managed mode. This is to disallow applications from
656 * being closed by the window manager while in a modal state.
658 if (IsWindowEnabled(hwnd))
660 HMENU hSysMenu;
662 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
663 hSysMenu = GetSystemMenu(hwnd, FALSE);
664 if (hSysMenu)
666 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
667 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
668 return;
670 if (GetActiveWindow() != hwnd)
672 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
673 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
674 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
675 switch(ma)
677 case MA_NOACTIVATEANDEAT:
678 case MA_ACTIVATEANDEAT:
679 return;
680 case MA_NOACTIVATE:
681 break;
682 case MA_ACTIVATE:
683 case 0:
684 SetActiveWindow(hwnd);
685 break;
686 default:
687 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
688 break;
692 PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
695 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
697 HWND last_focus = x11drv_thread_data()->last_focus;
699 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
700 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
701 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
703 if (can_activate_window(hwnd))
705 /* simulate a mouse click on the caption to find out
706 * whether the window wants to be activated */
707 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
708 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
709 MAKELONG( HTMENU, WM_LBUTTONDOWN ) );
710 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
712 set_focus( event->display, hwnd, event_time );
713 return;
716 else if (hwnd == GetDesktopWindow())
718 hwnd = GetForegroundWindow();
719 if (!hwnd) hwnd = last_focus;
720 if (!hwnd) hwnd = GetDesktopWindow();
721 set_focus( event->display, hwnd, event_time );
722 return;
724 /* try to find some other window to give the focus to */
725 hwnd = GetFocus();
726 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
727 if (!hwnd) hwnd = GetActiveWindow();
728 if (!hwnd) hwnd = last_focus;
729 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
731 else if (protocol == x11drv_atom(_NET_WM_PING))
733 XClientMessageEvent xev;
734 xev = *event;
736 TRACE("NET_WM Ping\n");
737 xev.window = DefaultRootWindow(xev.display);
738 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
743 static const char * const focus_details[] =
745 "NotifyAncestor",
746 "NotifyVirtual",
747 "NotifyInferior",
748 "NotifyNonlinear",
749 "NotifyNonlinearVirtual",
750 "NotifyPointer",
751 "NotifyPointerRoot",
752 "NotifyDetailNone"
755 static const char * const focus_modes[] =
757 "NotifyNormal",
758 "NotifyGrab",
759 "NotifyUngrab",
760 "NotifyWhileGrabbed"
763 /**********************************************************************
764 * X11DRV_FocusIn
766 static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
768 XFocusChangeEvent *event = &xev->xfocus;
769 XIC xic;
771 if (!hwnd) return FALSE;
773 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] );
775 if (event->detail == NotifyPointer) return FALSE;
776 if (hwnd == GetDesktopWindow()) return FALSE;
778 switch (event->mode)
780 case NotifyGrab:
781 /* these are received when moving undecorated managed windows on mutter */
782 keyboard_grabbed = TRUE;
783 return FALSE;
784 case NotifyWhileGrabbed:
785 keyboard_grabbed = TRUE;
786 break;
787 case NotifyNormal:
788 keyboard_grabbed = FALSE;
789 break;
790 case NotifyUngrab:
791 keyboard_grabbed = FALSE;
792 retry_grab_clipping_window();
793 return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
796 if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic );
797 if (use_take_focus)
799 if (hwnd == GetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE );
800 return TRUE;
803 if (!can_activate_window(hwnd))
805 HWND hwnd = GetFocus();
806 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
807 if (!hwnd) hwnd = GetActiveWindow();
808 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
809 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
811 else SetForegroundWindow( hwnd );
812 return TRUE;
815 /**********************************************************************
816 * focus_out
818 static void focus_out( Display *display , HWND hwnd )
820 HWND hwnd_tmp;
821 Window focus_win;
822 int revert;
823 XIC xic;
825 if (ximInComposeMode) return;
827 x11drv_thread_data()->last_focus = hwnd;
828 if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
830 if (is_virtual_desktop())
832 if (hwnd == GetDesktopWindow()) reset_clipping_window();
833 return;
835 if (hwnd != GetForegroundWindow()) return;
836 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
838 /* don't reset the foreground window, if the window which is
839 getting the focus is a Wine window */
841 XGetInputFocus( display, &focus_win, &revert );
842 if (focus_win)
844 if (XFindContext( display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
845 focus_win = 0;
848 if (!focus_win)
850 /* Abey : 6-Oct-99. Check again if the focus out window is the
851 Foreground window, because in most cases the messages sent
852 above must have already changed the foreground window, in which
853 case we don't have to change the foreground window to 0 */
854 if (hwnd == GetForegroundWindow())
856 TRACE( "lost focus, setting fg to desktop\n" );
857 SetForegroundWindow( GetDesktopWindow() );
862 /**********************************************************************
863 * X11DRV_FocusOut
865 * Note: only top-level windows get FocusOut events.
867 static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev )
869 XFocusChangeEvent *event = &xev->xfocus;
871 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] );
873 if (event->detail == NotifyPointer)
875 if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
876 return TRUE;
878 if (!hwnd) return FALSE;
880 switch (event->mode)
882 case NotifyUngrab:
883 /* these are received when moving undecorated managed windows on mutter */
884 keyboard_grabbed = FALSE;
885 return FALSE;
886 case NotifyNormal:
887 keyboard_grabbed = FALSE;
888 break;
889 case NotifyWhileGrabbed:
890 keyboard_grabbed = TRUE;
891 break;
892 case NotifyGrab:
893 keyboard_grabbed = TRUE;
895 /* This will do nothing due to keyboard_grabbed == TRUE, but it
896 * will save the current clipping rect so we can restore it on
897 * FocusIn with NotifyUngrab mode.
899 retry_grab_clipping_window();
901 return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
904 focus_out( event->display, hwnd );
905 return TRUE;
909 /***********************************************************************
910 * X11DRV_Expose
912 static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev )
914 XExposeEvent *event = &xev->xexpose;
915 RECT rect, abs_rect;
916 POINT pos;
917 struct x11drv_win_data *data;
918 HRGN surface_region = 0;
919 UINT flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN;
921 TRACE( "win %p (%lx) %d,%d %dx%d\n",
922 hwnd, event->window, event->x, event->y, event->width, event->height );
924 if (event->window != root_window)
926 pos.x = event->x;
927 pos.y = event->y;
929 else pos = root_to_virtual_screen( event->x, event->y );
931 if (!(data = get_win_data( hwnd ))) return FALSE;
933 rect.left = pos.x;
934 rect.top = pos.y;
935 rect.right = pos.x + event->width;
936 rect.bottom = pos.y + event->height;
938 if (event->window != data->client_window)
940 if (data->surface)
942 surface_region = expose_surface( data->surface, &rect );
943 if (!surface_region) flags = 0;
944 else OffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
945 data->whole_rect.top - data->client_rect.top );
947 if (data->vis.visualid != default_visual.visualid)
948 data->surface->funcs->flush( data->surface );
950 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
951 data->whole_rect.top - data->client_rect.top );
954 if (event->window != root_window)
956 if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
957 mirror_rect( &data->client_rect, &rect );
958 abs_rect = rect;
959 MapWindowPoints( hwnd, 0, (POINT *)&abs_rect, 2 );
961 SERVER_START_REQ( update_window_zorder )
963 req->window = wine_server_user_handle( hwnd );
964 req->rect.left = abs_rect.left;
965 req->rect.top = abs_rect.top;
966 req->rect.right = abs_rect.right;
967 req->rect.bottom = abs_rect.bottom;
968 wine_server_call( req );
970 SERVER_END_REQ;
972 else flags &= ~RDW_ALLCHILDREN;
974 release_win_data( data );
976 if (flags) RedrawWindow( hwnd, &rect, surface_region, flags );
977 if (surface_region) DeleteObject( surface_region );
978 return TRUE;
982 /**********************************************************************
983 * X11DRV_MapNotify
985 static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event )
987 struct x11drv_win_data *data;
989 if (event->xany.window == x11drv_thread_data()->clip_window) return TRUE;
991 if (!(data = get_win_data( hwnd ))) return FALSE;
993 if (!data->managed && !data->embedded && data->mapped)
995 HWND hwndFocus = GetFocus();
996 if (hwndFocus && IsChild( hwnd, hwndFocus ))
997 set_input_focus( data );
999 release_win_data( data );
1000 return TRUE;
1004 /**********************************************************************
1005 * X11DRV_UnmapNotify
1007 static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
1009 return TRUE;
1013 /***********************************************************************
1014 * reparent_notify
1016 static void reparent_notify( Display *display, HWND hwnd, Window xparent, int x, int y )
1018 HWND parent, old_parent;
1019 DWORD style;
1021 style = GetWindowLongW( hwnd, GWL_STYLE );
1022 if (xparent == root_window)
1024 parent = GetDesktopWindow();
1025 style = (style & ~WS_CHILD) | WS_POPUP;
1027 else
1029 if (!(parent = create_foreign_window( display, xparent ))) return;
1030 style = (style & ~WS_POPUP) | WS_CHILD;
1033 ShowWindow( hwnd, SW_HIDE );
1034 old_parent = SetParent( hwnd, parent );
1035 SetWindowLongW( hwnd, GWL_STYLE, style );
1036 SetWindowPos( hwnd, HWND_TOP, x, y, 0, 0,
1037 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
1038 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
1040 /* make old parent destroy itself if it no longer has children */
1041 if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
1045 /***********************************************************************
1046 * X11DRV_ReparentNotify
1048 static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
1050 XReparentEvent *event = &xev->xreparent;
1051 struct x11drv_win_data *data;
1053 if (!(data = get_win_data( hwnd ))) return FALSE;
1055 if (!data->embedded)
1057 release_win_data( data );
1058 return FALSE;
1061 if (data->whole_window)
1063 if (event->parent == root_window)
1065 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
1066 data->embedder = 0;
1067 release_win_data( data );
1068 SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1069 return TRUE;
1071 data->embedder = event->parent;
1074 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
1075 release_win_data( data );
1077 reparent_notify( event->display, hwnd, event->parent, event->x, event->y );
1078 return TRUE;
1082 /***********************************************************************
1083 * X11DRV_ConfigureNotify
1085 static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
1087 XConfigureEvent *event = &xev->xconfigure;
1088 struct x11drv_win_data *data;
1089 RECT rect;
1090 POINT pos;
1091 UINT flags;
1092 HWND parent;
1093 BOOL root_coords;
1094 int cx, cy, x = event->x, y = event->y;
1095 DWORD style;
1097 if (!hwnd) return FALSE;
1098 if (!(data = get_win_data( hwnd ))) return FALSE;
1099 if (!data->mapped || data->iconic) goto done;
1100 if (data->whole_window && !data->managed) goto done;
1101 /* ignore synthetic events on foreign windows */
1102 if (event->send_event && !data->whole_window) goto done;
1103 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
1105 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1106 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
1107 event->serial, data->configure_serial );
1108 goto done;
1111 /* Get geometry */
1113 parent = GetAncestor( hwnd, GA_PARENT );
1114 root_coords = event->send_event; /* synthetic events are always in root coords */
1116 if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
1118 Window child;
1119 XTranslateCoordinates( event->display, event->window, root_window,
1120 0, 0, &x, &y, &child );
1121 root_coords = TRUE;
1124 if (!root_coords)
1126 pos.x = x;
1127 pos.y = y;
1129 else pos = root_to_virtual_screen( x, y );
1131 X11DRV_X_to_window_rect( data, &rect, pos.x, pos.y, event->width, event->height );
1132 if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1134 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1135 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1136 event->x, event->y, event->width, event->height );
1138 /* Compare what has changed */
1140 x = rect.left;
1141 y = rect.top;
1142 cx = rect.right - rect.left;
1143 cy = rect.bottom - rect.top;
1144 flags = SWP_NOACTIVATE | SWP_NOZORDER;
1146 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
1148 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1149 else
1150 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1151 hwnd, data->window_rect.left, data->window_rect.top, x, y );
1153 if ((data->window_rect.right - data->window_rect.left == cx &&
1154 data->window_rect.bottom - data->window_rect.top == cy) ||
1155 IsRectEmpty( &data->window_rect ))
1156 flags |= SWP_NOSIZE;
1157 else
1158 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1159 hwnd, data->window_rect.right - data->window_rect.left,
1160 data->window_rect.bottom - data->window_rect.top, cx, cy );
1162 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1163 if ((style & WS_CAPTION) == WS_CAPTION)
1165 read_net_wm_states( event->display, data );
1166 if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1168 if (!(style & WS_MAXIMIZE))
1170 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1171 release_win_data( data );
1172 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1173 return TRUE;
1176 else if (style & WS_MAXIMIZE)
1178 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1179 release_win_data( data );
1180 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1181 return TRUE;
1185 if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
1187 release_win_data( data );
1188 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1189 return TRUE;
1192 done:
1193 release_win_data( data );
1194 return FALSE;
1198 /**********************************************************************
1199 * X11DRV_GravityNotify
1201 static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1203 XGravityEvent *event = &xev->xgravity;
1204 struct x11drv_win_data *data = get_win_data( hwnd );
1205 RECT window_rect;
1206 int x, y;
1208 if (!data) return FALSE;
1210 if (data->whole_window) /* only handle this for foreign windows */
1212 release_win_data( data );
1213 return FALSE;
1216 x = event->x + data->window_rect.left - data->whole_rect.left;
1217 y = event->y + data->window_rect.top - data->whole_rect.top;
1219 TRACE( "win %p/%lx new X pos %d,%d (event %d,%d)\n",
1220 hwnd, data->whole_window, x, y, event->x, event->y );
1222 window_rect = data->window_rect;
1223 release_win_data( data );
1225 if (window_rect.left != x || window_rect.top != y)
1226 SetWindowPos( hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1228 return TRUE;
1232 /***********************************************************************
1233 * get_window_wm_state
1235 static int get_window_wm_state( Display *display, Window window )
1237 struct
1239 CARD32 state;
1240 XID icon;
1241 } *state;
1242 Atom type;
1243 int format, ret = -1;
1244 unsigned long count, remaining;
1246 if (!XGetWindowProperty( display, window, x11drv_atom(WM_STATE), 0,
1247 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1248 &type, &format, &count, &remaining, (unsigned char **)&state ))
1250 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1251 ret = state->state;
1252 XFree( state );
1254 return ret;
1258 /***********************************************************************
1259 * handle_wm_state_notify
1261 * Handle a PropertyNotify for WM_STATE.
1263 static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
1265 struct x11drv_win_data *data = get_win_data( hwnd );
1266 DWORD style;
1268 if (!data) return;
1270 switch(event->state)
1272 case PropertyDelete:
1273 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1274 data->wm_state = WithdrawnState;
1275 break;
1276 case PropertyNewValue:
1278 int old_state = data->wm_state;
1279 int new_state = get_window_wm_state( event->display, data->whole_window );
1280 if (new_state != -1 && new_state != data->wm_state)
1282 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1283 data->hwnd, data->whole_window, new_state, old_state );
1284 data->wm_state = new_state;
1285 /* ignore the initial state transition out of withdrawn state */
1286 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1287 if (!old_state) goto done;
1290 break;
1293 if (!update_window || !data->managed || !data->mapped) goto done;
1295 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1297 if (data->iconic && data->wm_state == NormalState) /* restore window */
1299 data->iconic = FALSE;
1300 read_net_wm_states( event->display, data );
1301 if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1303 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1305 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1306 release_win_data( data );
1307 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1308 return;
1310 TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1312 else
1314 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1316 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1317 release_win_data( data );
1318 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
1319 SetActiveWindow( hwnd );
1320 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1321 return;
1323 TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1326 else if (!data->iconic && data->wm_state == IconicState)
1328 data->iconic = TRUE;
1329 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1331 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1332 release_win_data( data );
1333 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1334 return;
1336 TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1338 done:
1339 release_win_data( data );
1343 /***********************************************************************
1344 * X11DRV_PropertyNotify
1346 static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1348 XPropertyEvent *event = &xev->xproperty;
1350 if (!hwnd) return FALSE;
1351 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
1352 return TRUE;
1356 /* event filter to wait for a WM_STATE change notification on a window */
1357 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1359 if (event->xany.window != (Window)arg) return 0;
1360 return (event->type == DestroyNotify ||
1361 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1364 /***********************************************************************
1365 * wait_for_withdrawn_state
1367 void wait_for_withdrawn_state( HWND hwnd, BOOL set )
1369 Display *display = thread_display();
1370 struct x11drv_win_data *data;
1371 DWORD end = GetTickCount() + 2000;
1373 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
1375 for (;;)
1377 XEvent event;
1378 Window window;
1379 int count = 0;
1381 if (!(data = get_win_data( hwnd ))) break;
1382 if (!data->managed || data->embedded || data->display != display) break;
1383 if (!(window = data->whole_window)) break;
1384 if (!data->mapped == !set)
1386 TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
1387 break;
1389 if ((data->wm_state == WithdrawnState) != !set)
1391 TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
1392 break;
1394 release_win_data( data );
1396 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
1398 count++;
1399 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1400 if (event.type == DestroyNotify) call_event_handler( display, &event );
1401 else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
1404 if (!count)
1406 struct pollfd pfd;
1407 int timeout = end - GetTickCount();
1409 pfd.fd = ConnectionNumber(display);
1410 pfd.events = POLLIN;
1411 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1413 FIXME( "window %p/%lx wait timed out\n", hwnd, window );
1414 return;
1418 release_win_data( data );
1422 /*****************************************************************
1423 * SetFocus (X11DRV.@)
1425 * Set the X focus.
1427 void CDECL X11DRV_SetFocus( HWND hwnd )
1429 struct x11drv_win_data *data;
1431 HWND parent;
1433 for (;;)
1435 if (!(data = get_win_data( hwnd ))) return;
1436 if (data->embedded) break;
1437 parent = GetAncestor( hwnd, GA_PARENT );
1438 if (!parent || parent == GetDesktopWindow()) break;
1439 release_win_data( data );
1440 hwnd = parent;
1442 if (!data->managed || data->embedder) set_input_focus( data );
1443 release_win_data( data );
1447 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1449 RECT tempRect;
1451 if (!IsWindowEnabled(hQueryWnd)) return 0;
1453 GetWindowRect(hQueryWnd, &tempRect);
1455 if(!PtInRect(&tempRect, *lpPt)) return 0;
1457 if (!IsIconic( hQueryWnd ))
1459 POINT pt = *lpPt;
1460 ScreenToClient( hQueryWnd, &pt );
1461 GetClientRect( hQueryWnd, &tempRect );
1463 if (PtInRect( &tempRect, pt))
1465 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1466 if (ret && ret != hQueryWnd)
1468 ret = find_drop_window( ret, lpPt );
1469 if (ret) return ret;
1474 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1476 ScreenToClient(hQueryWnd, lpPt);
1478 return hQueryWnd;
1481 /**********************************************************************
1482 * EVENT_DropFromOffix
1484 * don't know if it still works (last Changelog is from 96/11/04)
1486 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1488 struct x11drv_win_data *data;
1489 POINT pt;
1490 unsigned long data_length;
1491 unsigned long aux_long;
1492 unsigned char* p_data = NULL;
1493 Atom atom_aux;
1494 int x, y, cx, cy, dummy;
1495 Window win, w_aux_root, w_aux_child;
1497 if (!(data = get_win_data( hWnd ))) return;
1498 cx = data->whole_rect.right - data->whole_rect.left;
1499 cy = data->whole_rect.bottom - data->whole_rect.top;
1500 win = data->whole_window;
1501 release_win_data( data );
1503 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1504 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1505 pt = root_to_virtual_screen( x, y );
1507 /* find out drop point and drop window */
1508 if (pt.x < 0 || pt.y < 0 || pt.x > cx || pt.y > cy)
1510 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1511 pt.x = pt.y = 0;
1513 else
1515 if (!find_drop_window( hWnd, &pt )) return;
1518 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1519 x11drv_atom(DndSelection), 0, 65535, FALSE,
1520 AnyPropertyType, &atom_aux, &dummy,
1521 &data_length, &aux_long, &p_data);
1523 if( !aux_long && p_data) /* don't bother if > 64K */
1525 char *p = (char *)p_data;
1526 char *p_drop;
1528 aux_long = 0;
1529 while( *p ) /* calculate buffer size */
1531 INT len = GetShortPathNameA( p, NULL, 0 );
1532 if (len) aux_long += len + 1;
1533 p += strlen(p) + 1;
1535 if( aux_long && aux_long < 65535 )
1537 HDROP hDrop;
1538 DROPFILES *lpDrop;
1540 aux_long += sizeof(DROPFILES) + 1;
1541 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1542 lpDrop = GlobalLock( hDrop );
1544 if( lpDrop )
1546 lpDrop->pFiles = sizeof(DROPFILES);
1547 lpDrop->pt = pt;
1548 lpDrop->fNC = FALSE;
1549 lpDrop->fWide = FALSE;
1550 p_drop = (char *)(lpDrop + 1);
1551 p = (char *)p_data;
1552 while(*p)
1554 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1555 p_drop += strlen( p_drop ) + 1;
1556 p += strlen(p) + 1;
1558 *p_drop = '\0';
1559 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1563 if( p_data ) XFree(p_data);
1566 /**********************************************************************
1567 * EVENT_DropURLs
1569 * drop items are separated by \n
1570 * each item is prefixed by its mime type
1572 * event->data.l[3], event->data.l[4] contains drop x,y position
1574 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1576 struct x11drv_win_data *win_data;
1577 unsigned long data_length;
1578 unsigned long aux_long, drop_len = 0;
1579 unsigned char *p_data = NULL; /* property data */
1580 char *p_drop = NULL;
1581 char *p, *next;
1582 int x, y;
1583 POINT pos;
1584 DROPFILES *lpDrop;
1585 HDROP hDrop;
1586 union {
1587 Atom atom_aux;
1588 int i;
1589 Window w_aux;
1590 unsigned int u;
1591 } u; /* unused */
1593 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1595 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1596 x11drv_atom(DndSelection), 0, 65535, FALSE,
1597 AnyPropertyType, &u.atom_aux, &u.i,
1598 &data_length, &aux_long, &p_data);
1599 if (aux_long)
1600 WARN("property too large, truncated!\n");
1601 TRACE("urls=%s\n", p_data);
1603 if( !aux_long && p_data) { /* don't bother if > 64K */
1604 /* calculate length */
1605 p = (char*) p_data;
1606 next = strchr(p, '\n');
1607 while (p) {
1608 if (next) *next=0;
1609 if (strncmp(p,"file:",5) == 0 ) {
1610 INT len = GetShortPathNameA( p+5, NULL, 0 );
1611 if (len) drop_len += len + 1;
1613 if (next) {
1614 *next = '\n';
1615 p = next + 1;
1616 next = strchr(p, '\n');
1617 } else {
1618 p = NULL;
1622 if( drop_len && drop_len < 65535 ) {
1623 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1624 &x, &y, &u.i, &u.i, &u.u);
1625 pos = root_to_virtual_screen( x, y );
1627 drop_len += sizeof(DROPFILES) + 1;
1628 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1629 lpDrop = GlobalLock( hDrop );
1631 if( lpDrop && (win_data = get_win_data( hWnd )))
1633 lpDrop->pFiles = sizeof(DROPFILES);
1634 lpDrop->pt = pos;
1635 lpDrop->fNC =
1636 (pos.x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1637 pos.y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1638 pos.x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1639 pos.y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1640 lpDrop->fWide = FALSE;
1641 p_drop = (char*)(lpDrop + 1);
1642 release_win_data( win_data );
1645 /* create message content */
1646 if (p_drop) {
1647 p = (char*) p_data;
1648 next = strchr(p, '\n');
1649 while (p) {
1650 if (next) *next=0;
1651 if (strncmp(p,"file:",5) == 0 ) {
1652 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1653 if (len) {
1654 TRACE("drop file %s as %s\n", p+5, p_drop);
1655 p_drop += len+1;
1656 } else {
1657 WARN("can't convert file %s to dos name\n", p+5);
1659 } else {
1660 WARN("unknown mime type %s\n", p);
1662 if (next) {
1663 *next = '\n';
1664 p = next + 1;
1665 next = strchr(p, '\n');
1666 } else {
1667 p = NULL;
1669 *p_drop = '\0';
1672 GlobalUnlock(hDrop);
1673 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1677 if( p_data ) XFree(p_data);
1681 /**********************************************************************
1682 * handle_xembed_protocol
1684 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1686 switch (event->data.l[1])
1688 case XEMBED_EMBEDDED_NOTIFY:
1690 struct x11drv_win_data *data = get_win_data( hwnd );
1691 if (!data) break;
1693 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1694 data->embedder = event->data.l[3];
1696 /* window has been marked as embedded before (e.g. systray) */
1697 if (data->embedded || !data->embedder /* broken QX11EmbedContainer implementation */)
1699 release_win_data( data );
1700 break;
1703 make_window_embedded( data );
1704 release_win_data( data );
1705 reparent_notify( event->display, hwnd, event->data.l[3], 0, 0 );
1707 break;
1709 case XEMBED_WINDOW_DEACTIVATE:
1710 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd, event->window );
1711 focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
1712 break;
1714 case XEMBED_FOCUS_OUT:
1715 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd, event->window );
1716 focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
1717 break;
1719 case XEMBED_MODALITY_ON:
1720 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd, event->window );
1721 EnableWindow( hwnd, FALSE );
1722 break;
1724 case XEMBED_MODALITY_OFF:
1725 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd, event->window );
1726 EnableWindow( hwnd, TRUE );
1727 break;
1729 default:
1730 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1731 hwnd, event->window, event->data.l[1], event->data.l[2] );
1732 break;
1737 /**********************************************************************
1738 * handle_dnd_protocol
1740 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1742 Window root, child;
1743 int root_x, root_y, child_x, child_y;
1744 unsigned int u;
1746 /* query window (drag&drop event contains only drag window) */
1747 XQueryPointer( event->display, root_window, &root, &child,
1748 &root_x, &root_y, &child_x, &child_y, &u);
1749 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1750 if (!hwnd) return;
1751 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1752 EVENT_DropFromOffiX(hwnd, event);
1753 else if (event->data.l[0] == DndURL)
1754 EVENT_DropURLs(hwnd, event);
1758 struct client_message_handler
1760 int atom; /* protocol atom */
1761 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1764 static const struct client_message_handler client_messages[] =
1766 { XATOM_MANAGER, handle_manager_message },
1767 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1768 { XATOM__XEMBED, handle_xembed_protocol },
1769 { XATOM_DndProtocol, handle_dnd_protocol },
1770 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1771 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1772 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1773 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1777 /**********************************************************************
1778 * X11DRV_ClientMessage
1780 static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1782 XClientMessageEvent *event = &xev->xclient;
1783 unsigned int i;
1785 if (!hwnd) return FALSE;
1787 if (event->format != 32)
1789 WARN( "Don't know how to handle format %d\n", event->format );
1790 return FALSE;
1793 for (i = 0; i < ARRAY_SIZE( client_messages ); i++)
1795 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1797 client_messages[i].handler( hwnd, event );
1798 return TRUE;
1801 TRACE( "no handler found for %ld\n", event->message_type );
1802 return FALSE;