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 extern BOOL ximInComposeMode
;
54 #define DndNotDnd -1 /* OffiX drag&drop */
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
;
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
;
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
);
178 /***********************************************************************
179 * xembed_request_focus
181 static void xembed_request_focus( Display
*display
, Window window
, DWORD timestamp
)
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
);
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 /***********************************************************************
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;
234 return (mask
& (QS_KEY
|QS_HOTKEY
)) != 0;
237 return (mask
& QS_MOUSEBUTTON
) != 0;
244 return (mask
& QS_MOUSEMOVE
) != 0;
246 return (mask
& QS_PAINT
) != 0;
251 case ConfigureNotify
:
254 return (mask
& QS_POSTMESSAGE
) != 0;
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
)
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" );
304 /* can't merge events with disjoint masks */
309 /***********************************************************************
312 * Try to merge 2 consecutive events.
314 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
318 case ConfigureNotify
:
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
;
337 if (prev
->xany
.window
== next
->xany
.window
)
339 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
340 return MERGE_DISCARD
;
343 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
345 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
346 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
347 if (x11drv_thread_data()->warp_serial
) break;
352 if (prev
->xcookie
.extension
!= xinput2_opcode
) break;
353 if (prev
->xcookie
.evtype
!= XI_RawMotion
) break;
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
);
369 /***********************************************************************
372 static inline BOOL
call_event_handler( Display
*display
, XEvent
*event
)
376 struct x11drv_thread_data
*thread_data
;
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 */
386 if (event
->type
== GenericEvent
) hwnd
= 0; else
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
;
403 /***********************************************************************
406 static BOOL
process_events( Display
*display
, Bool (*filter
)(Display
*, XEvent
*,XPointer
), ULONG_PTR arg
)
408 XEvent event
, prev_event
;
411 enum event_merge_action action
= MERGE_DISCARD
;
414 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
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
)
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 */
445 continue; /* filtered, ignore it */
447 get_event_data( &event
);
448 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
451 case MERGE_HANDLE
: /* handle prev, keep new */
452 queued
|= call_event_handler( display
, &prev_event
);
454 case MERGE_DISCARD
: /* discard prev, keep new */
455 free_event_data( &prev_event
);
458 case MERGE_KEEP
: /* handle new, keep prev for future merging */
459 queued
|= call_event_handler( display
, &event
);
461 case MERGE_IGNORE
: /* ignore new, keep prev for future merging */
462 free_event_data( &event
);
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
);
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();
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
;
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();
516 if (! adjust
&& time
!= 0)
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. */
528 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
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
);
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 /**********************************************************************
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
;
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);
576 timestamp
= CurrentTime
;
578 /* Set X focus and install colormap */
579 changes
.stack_mode
= Above
;
580 XConfigureWindow( data
->display
, data
->whole_window
, CWStackMode
, &changes
);
583 xembed_request_focus( data
->display
, data
->embedder
, timestamp
);
585 XSetInputFocus( data
->display
, data
->whole_window
, RevertToParent
, timestamp
);
589 /**********************************************************************
592 static void set_focus( Display
*display
, HWND hwnd
, Time time
)
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
);
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
, ¶ms
, 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 );
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
))
665 if (NtUserGetClassLongW( hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
666 hSysMenu
= NtUserGetSystemMenu( hwnd
, FALSE
);
669 UINT state
= NtUserThunkedMenuItemInfo( hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
,
670 NtUserGetMenuState
, NULL
, NULL
);
671 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
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
) );
681 case MA_NOACTIVATEANDEAT
:
682 case MA_ACTIVATEANDEAT
:
688 NtUserSetActiveWindow( hwnd
);
691 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
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
);
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
);
728 /* try to find some other window to give the focus to */
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
;
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
[] =
753 "NotifyNonlinearVirtual",
759 static const char * const focus_modes
[] =
767 /**********************************************************************
770 static BOOL
X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
772 XFocusChangeEvent
*event
= &xev
->xfocus
;
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
;
785 /* these are received when moving undecorated managed windows on mutter */
786 keyboard_grabbed
= TRUE
;
788 case NotifyWhileGrabbed
:
789 keyboard_grabbed
= TRUE
;
792 keyboard_grabbed
= FALSE
;
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
);
803 if (hwnd
== NtUserGetForegroundWindow()) clip_fullscreen_window( hwnd
, FALSE
);
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
);
819 /**********************************************************************
822 static void focus_out( Display
*display
, HWND hwnd
)
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();
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
);
849 if (XFindContext( display
, focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
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 /**********************************************************************
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();
883 if (!hwnd
) return FALSE
;
888 /* these are received when moving undecorated managed windows on mutter */
889 keyboard_grabbed
= FALSE
;
892 keyboard_grabbed
= FALSE
;
894 case NotifyWhileGrabbed
:
895 keyboard_grabbed
= TRUE
;
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
);
914 /***********************************************************************
917 static BOOL
X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
919 XExposeEvent
*event
= &xev
->xexpose
;
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
)
934 else pos
= root_to_virtual_screen( event
->x
, event
->y
);
936 if (!(data
= get_win_data( hwnd
))) return FALSE
;
940 rect
.right
= pos
.x
+ event
->width
;
941 rect
.bottom
= pos
.y
+ event
->height
;
943 if (event
->window
!= data
->client_window
)
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
);
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
);
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
);
987 /**********************************************************************
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
);
1009 /**********************************************************************
1010 * X11DRV_UnmapNotify
1012 static BOOL
X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
)
1018 /***********************************************************************
1021 static void reparent_notify( Display
*display
, HWND hwnd
, Window xparent
, int x
, int y
)
1023 HWND parent
, old_parent
;
1026 style
= NtUserGetWindowLongW( hwnd
, GWL_STYLE
);
1027 if (xparent
== root_window
)
1029 parent
= NtUserGetDesktopWindow();
1030 style
= (style
& ~WS_CHILD
) | WS_POPUP
;
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
);
1066 if (data
->whole_window
)
1068 if (event
->parent
== root_window
)
1070 TRACE( "%p/%lx reparented to root\n", hwnd
, data
->whole_window
);
1072 release_win_data( data
);
1073 send_message( hwnd
, WM_CLOSE
, 0, 0 );
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
);
1087 /***********************************************************************
1088 * X11DRV_ConfigureNotify
1090 static BOOL
X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
1092 XConfigureEvent
*event
= &xev
->xconfigure
;
1093 struct x11drv_win_data
*data
;
1099 int cx
, cy
, x
= event
->x
, y
= event
->y
;
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
);
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 */
1124 XTranslateCoordinates( event
->display
, event
->window
, root_window
,
1125 0, 0, &x
, &y
, &child
);
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 */
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
;
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
;
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 );
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 );
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
);
1198 release_win_data( data
);
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
);
1213 if (!data
) return FALSE
;
1215 if (data
->whole_window
) /* only handle this for foreign windows */
1217 release_win_data( data
);
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
);
1237 /***********************************************************************
1238 * get_window_wm_state
1240 static int get_window_wm_state( Display
*display
, Window window
)
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
))
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
);
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
;
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
;
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 );
1315 TRACE( "not restoring to max win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
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 );
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 );
1341 TRACE( "not minimizing win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
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
);
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 " );
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" );
1394 if ((data
->wm_state
== WithdrawnState
) != !set
)
1396 TRACE( "window %p/%lx state now %d\n", hwnd
, window
, data
->wm_state
);
1399 release_win_data( data
);
1401 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)window
))
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
);
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
);
1423 release_win_data( data
);
1427 /*****************************************************************
1428 * SetFocus (X11DRV.@)
1432 void X11DRV_SetFocus( HWND hwnd
)
1434 struct x11drv_win_data
*data
;
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
);
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
)
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
))
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
);
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
;
1502 unsigned long data_length
;
1503 unsigned long aux_long
;
1504 unsigned char* p_data
= NULL
;
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;
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 */
1540 drop
= file_list_to_drop_files( p_data
, get_property_size( format
, data_length
), &drop_size
);
1543 post_drop( hWnd
, drop
, drop_size
);
1548 if (p_data
) XFree(p_data
);
1551 /**********************************************************************
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 */
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
);
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 */
1588 drop
= uri_list_to_drop_files( p_data
, get_property_size( format
, data_length
), &drop_size
);
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
)))
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
);
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
);
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
);
1636 make_window_embedded( data
);
1637 release_win_data( data
);
1638 reparent_notify( event
->display
, hwnd
, event
->data
.l
[3], 0, 0 );
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
) );
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
) );
1652 case XEMBED_MODALITY_ON
:
1653 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd
, event
->window
);
1654 NtUserEnableWindow( hwnd
, FALSE
);
1657 case XEMBED_MODALITY_OFF
:
1658 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd
, event
->window
);
1659 NtUserEnableWindow( hwnd
, TRUE
);
1663 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1664 hwnd
, event
->window
, event
->data
.l
[1], event
->data
.l
[2] );
1670 /**********************************************************************
1671 * handle_dnd_protocol
1673 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1676 int root_x
, root_y
, child_x
, child_y
;
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;
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;
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
);
1717 /* If the source supports more than 3 data types we retrieve
1718 * the entire list. */
1719 if (event
->data
.l
[1] & 1)
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
);
1733 xdndtypes
= (Atom
*)&event
->data
.l
[2];
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
);
1751 data
= import_xdnd_selection( event
->display
, event
->window
, x11drv_atom(XdndSelection
),
1752 xdndtypes
, count
, &size
);
1755 x11drv_client_func( client_func_dnd_enter_event
, data
, size
);
1759 if (event
->data
.l
[1] & 1)
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
)
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
;
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
, ¶ms
, 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
);
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
;
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
);
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
;
1887 if (!hwnd
) return FALSE
;
1889 if (event
->format
!= 32)
1891 WARN( "Don't know how to handle format %d\n", event
->format
);
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
);
1903 TRACE( "no handler found for %ld\n", event
->message_type
);