sapi: Implement ISpRegDataKey CreateKey.
[wine.git] / dlls / winex11.drv / event.c
blob4a1a8dc04430b98de0f73fa81dd0e085163295fb
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 #if 0
23 #pragma makedep unix
24 #endif
26 #include "config.h"
28 #include <poll.h>
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xresource.h>
33 #include <X11/Xutil.h>
34 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
35 #include <X11/extensions/XInput2.h>
36 #endif
38 #include <assert.h>
39 #include <stdarg.h>
40 #include <string.h>
42 #include "x11drv.h"
43 #include "shlobj.h" /* DROPFILES */
44 #include "shellapi.h"
46 #include "wine/server.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(event);
50 WINE_DECLARE_DEBUG_CHANNEL(xdnd);
52 extern BOOL ximInComposeMode;
54 #define DndNotDnd -1 /* OffiX drag&drop */
55 #define DndUnknown 0
56 #define DndRawData 1
57 #define DndFile 2
58 #define DndFiles 3
59 #define DndText 4
60 #define DndDir 5
61 #define DndLink 6
62 #define DndExe 7
64 #define DndEND 8
66 #define DndURL 128 /* KDE drag&drop */
68 #define XEMBED_EMBEDDED_NOTIFY 0
69 #define XEMBED_WINDOW_ACTIVATE 1
70 #define XEMBED_WINDOW_DEACTIVATE 2
71 #define XEMBED_REQUEST_FOCUS 3
72 #define XEMBED_FOCUS_IN 4
73 #define XEMBED_FOCUS_OUT 5
74 #define XEMBED_FOCUS_NEXT 6
75 #define XEMBED_FOCUS_PREV 7
76 #define XEMBED_MODALITY_ON 10
77 #define XEMBED_MODALITY_OFF 11
78 #define XEMBED_REGISTER_ACCELERATOR 12
79 #define XEMBED_UNREGISTER_ACCELERATOR 13
80 #define XEMBED_ACTIVATE_ACCELERATOR 14
82 Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
83 void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
85 /* Event handlers */
86 static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *event );
87 static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *event );
88 static BOOL X11DRV_Expose( HWND hwnd, XEvent *event );
89 static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event );
90 static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
91 static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
92 static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
93 static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
94 static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *event );
95 static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *event );
97 #define MAX_EVENT_HANDLERS 128
99 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
101 NULL, /* 0 reserved */
102 NULL, /* 1 reserved */
103 X11DRV_KeyEvent, /* 2 KeyPress */
104 X11DRV_KeyEvent, /* 3 KeyRelease */
105 X11DRV_ButtonPress, /* 4 ButtonPress */
106 X11DRV_ButtonRelease, /* 5 ButtonRelease */
107 X11DRV_MotionNotify, /* 6 MotionNotify */
108 X11DRV_EnterNotify, /* 7 EnterNotify */
109 NULL, /* 8 LeaveNotify */
110 X11DRV_FocusIn, /* 9 FocusIn */
111 X11DRV_FocusOut, /* 10 FocusOut */
112 X11DRV_KeymapNotify, /* 11 KeymapNotify */
113 X11DRV_Expose, /* 12 Expose */
114 NULL, /* 13 GraphicsExpose */
115 NULL, /* 14 NoExpose */
116 NULL, /* 15 VisibilityNotify */
117 NULL, /* 16 CreateNotify */
118 X11DRV_DestroyNotify, /* 17 DestroyNotify */
119 X11DRV_UnmapNotify, /* 18 UnmapNotify */
120 X11DRV_MapNotify, /* 19 MapNotify */
121 NULL, /* 20 MapRequest */
122 X11DRV_ReparentNotify, /* 21 ReparentNotify */
123 X11DRV_ConfigureNotify, /* 22 ConfigureNotify */
124 NULL, /* 23 ConfigureRequest */
125 X11DRV_GravityNotify, /* 24 GravityNotify */
126 NULL, /* 25 ResizeRequest */
127 NULL, /* 26 CirculateNotify */
128 NULL, /* 27 CirculateRequest */
129 X11DRV_PropertyNotify, /* 28 PropertyNotify */
130 X11DRV_SelectionClear, /* 29 SelectionClear */
131 X11DRV_SelectionRequest, /* 30 SelectionRequest */
132 NULL, /* 31 SelectionNotify */
133 NULL, /* 32 ColormapNotify */
134 X11DRV_ClientMessage, /* 33 ClientMessage */
135 X11DRV_MappingNotify, /* 34 MappingNotify */
136 X11DRV_GenericEvent /* 35 GenericEvent */
139 static const char * event_names[MAX_EVENT_HANDLERS] =
141 NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
142 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
143 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
144 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
145 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
146 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
147 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
150 /* is someone else grabbing the keyboard, for example the WM, when manipulating the window */
151 BOOL keyboard_grabbed = FALSE;
153 int xinput2_opcode = 0;
155 /* return the name of an X event */
156 static const char *dbgstr_event( int type )
158 if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
159 return wine_dbg_sprintf( "Unknown event %d", type );
162 static inline void get_event_data( XEvent *event )
164 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
165 if (event->xany.type != GenericEvent) return;
166 if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
167 #endif
170 static inline void free_event_data( XEvent *event )
172 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
173 if (event->xany.type != GenericEvent) return;
174 if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
175 #endif
178 /***********************************************************************
179 * xembed_request_focus
181 static void xembed_request_focus( Display *display, Window window, DWORD timestamp )
183 XEvent xev;
185 xev.xclient.type = ClientMessage;
186 xev.xclient.window = window;
187 xev.xclient.message_type = x11drv_atom(_XEMBED);
188 xev.xclient.serial = 0;
189 xev.xclient.display = display;
190 xev.xclient.send_event = True;
191 xev.xclient.format = 32;
193 xev.xclient.data.l[0] = timestamp;
194 xev.xclient.data.l[1] = XEMBED_REQUEST_FOCUS;
195 xev.xclient.data.l[2] = 0;
196 xev.xclient.data.l[3] = 0;
197 xev.xclient.data.l[4] = 0;
199 XSendEvent(display, window, False, NoEventMask, &xev);
200 XFlush( display );
203 /***********************************************************************
204 * X11DRV_register_event_handler
206 * Register a handler for a given event type.
207 * If already registered, overwrite the previous handler.
209 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
211 assert( type < MAX_EVENT_HANDLERS );
212 assert( !handlers[type] || handlers[type] == handler );
213 handlers[type] = handler;
214 event_names[type] = name;
215 TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
219 /***********************************************************************
220 * filter_event
222 static Bool filter_event( Display *display, XEvent *event, char *arg )
224 ULONG_PTR mask = (ULONG_PTR)arg;
226 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
228 switch(event->type)
230 case KeyPress:
231 case KeyRelease:
232 case KeymapNotify:
233 case MappingNotify:
234 return (mask & (QS_KEY|QS_HOTKEY)) != 0;
235 case ButtonPress:
236 case ButtonRelease:
237 return (mask & QS_MOUSEBUTTON) != 0;
238 #ifdef GenericEvent
239 case GenericEvent:
240 #endif
241 case MotionNotify:
242 case EnterNotify:
243 case LeaveNotify:
244 return (mask & QS_MOUSEMOVE) != 0;
245 case Expose:
246 return (mask & QS_PAINT) != 0;
247 case FocusIn:
248 case FocusOut:
249 case MapNotify:
250 case UnmapNotify:
251 case ConfigureNotify:
252 case PropertyNotify:
253 case ClientMessage:
254 return (mask & QS_POSTMESSAGE) != 0;
255 default:
256 return (mask & QS_SENDMESSAGE) != 0;
261 enum event_merge_action
263 MERGE_DISCARD, /* discard the old event */
264 MERGE_HANDLE, /* handle the old event */
265 MERGE_KEEP, /* keep the old event for future merging */
266 MERGE_IGNORE /* ignore the new event, keep the old one */
269 /***********************************************************************
270 * merge_raw_motion_events
272 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
273 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
275 int i, j, k;
276 unsigned char mask;
278 if (!prev->valuators.mask_len) return MERGE_HANDLE;
279 if (!next->valuators.mask_len) return MERGE_HANDLE;
281 mask = prev->valuators.mask[0] | next->valuators.mask[0];
282 if (mask == next->valuators.mask[0]) /* keep next */
284 for (i = j = k = 0; i < 8; i++)
286 if (XIMaskIsSet( prev->valuators.mask, i ))
287 next->valuators.values[j] += prev->valuators.values[k++];
288 if (XIMaskIsSet( next->valuators.mask, i )) j++;
290 TRACE( "merging duplicate GenericEvent\n" );
291 return MERGE_DISCARD;
293 if (mask == prev->valuators.mask[0]) /* keep prev */
295 for (i = j = k = 0; i < 8; i++)
297 if (XIMaskIsSet( next->valuators.mask, i ))
298 prev->valuators.values[j] += next->valuators.values[k++];
299 if (XIMaskIsSet( prev->valuators.mask, i )) j++;
301 TRACE( "merging duplicate GenericEvent\n" );
302 return MERGE_IGNORE;
304 /* can't merge events with disjoint masks */
305 return MERGE_HANDLE;
307 #endif
309 /***********************************************************************
310 * merge_events
312 * Try to merge 2 consecutive events.
314 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
316 switch (prev->type)
318 case ConfigureNotify:
319 switch (next->type)
321 case ConfigureNotify:
322 if (prev->xany.window == next->xany.window)
324 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
325 return MERGE_DISCARD;
327 break;
328 case Expose:
329 case PropertyNotify:
330 return MERGE_KEEP;
332 break;
333 case MotionNotify:
334 switch (next->type)
336 case MotionNotify:
337 if (prev->xany.window == next->xany.window)
339 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
340 return MERGE_DISCARD;
342 break;
343 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
344 case GenericEvent:
345 if (next->xcookie.extension != xinput2_opcode) break;
346 if (next->xcookie.evtype != XI_RawMotion) break;
347 if (x11drv_thread_data()->warp_serial) break;
348 return MERGE_KEEP;
350 break;
351 case GenericEvent:
352 if (prev->xcookie.extension != xinput2_opcode) break;
353 if (prev->xcookie.evtype != XI_RawMotion) break;
354 switch (next->type)
356 case GenericEvent:
357 if (next->xcookie.extension != xinput2_opcode) break;
358 if (next->xcookie.evtype != XI_RawMotion) break;
359 if (x11drv_thread_data()->warp_serial) break;
360 return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
361 #endif
363 break;
365 return MERGE_HANDLE;
369 /***********************************************************************
370 * call_event_handler
372 static inline BOOL call_event_handler( Display *display, XEvent *event )
374 HWND hwnd;
375 XEvent *prev;
376 struct x11drv_thread_data *thread_data;
377 BOOL ret;
379 if (!handlers[event->type])
381 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
382 return FALSE; /* no handler, ignore it */
385 #ifdef GenericEvent
386 if (event->type == GenericEvent) hwnd = 0; else
387 #endif
388 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
389 hwnd = 0; /* not for a registered window */
390 if (!hwnd && event->xany.window == root_window) hwnd = NtUserGetDesktopWindow();
392 TRACE( "%lu %s for hwnd/window %p/%lx\n",
393 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
394 thread_data = x11drv_thread_data();
395 prev = thread_data->current_event;
396 thread_data->current_event = event;
397 ret = handlers[event->type]( hwnd, event );
398 thread_data->current_event = prev;
399 return ret;
403 /***********************************************************************
404 * process_events
406 static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
408 XEvent event, prev_event;
409 int count = 0;
410 BOOL queued = FALSE;
411 enum event_merge_action action = MERGE_DISCARD;
413 prev_event.type = 0;
414 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
416 count++;
417 if (XFilterEvent( &event, None ))
420 * SCIM on linux filters key events strangely. It does not filter the
421 * KeyPress events for these keys however it does filter the
422 * KeyRelease events. This causes wine to become very confused as
423 * to the keyboard state.
425 * We need to let those KeyRelease events be processed so that the
426 * keyboard state is correct.
428 if (event.type == KeyRelease)
430 KeySym keysym = 0;
431 XKeyEvent *keyevent = &event.xkey;
433 XLookupString(keyevent, NULL, 0, &keysym, NULL);
434 if (!(keysym == XK_Shift_L ||
435 keysym == XK_Shift_R ||
436 keysym == XK_Control_L ||
437 keysym == XK_Control_R ||
438 keysym == XK_Alt_R ||
439 keysym == XK_Alt_L ||
440 keysym == XK_Meta_R ||
441 keysym == XK_Meta_L))
442 continue; /* not a key we care about, ignore it */
444 else
445 continue; /* filtered, ignore it */
447 get_event_data( &event );
448 if (prev_event.type) action = merge_events( &prev_event, &event );
449 switch( action )
451 case MERGE_HANDLE: /* handle prev, keep new */
452 queued |= call_event_handler( display, &prev_event );
453 /* fall through */
454 case MERGE_DISCARD: /* discard prev, keep new */
455 free_event_data( &prev_event );
456 prev_event = event;
457 break;
458 case MERGE_KEEP: /* handle new, keep prev for future merging */
459 queued |= call_event_handler( display, &event );
460 /* fall through */
461 case MERGE_IGNORE: /* ignore new, keep prev for future merging */
462 free_event_data( &event );
463 break;
466 if (prev_event.type) queued |= call_event_handler( display, &prev_event );
467 free_event_data( &prev_event );
468 XFlush( gdi_display );
469 if (count) TRACE( "processed %d events, returning %d\n", count, queued );
470 return queued;
474 /***********************************************************************
475 * MsgWaitForMultipleObjectsEx (X11DRV.@)
477 NTSTATUS X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
478 const LARGE_INTEGER *timeout, DWORD mask, DWORD flags )
480 struct x11drv_thread_data *data = x11drv_thread_data();
481 NTSTATUS ret;
483 if (!data)
485 if (!count && timeout && !timeout->QuadPart) return WAIT_TIMEOUT;
486 return NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL),
487 !!(flags & MWMO_ALERTABLE), timeout );
490 if (data->current_event) mask = 0; /* don't process nested events */
492 if (process_events( data->display, filter_event, mask )) ret = count - 1;
493 else if (count || !timeout || timeout->QuadPart)
495 ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL),
496 !!(flags & MWMO_ALERTABLE), timeout );
497 if (ret == count - 1) process_events( data->display, filter_event, mask );
499 else ret = WAIT_TIMEOUT;
501 return ret;
504 /***********************************************************************
505 * EVENT_x11_time_to_win32_time
507 * Make our timer and the X timer line up as best we can
508 * Pass 0 to retrieve the current adjustment value (times -1)
510 DWORD EVENT_x11_time_to_win32_time(Time time)
512 static DWORD adjust = 0;
513 DWORD now = NtGetTickCount();
514 DWORD ret;
516 if (! adjust && time != 0)
518 ret = now;
519 adjust = time - now;
521 else
523 /* If we got an event in the 'future', then our clock is clearly wrong.
524 If we got it more than 10000 ms in the future, then it's most likely
525 that the clock has wrapped. */
527 ret = time - adjust;
528 if (ret > now && ((ret - now) < 10000) && time != 0)
530 adjust += ret - now;
531 ret -= ret - now;
535 return ret;
539 /*******************************************************************
540 * can_activate_window
542 * Check if we can activate the specified window.
544 static inline BOOL can_activate_window( HWND hwnd )
546 LONG style = NtUserGetWindowLongW( hwnd, GWL_STYLE );
547 RECT rect;
549 if (!(style & WS_VISIBLE)) return FALSE;
550 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
551 if (style & WS_MINIMIZE) return FALSE;
552 if (NtUserGetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
553 if (hwnd == NtUserGetDesktopWindow()) return FALSE;
554 if (NtUserGetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE;
555 return !(style & WS_DISABLED);
559 /**********************************************************************
560 * set_input_focus
562 * Try to force focus for embedded or non-managed windows.
564 static void set_input_focus( struct x11drv_win_data *data )
566 XWindowChanges changes;
567 DWORD timestamp;
569 if (!data->whole_window) return;
571 if (EVENT_x11_time_to_win32_time(0))
572 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
573 /* FIXME: this is not entirely correct */
574 timestamp = NtUserGetThreadInfo()->message_time - EVENT_x11_time_to_win32_time(0);
575 else
576 timestamp = CurrentTime;
578 /* Set X focus and install colormap */
579 changes.stack_mode = Above;
580 XConfigureWindow( data->display, data->whole_window, CWStackMode, &changes );
582 if (data->embedder)
583 xembed_request_focus( data->display, data->embedder, timestamp );
584 else
585 XSetInputFocus( data->display, data->whole_window, RevertToParent, timestamp );
589 /**********************************************************************
590 * set_focus
592 static void set_focus( Display *display, HWND hwnd, Time time )
594 HWND focus;
595 Window win;
596 GUITHREADINFO threadinfo;
598 TRACE( "setting foreground window to %p\n", hwnd );
599 NtUserSetForegroundWindow( hwnd );
601 threadinfo.cbSize = sizeof(threadinfo);
602 NtUserGetGUIThreadInfo( 0, &threadinfo );
603 focus = threadinfo.hwndFocus;
604 if (!focus) focus = threadinfo.hwndActive;
605 if (focus) focus = NtUserGetAncestor( focus, GA_ROOT );
606 win = X11DRV_get_whole_window(focus);
608 if (win)
610 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
611 XSetInputFocus( display, win, RevertToParent, time );
616 /**********************************************************************
617 * handle_manager_message
619 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
621 if (hwnd != NtUserGetDesktopWindow()) return;
623 if (systray_atom && event->data.l[1] == systray_atom)
625 struct systray_change_owner_params params;
627 TRACE( "new owner %lx\n", event->data.l[2] );
629 params.event_handle = (UINT_PTR)event;
630 x11drv_client_func( client_func_systray_change_owner, &params, sizeof(params) );
635 /**********************************************************************
636 * handle_wm_protocols
638 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
640 Atom protocol = (Atom)event->data.l[0];
641 Time event_time = (Time)event->data.l[1];
643 if (!protocol) return;
645 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
647 update_user_time( event_time );
649 if (hwnd == NtUserGetDesktopWindow())
651 /* The desktop window does not have a close button that we can
652 * pretend to click. Therefore, we simply send it a close command. */
653 send_message( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
654 return;
657 /* Ignore the delete window request if the window has been disabled
658 * and we are in managed mode. This is to disallow applications from
659 * being closed by the window manager while in a modal state.
661 if (NtUserIsWindowEnabled( hwnd ))
663 HMENU hSysMenu;
665 if (NtUserGetClassLongW( hwnd, GCL_STYLE ) & CS_NOCLOSE) return;
666 hSysMenu = NtUserGetSystemMenu( hwnd, FALSE );
667 if (hSysMenu)
669 UINT state = NtUserThunkedMenuItemInfo( hSysMenu, SC_CLOSE, MF_BYCOMMAND,
670 NtUserGetMenuState, NULL, NULL );
671 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
672 return;
674 if (get_active_window() != hwnd)
676 LRESULT ma = send_message( hwnd, WM_MOUSEACTIVATE,
677 (WPARAM)NtUserGetAncestor( hwnd, GA_ROOT ),
678 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
679 switch(ma)
681 case MA_NOACTIVATEANDEAT:
682 case MA_ACTIVATEANDEAT:
683 return;
684 case MA_NOACTIVATE:
685 break;
686 case MA_ACTIVATE:
687 case 0:
688 NtUserSetActiveWindow( hwnd );
689 break;
690 default:
691 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
692 break;
696 NtUserPostMessage( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
699 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
701 HWND last_focus = x11drv_thread_data()->last_focus;
703 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
704 hwnd, NtUserIsWindowEnabled(hwnd), NtUserIsWindowVisible(hwnd), NtUserGetWindowLongW(hwnd, GWL_STYLE),
705 get_focus(), get_active_window(), NtUserGetForegroundWindow(), last_focus );
707 if (can_activate_window(hwnd))
709 /* simulate a mouse click on the menu to find out
710 * whether the window wants to be activated */
711 LRESULT ma = send_message( hwnd, WM_MOUSEACTIVATE,
712 (WPARAM)NtUserGetAncestor( hwnd, GA_ROOT ),
713 MAKELONG( HTMENU, WM_LBUTTONDOWN ) );
714 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
716 set_focus( event->display, hwnd, event_time );
717 return;
720 else if (hwnd == NtUserGetDesktopWindow())
722 hwnd = NtUserGetForegroundWindow();
723 if (!hwnd) hwnd = last_focus;
724 if (!hwnd) hwnd = NtUserGetDesktopWindow();
725 set_focus( event->display, hwnd, event_time );
726 return;
728 /* try to find some other window to give the focus to */
729 hwnd = get_focus();
730 if (hwnd) hwnd = NtUserGetAncestor( hwnd, GA_ROOT );
731 if (!hwnd) hwnd = get_active_window();
732 if (!hwnd) hwnd = last_focus;
733 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
735 else if (protocol == x11drv_atom(_NET_WM_PING))
737 XClientMessageEvent xev;
738 xev = *event;
740 TRACE("NET_WM Ping\n");
741 xev.window = DefaultRootWindow(xev.display);
742 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
747 static const char * const focus_details[] =
749 "NotifyAncestor",
750 "NotifyVirtual",
751 "NotifyInferior",
752 "NotifyNonlinear",
753 "NotifyNonlinearVirtual",
754 "NotifyPointer",
755 "NotifyPointerRoot",
756 "NotifyDetailNone"
759 static const char * const focus_modes[] =
761 "NotifyNormal",
762 "NotifyGrab",
763 "NotifyUngrab",
764 "NotifyWhileGrabbed"
767 /**********************************************************************
768 * X11DRV_FocusIn
770 static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
772 XFocusChangeEvent *event = &xev->xfocus;
773 XIC xic;
775 if (!hwnd) return FALSE;
777 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] );
779 if (event->detail == NotifyPointer) return FALSE;
780 if (hwnd == NtUserGetDesktopWindow()) return FALSE;
782 switch (event->mode)
784 case NotifyGrab:
785 /* these are received when moving undecorated managed windows on mutter */
786 keyboard_grabbed = TRUE;
787 return FALSE;
788 case NotifyWhileGrabbed:
789 keyboard_grabbed = TRUE;
790 break;
791 case NotifyNormal:
792 keyboard_grabbed = FALSE;
793 break;
794 case NotifyUngrab:
795 keyboard_grabbed = FALSE;
796 retry_grab_clipping_window();
797 return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
800 if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic );
801 if (use_take_focus)
803 if (hwnd == NtUserGetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE );
804 return TRUE;
807 if (!can_activate_window(hwnd))
809 HWND hwnd = get_focus();
810 if (hwnd) hwnd = NtUserGetAncestor( hwnd, GA_ROOT );
811 if (!hwnd) hwnd = get_active_window();
812 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
813 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
815 else NtUserSetForegroundWindow( hwnd );
816 return TRUE;
819 /**********************************************************************
820 * focus_out
822 static void focus_out( Display *display , HWND hwnd )
824 HWND hwnd_tmp;
825 Window focus_win;
826 int revert;
827 XIC xic;
829 if (ximInComposeMode) return;
831 x11drv_thread_data()->last_focus = hwnd;
832 if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
834 if (is_virtual_desktop())
836 if (hwnd == NtUserGetDesktopWindow()) reset_clipping_window();
837 return;
839 if (hwnd != NtUserGetForegroundWindow()) return;
840 if (!(NtUserGetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE))
841 send_message( hwnd, WM_CANCELMODE, 0, 0 );
843 /* don't reset the foreground window, if the window which is
844 getting the focus is a Wine window */
846 XGetInputFocus( display, &focus_win, &revert );
847 if (focus_win)
849 if (XFindContext( display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
850 focus_win = 0;
853 if (!focus_win)
855 /* Abey : 6-Oct-99. Check again if the focus out window is the
856 Foreground window, because in most cases the messages sent
857 above must have already changed the foreground window, in which
858 case we don't have to change the foreground window to 0 */
859 if (hwnd == NtUserGetForegroundWindow())
861 TRACE( "lost focus, setting fg to desktop\n" );
862 NtUserSetForegroundWindow( NtUserGetDesktopWindow() );
867 /**********************************************************************
868 * X11DRV_FocusOut
870 * Note: only top-level windows get FocusOut events.
872 static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev )
874 XFocusChangeEvent *event = &xev->xfocus;
876 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] );
878 if (event->detail == NotifyPointer)
880 if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
881 return TRUE;
883 if (!hwnd) return FALSE;
885 switch (event->mode)
887 case NotifyUngrab:
888 /* these are received when moving undecorated managed windows on mutter */
889 keyboard_grabbed = FALSE;
890 return FALSE;
891 case NotifyNormal:
892 keyboard_grabbed = FALSE;
893 break;
894 case NotifyWhileGrabbed:
895 keyboard_grabbed = TRUE;
896 break;
897 case NotifyGrab:
898 keyboard_grabbed = TRUE;
900 /* This will do nothing due to keyboard_grabbed == TRUE, but it
901 * will save the current clipping rect so we can restore it on
902 * FocusIn with NotifyUngrab mode.
904 retry_grab_clipping_window();
906 return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
909 focus_out( event->display, hwnd );
910 return TRUE;
914 /***********************************************************************
915 * X11DRV_Expose
917 static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev )
919 XExposeEvent *event = &xev->xexpose;
920 RECT rect, abs_rect;
921 POINT pos;
922 struct x11drv_win_data *data;
923 HRGN surface_region = 0;
924 UINT flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN;
926 TRACE( "win %p (%lx) %d,%d %dx%d\n",
927 hwnd, event->window, event->x, event->y, event->width, event->height );
929 if (event->window != root_window)
931 pos.x = event->x;
932 pos.y = event->y;
934 else pos = root_to_virtual_screen( event->x, event->y );
936 if (!(data = get_win_data( hwnd ))) return FALSE;
938 rect.left = pos.x;
939 rect.top = pos.y;
940 rect.right = pos.x + event->width;
941 rect.bottom = pos.y + event->height;
943 if (event->window != data->client_window)
945 if (data->surface)
947 surface_region = expose_surface( data->surface, &rect );
948 if (!surface_region) flags = 0;
949 else NtGdiOffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
950 data->whole_rect.top - data->client_rect.top );
952 if (data->vis.visualid != default_visual.visualid)
953 data->surface->funcs->flush( data->surface );
955 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
956 data->whole_rect.top - data->client_rect.top );
959 if (event->window != root_window)
961 if (NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
962 mirror_rect( &data->client_rect, &rect );
963 abs_rect = rect;
964 NtUserMapWindowPoints( hwnd, 0, (POINT *)&abs_rect, 2 );
966 SERVER_START_REQ( update_window_zorder )
968 req->window = wine_server_user_handle( hwnd );
969 req->rect.left = abs_rect.left;
970 req->rect.top = abs_rect.top;
971 req->rect.right = abs_rect.right;
972 req->rect.bottom = abs_rect.bottom;
973 wine_server_call( req );
975 SERVER_END_REQ;
977 else flags &= ~RDW_ALLCHILDREN;
979 release_win_data( data );
981 if (flags) NtUserRedrawWindow( hwnd, &rect, surface_region, flags );
982 if (surface_region) NtGdiDeleteObjectApp( surface_region );
983 return TRUE;
987 /**********************************************************************
988 * X11DRV_MapNotify
990 static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event )
992 struct x11drv_win_data *data;
994 if (event->xany.window == x11drv_thread_data()->clip_window) return TRUE;
996 if (!(data = get_win_data( hwnd ))) return FALSE;
998 if (!data->managed && !data->embedded && data->mapped)
1000 HWND hwndFocus = get_focus();
1001 if (hwndFocus && NtUserIsChild( hwnd, hwndFocus ))
1002 set_input_focus( data );
1004 release_win_data( data );
1005 return TRUE;
1009 /**********************************************************************
1010 * X11DRV_UnmapNotify
1012 static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
1014 return TRUE;
1018 /***********************************************************************
1019 * reparent_notify
1021 static void reparent_notify( Display *display, HWND hwnd, Window xparent, int x, int y )
1023 HWND parent, old_parent;
1024 DWORD style;
1026 style = NtUserGetWindowLongW( hwnd, GWL_STYLE );
1027 if (xparent == root_window)
1029 parent = NtUserGetDesktopWindow();
1030 style = (style & ~WS_CHILD) | WS_POPUP;
1032 else
1034 if (!(parent = create_foreign_window( display, xparent ))) return;
1035 style = (style & ~WS_POPUP) | WS_CHILD;
1038 NtUserShowWindow( hwnd, SW_HIDE );
1039 old_parent = NtUserSetParent( hwnd, parent );
1040 NtUserSetWindowLong( hwnd, GWL_STYLE, style, FALSE );
1041 NtUserSetWindowPos( hwnd, HWND_TOP, x, y, 0, 0,
1042 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
1043 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
1045 /* make old parent destroy itself if it no longer has children */
1046 if (old_parent != NtUserGetDesktopWindow()) NtUserPostMessage( old_parent, WM_CLOSE, 0, 0 );
1050 /***********************************************************************
1051 * X11DRV_ReparentNotify
1053 static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
1055 XReparentEvent *event = &xev->xreparent;
1056 struct x11drv_win_data *data;
1058 if (!(data = get_win_data( hwnd ))) return FALSE;
1060 if (!data->embedded)
1062 release_win_data( data );
1063 return FALSE;
1066 if (data->whole_window)
1068 if (event->parent == root_window)
1070 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
1071 data->embedder = 0;
1072 release_win_data( data );
1073 send_message( hwnd, WM_CLOSE, 0, 0 );
1074 return TRUE;
1076 data->embedder = event->parent;
1079 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
1080 release_win_data( data );
1082 reparent_notify( event->display, hwnd, event->parent, event->x, event->y );
1083 return TRUE;
1087 /***********************************************************************
1088 * X11DRV_ConfigureNotify
1090 static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
1092 XConfigureEvent *event = &xev->xconfigure;
1093 struct x11drv_win_data *data;
1094 RECT rect;
1095 POINT pos;
1096 UINT flags;
1097 HWND parent;
1098 BOOL root_coords;
1099 int cx, cy, x = event->x, y = event->y;
1100 DWORD style;
1102 if (!hwnd) return FALSE;
1103 if (!(data = get_win_data( hwnd ))) return FALSE;
1104 if (!data->mapped || data->iconic) goto done;
1105 if (data->whole_window && !data->managed) goto done;
1106 /* ignore synthetic events on foreign windows */
1107 if (event->send_event && !data->whole_window) goto done;
1108 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
1110 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1111 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
1112 event->serial, data->configure_serial );
1113 goto done;
1116 /* Get geometry */
1118 parent = NtUserGetAncestor( hwnd, GA_PARENT );
1119 root_coords = event->send_event; /* synthetic events are always in root coords */
1121 if (!root_coords && parent == NtUserGetDesktopWindow()) /* normal event, map coordinates to the root */
1123 Window child;
1124 XTranslateCoordinates( event->display, event->window, root_window,
1125 0, 0, &x, &y, &child );
1126 root_coords = TRUE;
1129 if (!root_coords)
1131 pos.x = x;
1132 pos.y = y;
1134 else pos = root_to_virtual_screen( x, y );
1136 X11DRV_X_to_window_rect( data, &rect, pos.x, pos.y, event->width, event->height );
1137 if (root_coords) NtUserMapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1139 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1140 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1141 event->x, event->y, event->width, event->height );
1143 /* Compare what has changed */
1145 x = rect.left;
1146 y = rect.top;
1147 cx = rect.right - rect.left;
1148 cy = rect.bottom - rect.top;
1149 flags = SWP_NOACTIVATE | SWP_NOZORDER;
1151 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
1153 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1154 else
1155 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1156 hwnd, data->window_rect.left, data->window_rect.top, x, y );
1158 if ((data->window_rect.right - data->window_rect.left == cx &&
1159 data->window_rect.bottom - data->window_rect.top == cy) ||
1160 IsRectEmpty( &data->window_rect ))
1161 flags |= SWP_NOSIZE;
1162 else
1163 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1164 hwnd, data->window_rect.right - data->window_rect.left,
1165 data->window_rect.bottom - data->window_rect.top, cx, cy );
1167 style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
1168 if ((style & WS_CAPTION) == WS_CAPTION || !NtUserIsWindowRectFullScreen( &data->whole_rect ))
1170 read_net_wm_states( event->display, data );
1171 if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1173 if (!(style & WS_MAXIMIZE))
1175 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1176 release_win_data( data );
1177 send_message( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1178 return TRUE;
1181 else if (style & WS_MAXIMIZE)
1183 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1184 release_win_data( data );
1185 send_message( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1186 return TRUE;
1190 if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
1192 release_win_data( data );
1193 NtUserSetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1194 return TRUE;
1197 done:
1198 release_win_data( data );
1199 return FALSE;
1203 /**********************************************************************
1204 * X11DRV_GravityNotify
1206 static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1208 XGravityEvent *event = &xev->xgravity;
1209 struct x11drv_win_data *data = get_win_data( hwnd );
1210 RECT window_rect;
1211 int x, y;
1213 if (!data) return FALSE;
1215 if (data->whole_window) /* only handle this for foreign windows */
1217 release_win_data( data );
1218 return FALSE;
1221 x = event->x + data->window_rect.left - data->whole_rect.left;
1222 y = event->y + data->window_rect.top - data->whole_rect.top;
1224 TRACE( "win %p/%lx new X pos %d,%d (event %d,%d)\n",
1225 hwnd, data->whole_window, x, y, event->x, event->y );
1227 window_rect = data->window_rect;
1228 release_win_data( data );
1230 if (window_rect.left != x || window_rect.top != y)
1231 NtUserSetWindowPos( hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1233 return TRUE;
1237 /***********************************************************************
1238 * get_window_wm_state
1240 static int get_window_wm_state( Display *display, Window window )
1242 struct
1244 CARD32 state;
1245 XID icon;
1246 } *state;
1247 Atom type;
1248 int format, ret = -1;
1249 unsigned long count, remaining;
1251 if (!XGetWindowProperty( display, window, x11drv_atom(WM_STATE), 0,
1252 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1253 &type, &format, &count, &remaining, (unsigned char **)&state ))
1255 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1256 ret = state->state;
1257 XFree( state );
1259 return ret;
1263 /***********************************************************************
1264 * handle_wm_state_notify
1266 * Handle a PropertyNotify for WM_STATE.
1268 static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
1270 struct x11drv_win_data *data = get_win_data( hwnd );
1271 DWORD style;
1273 if (!data) return;
1275 switch(event->state)
1277 case PropertyDelete:
1278 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1279 data->wm_state = WithdrawnState;
1280 break;
1281 case PropertyNewValue:
1283 int old_state = data->wm_state;
1284 int new_state = get_window_wm_state( event->display, data->whole_window );
1285 if (new_state != -1 && new_state != data->wm_state)
1287 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1288 data->hwnd, data->whole_window, new_state, old_state );
1289 data->wm_state = new_state;
1290 /* ignore the initial state transition out of withdrawn state */
1291 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1292 if (!old_state) goto done;
1295 break;
1298 if (!update_window || !data->managed || !data->mapped) goto done;
1300 style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
1302 if (data->iconic && data->wm_state == NormalState) /* restore window */
1304 data->iconic = FALSE;
1305 read_net_wm_states( event->display, data );
1306 if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1308 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1310 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1311 release_win_data( data );
1312 send_message( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1313 return;
1315 TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1317 else
1319 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1321 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1322 release_win_data( data );
1323 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
1324 NtUserSetActiveWindow( hwnd );
1325 send_message( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1326 return;
1328 TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1331 else if (!data->iconic && data->wm_state == IconicState)
1333 data->iconic = TRUE;
1334 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1336 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1337 release_win_data( data );
1338 send_message( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1339 return;
1341 TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1343 done:
1344 release_win_data( data );
1348 /***********************************************************************
1349 * X11DRV_PropertyNotify
1351 static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1353 XPropertyEvent *event = &xev->xproperty;
1355 if (!hwnd) return FALSE;
1356 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
1357 return TRUE;
1361 /* event filter to wait for a WM_STATE change notification on a window */
1362 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1364 if (event->xany.window != (Window)arg) return 0;
1365 return (event->type == DestroyNotify ||
1366 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1369 /***********************************************************************
1370 * wait_for_withdrawn_state
1372 void wait_for_withdrawn_state( HWND hwnd, BOOL set )
1374 Display *display = thread_display();
1375 struct x11drv_win_data *data;
1376 DWORD end = NtGetTickCount() + 2000;
1378 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
1380 for (;;)
1382 XEvent event;
1383 Window window;
1384 int count = 0;
1386 if (!(data = get_win_data( hwnd ))) break;
1387 if (!data->managed || data->embedded || data->display != display) break;
1388 if (!(window = data->whole_window)) break;
1389 if (!data->mapped == !set)
1391 TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
1392 break;
1394 if ((data->wm_state == WithdrawnState) != !set)
1396 TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
1397 break;
1399 release_win_data( data );
1401 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
1403 count++;
1404 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1405 if (event.type == DestroyNotify) call_event_handler( display, &event );
1406 else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
1409 if (!count)
1411 struct pollfd pfd;
1412 int timeout = end - NtGetTickCount();
1414 pfd.fd = ConnectionNumber(display);
1415 pfd.events = POLLIN;
1416 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1418 FIXME( "window %p/%lx wait timed out\n", hwnd, window );
1419 return;
1423 release_win_data( data );
1427 /*****************************************************************
1428 * SetFocus (X11DRV.@)
1430 * Set the X focus.
1432 void X11DRV_SetFocus( HWND hwnd )
1434 struct x11drv_win_data *data;
1436 HWND parent;
1438 for (;;)
1440 if (!(data = get_win_data( hwnd ))) return;
1441 if (data->embedded) break;
1442 parent = NtUserGetAncestor( hwnd, GA_PARENT );
1443 if (!parent || parent == NtUserGetDesktopWindow()) break;
1444 release_win_data( data );
1445 hwnd = parent;
1447 if (!data->managed || data->embedder) set_input_focus( data );
1448 release_win_data( data );
1452 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1454 RECT tempRect;
1456 if (!NtUserIsWindowEnabled(hQueryWnd)) return 0;
1458 NtUserGetWindowRect(hQueryWnd, &tempRect);
1460 if(!PtInRect(&tempRect, *lpPt)) return 0;
1462 if (!(NtUserGetWindowLongW( hQueryWnd, GWL_STYLE ) & WS_MINIMIZE))
1464 POINT pt = *lpPt;
1465 NtUserScreenToClient( hQueryWnd, &pt );
1466 NtUserGetClientRect( hQueryWnd, &tempRect );
1468 if (PtInRect( &tempRect, pt))
1470 HWND ret = NtUserChildWindowFromPointEx( hQueryWnd, pt.x, pt.y,
1471 CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1472 if (ret && ret != hQueryWnd)
1474 ret = find_drop_window( ret, lpPt );
1475 if (ret) return ret;
1480 if(!(NtUserGetWindowLongW( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1482 NtUserScreenToClient( hQueryWnd, lpPt );
1484 return hQueryWnd;
1487 static void post_drop( HWND hwnd, DROPFILES *drop, ULONG size )
1489 drop->fWide = HandleToUlong( hwnd ); /* abuse fWide to pass window handle */
1490 x11drv_client_func( client_func_dnd_post_drop, drop, size );
1493 /**********************************************************************
1494 * EVENT_DropFromOffix
1496 * don't know if it still works (last Changelog is from 96/11/04)
1498 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1500 struct x11drv_win_data *data;
1501 POINT pt;
1502 unsigned long data_length;
1503 unsigned long aux_long;
1504 unsigned char* p_data = NULL;
1505 Atom atom_aux;
1506 int x, y, cx, cy, dummy, format;
1507 Window win, w_aux_root, w_aux_child;
1509 if (!(data = get_win_data( hWnd ))) return;
1510 cx = data->whole_rect.right - data->whole_rect.left;
1511 cy = data->whole_rect.bottom - data->whole_rect.top;
1512 win = data->whole_window;
1513 release_win_data( data );
1515 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1516 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1517 pt = root_to_virtual_screen( x, y );
1519 /* find out drop point and drop window */
1520 if (pt.x < 0 || pt.y < 0 || pt.x > cx || pt.y > cy)
1522 if (!(NtUserGetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1523 pt.x = pt.y = 0;
1525 else
1527 if (!find_drop_window( hWnd, &pt )) return;
1530 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1531 x11drv_atom(DndSelection), 0, 65535, FALSE,
1532 AnyPropertyType, &atom_aux, &format,
1533 &data_length, &aux_long, &p_data);
1535 if (!aux_long && p_data) /* don't bother if > 64K */
1537 DROPFILES *drop;
1538 size_t drop_size;
1540 drop = file_list_to_drop_files( p_data, get_property_size( format, data_length ), &drop_size );
1541 if (drop)
1543 post_drop( hWnd, drop, drop_size );
1544 free( drop );
1548 if (p_data) XFree(p_data);
1551 /**********************************************************************
1552 * EVENT_DropURLs
1554 * drop items are separated by \n
1555 * each item is prefixed by its mime type
1557 * event->data.l[3], event->data.l[4] contains drop x,y position
1559 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1561 struct x11drv_win_data *win_data;
1562 unsigned long data_length;
1563 unsigned long aux_long;
1564 unsigned char *p_data = NULL; /* property data */
1565 int x, y;
1566 DROPFILES *drop;
1567 int format;
1568 union {
1569 Atom atom_aux;
1570 int i;
1571 Window w_aux;
1572 unsigned int u;
1573 } u; /* unused */
1575 if (!(NtUserGetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1577 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1578 x11drv_atom(DndSelection), 0, 65535, FALSE,
1579 AnyPropertyType, &u.atom_aux, &format,
1580 &data_length, &aux_long, &p_data);
1581 if (aux_long)
1582 WARN("property too large, truncated!\n");
1583 TRACE("urls=%s\n", p_data);
1585 if (!aux_long && p_data) /* don't bother if > 64K */
1587 size_t drop_size;
1588 drop = uri_list_to_drop_files( p_data, get_property_size( format, data_length ), &drop_size );
1590 if (drop)
1592 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1593 &x, &y, &u.i, &u.i, &u.u);
1594 drop->pt = root_to_virtual_screen( x, y );
1596 if ((win_data = get_win_data( hWnd )))
1598 drop->fNC =
1599 (drop->pt.x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1600 drop->pt.y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1601 drop->pt.x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1602 drop->pt.y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1603 release_win_data( win_data );
1606 post_drop( hWnd, drop, drop_size );
1607 free( drop );
1610 if (p_data) XFree( p_data );
1614 /**********************************************************************
1615 * handle_xembed_protocol
1617 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1619 switch (event->data.l[1])
1621 case XEMBED_EMBEDDED_NOTIFY:
1623 struct x11drv_win_data *data = get_win_data( hwnd );
1624 if (!data) break;
1626 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1627 data->embedder = event->data.l[3];
1629 /* window has been marked as embedded before (e.g. systray) */
1630 if (data->embedded || !data->embedder /* broken QX11EmbedContainer implementation */)
1632 release_win_data( data );
1633 break;
1636 make_window_embedded( data );
1637 release_win_data( data );
1638 reparent_notify( event->display, hwnd, event->data.l[3], 0, 0 );
1640 break;
1642 case XEMBED_WINDOW_DEACTIVATE:
1643 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd, event->window );
1644 focus_out( event->display, NtUserGetAncestor( hwnd, GA_ROOT ) );
1645 break;
1647 case XEMBED_FOCUS_OUT:
1648 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd, event->window );
1649 focus_out( event->display, NtUserGetAncestor( hwnd, GA_ROOT ) );
1650 break;
1652 case XEMBED_MODALITY_ON:
1653 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd, event->window );
1654 NtUserEnableWindow( hwnd, FALSE );
1655 break;
1657 case XEMBED_MODALITY_OFF:
1658 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd, event->window );
1659 NtUserEnableWindow( hwnd, TRUE );
1660 break;
1662 default:
1663 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1664 hwnd, event->window, event->data.l[1], event->data.l[2] );
1665 break;
1670 /**********************************************************************
1671 * handle_dnd_protocol
1673 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1675 Window root, child;
1676 int root_x, root_y, child_x, child_y;
1677 unsigned int u;
1679 /* query window (drag&drop event contains only drag window) */
1680 XQueryPointer( event->display, root_window, &root, &child,
1681 &root_x, &root_y, &child_x, &child_y, &u);
1682 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1683 if (!hwnd) return;
1684 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1685 EVENT_DropFromOffiX(hwnd, event);
1686 else if (event->data.l[0] == DndURL)
1687 EVENT_DropURLs(hwnd, event);
1691 /**************************************************************************
1692 * handle_xdnd_enter_event
1694 * Handle an XdndEnter event.
1696 static void handle_xdnd_enter_event( HWND hWnd, XClientMessageEvent *event )
1698 struct format_entry *data;
1699 unsigned long count = 0;
1700 Atom *xdndtypes;
1701 size_t size;
1702 int version;
1704 version = (event->data.l[1] & 0xFF000000) >> 24;
1706 TRACE( "ver(%d) check-XdndTypeList(%ld) data=%ld,%ld,%ld,%ld,%ld\n",
1707 version, (event->data.l[1] & 1),
1708 event->data.l[0], event->data.l[1], event->data.l[2],
1709 event->data.l[3], event->data.l[4] );
1711 if (version > WINE_XDND_VERSION)
1713 ERR("ignoring unsupported XDND version %d\n", version);
1714 return;
1717 /* If the source supports more than 3 data types we retrieve
1718 * the entire list. */
1719 if (event->data.l[1] & 1)
1721 Atom acttype;
1722 int actfmt;
1723 unsigned long bytesret;
1725 /* Request supported formats from source window */
1726 XGetWindowProperty( event->display, event->data.l[0], x11drv_atom(XdndTypeList),
1727 0, 65535, FALSE, AnyPropertyType, &acttype, &actfmt, &count,
1728 &bytesret, (unsigned char **)&xdndtypes );
1730 else
1732 count = 3;
1733 xdndtypes = (Atom *)&event->data.l[2];
1736 if (TRACE_ON(xdnd))
1738 unsigned int i;
1740 for (i = 0; i < count; i++)
1742 if (xdndtypes[i] != 0)
1744 char * pn = XGetAtomName( event->display, xdndtypes[i] );
1745 TRACE( "XDNDEnterAtom %ld: %s\n", xdndtypes[i], pn );
1746 XFree( pn );
1751 data = import_xdnd_selection( event->display, event->window, x11drv_atom(XdndSelection),
1752 xdndtypes, count, &size );
1753 if (data)
1755 x11drv_client_func( client_func_dnd_enter_event, data, size );
1756 free( data );
1759 if (event->data.l[1] & 1)
1760 XFree(xdndtypes);
1764 static DWORD xdnd_action_to_drop_effect( long action )
1766 /* In Windows, nothing but the given effects is allowed.
1767 * In X the given action is just a hint, and you can always
1768 * XdndActionCopy and XdndActionPrivate, so be more permissive. */
1769 if (action == x11drv_atom(XdndActionCopy))
1770 return DROPEFFECT_COPY;
1771 else if (action == x11drv_atom(XdndActionMove))
1772 return DROPEFFECT_MOVE | DROPEFFECT_COPY;
1773 else if (action == x11drv_atom(XdndActionLink))
1774 return DROPEFFECT_LINK | DROPEFFECT_COPY;
1775 else if (action == x11drv_atom(XdndActionAsk))
1776 /* FIXME: should we somehow ask the user what to do here? */
1777 return DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
1779 FIXME( "unknown action %ld, assuming DROPEFFECT_COPY\n", action );
1780 return DROPEFFECT_COPY;
1784 static long drop_effect_to_xdnd_action( DWORD effect )
1786 if (effect == DROPEFFECT_COPY)
1787 return x11drv_atom(XdndActionCopy);
1788 else if (effect == DROPEFFECT_MOVE)
1789 return x11drv_atom(XdndActionMove);
1790 else if (effect == DROPEFFECT_LINK)
1791 return x11drv_atom(XdndActionLink);
1792 else if (effect == DROPEFFECT_NONE)
1793 return None;
1795 FIXME( "unknown drop effect %u, assuming XdndActionCopy\n", effect );
1796 return x11drv_atom(XdndActionCopy);
1800 static void handle_xdnd_position_event( HWND hwnd, XClientMessageEvent *event )
1802 struct dnd_position_event_params params;
1803 XClientMessageEvent e;
1804 DWORD effect;
1806 params.hwnd = HandleToUlong( hwnd );
1807 params.point = root_to_virtual_screen( event->data.l[2] >> 16, event->data.l[2] & 0xFFFF );
1808 params.effect = effect = xdnd_action_to_drop_effect( event->data.l[4] );
1810 effect = x11drv_client_func( client_func_dnd_position_event, &params, sizeof(params) );
1812 TRACE( "actionRequested(%ld) chosen(0x%x) at x(%d),y(%d)\n",
1813 event->data.l[4], effect, params.point.x, params.point.y );
1816 * Let source know if we're accepting the drop by
1817 * sending a status message.
1819 e.type = ClientMessage;
1820 e.display = event->display;
1821 e.window = event->data.l[0];
1822 e.message_type = x11drv_atom(XdndStatus);
1823 e.format = 32;
1824 e.data.l[0] = event->window;
1825 e.data.l[1] = !!effect;
1826 e.data.l[2] = 0; /* Empty Rect */
1827 e.data.l[3] = 0; /* Empty Rect */
1828 e.data.l[4] = drop_effect_to_xdnd_action( effect );
1829 XSendEvent( event->display, event->data.l[0], False, NoEventMask, (XEvent *)&e );
1833 static void handle_xdnd_drop_event( HWND hwnd, XClientMessageEvent *event )
1835 XClientMessageEvent e;
1836 DWORD effect;
1838 effect = x11drv_client_call( client_dnd_drop_event, HandleToUlong( hwnd ));
1840 /* Tell the target we are finished. */
1841 memset( &e, 0, sizeof(e) );
1842 e.type = ClientMessage;
1843 e.display = event->display;
1844 e.window = event->data.l[0];
1845 e.message_type = x11drv_atom(XdndFinished);
1846 e.format = 32;
1847 e.data.l[0] = event->window;
1848 e.data.l[1] = !!effect;
1849 e.data.l[2] = drop_effect_to_xdnd_action( effect );
1850 XSendEvent( event->display, event->data.l[0], False, NoEventMask, (XEvent *)&e );
1854 static void handle_xdnd_leave_event( HWND hwnd, XClientMessageEvent *event )
1856 x11drv_client_call( client_dnd_leave_event, 0 );
1860 struct client_message_handler
1862 int atom; /* protocol atom */
1863 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1866 static const struct client_message_handler client_messages[] =
1868 { XATOM_MANAGER, handle_manager_message },
1869 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1870 { XATOM__XEMBED, handle_xembed_protocol },
1871 { XATOM_DndProtocol, handle_dnd_protocol },
1872 { XATOM_XdndEnter, handle_xdnd_enter_event },
1873 { XATOM_XdndPosition, handle_xdnd_position_event },
1874 { XATOM_XdndDrop, handle_xdnd_drop_event },
1875 { XATOM_XdndLeave, handle_xdnd_leave_event }
1879 /**********************************************************************
1880 * X11DRV_ClientMessage
1882 static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1884 XClientMessageEvent *event = &xev->xclient;
1885 unsigned int i;
1887 if (!hwnd) return FALSE;
1889 if (event->format != 32)
1891 WARN( "Don't know how to handle format %d\n", event->format );
1892 return FALSE;
1895 for (i = 0; i < ARRAY_SIZE( client_messages ); i++)
1897 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1899 client_messages[i].handler( hwnd, event );
1900 return TRUE;
1903 TRACE( "no handler found for %ld\n", event->message_type );
1904 return FALSE;