4 * Copyright 1993 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
32 #include <X11/Xresource.h>
33 #include <X11/Xutil.h>
34 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
35 #include <X11/extensions/XInput2.h>
43 #include "shlobj.h" /* DROPFILES */
46 #include "wine/server.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(event
);
50 WINE_DECLARE_DEBUG_CHANNEL(xdnd
);
52 #define DndNotDnd -1 /* OffiX drag&drop */
64 #define DndURL 128 /* KDE drag&drop */
66 #define XEMBED_EMBEDDED_NOTIFY 0
67 #define XEMBED_WINDOW_ACTIVATE 1
68 #define XEMBED_WINDOW_DEACTIVATE 2
69 #define XEMBED_REQUEST_FOCUS 3
70 #define XEMBED_FOCUS_IN 4
71 #define XEMBED_FOCUS_OUT 5
72 #define XEMBED_FOCUS_NEXT 6
73 #define XEMBED_FOCUS_PREV 7
74 #define XEMBED_MODALITY_ON 10
75 #define XEMBED_MODALITY_OFF 11
76 #define XEMBED_REGISTER_ACCELERATOR 12
77 #define XEMBED_UNREGISTER_ACCELERATOR 13
78 #define XEMBED_ACTIVATE_ACCELERATOR 14
80 Bool (*pXGetEventData
)( Display
*display
, XEvent
/*XGenericEventCookie*/ *event
) = NULL
;
81 void (*pXFreeEventData
)( Display
*display
, XEvent
/*XGenericEventCookie*/ *event
) = NULL
;
84 static BOOL
X11DRV_FocusIn( HWND hwnd
, XEvent
*event
);
85 static BOOL
X11DRV_FocusOut( HWND hwnd
, XEvent
*event
);
86 static BOOL
X11DRV_Expose( HWND hwnd
, XEvent
*event
);
87 static BOOL
X11DRV_MapNotify( HWND hwnd
, XEvent
*event
);
88 static BOOL
X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
);
89 static BOOL
X11DRV_ReparentNotify( HWND hwnd
, XEvent
*event
);
90 static BOOL
X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*event
);
91 static BOOL
X11DRV_PropertyNotify( HWND hwnd
, XEvent
*event
);
92 static BOOL
X11DRV_ClientMessage( HWND hwnd
, XEvent
*event
);
93 static BOOL
X11DRV_GravityNotify( HWND hwnd
, XEvent
*event
);
95 #define MAX_EVENT_HANDLERS 128
97 static x11drv_event_handler handlers
[MAX_EVENT_HANDLERS
] =
99 NULL
, /* 0 reserved */
100 NULL
, /* 1 reserved */
101 X11DRV_KeyEvent
, /* 2 KeyPress */
102 X11DRV_KeyEvent
, /* 3 KeyRelease */
103 X11DRV_ButtonPress
, /* 4 ButtonPress */
104 X11DRV_ButtonRelease
, /* 5 ButtonRelease */
105 X11DRV_MotionNotify
, /* 6 MotionNotify */
106 X11DRV_EnterNotify
, /* 7 EnterNotify */
107 NULL
, /* 8 LeaveNotify */
108 X11DRV_FocusIn
, /* 9 FocusIn */
109 X11DRV_FocusOut
, /* 10 FocusOut */
110 X11DRV_KeymapNotify
, /* 11 KeymapNotify */
111 X11DRV_Expose
, /* 12 Expose */
112 NULL
, /* 13 GraphicsExpose */
113 NULL
, /* 14 NoExpose */
114 NULL
, /* 15 VisibilityNotify */
115 NULL
, /* 16 CreateNotify */
116 X11DRV_DestroyNotify
, /* 17 DestroyNotify */
117 X11DRV_UnmapNotify
, /* 18 UnmapNotify */
118 X11DRV_MapNotify
, /* 19 MapNotify */
119 NULL
, /* 20 MapRequest */
120 X11DRV_ReparentNotify
, /* 21 ReparentNotify */
121 X11DRV_ConfigureNotify
, /* 22 ConfigureNotify */
122 NULL
, /* 23 ConfigureRequest */
123 X11DRV_GravityNotify
, /* 24 GravityNotify */
124 NULL
, /* 25 ResizeRequest */
125 NULL
, /* 26 CirculateNotify */
126 NULL
, /* 27 CirculateRequest */
127 X11DRV_PropertyNotify
, /* 28 PropertyNotify */
128 X11DRV_SelectionClear
, /* 29 SelectionClear */
129 X11DRV_SelectionRequest
, /* 30 SelectionRequest */
130 NULL
, /* 31 SelectionNotify */
131 NULL
, /* 32 ColormapNotify */
132 X11DRV_ClientMessage
, /* 33 ClientMessage */
133 X11DRV_MappingNotify
, /* 34 MappingNotify */
134 X11DRV_GenericEvent
/* 35 GenericEvent */
137 static const char * event_names
[MAX_EVENT_HANDLERS
] =
139 NULL
, NULL
, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
140 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
141 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
142 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
143 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
144 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
145 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
148 /* is someone else grabbing the keyboard, for example the WM, when manipulating the window */
149 BOOL keyboard_grabbed
= FALSE
;
151 int xinput2_opcode
= 0;
153 /* return the name of an X event */
154 static const char *dbgstr_event( int type
)
156 if (type
< MAX_EVENT_HANDLERS
&& event_names
[type
]) return event_names
[type
];
157 return wine_dbg_sprintf( "Unknown event %d", type
);
160 static inline void get_event_data( XEvent
*event
)
162 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
163 if (event
->xany
.type
!= GenericEvent
) return;
164 if (!pXGetEventData
|| !pXGetEventData( event
->xany
.display
, event
)) event
->xcookie
.data
= NULL
;
168 static inline void free_event_data( XEvent
*event
)
170 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
171 if (event
->xany
.type
!= GenericEvent
) return;
172 if (event
->xcookie
.data
) pXFreeEventData( event
->xany
.display
, event
);
176 /***********************************************************************
177 * xembed_request_focus
179 static void xembed_request_focus( Display
*display
, Window window
, DWORD timestamp
)
183 xev
.xclient
.type
= ClientMessage
;
184 xev
.xclient
.window
= window
;
185 xev
.xclient
.message_type
= x11drv_atom(_XEMBED
);
186 xev
.xclient
.serial
= 0;
187 xev
.xclient
.display
= display
;
188 xev
.xclient
.send_event
= True
;
189 xev
.xclient
.format
= 32;
191 xev
.xclient
.data
.l
[0] = timestamp
;
192 xev
.xclient
.data
.l
[1] = XEMBED_REQUEST_FOCUS
;
193 xev
.xclient
.data
.l
[2] = 0;
194 xev
.xclient
.data
.l
[3] = 0;
195 xev
.xclient
.data
.l
[4] = 0;
197 XSendEvent(display
, window
, False
, NoEventMask
, &xev
);
201 /***********************************************************************
202 * X11DRV_register_event_handler
204 * Register a handler for a given event type.
205 * If already registered, overwrite the previous handler.
207 void X11DRV_register_event_handler( int type
, x11drv_event_handler handler
, const char *name
)
209 assert( type
< MAX_EVENT_HANDLERS
);
210 assert( !handlers
[type
] || handlers
[type
] == handler
);
211 handlers
[type
] = handler
;
212 event_names
[type
] = name
;
213 TRACE("registered handler %p for event %d %s\n", handler
, type
, debugstr_a(name
) );
217 /***********************************************************************
220 static Bool
filter_event( Display
*display
, XEvent
*event
, char *arg
)
222 ULONG_PTR mask
= (ULONG_PTR
)arg
;
224 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return 1;
232 return (mask
& (QS_KEY
| QS_HOTKEY
| QS_RAWINPUT
)) != 0;
235 return (mask
& (QS_MOUSEBUTTON
| QS_RAWINPUT
)) != 0;
239 return (mask
& (QS_MOUSEMOVE
| QS_RAWINPUT
)) != 0;
241 return (mask
& QS_PAINT
) != 0;
246 case ConfigureNotify
:
249 return (mask
& QS_POSTMESSAGE
) != 0;
252 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
253 if (event
->xcookie
.extension
== xinput2_opcode
) return (mask
& QS_INPUT
) != 0;
258 return (mask
& QS_SENDMESSAGE
) != 0;
263 enum event_merge_action
265 MERGE_DISCARD
, /* discard the old event */
266 MERGE_HANDLE
, /* handle the old event */
267 MERGE_KEEP
, /* keep the old event for future merging */
268 MERGE_IGNORE
/* ignore the new event, keep the old one */
271 /***********************************************************************
272 * merge_raw_motion_events
274 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
275 static enum event_merge_action
merge_raw_motion_events( XIRawEvent
*prev
, XIRawEvent
*next
)
280 if (!prev
->valuators
.mask_len
) return MERGE_HANDLE
;
281 if (!next
->valuators
.mask_len
) return MERGE_HANDLE
;
283 mask
= prev
->valuators
.mask
[0] | next
->valuators
.mask
[0];
284 if (mask
== next
->valuators
.mask
[0]) /* keep next */
286 for (i
= j
= k
= 0; i
< 8; i
++)
288 if (XIMaskIsSet( prev
->valuators
.mask
, i
))
289 next
->valuators
.values
[j
] += prev
->valuators
.values
[k
++];
290 if (XIMaskIsSet( next
->valuators
.mask
, i
)) j
++;
292 TRACE( "merging duplicate GenericEvent\n" );
293 return MERGE_DISCARD
;
295 if (mask
== prev
->valuators
.mask
[0]) /* keep prev */
297 for (i
= j
= k
= 0; i
< 8; i
++)
299 if (XIMaskIsSet( next
->valuators
.mask
, i
))
300 prev
->valuators
.values
[j
] += next
->valuators
.values
[k
++];
301 if (XIMaskIsSet( prev
->valuators
.mask
, i
)) j
++;
303 TRACE( "merging duplicate GenericEvent\n" );
306 /* can't merge events with disjoint masks */
311 /***********************************************************************
314 * Try to merge 2 consecutive events.
316 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
320 case ConfigureNotify
:
323 case ConfigureNotify
:
324 if (prev
->xany
.window
== next
->xany
.window
)
326 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev
->xany
.window
);
327 return MERGE_DISCARD
;
339 if (prev
->xany
.window
== next
->xany
.window
)
341 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
342 return MERGE_DISCARD
;
345 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
347 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
348 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
349 if (x11drv_thread_data()->warp_serial
) break;
354 if (prev
->xcookie
.extension
!= xinput2_opcode
) break;
355 if (prev
->xcookie
.evtype
!= XI_RawMotion
) break;
359 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
360 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
361 if (x11drv_thread_data()->warp_serial
) break;
362 return merge_raw_motion_events( prev
->xcookie
.data
, next
->xcookie
.data
);
371 /***********************************************************************
374 static inline BOOL
call_event_handler( Display
*display
, XEvent
*event
)
378 struct x11drv_thread_data
*thread_data
;
381 if (!handlers
[event
->type
])
383 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
->type
), event
->xany
.window
);
384 return FALSE
; /* no handler, ignore it */
388 if (event
->type
== GenericEvent
) hwnd
= 0; else
390 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hwnd
) != 0)
391 hwnd
= 0; /* not for a registered window */
392 if (!hwnd
&& event
->xany
.window
== root_window
) hwnd
= NtUserGetDesktopWindow();
394 TRACE( "%lu %s for hwnd/window %p/%lx\n",
395 event
->xany
.serial
, dbgstr_event( event
->type
), hwnd
, event
->xany
.window
);
396 thread_data
= x11drv_thread_data();
397 prev
= thread_data
->current_event
;
398 thread_data
->current_event
= event
;
399 ret
= handlers
[event
->type
]( hwnd
, event
);
400 thread_data
->current_event
= prev
;
405 /***********************************************************************
408 BOOL
process_events( Display
*display
, Bool (*filter
)(Display
*, XEvent
*,XPointer
), ULONG_PTR arg
)
410 XEvent event
, prev_event
;
413 enum event_merge_action action
= MERGE_DISCARD
;
416 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
419 if (XFilterEvent( &event
, None
))
422 * SCIM on linux filters key events strangely. It does not filter the
423 * KeyPress events for these keys however it does filter the
424 * KeyRelease events. This causes wine to become very confused as
425 * to the keyboard state.
427 * We need to let those KeyRelease events be processed so that the
428 * keyboard state is correct.
430 if (event
.type
== KeyRelease
)
433 XKeyEvent
*keyevent
= &event
.xkey
;
435 XLookupString(keyevent
, NULL
, 0, &keysym
, NULL
);
436 if (!(keysym
== XK_Shift_L
||
437 keysym
== XK_Shift_R
||
438 keysym
== XK_Control_L
||
439 keysym
== XK_Control_R
||
440 keysym
== XK_Alt_R
||
441 keysym
== XK_Alt_L
||
442 keysym
== XK_Meta_R
||
443 keysym
== XK_Meta_L
))
444 continue; /* not a key we care about, ignore it */
447 continue; /* filtered, ignore it */
449 get_event_data( &event
);
450 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
453 case MERGE_HANDLE
: /* handle prev, keep new */
454 queued
|= call_event_handler( display
, &prev_event
);
456 case MERGE_DISCARD
: /* discard prev, keep new */
457 free_event_data( &prev_event
);
460 case MERGE_KEEP
: /* handle new, keep prev for future merging */
461 queued
|= call_event_handler( display
, &event
);
463 case MERGE_IGNORE
: /* ignore new, keep prev for future merging */
464 free_event_data( &event
);
468 if (prev_event
.type
) queued
|= call_event_handler( display
, &prev_event
);
469 free_event_data( &prev_event
);
470 XFlush( gdi_display
);
471 if (count
) TRACE( "processed %d events, returning %d\n", count
, queued
);
476 /***********************************************************************
477 * ProcessEvents (X11DRV.@)
479 BOOL
X11DRV_ProcessEvents( DWORD mask
)
481 struct x11drv_thread_data
*data
= x11drv_thread_data();
483 if (!data
) return FALSE
;
484 if (data
->current_event
) mask
= 0; /* don't process nested events */
486 return process_events( data
->display
, filter_event
, mask
);
489 /***********************************************************************
490 * EVENT_x11_time_to_win32_time
492 * Make our timer and the X timer line up as best we can
493 * Pass 0 to retrieve the current adjustment value (times -1)
495 DWORD
EVENT_x11_time_to_win32_time(Time time
)
497 static DWORD adjust
= 0;
498 DWORD now
= NtGetTickCount();
501 if (! adjust
&& time
!= 0)
508 /* If we got an event in the 'future', then our clock is clearly wrong.
509 If we got it more than 10000 ms in the future, then it's most likely
510 that the clock has wrapped. */
513 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
524 /*******************************************************************
525 * can_activate_window
527 * Check if we can activate the specified window.
529 static inline BOOL
can_activate_window( HWND hwnd
)
531 LONG style
= NtUserGetWindowLongW( hwnd
, GWL_STYLE
);
534 if (!(style
& WS_VISIBLE
)) return FALSE
;
535 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
536 if (style
& WS_MINIMIZE
) return FALSE
;
537 if (NtUserGetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_NOACTIVATE
) return FALSE
;
538 if (hwnd
== NtUserGetDesktopWindow()) return FALSE
;
539 if (NtUserGetWindowRect( hwnd
, &rect
, get_win_monitor_dpi( hwnd
) ) && IsRectEmpty( &rect
)) return FALSE
;
540 return !(style
& WS_DISABLED
);
544 /**********************************************************************
547 * Try to force focus for embedded or non-managed windows.
549 static void set_input_focus( struct x11drv_win_data
*data
)
551 XWindowChanges changes
;
554 if (!data
->whole_window
) return;
556 if (EVENT_x11_time_to_win32_time(0))
557 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
558 /* FIXME: this is not entirely correct */
559 timestamp
= NtUserGetThreadInfo()->message_time
- EVENT_x11_time_to_win32_time(0);
561 timestamp
= CurrentTime
;
563 /* Set X focus and install colormap */
564 changes
.stack_mode
= Above
;
565 XConfigureWindow( data
->display
, data
->whole_window
, CWStackMode
, &changes
);
568 xembed_request_focus( data
->display
, data
->embedder
, timestamp
);
570 XSetInputFocus( data
->display
, data
->whole_window
, RevertToParent
, timestamp
);
574 /**********************************************************************
577 static void set_focus( Display
*display
, HWND hwnd
, Time time
)
581 GUITHREADINFO threadinfo
;
583 TRACE( "setting foreground window to %p\n", hwnd
);
584 NtUserSetForegroundWindow( hwnd
);
586 threadinfo
.cbSize
= sizeof(threadinfo
);
587 NtUserGetGUIThreadInfo( 0, &threadinfo
);
588 focus
= threadinfo
.hwndFocus
;
589 if (!focus
) focus
= threadinfo
.hwndActive
;
590 if (focus
) focus
= NtUserGetAncestor( focus
, GA_ROOT
);
591 win
= X11DRV_get_whole_window(focus
);
595 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
596 XSetInputFocus( display
, win
, RevertToParent
, time
);
601 /**********************************************************************
602 * handle_manager_message
604 static void handle_manager_message( HWND hwnd
, XClientMessageEvent
*event
)
606 if (hwnd
!= NtUserGetDesktopWindow()) return;
608 if (systray_atom
&& event
->data
.l
[1] == systray_atom
)
610 TRACE( "new owner %lx\n", event
->data
.l
[2] );
611 NtUserPostMessage( systray_hwnd
, WM_USER
+ 1, 0, 0 );
616 /**********************************************************************
617 * handle_wm_protocols
619 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
621 Atom protocol
= (Atom
)event
->data
.l
[0];
622 Time event_time
= (Time
)event
->data
.l
[1];
624 if (!protocol
) return;
626 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
628 update_user_time( event_time
);
630 if (hwnd
== NtUserGetDesktopWindow())
632 /* The desktop window does not have a close button that we can
633 * pretend to click. Therefore, we simply send it a close command. */
634 send_message( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
638 /* Ignore the delete window request if the window has been disabled
639 * and we are in managed mode. This is to disallow applications from
640 * being closed by the window manager while in a modal state.
642 if (NtUserIsWindowEnabled( hwnd
))
646 if (NtUserGetClassLongW( hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
647 hSysMenu
= NtUserGetSystemMenu( hwnd
, FALSE
);
650 UINT state
= NtUserThunkedMenuItemInfo( hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
,
651 NtUserGetMenuState
, NULL
, NULL
);
652 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
655 if (get_active_window() != hwnd
)
657 LRESULT ma
= send_message( hwnd
, WM_MOUSEACTIVATE
,
658 (WPARAM
)NtUserGetAncestor( hwnd
, GA_ROOT
),
659 MAKELPARAM( HTCLOSE
, WM_NCLBUTTONDOWN
) );
662 case MA_NOACTIVATEANDEAT
:
663 case MA_ACTIVATEANDEAT
:
669 NtUserSetActiveWindow( hwnd
);
672 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
677 NtUserPostMessage( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
680 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
682 HWND last_focus
= x11drv_thread_data()->last_focus
;
684 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
685 hwnd
, NtUserIsWindowEnabled(hwnd
), NtUserIsWindowVisible(hwnd
),
686 (int)NtUserGetWindowLongW(hwnd
, GWL_STYLE
),
687 get_focus(), get_active_window(), NtUserGetForegroundWindow(), last_focus
);
689 if (can_activate_window(hwnd
))
691 /* simulate a mouse click on the menu to find out
692 * whether the window wants to be activated */
693 LRESULT ma
= send_message( hwnd
, WM_MOUSEACTIVATE
,
694 (WPARAM
)NtUserGetAncestor( hwnd
, GA_ROOT
),
695 MAKELONG( HTMENU
, WM_LBUTTONDOWN
) );
696 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
698 set_focus( event
->display
, hwnd
, event_time
);
702 else if (hwnd
== NtUserGetDesktopWindow())
704 hwnd
= NtUserGetForegroundWindow();
705 if (!hwnd
) hwnd
= last_focus
;
706 if (!hwnd
) hwnd
= NtUserGetDesktopWindow();
707 set_focus( event
->display
, hwnd
, event_time
);
710 /* try to find some other window to give the focus to */
712 if (hwnd
) hwnd
= NtUserGetAncestor( hwnd
, GA_ROOT
);
713 if (!hwnd
) hwnd
= get_active_window();
714 if (!hwnd
) hwnd
= last_focus
;
715 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, event_time
);
717 else if (protocol
== x11drv_atom(_NET_WM_PING
))
719 XClientMessageEvent xev
;
722 TRACE("NET_WM Ping\n");
723 xev
.window
= DefaultRootWindow(xev
.display
);
724 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
729 static const char * const focus_details
[] =
735 "NotifyNonlinearVirtual",
741 static const char * const focus_modes
[] =
749 BOOL
is_current_process_focused(void)
751 Display
*display
= x11drv_thread_data()->display
;
756 XGetInputFocus( display
, &focus
, &revert
);
757 if (focus
&& !XFindContext( display
, focus
, winContext
, (char **)&hwnd
)) return TRUE
;
761 /**********************************************************************
764 static BOOL
X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
766 XFocusChangeEvent
*event
= &xev
->xfocus
;
769 if (!hwnd
) return FALSE
;
771 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
], focus_modes
[event
->mode
] );
773 if (event
->detail
== NotifyPointer
) return FALSE
;
774 /* when focusing in the virtual desktop window, re-apply the cursor clipping rect */
775 if (is_virtual_desktop() && hwnd
== NtUserGetDesktopWindow()) reapply_cursor_clipping();
776 if (hwnd
== NtUserGetDesktopWindow()) return FALSE
;
778 x11drv_thread_data()->keymapnotify_hwnd
= hwnd
;
780 /* when keyboard grab is released, re-apply the cursor clipping rect */
781 was_grabbed
= keyboard_grabbed
;
782 keyboard_grabbed
= event
->mode
== NotifyGrab
|| event
->mode
== NotifyWhileGrabbed
;
783 if (was_grabbed
> keyboard_grabbed
) reapply_cursor_clipping();
784 /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
785 if (event
->mode
== NotifyGrab
|| event
->mode
== NotifyUngrab
) return FALSE
;
787 xim_set_focus( hwnd
, TRUE
);
789 if (use_take_focus
) return TRUE
;
791 if (!can_activate_window(hwnd
))
793 HWND hwnd
= get_focus();
794 if (hwnd
) hwnd
= NtUserGetAncestor( hwnd
, GA_ROOT
);
795 if (!hwnd
) hwnd
= get_active_window();
796 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
797 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, CurrentTime
);
799 else NtUserSetForegroundWindow( hwnd
);
803 /**********************************************************************
806 static void focus_out( Display
*display
, HWND hwnd
)
808 if (xim_in_compose_mode()) return;
810 x11drv_thread_data()->last_focus
= hwnd
;
811 xim_set_focus( hwnd
, FALSE
);
813 if (is_virtual_desktop()) return;
814 if (hwnd
!= NtUserGetForegroundWindow()) return;
815 if (!(NtUserGetWindowLongW( hwnd
, GWL_STYLE
) & WS_MINIMIZE
))
816 send_message( hwnd
, WM_CANCELMODE
, 0, 0 );
818 /* don't reset the foreground window, if the window which is
819 getting the focus is a Wine window */
821 if (!is_current_process_focused())
823 /* Abey : 6-Oct-99. Check again if the focus out window is the
824 Foreground window, because in most cases the messages sent
825 above must have already changed the foreground window, in which
826 case we don't have to change the foreground window to 0 */
827 if (hwnd
== NtUserGetForegroundWindow())
829 TRACE( "lost focus, setting fg to desktop\n" );
830 NtUserSetForegroundWindow( NtUserGetDesktopWindow() );
835 /**********************************************************************
838 * Note: only top-level windows get FocusOut events.
840 static BOOL
X11DRV_FocusOut( HWND hwnd
, XEvent
*xev
)
842 XFocusChangeEvent
*event
= &xev
->xfocus
;
844 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
], focus_modes
[event
->mode
] );
846 if (event
->detail
== NotifyPointer
)
848 if (!hwnd
&& event
->window
== x11drv_thread_data()->clip_window
)
850 NtUserClipCursor( NULL
);
851 /* NtUserClipCursor will ask the foreground window to ungrab the cursor, but
852 * it might not be responsive, so unmap the clipping window ourselves too */
853 XUnmapWindow( event
->display
, event
->window
);
857 if (!hwnd
) return FALSE
;
859 /* in virtual desktop mode or when keyboard is grabbed, release any cursor grab but keep the clipping rect */
860 keyboard_grabbed
= event
->mode
== NotifyGrab
|| event
->mode
== NotifyWhileGrabbed
;
861 if (is_virtual_desktop() || keyboard_grabbed
) ungrab_clipping_window();
862 /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
863 if (event
->mode
== NotifyGrab
|| event
->mode
== NotifyUngrab
) return FALSE
;
865 focus_out( event
->display
, hwnd
);
870 /***********************************************************************
873 static BOOL
X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
875 XExposeEvent
*event
= &xev
->xexpose
;
878 struct x11drv_win_data
*data
;
879 HRGN surface_region
= 0;
880 UINT flags
= RDW_INVALIDATE
| RDW_ERASE
| RDW_FRAME
| RDW_ALLCHILDREN
;
882 TRACE( "win %p (%lx) %d,%d %dx%d\n",
883 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
885 if (event
->window
!= root_window
)
890 else pos
= root_to_virtual_screen( event
->x
, event
->y
);
892 if (!(data
= get_win_data( hwnd
))) return FALSE
;
896 rect
.right
= pos
.x
+ event
->width
;
897 rect
.bottom
= pos
.y
+ event
->height
;
899 if (event
->window
!= data
->client_window
)
903 surface_region
= expose_surface( data
->surface
, &rect
);
904 if (!surface_region
) flags
= 0;
905 else NtGdiOffsetRgn( surface_region
, data
->whole_rect
.left
- data
->client_rect
.left
,
906 data
->whole_rect
.top
- data
->client_rect
.top
);
908 if (data
->vis
.visualid
!= default_visual
.visualid
)
909 window_surface_flush( data
->surface
);
911 OffsetRect( &rect
, data
->whole_rect
.left
- data
->client_rect
.left
,
912 data
->whole_rect
.top
- data
->client_rect
.top
);
915 if (event
->window
!= root_window
)
917 if (NtUserGetWindowLongW( data
->hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
918 mirror_rect( &data
->client_rect
, &rect
);
920 NtUserMapWindowPoints( hwnd
, 0, (POINT
*)&abs_rect
, 2, 0 /* per-monitor DPI */ );
922 SERVER_START_REQ( update_window_zorder
)
924 req
->window
= wine_server_user_handle( hwnd
);
925 req
->rect
= wine_server_rectangle( abs_rect
);
926 wine_server_call( req
);
930 else flags
&= ~RDW_ALLCHILDREN
;
932 release_win_data( data
);
934 if (flags
) redraw_window( hwnd
, &rect
, surface_region
, flags
);
935 if (surface_region
) NtGdiDeleteObjectApp( surface_region
);
940 /**********************************************************************
943 static BOOL
X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
945 struct x11drv_win_data
*data
;
947 if (event
->xany
.window
== x11drv_thread_data()->clip_window
) return TRUE
;
949 if (!(data
= get_win_data( hwnd
))) return FALSE
;
951 if (!data
->managed
&& !data
->embedded
&& data
->mapped
)
953 HWND hwndFocus
= get_focus();
954 if (hwndFocus
&& NtUserIsChild( hwnd
, hwndFocus
))
955 set_input_focus( data
);
957 release_win_data( data
);
962 /**********************************************************************
965 static BOOL
X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
)
971 /***********************************************************************
974 static void reparent_notify( Display
*display
, HWND hwnd
, Window xparent
, int x
, int y
)
976 HWND parent
, old_parent
;
977 DWORD style
, flags
= 0;
979 style
= NtUserGetWindowLongW( hwnd
, GWL_STYLE
);
980 if (xparent
== root_window
)
982 parent
= NtUserGetDesktopWindow();
983 style
= (style
& ~WS_CHILD
) | WS_POPUP
;
987 if (!(parent
= create_foreign_window( display
, xparent
))) return;
988 style
= (style
& ~WS_POPUP
) | WS_CHILD
;
991 NtUserShowWindow( hwnd
, SW_HIDE
);
992 old_parent
= NtUserSetParent( hwnd
, parent
);
993 NtUserSetWindowLong( hwnd
, GWL_STYLE
, style
, FALSE
);
995 if (style
& WS_VISIBLE
) flags
= SWP_SHOWWINDOW
;
996 set_window_pos( hwnd
, HWND_TOP
, x
, y
, 0, 0, SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOCOPYBITS
| flags
);
998 /* make old parent destroy itself if it no longer has children */
999 if (old_parent
!= NtUserGetDesktopWindow()) NtUserPostMessage( old_parent
, WM_CLOSE
, 0, 0 );
1003 /***********************************************************************
1004 * X11DRV_ReparentNotify
1006 static BOOL
X11DRV_ReparentNotify( HWND hwnd
, XEvent
*xev
)
1008 XReparentEvent
*event
= &xev
->xreparent
;
1009 struct x11drv_win_data
*data
;
1011 if (!(data
= get_win_data( hwnd
))) return FALSE
;
1013 if (!data
->embedded
)
1015 release_win_data( data
);
1019 if (data
->whole_window
)
1021 if (event
->parent
== root_window
)
1023 TRACE( "%p/%lx reparented to root\n", hwnd
, data
->whole_window
);
1025 release_win_data( data
);
1026 send_message( hwnd
, WM_CLOSE
, 0, 0 );
1029 data
->embedder
= event
->parent
;
1032 TRACE( "%p/%lx reparented to %lx\n", hwnd
, data
->whole_window
, event
->parent
);
1033 release_win_data( data
);
1035 reparent_notify( event
->display
, hwnd
, event
->parent
, event
->x
, event
->y
);
1040 /***********************************************************************
1041 * X11DRV_ConfigureNotify
1043 static BOOL
X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
1045 XConfigureEvent
*event
= &xev
->xconfigure
;
1046 struct x11drv_win_data
*data
;
1052 int cx
, cy
, x
= event
->x
, y
= event
->y
;
1055 if (!hwnd
) return FALSE
;
1056 if (!(data
= get_win_data( hwnd
))) return FALSE
;
1057 if (!data
->mapped
|| data
->iconic
) goto done
;
1058 if (data
->whole_window
&& !data
->managed
) goto done
;
1059 /* ignore synthetic events on foreign windows */
1060 if (event
->send_event
&& !data
->whole_window
) goto done
;
1061 if (data
->configure_serial
&& (long)(data
->configure_serial
- event
->serial
) > 0)
1063 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1064 hwnd
, data
->whole_window
, event
->x
, event
->y
, event
->width
, event
->height
,
1065 event
->serial
, data
->configure_serial
);
1071 dpi
= get_win_monitor_dpi( data
->hwnd
);
1072 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1073 root_coords
= event
->send_event
; /* synthetic events are always in root coords */
1075 if (!root_coords
&& parent
== NtUserGetDesktopWindow()) /* normal event, map coordinates to the root */
1078 XTranslateCoordinates( event
->display
, event
->window
, root_window
,
1079 0, 0, &x
, &y
, &child
);
1088 else pos
= root_to_virtual_screen( x
, y
);
1090 X11DRV_X_to_window_rect( data
, &rect
, pos
.x
, pos
.y
, event
->width
, event
->height
);
1091 if (root_coords
) NtUserMapWindowPoints( 0, parent
, (POINT
*)&rect
, 2, 0 /* per-monitor DPI */ );
1093 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1094 hwnd
, data
->whole_window
, (int)rect
.left
, (int)rect
.top
,
1095 (int)(rect
.right
-rect
.left
), (int)(rect
.bottom
-rect
.top
),
1096 event
->x
, event
->y
, event
->width
, event
->height
);
1098 /* Compare what has changed */
1102 cx
= rect
.right
- rect
.left
;
1103 cy
= rect
.bottom
- rect
.top
;
1104 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
1106 if (!data
->whole_window
) flags
|= SWP_NOCOPYBITS
; /* we can't copy bits of foreign windows */
1108 if (data
->window_rect
.left
== x
&& data
->window_rect
.top
== y
) flags
|= SWP_NOMOVE
;
1110 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1111 hwnd
, (int)data
->window_rect
.left
, (int)data
->window_rect
.top
, x
, y
);
1113 if ((data
->window_rect
.right
- data
->window_rect
.left
== cx
&&
1114 data
->window_rect
.bottom
- data
->window_rect
.top
== cy
) ||
1115 IsRectEmpty( &data
->window_rect
))
1116 flags
|= SWP_NOSIZE
;
1118 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1119 hwnd
, (int)(data
->window_rect
.right
- data
->window_rect
.left
),
1120 (int)(data
->window_rect
.bottom
- data
->window_rect
.top
), cx
, cy
);
1122 style
= NtUserGetWindowLongW( data
->hwnd
, GWL_STYLE
);
1123 if ((style
& WS_CAPTION
) == WS_CAPTION
|| !NtUserIsWindowRectFullScreen( &data
->whole_rect
, dpi
))
1125 read_net_wm_states( event
->display
, data
);
1126 if ((data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1128 if (!(style
& WS_MAXIMIZE
))
1130 TRACE( "win %p/%lx is maximized\n", data
->hwnd
, data
->whole_window
);
1131 release_win_data( data
);
1132 send_message( data
->hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1136 else if (style
& WS_MAXIMIZE
)
1138 TRACE( "window %p/%lx is no longer maximized\n", data
->hwnd
, data
->whole_window
);
1139 release_win_data( data
);
1140 send_message( data
->hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1145 if ((flags
& (SWP_NOSIZE
| SWP_NOMOVE
)) != (SWP_NOSIZE
| SWP_NOMOVE
))
1147 release_win_data( data
);
1148 set_window_pos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
1153 release_win_data( data
);
1158 /**********************************************************************
1159 * X11DRV_GravityNotify
1161 static BOOL
X11DRV_GravityNotify( HWND hwnd
, XEvent
*xev
)
1163 XGravityEvent
*event
= &xev
->xgravity
;
1164 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1168 if (!data
) return FALSE
;
1170 if (data
->whole_window
) /* only handle this for foreign windows */
1172 release_win_data( data
);
1176 x
= event
->x
+ data
->window_rect
.left
- data
->whole_rect
.left
;
1177 y
= event
->y
+ data
->window_rect
.top
- data
->whole_rect
.top
;
1179 TRACE( "win %p/%lx new X pos %d,%d (event %d,%d)\n",
1180 hwnd
, data
->whole_window
, x
, y
, event
->x
, event
->y
);
1182 window_rect
= data
->window_rect
;
1183 release_win_data( data
);
1185 if (window_rect
.left
!= x
|| window_rect
.top
!= y
)
1186 set_window_pos( hwnd
, 0, x
, y
, 0, 0, SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
1192 /***********************************************************************
1193 * get_window_wm_state
1195 static int get_window_wm_state( Display
*display
, Window window
)
1203 int format
, ret
= -1;
1204 unsigned long count
, remaining
;
1206 if (!XGetWindowProperty( display
, window
, x11drv_atom(WM_STATE
), 0,
1207 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
1208 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
1210 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
1218 /***********************************************************************
1219 * handle_wm_state_notify
1221 * Handle a PropertyNotify for WM_STATE.
1223 static void handle_wm_state_notify( HWND hwnd
, XPropertyEvent
*event
, BOOL update_window
)
1225 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1230 switch(event
->state
)
1232 case PropertyDelete
:
1233 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
1234 data
->wm_state
= WithdrawnState
;
1236 case PropertyNewValue
:
1238 int old_state
= data
->wm_state
;
1239 int new_state
= get_window_wm_state( event
->display
, data
->whole_window
);
1240 if (new_state
!= -1 && new_state
!= data
->wm_state
)
1242 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1243 data
->hwnd
, data
->whole_window
, new_state
, old_state
);
1244 data
->wm_state
= new_state
;
1245 /* ignore the initial state transition out of withdrawn state */
1246 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1247 if (!old_state
) goto done
;
1253 if (!update_window
|| !data
->managed
|| !data
->mapped
) goto done
;
1255 style
= NtUserGetWindowLongW( data
->hwnd
, GWL_STYLE
);
1257 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
1259 data
->iconic
= FALSE
;
1260 read_net_wm_states( event
->display
, data
);
1261 if ((style
& WS_CAPTION
) == WS_CAPTION
&& (data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1263 if ((style
& WS_MAXIMIZEBOX
) && !(style
& WS_DISABLED
))
1265 TRACE( "restoring to max %p/%lx\n", data
->hwnd
, data
->whole_window
);
1266 release_win_data( data
);
1267 send_message( hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1270 TRACE( "not restoring to max win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1274 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1276 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1277 release_win_data( data
);
1278 if ((style
& (WS_MINIMIZE
| WS_VISIBLE
)) == (WS_MINIMIZE
| WS_VISIBLE
))
1279 NtUserSetActiveWindow( hwnd
);
1280 send_message( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1283 TRACE( "not restoring win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1286 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
1288 data
->iconic
= TRUE
;
1289 if ((style
& WS_MINIMIZEBOX
) && !(style
& WS_DISABLED
))
1291 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1292 release_win_data( data
);
1293 send_message( hwnd
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0 );
1296 TRACE( "not minimizing win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1299 release_win_data( data
);
1303 /***********************************************************************
1304 * X11DRV_PropertyNotify
1306 static BOOL
X11DRV_PropertyNotify( HWND hwnd
, XEvent
*xev
)
1308 XPropertyEvent
*event
= &xev
->xproperty
;
1310 if (!hwnd
) return FALSE
;
1311 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( hwnd
, event
, TRUE
);
1316 /* event filter to wait for a WM_STATE change notification on a window */
1317 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
1319 if (event
->xany
.window
!= (Window
)arg
) return 0;
1320 return (event
->type
== DestroyNotify
||
1321 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
1324 /***********************************************************************
1325 * wait_for_withdrawn_state
1327 void wait_for_withdrawn_state( HWND hwnd
, BOOL set
)
1329 Display
*display
= thread_display();
1330 struct x11drv_win_data
*data
;
1331 DWORD end
= NtGetTickCount() + 2000;
1333 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd
, set
? "" : "not " );
1341 if (!(data
= get_win_data( hwnd
))) break;
1342 if (!data
->managed
|| data
->embedded
|| data
->display
!= display
) break;
1343 if (!(window
= data
->whole_window
)) break;
1344 if (!data
->mapped
== !set
)
1346 TRACE( "window %p/%lx now %smapped\n", hwnd
, window
, data
->mapped
? "" : "un" );
1349 if ((data
->wm_state
== WithdrawnState
) != !set
)
1351 TRACE( "window %p/%lx state now %d\n", hwnd
, window
, data
->wm_state
);
1354 release_win_data( data
);
1356 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)window
))
1359 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
1360 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
1361 else handle_wm_state_notify( hwnd
, &event
.xproperty
, FALSE
);
1367 int timeout
= end
- NtGetTickCount();
1369 pfd
.fd
= ConnectionNumber(display
);
1370 pfd
.events
= POLLIN
;
1371 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
1373 FIXME( "window %p/%lx wait timed out\n", hwnd
, window
);
1378 release_win_data( data
);
1382 /*****************************************************************
1383 * SetFocus (X11DRV.@)
1387 void X11DRV_SetFocus( HWND hwnd
)
1389 struct x11drv_win_data
*data
;
1395 if (!(data
= get_win_data( hwnd
))) return;
1396 if (data
->embedded
) break;
1397 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1398 if (!parent
|| parent
== NtUserGetDesktopWindow()) break;
1399 release_win_data( data
);
1402 if (!data
->managed
|| data
->embedder
) set_input_focus( data
);
1403 release_win_data( data
);
1407 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
1409 UINT dpi
= get_win_monitor_dpi( hQueryWnd
);
1412 if (!NtUserIsWindowEnabled(hQueryWnd
)) return 0;
1414 NtUserGetWindowRect( hQueryWnd
, &tempRect
, dpi
);
1416 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
1418 if (!(NtUserGetWindowLongW( hQueryWnd
, GWL_STYLE
) & WS_MINIMIZE
))
1421 NtUserMapWindowPoints( 0, hQueryWnd
, &pt
, 1, 0 /* per-monitor DPI */ );
1422 NtUserGetClientRect( hQueryWnd
, &tempRect
, dpi
);
1424 if (PtInRect( &tempRect
, pt
))
1426 HWND ret
= child_window_from_point( hQueryWnd
, pt
.x
, pt
.y
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
1427 if (ret
&& ret
!= hQueryWnd
)
1429 ret
= find_drop_window( ret
, lpPt
);
1430 if (ret
) return ret
;
1435 if(!(NtUserGetWindowLongW( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
1437 NtUserMapWindowPoints( 0, hQueryWnd
, lpPt
, 1, 0 /* per-monitor DPI */ );
1442 static void post_drop( HWND hwnd
, DROPFILES
*drop
, ULONG size
)
1444 drop
->fWide
= HandleToUlong( hwnd
); /* abuse fWide to pass window handle */
1445 x11drv_client_func( client_func_dnd_post_drop
, drop
, size
);
1448 /**********************************************************************
1449 * EVENT_DropFromOffix
1451 * don't know if it still works (last Changelog is from 96/11/04)
1453 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1455 struct x11drv_win_data
*data
;
1457 unsigned long data_length
;
1458 unsigned long aux_long
;
1459 unsigned char* p_data
= NULL
;
1461 int x
, y
, cx
, cy
, dummy
, format
;
1462 Window win
, w_aux_root
, w_aux_child
;
1464 if (!(data
= get_win_data( hWnd
))) return;
1465 cx
= data
->whole_rect
.right
- data
->whole_rect
.left
;
1466 cy
= data
->whole_rect
.bottom
- data
->whole_rect
.top
;
1467 win
= data
->whole_window
;
1468 release_win_data( data
);
1470 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
1471 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
1472 pt
= root_to_virtual_screen( x
, y
);
1474 /* find out drop point and drop window */
1475 if (pt
.x
< 0 || pt
.y
< 0 || pt
.x
> cx
|| pt
.y
> cy
)
1477 if (!(NtUserGetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1482 if (!find_drop_window( hWnd
, &pt
)) return;
1485 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1486 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1487 AnyPropertyType
, &atom_aux
, &format
,
1488 &data_length
, &aux_long
, &p_data
);
1490 if (!aux_long
&& p_data
) /* don't bother if > 64K */
1495 drop
= file_list_to_drop_files( p_data
, get_property_size( format
, data_length
), &drop_size
);
1498 post_drop( hWnd
, drop
, drop_size
);
1503 if (p_data
) XFree(p_data
);
1506 /**********************************************************************
1509 * drop items are separated by \n
1510 * each item is prefixed by its mime type
1512 * event->data.l[3], event->data.l[4] contains drop x,y position
1514 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1516 struct x11drv_win_data
*win_data
;
1517 unsigned long data_length
;
1518 unsigned long aux_long
;
1519 unsigned char *p_data
= NULL
; /* property data */
1530 if (!(NtUserGetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1532 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1533 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1534 AnyPropertyType
, &u
.atom_aux
, &format
,
1535 &data_length
, &aux_long
, &p_data
);
1537 WARN("property too large, truncated!\n");
1538 TRACE("urls=%s\n", p_data
);
1540 if (!aux_long
&& p_data
) /* don't bother if > 64K */
1543 drop
= uri_list_to_drop_files( p_data
, get_property_size( format
, data_length
), &drop_size
);
1547 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1548 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1549 drop
->pt
= root_to_virtual_screen( x
, y
);
1551 if ((win_data
= get_win_data( hWnd
)))
1554 (drop
->pt
.x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1555 drop
->pt
.y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1556 drop
->pt
.x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1557 drop
->pt
.y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1558 release_win_data( win_data
);
1561 post_drop( hWnd
, drop
, drop_size
);
1565 if (p_data
) XFree( p_data
);
1569 /**********************************************************************
1570 * handle_xembed_protocol
1572 static void handle_xembed_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1574 switch (event
->data
.l
[1])
1576 case XEMBED_EMBEDDED_NOTIFY
:
1578 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1581 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd
, event
->window
, event
->data
.l
[3] );
1582 data
->embedder
= event
->data
.l
[3];
1584 /* window has been marked as embedded before (e.g. systray) */
1585 if (data
->embedded
|| !data
->embedder
/* broken QX11EmbedContainer implementation */)
1587 release_win_data( data
);
1591 make_window_embedded( data
);
1592 release_win_data( data
);
1593 reparent_notify( event
->display
, hwnd
, event
->data
.l
[3], 0, 0 );
1597 case XEMBED_WINDOW_DEACTIVATE
:
1598 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd
, event
->window
);
1599 focus_out( event
->display
, NtUserGetAncestor( hwnd
, GA_ROOT
) );
1602 case XEMBED_FOCUS_OUT
:
1603 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd
, event
->window
);
1604 focus_out( event
->display
, NtUserGetAncestor( hwnd
, GA_ROOT
) );
1607 case XEMBED_MODALITY_ON
:
1608 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd
, event
->window
);
1609 NtUserEnableWindow( hwnd
, FALSE
);
1612 case XEMBED_MODALITY_OFF
:
1613 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd
, event
->window
);
1614 NtUserEnableWindow( hwnd
, TRUE
);
1618 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1619 hwnd
, event
->window
, event
->data
.l
[1], event
->data
.l
[2] );
1625 /**********************************************************************
1626 * handle_dnd_protocol
1628 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1631 int root_x
, root_y
, child_x
, child_y
;
1634 /* query window (drag&drop event contains only drag window) */
1635 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1636 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1637 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1639 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1640 EVENT_DropFromOffiX(hwnd
, event
);
1641 else if (event
->data
.l
[0] == DndURL
)
1642 EVENT_DropURLs(hwnd
, event
);
1646 /**************************************************************************
1647 * handle_xdnd_enter_event
1649 * Handle an XdndEnter event.
1651 static void handle_xdnd_enter_event( HWND hWnd
, XClientMessageEvent
*event
)
1653 struct format_entry
*data
;
1654 unsigned long count
= 0;
1659 version
= (event
->data
.l
[1] & 0xFF000000) >> 24;
1661 TRACE( "ver(%d) check-XdndTypeList(%ld) data=%ld,%ld,%ld,%ld,%ld\n",
1662 version
, (event
->data
.l
[1] & 1),
1663 event
->data
.l
[0], event
->data
.l
[1], event
->data
.l
[2],
1664 event
->data
.l
[3], event
->data
.l
[4] );
1666 if (version
> WINE_XDND_VERSION
)
1668 ERR("ignoring unsupported XDND version %d\n", version
);
1672 /* If the source supports more than 3 data types we retrieve
1673 * the entire list. */
1674 if (event
->data
.l
[1] & 1)
1678 unsigned long bytesret
;
1680 /* Request supported formats from source window */
1681 XGetWindowProperty( event
->display
, event
->data
.l
[0], x11drv_atom(XdndTypeList
),
1682 0, 65535, FALSE
, AnyPropertyType
, &acttype
, &actfmt
, &count
,
1683 &bytesret
, (unsigned char **)&xdndtypes
);
1688 xdndtypes
= (Atom
*)&event
->data
.l
[2];
1695 for (i
= 0; i
< count
; i
++)
1697 if (xdndtypes
[i
] != 0)
1699 char * pn
= XGetAtomName( event
->display
, xdndtypes
[i
] );
1700 TRACE( "XDNDEnterAtom %ld: %s\n", xdndtypes
[i
], pn
);
1706 data
= import_xdnd_selection( event
->display
, event
->window
, x11drv_atom(XdndSelection
),
1707 xdndtypes
, count
, &size
);
1710 x11drv_client_func( client_func_dnd_enter_event
, data
, size
);
1714 if (event
->data
.l
[1] & 1)
1719 static DWORD
xdnd_action_to_drop_effect( long action
)
1721 /* In Windows, nothing but the given effects is allowed.
1722 * In X the given action is just a hint, and you can always
1723 * XdndActionCopy and XdndActionPrivate, so be more permissive. */
1724 if (action
== x11drv_atom(XdndActionCopy
))
1725 return DROPEFFECT_COPY
;
1726 else if (action
== x11drv_atom(XdndActionMove
))
1727 return DROPEFFECT_MOVE
| DROPEFFECT_COPY
;
1728 else if (action
== x11drv_atom(XdndActionLink
))
1729 return DROPEFFECT_LINK
| DROPEFFECT_COPY
;
1730 else if (action
== x11drv_atom(XdndActionAsk
))
1731 /* FIXME: should we somehow ask the user what to do here? */
1732 return DROPEFFECT_COPY
| DROPEFFECT_MOVE
| DROPEFFECT_LINK
;
1734 FIXME( "unknown action %ld, assuming DROPEFFECT_COPY\n", action
);
1735 return DROPEFFECT_COPY
;
1739 static long drop_effect_to_xdnd_action( UINT effect
)
1741 if (effect
== DROPEFFECT_COPY
)
1742 return x11drv_atom(XdndActionCopy
);
1743 else if (effect
== DROPEFFECT_MOVE
)
1744 return x11drv_atom(XdndActionMove
);
1745 else if (effect
== DROPEFFECT_LINK
)
1746 return x11drv_atom(XdndActionLink
);
1747 else if (effect
== DROPEFFECT_NONE
)
1750 FIXME( "unknown drop effect %u, assuming XdndActionCopy\n", effect
);
1751 return x11drv_atom(XdndActionCopy
);
1755 static void handle_xdnd_position_event( HWND hwnd
, XClientMessageEvent
*event
)
1757 struct dnd_position_event_params params
;
1758 XClientMessageEvent e
;
1763 params
.hwnd
= HandleToUlong( hwnd
);
1764 params
.point
= root_to_virtual_screen( event
->data
.l
[2] >> 16, event
->data
.l
[2] & 0xFFFF );
1765 params
.effect
= effect
= xdnd_action_to_drop_effect( event
->data
.l
[4] );
1767 if (KeUserModeCallback( client_func_dnd_position_event
, ¶ms
, sizeof(params
),
1768 &ret_ptr
, &ret_len
) || ret_len
!= sizeof(effect
))
1770 effect
= *(UINT
*)ret_ptr
;
1772 TRACE( "actionRequested(%ld) chosen(0x%x) at x(%d),y(%d)\n",
1773 event
->data
.l
[4], effect
, (int)params
.point
.x
, (int)params
.point
.y
);
1776 * Let source know if we're accepting the drop by
1777 * sending a status message.
1779 e
.type
= ClientMessage
;
1780 e
.display
= event
->display
;
1781 e
.window
= event
->data
.l
[0];
1782 e
.message_type
= x11drv_atom(XdndStatus
);
1784 e
.data
.l
[0] = event
->window
;
1785 e
.data
.l
[1] = !!effect
;
1786 e
.data
.l
[2] = 0; /* Empty Rect */
1787 e
.data
.l
[3] = 0; /* Empty Rect */
1788 e
.data
.l
[4] = drop_effect_to_xdnd_action( effect
);
1789 XSendEvent( event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
1793 static void handle_xdnd_drop_event( HWND hwnd
, XClientMessageEvent
*event
)
1795 XClientMessageEvent e
;
1798 ULONG arg
= HandleToUlong( hwnd
);
1801 if (KeUserModeCallback( client_func_dnd_drop_event
, &arg
, sizeof(arg
),
1802 &ret_ptr
, &ret_len
) || ret_len
!= sizeof(effect
))
1804 effect
= *(UINT
*)ret_ptr
;
1806 /* Tell the target we are finished. */
1807 memset( &e
, 0, sizeof(e
) );
1808 e
.type
= ClientMessage
;
1809 e
.display
= event
->display
;
1810 e
.window
= event
->data
.l
[0];
1811 e
.message_type
= x11drv_atom(XdndFinished
);
1813 e
.data
.l
[0] = event
->window
;
1814 e
.data
.l
[1] = !!effect
;
1815 e
.data
.l
[2] = drop_effect_to_xdnd_action( effect
);
1816 XSendEvent( event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
1820 static void handle_xdnd_leave_event( HWND hwnd
, XClientMessageEvent
*event
)
1822 x11drv_client_func( client_func_dnd_leave_event
, NULL
, 0 );
1826 struct client_message_handler
1828 int atom
; /* protocol atom */
1829 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1832 static const struct client_message_handler client_messages
[] =
1834 { XATOM_MANAGER
, handle_manager_message
},
1835 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1836 { XATOM__XEMBED
, handle_xembed_protocol
},
1837 { XATOM_DndProtocol
, handle_dnd_protocol
},
1838 { XATOM_XdndEnter
, handle_xdnd_enter_event
},
1839 { XATOM_XdndPosition
, handle_xdnd_position_event
},
1840 { XATOM_XdndDrop
, handle_xdnd_drop_event
},
1841 { XATOM_XdndLeave
, handle_xdnd_leave_event
}
1845 /**********************************************************************
1846 * X11DRV_ClientMessage
1848 static BOOL
X11DRV_ClientMessage( HWND hwnd
, XEvent
*xev
)
1850 XClientMessageEvent
*event
= &xev
->xclient
;
1853 if (!hwnd
) return FALSE
;
1855 if (event
->format
!= 32)
1857 WARN( "Don't know how to handle format %d\n", event
->format
);
1861 for (i
= 0; i
< ARRAY_SIZE( client_messages
); i
++)
1863 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1865 client_messages
[i
].handler( hwnd
, event
);
1869 TRACE( "no handler found for %ld\n", event
->message_type
);