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
)) != 0;
235 return (mask
& QS_MOUSEBUTTON
) != 0;
242 return (mask
& QS_MOUSEMOVE
) != 0;
244 return (mask
& QS_PAINT
) != 0;
249 case ConfigureNotify
:
252 return (mask
& QS_POSTMESSAGE
) != 0;
254 return (mask
& QS_SENDMESSAGE
) != 0;
259 enum event_merge_action
261 MERGE_DISCARD
, /* discard the old event */
262 MERGE_HANDLE
, /* handle the old event */
263 MERGE_KEEP
, /* keep the old event for future merging */
264 MERGE_IGNORE
/* ignore the new event, keep the old one */
267 /***********************************************************************
268 * merge_raw_motion_events
270 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
271 static enum event_merge_action
merge_raw_motion_events( XIRawEvent
*prev
, XIRawEvent
*next
)
276 if (!prev
->valuators
.mask_len
) return MERGE_HANDLE
;
277 if (!next
->valuators
.mask_len
) return MERGE_HANDLE
;
279 mask
= prev
->valuators
.mask
[0] | next
->valuators
.mask
[0];
280 if (mask
== next
->valuators
.mask
[0]) /* keep next */
282 for (i
= j
= k
= 0; i
< 8; i
++)
284 if (XIMaskIsSet( prev
->valuators
.mask
, i
))
285 next
->valuators
.values
[j
] += prev
->valuators
.values
[k
++];
286 if (XIMaskIsSet( next
->valuators
.mask
, i
)) j
++;
288 TRACE( "merging duplicate GenericEvent\n" );
289 return MERGE_DISCARD
;
291 if (mask
== prev
->valuators
.mask
[0]) /* keep prev */
293 for (i
= j
= k
= 0; i
< 8; i
++)
295 if (XIMaskIsSet( next
->valuators
.mask
, i
))
296 prev
->valuators
.values
[j
] += next
->valuators
.values
[k
++];
297 if (XIMaskIsSet( prev
->valuators
.mask
, i
)) j
++;
299 TRACE( "merging duplicate GenericEvent\n" );
302 /* can't merge events with disjoint masks */
307 /***********************************************************************
310 * Try to merge 2 consecutive events.
312 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
316 case ConfigureNotify
:
319 case ConfigureNotify
:
320 if (prev
->xany
.window
== next
->xany
.window
)
322 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev
->xany
.window
);
323 return MERGE_DISCARD
;
335 if (prev
->xany
.window
== next
->xany
.window
)
337 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
338 return MERGE_DISCARD
;
341 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
343 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
344 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
345 if (x11drv_thread_data()->warp_serial
) break;
350 if (prev
->xcookie
.extension
!= xinput2_opcode
) break;
351 if (prev
->xcookie
.evtype
!= XI_RawMotion
) break;
355 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
356 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
357 if (x11drv_thread_data()->warp_serial
) break;
358 return merge_raw_motion_events( prev
->xcookie
.data
, next
->xcookie
.data
);
367 /***********************************************************************
370 static inline BOOL
call_event_handler( Display
*display
, XEvent
*event
)
374 struct x11drv_thread_data
*thread_data
;
377 if (!handlers
[event
->type
])
379 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
->type
), event
->xany
.window
);
380 return FALSE
; /* no handler, ignore it */
384 if (event
->type
== GenericEvent
) hwnd
= 0; else
386 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hwnd
) != 0)
387 hwnd
= 0; /* not for a registered window */
388 if (!hwnd
&& event
->xany
.window
== root_window
) hwnd
= NtUserGetDesktopWindow();
390 TRACE( "%lu %s for hwnd/window %p/%lx\n",
391 event
->xany
.serial
, dbgstr_event( event
->type
), hwnd
, event
->xany
.window
);
392 thread_data
= x11drv_thread_data();
393 prev
= thread_data
->current_event
;
394 thread_data
->current_event
= event
;
395 ret
= handlers
[event
->type
]( hwnd
, event
);
396 thread_data
->current_event
= prev
;
401 /***********************************************************************
404 static BOOL
process_events( Display
*display
, Bool (*filter
)(Display
*, XEvent
*,XPointer
), ULONG_PTR arg
)
406 XEvent event
, prev_event
;
409 enum event_merge_action action
= MERGE_DISCARD
;
412 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
415 if (XFilterEvent( &event
, None
))
418 * SCIM on linux filters key events strangely. It does not filter the
419 * KeyPress events for these keys however it does filter the
420 * KeyRelease events. This causes wine to become very confused as
421 * to the keyboard state.
423 * We need to let those KeyRelease events be processed so that the
424 * keyboard state is correct.
426 if (event
.type
== KeyRelease
)
429 XKeyEvent
*keyevent
= &event
.xkey
;
431 XLookupString(keyevent
, NULL
, 0, &keysym
, NULL
);
432 if (!(keysym
== XK_Shift_L
||
433 keysym
== XK_Shift_R
||
434 keysym
== XK_Control_L
||
435 keysym
== XK_Control_R
||
436 keysym
== XK_Alt_R
||
437 keysym
== XK_Alt_L
||
438 keysym
== XK_Meta_R
||
439 keysym
== XK_Meta_L
))
440 continue; /* not a key we care about, ignore it */
443 continue; /* filtered, ignore it */
445 get_event_data( &event
);
446 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
449 case MERGE_HANDLE
: /* handle prev, keep new */
450 queued
|= call_event_handler( display
, &prev_event
);
452 case MERGE_DISCARD
: /* discard prev, keep new */
453 free_event_data( &prev_event
);
456 case MERGE_KEEP
: /* handle new, keep prev for future merging */
457 queued
|= call_event_handler( display
, &event
);
459 case MERGE_IGNORE
: /* ignore new, keep prev for future merging */
460 free_event_data( &event
);
464 if (prev_event
.type
) queued
|= call_event_handler( display
, &prev_event
);
465 free_event_data( &prev_event
);
466 XFlush( gdi_display
);
467 if (count
) TRACE( "processed %d events, returning %d\n", count
, queued
);
472 /***********************************************************************
473 * ProcessEvents (X11DRV.@)
475 BOOL
X11DRV_ProcessEvents( DWORD mask
)
477 struct x11drv_thread_data
*data
= x11drv_thread_data();
479 if (!data
) return FALSE
;
480 if (data
->current_event
) mask
= 0; /* don't process nested events */
482 return process_events( data
->display
, filter_event
, mask
);
485 /***********************************************************************
486 * EVENT_x11_time_to_win32_time
488 * Make our timer and the X timer line up as best we can
489 * Pass 0 to retrieve the current adjustment value (times -1)
491 DWORD
EVENT_x11_time_to_win32_time(Time time
)
493 static DWORD adjust
= 0;
494 DWORD now
= NtGetTickCount();
497 if (! adjust
&& time
!= 0)
504 /* If we got an event in the 'future', then our clock is clearly wrong.
505 If we got it more than 10000 ms in the future, then it's most likely
506 that the clock has wrapped. */
509 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
520 /*******************************************************************
521 * can_activate_window
523 * Check if we can activate the specified window.
525 static inline BOOL
can_activate_window( HWND hwnd
)
527 LONG style
= NtUserGetWindowLongW( hwnd
, GWL_STYLE
);
530 if (!(style
& WS_VISIBLE
)) return FALSE
;
531 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
532 if (style
& WS_MINIMIZE
) return FALSE
;
533 if (NtUserGetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_NOACTIVATE
) return FALSE
;
534 if (hwnd
== NtUserGetDesktopWindow()) return FALSE
;
535 if (NtUserGetWindowRect( hwnd
, &rect
) && IsRectEmpty( &rect
)) return FALSE
;
536 return !(style
& WS_DISABLED
);
540 /**********************************************************************
543 * Try to force focus for embedded or non-managed windows.
545 static void set_input_focus( struct x11drv_win_data
*data
)
547 XWindowChanges changes
;
550 if (!data
->whole_window
) return;
552 if (EVENT_x11_time_to_win32_time(0))
553 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
554 /* FIXME: this is not entirely correct */
555 timestamp
= NtUserGetThreadInfo()->message_time
- EVENT_x11_time_to_win32_time(0);
557 timestamp
= CurrentTime
;
559 /* Set X focus and install colormap */
560 changes
.stack_mode
= Above
;
561 XConfigureWindow( data
->display
, data
->whole_window
, CWStackMode
, &changes
);
564 xembed_request_focus( data
->display
, data
->embedder
, timestamp
);
566 XSetInputFocus( data
->display
, data
->whole_window
, RevertToParent
, timestamp
);
570 /**********************************************************************
573 static void set_focus( Display
*display
, HWND hwnd
, Time time
)
577 GUITHREADINFO threadinfo
;
579 TRACE( "setting foreground window to %p\n", hwnd
);
580 NtUserSetForegroundWindow( hwnd
);
582 threadinfo
.cbSize
= sizeof(threadinfo
);
583 NtUserGetGUIThreadInfo( 0, &threadinfo
);
584 focus
= threadinfo
.hwndFocus
;
585 if (!focus
) focus
= threadinfo
.hwndActive
;
586 if (focus
) focus
= NtUserGetAncestor( focus
, GA_ROOT
);
587 win
= X11DRV_get_whole_window(focus
);
591 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
592 XSetInputFocus( display
, win
, RevertToParent
, time
);
597 /**********************************************************************
598 * handle_manager_message
600 static void handle_manager_message( HWND hwnd
, XClientMessageEvent
*event
)
602 if (hwnd
!= NtUserGetDesktopWindow()) return;
604 if (systray_atom
&& event
->data
.l
[1] == systray_atom
)
606 struct systray_change_owner_params params
;
608 TRACE( "new owner %lx\n", event
->data
.l
[2] );
610 params
.event_handle
= (UINT_PTR
)event
;
611 x11drv_client_func( client_func_systray_change_owner
, ¶ms
, sizeof(params
) );
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 /**********************************************************************
752 static BOOL
X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
754 XFocusChangeEvent
*event
= &xev
->xfocus
;
756 if (!hwnd
) return FALSE
;
758 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
], focus_modes
[event
->mode
] );
760 if (event
->detail
== NotifyPointer
) return FALSE
;
761 if (hwnd
== NtUserGetDesktopWindow()) return FALSE
;
766 /* these are received when moving undecorated managed windows on mutter */
767 keyboard_grabbed
= TRUE
;
769 case NotifyWhileGrabbed
:
770 keyboard_grabbed
= TRUE
;
773 keyboard_grabbed
= FALSE
;
776 keyboard_grabbed
= FALSE
;
777 retry_grab_clipping_window();
778 return TRUE
; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
781 xim_set_focus( hwnd
, TRUE
);
785 if (hwnd
== NtUserGetForegroundWindow()) clip_fullscreen_window( hwnd
, FALSE
);
789 if (!can_activate_window(hwnd
))
791 HWND hwnd
= get_focus();
792 if (hwnd
) hwnd
= NtUserGetAncestor( hwnd
, GA_ROOT
);
793 if (!hwnd
) hwnd
= get_active_window();
794 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
795 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, CurrentTime
);
797 else NtUserSetForegroundWindow( hwnd
);
801 /**********************************************************************
804 static void focus_out( Display
*display
, HWND hwnd
)
810 if (xim_in_compose_mode()) return;
812 x11drv_thread_data()->last_focus
= hwnd
;
813 xim_set_focus( hwnd
, FALSE
);
815 if (is_virtual_desktop())
817 if (hwnd
== NtUserGetDesktopWindow()) reset_clipping_window();
820 if (hwnd
!= NtUserGetForegroundWindow()) return;
821 if (!(NtUserGetWindowLongW( hwnd
, GWL_STYLE
) & WS_MINIMIZE
))
822 send_message( hwnd
, WM_CANCELMODE
, 0, 0 );
824 /* don't reset the foreground window, if the window which is
825 getting the focus is a Wine window */
827 XGetInputFocus( display
, &focus_win
, &revert
);
830 if (XFindContext( display
, focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
836 /* Abey : 6-Oct-99. Check again if the focus out window is the
837 Foreground window, because in most cases the messages sent
838 above must have already changed the foreground window, in which
839 case we don't have to change the foreground window to 0 */
840 if (hwnd
== NtUserGetForegroundWindow())
842 TRACE( "lost focus, setting fg to desktop\n" );
843 NtUserSetForegroundWindow( NtUserGetDesktopWindow() );
848 /**********************************************************************
851 * Note: only top-level windows get FocusOut events.
853 static BOOL
X11DRV_FocusOut( HWND hwnd
, XEvent
*xev
)
855 XFocusChangeEvent
*event
= &xev
->xfocus
;
857 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
], focus_modes
[event
->mode
] );
859 if (event
->detail
== NotifyPointer
)
861 if (!hwnd
&& event
->window
== x11drv_thread_data()->clip_window
) reset_clipping_window();
864 if (!hwnd
) return FALSE
;
869 /* these are received when moving undecorated managed windows on mutter */
870 keyboard_grabbed
= FALSE
;
873 keyboard_grabbed
= FALSE
;
875 case NotifyWhileGrabbed
:
876 keyboard_grabbed
= TRUE
;
879 keyboard_grabbed
= TRUE
;
881 /* This will do nothing due to keyboard_grabbed == TRUE, but it
882 * will save the current clipping rect so we can restore it on
883 * FocusIn with NotifyUngrab mode.
885 retry_grab_clipping_window();
887 return TRUE
; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
890 focus_out( event
->display
, hwnd
);
895 /***********************************************************************
898 static BOOL
X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
900 XExposeEvent
*event
= &xev
->xexpose
;
903 struct x11drv_win_data
*data
;
904 HRGN surface_region
= 0;
905 UINT flags
= RDW_INVALIDATE
| RDW_ERASE
| RDW_FRAME
| RDW_ALLCHILDREN
;
907 TRACE( "win %p (%lx) %d,%d %dx%d\n",
908 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
910 if (event
->window
!= root_window
)
915 else pos
= root_to_virtual_screen( event
->x
, event
->y
);
917 if (!(data
= get_win_data( hwnd
))) return FALSE
;
921 rect
.right
= pos
.x
+ event
->width
;
922 rect
.bottom
= pos
.y
+ event
->height
;
924 if (event
->window
!= data
->client_window
)
928 surface_region
= expose_surface( data
->surface
, &rect
);
929 if (!surface_region
) flags
= 0;
930 else NtGdiOffsetRgn( surface_region
, data
->whole_rect
.left
- data
->client_rect
.left
,
931 data
->whole_rect
.top
- data
->client_rect
.top
);
933 if (data
->vis
.visualid
!= default_visual
.visualid
)
934 data
->surface
->funcs
->flush( data
->surface
);
936 OffsetRect( &rect
, data
->whole_rect
.left
- data
->client_rect
.left
,
937 data
->whole_rect
.top
- data
->client_rect
.top
);
940 if (event
->window
!= root_window
)
942 if (NtUserGetWindowLongW( data
->hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
943 mirror_rect( &data
->client_rect
, &rect
);
945 NtUserMapWindowPoints( hwnd
, 0, (POINT
*)&abs_rect
, 2 );
947 SERVER_START_REQ( update_window_zorder
)
949 req
->window
= wine_server_user_handle( hwnd
);
950 req
->rect
.left
= abs_rect
.left
;
951 req
->rect
.top
= abs_rect
.top
;
952 req
->rect
.right
= abs_rect
.right
;
953 req
->rect
.bottom
= abs_rect
.bottom
;
954 wine_server_call( req
);
958 else flags
&= ~RDW_ALLCHILDREN
;
960 release_win_data( data
);
962 if (flags
) NtUserRedrawWindow( hwnd
, &rect
, surface_region
, flags
);
963 if (surface_region
) NtGdiDeleteObjectApp( surface_region
);
968 /**********************************************************************
971 static BOOL
X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
973 struct x11drv_win_data
*data
;
975 if (event
->xany
.window
== x11drv_thread_data()->clip_window
) return TRUE
;
977 if (!(data
= get_win_data( hwnd
))) return FALSE
;
979 if (!data
->managed
&& !data
->embedded
&& data
->mapped
)
981 HWND hwndFocus
= get_focus();
982 if (hwndFocus
&& NtUserIsChild( hwnd
, hwndFocus
))
983 set_input_focus( data
);
985 release_win_data( data
);
990 /**********************************************************************
993 static BOOL
X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
)
999 /***********************************************************************
1002 static void reparent_notify( Display
*display
, HWND hwnd
, Window xparent
, int x
, int y
)
1004 HWND parent
, old_parent
;
1007 style
= NtUserGetWindowLongW( hwnd
, GWL_STYLE
);
1008 if (xparent
== root_window
)
1010 parent
= NtUserGetDesktopWindow();
1011 style
= (style
& ~WS_CHILD
) | WS_POPUP
;
1015 if (!(parent
= create_foreign_window( display
, xparent
))) return;
1016 style
= (style
& ~WS_POPUP
) | WS_CHILD
;
1019 NtUserShowWindow( hwnd
, SW_HIDE
);
1020 old_parent
= NtUserSetParent( hwnd
, parent
);
1021 NtUserSetWindowLong( hwnd
, GWL_STYLE
, style
, FALSE
);
1022 NtUserSetWindowPos( hwnd
, HWND_TOP
, x
, y
, 0, 0,
1023 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOCOPYBITS
|
1024 ((style
& WS_VISIBLE
) ? SWP_SHOWWINDOW
: 0) );
1026 /* make old parent destroy itself if it no longer has children */
1027 if (old_parent
!= NtUserGetDesktopWindow()) NtUserPostMessage( old_parent
, WM_CLOSE
, 0, 0 );
1031 /***********************************************************************
1032 * X11DRV_ReparentNotify
1034 static BOOL
X11DRV_ReparentNotify( HWND hwnd
, XEvent
*xev
)
1036 XReparentEvent
*event
= &xev
->xreparent
;
1037 struct x11drv_win_data
*data
;
1039 if (!(data
= get_win_data( hwnd
))) return FALSE
;
1041 if (!data
->embedded
)
1043 release_win_data( data
);
1047 if (data
->whole_window
)
1049 if (event
->parent
== root_window
)
1051 TRACE( "%p/%lx reparented to root\n", hwnd
, data
->whole_window
);
1053 release_win_data( data
);
1054 send_message( hwnd
, WM_CLOSE
, 0, 0 );
1057 data
->embedder
= event
->parent
;
1060 TRACE( "%p/%lx reparented to %lx\n", hwnd
, data
->whole_window
, event
->parent
);
1061 release_win_data( data
);
1063 reparent_notify( event
->display
, hwnd
, event
->parent
, event
->x
, event
->y
);
1068 /***********************************************************************
1069 * X11DRV_ConfigureNotify
1071 static BOOL
X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
1073 XConfigureEvent
*event
= &xev
->xconfigure
;
1074 struct x11drv_win_data
*data
;
1080 int cx
, cy
, x
= event
->x
, y
= event
->y
;
1083 if (!hwnd
) return FALSE
;
1084 if (!(data
= get_win_data( hwnd
))) return FALSE
;
1085 if (!data
->mapped
|| data
->iconic
) goto done
;
1086 if (data
->whole_window
&& !data
->managed
) goto done
;
1087 /* ignore synthetic events on foreign windows */
1088 if (event
->send_event
&& !data
->whole_window
) goto done
;
1089 if (data
->configure_serial
&& (long)(data
->configure_serial
- event
->serial
) > 0)
1091 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1092 hwnd
, data
->whole_window
, event
->x
, event
->y
, event
->width
, event
->height
,
1093 event
->serial
, data
->configure_serial
);
1099 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1100 root_coords
= event
->send_event
; /* synthetic events are always in root coords */
1102 if (!root_coords
&& parent
== NtUserGetDesktopWindow()) /* normal event, map coordinates to the root */
1105 XTranslateCoordinates( event
->display
, event
->window
, root_window
,
1106 0, 0, &x
, &y
, &child
);
1115 else pos
= root_to_virtual_screen( x
, y
);
1117 X11DRV_X_to_window_rect( data
, &rect
, pos
.x
, pos
.y
, event
->width
, event
->height
);
1118 if (root_coords
) NtUserMapWindowPoints( 0, parent
, (POINT
*)&rect
, 2 );
1120 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1121 hwnd
, data
->whole_window
, (int)rect
.left
, (int)rect
.top
,
1122 (int)(rect
.right
-rect
.left
), (int)(rect
.bottom
-rect
.top
),
1123 event
->x
, event
->y
, event
->width
, event
->height
);
1125 /* Compare what has changed */
1129 cx
= rect
.right
- rect
.left
;
1130 cy
= rect
.bottom
- rect
.top
;
1131 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
1133 if (!data
->whole_window
) flags
|= SWP_NOCOPYBITS
; /* we can't copy bits of foreign windows */
1135 if (data
->window_rect
.left
== x
&& data
->window_rect
.top
== y
) flags
|= SWP_NOMOVE
;
1137 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1138 hwnd
, (int)data
->window_rect
.left
, (int)data
->window_rect
.top
, x
, y
);
1140 if ((data
->window_rect
.right
- data
->window_rect
.left
== cx
&&
1141 data
->window_rect
.bottom
- data
->window_rect
.top
== cy
) ||
1142 IsRectEmpty( &data
->window_rect
))
1143 flags
|= SWP_NOSIZE
;
1145 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1146 hwnd
, (int)(data
->window_rect
.right
- data
->window_rect
.left
),
1147 (int)(data
->window_rect
.bottom
- data
->window_rect
.top
), cx
, cy
);
1149 style
= NtUserGetWindowLongW( data
->hwnd
, GWL_STYLE
);
1150 if ((style
& WS_CAPTION
) == WS_CAPTION
|| !NtUserIsWindowRectFullScreen( &data
->whole_rect
))
1152 read_net_wm_states( event
->display
, data
);
1153 if ((data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1155 if (!(style
& WS_MAXIMIZE
))
1157 TRACE( "win %p/%lx is maximized\n", data
->hwnd
, data
->whole_window
);
1158 release_win_data( data
);
1159 send_message( data
->hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1163 else if (style
& WS_MAXIMIZE
)
1165 TRACE( "window %p/%lx is no longer maximized\n", data
->hwnd
, data
->whole_window
);
1166 release_win_data( data
);
1167 send_message( data
->hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1172 if ((flags
& (SWP_NOSIZE
| SWP_NOMOVE
)) != (SWP_NOSIZE
| SWP_NOMOVE
))
1174 release_win_data( data
);
1175 NtUserSetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
1180 release_win_data( data
);
1185 /**********************************************************************
1186 * X11DRV_GravityNotify
1188 static BOOL
X11DRV_GravityNotify( HWND hwnd
, XEvent
*xev
)
1190 XGravityEvent
*event
= &xev
->xgravity
;
1191 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1195 if (!data
) return FALSE
;
1197 if (data
->whole_window
) /* only handle this for foreign windows */
1199 release_win_data( data
);
1203 x
= event
->x
+ data
->window_rect
.left
- data
->whole_rect
.left
;
1204 y
= event
->y
+ data
->window_rect
.top
- data
->whole_rect
.top
;
1206 TRACE( "win %p/%lx new X pos %d,%d (event %d,%d)\n",
1207 hwnd
, data
->whole_window
, x
, y
, event
->x
, event
->y
);
1209 window_rect
= data
->window_rect
;
1210 release_win_data( data
);
1212 if (window_rect
.left
!= x
|| window_rect
.top
!= y
)
1213 NtUserSetWindowPos( hwnd
, 0, x
, y
, 0, 0, SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
1219 /***********************************************************************
1220 * get_window_wm_state
1222 static int get_window_wm_state( Display
*display
, Window window
)
1230 int format
, ret
= -1;
1231 unsigned long count
, remaining
;
1233 if (!XGetWindowProperty( display
, window
, x11drv_atom(WM_STATE
), 0,
1234 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
1235 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
1237 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
1245 /***********************************************************************
1246 * handle_wm_state_notify
1248 * Handle a PropertyNotify for WM_STATE.
1250 static void handle_wm_state_notify( HWND hwnd
, XPropertyEvent
*event
, BOOL update_window
)
1252 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1257 switch(event
->state
)
1259 case PropertyDelete
:
1260 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
1261 data
->wm_state
= WithdrawnState
;
1263 case PropertyNewValue
:
1265 int old_state
= data
->wm_state
;
1266 int new_state
= get_window_wm_state( event
->display
, data
->whole_window
);
1267 if (new_state
!= -1 && new_state
!= data
->wm_state
)
1269 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1270 data
->hwnd
, data
->whole_window
, new_state
, old_state
);
1271 data
->wm_state
= new_state
;
1272 /* ignore the initial state transition out of withdrawn state */
1273 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1274 if (!old_state
) goto done
;
1280 if (!update_window
|| !data
->managed
|| !data
->mapped
) goto done
;
1282 style
= NtUserGetWindowLongW( data
->hwnd
, GWL_STYLE
);
1284 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
1286 data
->iconic
= FALSE
;
1287 read_net_wm_states( event
->display
, data
);
1288 if ((style
& WS_CAPTION
) == WS_CAPTION
&& (data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1290 if ((style
& WS_MAXIMIZEBOX
) && !(style
& WS_DISABLED
))
1292 TRACE( "restoring to max %p/%lx\n", data
->hwnd
, data
->whole_window
);
1293 release_win_data( data
);
1294 send_message( hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1297 TRACE( "not restoring to max win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1301 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1303 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1304 release_win_data( data
);
1305 if ((style
& (WS_MINIMIZE
| WS_VISIBLE
)) == (WS_MINIMIZE
| WS_VISIBLE
))
1306 NtUserSetActiveWindow( hwnd
);
1307 send_message( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1310 TRACE( "not restoring win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1313 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
1315 data
->iconic
= TRUE
;
1316 if ((style
& WS_MINIMIZEBOX
) && !(style
& WS_DISABLED
))
1318 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1319 release_win_data( data
);
1320 send_message( hwnd
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0 );
1323 TRACE( "not minimizing win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1326 release_win_data( data
);
1330 /***********************************************************************
1331 * X11DRV_PropertyNotify
1333 static BOOL
X11DRV_PropertyNotify( HWND hwnd
, XEvent
*xev
)
1335 XPropertyEvent
*event
= &xev
->xproperty
;
1337 if (!hwnd
) return FALSE
;
1338 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( hwnd
, event
, TRUE
);
1343 /* event filter to wait for a WM_STATE change notification on a window */
1344 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
1346 if (event
->xany
.window
!= (Window
)arg
) return 0;
1347 return (event
->type
== DestroyNotify
||
1348 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
1351 /***********************************************************************
1352 * wait_for_withdrawn_state
1354 void wait_for_withdrawn_state( HWND hwnd
, BOOL set
)
1356 Display
*display
= thread_display();
1357 struct x11drv_win_data
*data
;
1358 DWORD end
= NtGetTickCount() + 2000;
1360 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd
, set
? "" : "not " );
1368 if (!(data
= get_win_data( hwnd
))) break;
1369 if (!data
->managed
|| data
->embedded
|| data
->display
!= display
) break;
1370 if (!(window
= data
->whole_window
)) break;
1371 if (!data
->mapped
== !set
)
1373 TRACE( "window %p/%lx now %smapped\n", hwnd
, window
, data
->mapped
? "" : "un" );
1376 if ((data
->wm_state
== WithdrawnState
) != !set
)
1378 TRACE( "window %p/%lx state now %d\n", hwnd
, window
, data
->wm_state
);
1381 release_win_data( data
);
1383 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)window
))
1386 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
1387 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
1388 else handle_wm_state_notify( hwnd
, &event
.xproperty
, FALSE
);
1394 int timeout
= end
- NtGetTickCount();
1396 pfd
.fd
= ConnectionNumber(display
);
1397 pfd
.events
= POLLIN
;
1398 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
1400 FIXME( "window %p/%lx wait timed out\n", hwnd
, window
);
1405 release_win_data( data
);
1409 /*****************************************************************
1410 * SetFocus (X11DRV.@)
1414 void X11DRV_SetFocus( HWND hwnd
)
1416 struct x11drv_win_data
*data
;
1422 if (!(data
= get_win_data( hwnd
))) return;
1423 if (data
->embedded
) break;
1424 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1425 if (!parent
|| parent
== NtUserGetDesktopWindow()) break;
1426 release_win_data( data
);
1429 if (!data
->managed
|| data
->embedder
) set_input_focus( data
);
1430 release_win_data( data
);
1434 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
1438 if (!NtUserIsWindowEnabled(hQueryWnd
)) return 0;
1440 NtUserGetWindowRect(hQueryWnd
, &tempRect
);
1442 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
1444 if (!(NtUserGetWindowLongW( hQueryWnd
, GWL_STYLE
) & WS_MINIMIZE
))
1447 NtUserScreenToClient( hQueryWnd
, &pt
);
1448 NtUserGetClientRect( hQueryWnd
, &tempRect
);
1450 if (PtInRect( &tempRect
, pt
))
1452 HWND ret
= NtUserChildWindowFromPointEx( hQueryWnd
, pt
.x
, pt
.y
,
1453 CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
1454 if (ret
&& ret
!= hQueryWnd
)
1456 ret
= find_drop_window( ret
, lpPt
);
1457 if (ret
) return ret
;
1462 if(!(NtUserGetWindowLongW( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
1464 NtUserScreenToClient( hQueryWnd
, lpPt
);
1469 static void post_drop( HWND hwnd
, DROPFILES
*drop
, ULONG size
)
1471 drop
->fWide
= HandleToUlong( hwnd
); /* abuse fWide to pass window handle */
1472 x11drv_client_func( client_func_dnd_post_drop
, drop
, size
);
1475 /**********************************************************************
1476 * EVENT_DropFromOffix
1478 * don't know if it still works (last Changelog is from 96/11/04)
1480 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1482 struct x11drv_win_data
*data
;
1484 unsigned long data_length
;
1485 unsigned long aux_long
;
1486 unsigned char* p_data
= NULL
;
1488 int x
, y
, cx
, cy
, dummy
, format
;
1489 Window win
, w_aux_root
, w_aux_child
;
1491 if (!(data
= get_win_data( hWnd
))) return;
1492 cx
= data
->whole_rect
.right
- data
->whole_rect
.left
;
1493 cy
= data
->whole_rect
.bottom
- data
->whole_rect
.top
;
1494 win
= data
->whole_window
;
1495 release_win_data( data
);
1497 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
1498 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
1499 pt
= root_to_virtual_screen( x
, y
);
1501 /* find out drop point and drop window */
1502 if (pt
.x
< 0 || pt
.y
< 0 || pt
.x
> cx
|| pt
.y
> cy
)
1504 if (!(NtUserGetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1509 if (!find_drop_window( hWnd
, &pt
)) return;
1512 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1513 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1514 AnyPropertyType
, &atom_aux
, &format
,
1515 &data_length
, &aux_long
, &p_data
);
1517 if (!aux_long
&& p_data
) /* don't bother if > 64K */
1522 drop
= file_list_to_drop_files( p_data
, get_property_size( format
, data_length
), &drop_size
);
1525 post_drop( hWnd
, drop
, drop_size
);
1530 if (p_data
) XFree(p_data
);
1533 /**********************************************************************
1536 * drop items are separated by \n
1537 * each item is prefixed by its mime type
1539 * event->data.l[3], event->data.l[4] contains drop x,y position
1541 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1543 struct x11drv_win_data
*win_data
;
1544 unsigned long data_length
;
1545 unsigned long aux_long
;
1546 unsigned char *p_data
= NULL
; /* property data */
1557 if (!(NtUserGetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1559 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1560 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1561 AnyPropertyType
, &u
.atom_aux
, &format
,
1562 &data_length
, &aux_long
, &p_data
);
1564 WARN("property too large, truncated!\n");
1565 TRACE("urls=%s\n", p_data
);
1567 if (!aux_long
&& p_data
) /* don't bother if > 64K */
1570 drop
= uri_list_to_drop_files( p_data
, get_property_size( format
, data_length
), &drop_size
);
1574 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1575 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1576 drop
->pt
= root_to_virtual_screen( x
, y
);
1578 if ((win_data
= get_win_data( hWnd
)))
1581 (drop
->pt
.x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1582 drop
->pt
.y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1583 drop
->pt
.x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1584 drop
->pt
.y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1585 release_win_data( win_data
);
1588 post_drop( hWnd
, drop
, drop_size
);
1592 if (p_data
) XFree( p_data
);
1596 /**********************************************************************
1597 * handle_xembed_protocol
1599 static void handle_xembed_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1601 switch (event
->data
.l
[1])
1603 case XEMBED_EMBEDDED_NOTIFY
:
1605 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1608 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd
, event
->window
, event
->data
.l
[3] );
1609 data
->embedder
= event
->data
.l
[3];
1611 /* window has been marked as embedded before (e.g. systray) */
1612 if (data
->embedded
|| !data
->embedder
/* broken QX11EmbedContainer implementation */)
1614 release_win_data( data
);
1618 make_window_embedded( data
);
1619 release_win_data( data
);
1620 reparent_notify( event
->display
, hwnd
, event
->data
.l
[3], 0, 0 );
1624 case XEMBED_WINDOW_DEACTIVATE
:
1625 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd
, event
->window
);
1626 focus_out( event
->display
, NtUserGetAncestor( hwnd
, GA_ROOT
) );
1629 case XEMBED_FOCUS_OUT
:
1630 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd
, event
->window
);
1631 focus_out( event
->display
, NtUserGetAncestor( hwnd
, GA_ROOT
) );
1634 case XEMBED_MODALITY_ON
:
1635 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd
, event
->window
);
1636 NtUserEnableWindow( hwnd
, FALSE
);
1639 case XEMBED_MODALITY_OFF
:
1640 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd
, event
->window
);
1641 NtUserEnableWindow( hwnd
, TRUE
);
1645 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1646 hwnd
, event
->window
, event
->data
.l
[1], event
->data
.l
[2] );
1652 /**********************************************************************
1653 * handle_dnd_protocol
1655 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1658 int root_x
, root_y
, child_x
, child_y
;
1661 /* query window (drag&drop event contains only drag window) */
1662 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1663 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1664 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1666 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1667 EVENT_DropFromOffiX(hwnd
, event
);
1668 else if (event
->data
.l
[0] == DndURL
)
1669 EVENT_DropURLs(hwnd
, event
);
1673 /**************************************************************************
1674 * handle_xdnd_enter_event
1676 * Handle an XdndEnter event.
1678 static void handle_xdnd_enter_event( HWND hWnd
, XClientMessageEvent
*event
)
1680 struct format_entry
*data
;
1681 unsigned long count
= 0;
1686 version
= (event
->data
.l
[1] & 0xFF000000) >> 24;
1688 TRACE( "ver(%d) check-XdndTypeList(%ld) data=%ld,%ld,%ld,%ld,%ld\n",
1689 version
, (event
->data
.l
[1] & 1),
1690 event
->data
.l
[0], event
->data
.l
[1], event
->data
.l
[2],
1691 event
->data
.l
[3], event
->data
.l
[4] );
1693 if (version
> WINE_XDND_VERSION
)
1695 ERR("ignoring unsupported XDND version %d\n", version
);
1699 /* If the source supports more than 3 data types we retrieve
1700 * the entire list. */
1701 if (event
->data
.l
[1] & 1)
1705 unsigned long bytesret
;
1707 /* Request supported formats from source window */
1708 XGetWindowProperty( event
->display
, event
->data
.l
[0], x11drv_atom(XdndTypeList
),
1709 0, 65535, FALSE
, AnyPropertyType
, &acttype
, &actfmt
, &count
,
1710 &bytesret
, (unsigned char **)&xdndtypes
);
1715 xdndtypes
= (Atom
*)&event
->data
.l
[2];
1722 for (i
= 0; i
< count
; i
++)
1724 if (xdndtypes
[i
] != 0)
1726 char * pn
= XGetAtomName( event
->display
, xdndtypes
[i
] );
1727 TRACE( "XDNDEnterAtom %ld: %s\n", xdndtypes
[i
], pn
);
1733 data
= import_xdnd_selection( event
->display
, event
->window
, x11drv_atom(XdndSelection
),
1734 xdndtypes
, count
, &size
);
1737 x11drv_client_func( client_func_dnd_enter_event
, data
, size
);
1741 if (event
->data
.l
[1] & 1)
1746 static DWORD
xdnd_action_to_drop_effect( long action
)
1748 /* In Windows, nothing but the given effects is allowed.
1749 * In X the given action is just a hint, and you can always
1750 * XdndActionCopy and XdndActionPrivate, so be more permissive. */
1751 if (action
== x11drv_atom(XdndActionCopy
))
1752 return DROPEFFECT_COPY
;
1753 else if (action
== x11drv_atom(XdndActionMove
))
1754 return DROPEFFECT_MOVE
| DROPEFFECT_COPY
;
1755 else if (action
== x11drv_atom(XdndActionLink
))
1756 return DROPEFFECT_LINK
| DROPEFFECT_COPY
;
1757 else if (action
== x11drv_atom(XdndActionAsk
))
1758 /* FIXME: should we somehow ask the user what to do here? */
1759 return DROPEFFECT_COPY
| DROPEFFECT_MOVE
| DROPEFFECT_LINK
;
1761 FIXME( "unknown action %ld, assuming DROPEFFECT_COPY\n", action
);
1762 return DROPEFFECT_COPY
;
1766 static long drop_effect_to_xdnd_action( UINT effect
)
1768 if (effect
== DROPEFFECT_COPY
)
1769 return x11drv_atom(XdndActionCopy
);
1770 else if (effect
== DROPEFFECT_MOVE
)
1771 return x11drv_atom(XdndActionMove
);
1772 else if (effect
== DROPEFFECT_LINK
)
1773 return x11drv_atom(XdndActionLink
);
1774 else if (effect
== DROPEFFECT_NONE
)
1777 FIXME( "unknown drop effect %u, assuming XdndActionCopy\n", effect
);
1778 return x11drv_atom(XdndActionCopy
);
1782 static void handle_xdnd_position_event( HWND hwnd
, XClientMessageEvent
*event
)
1784 struct dnd_position_event_params params
;
1785 XClientMessageEvent e
;
1788 params
.hwnd
= HandleToUlong( hwnd
);
1789 params
.point
= root_to_virtual_screen( event
->data
.l
[2] >> 16, event
->data
.l
[2] & 0xFFFF );
1790 params
.effect
= effect
= xdnd_action_to_drop_effect( event
->data
.l
[4] );
1792 effect
= x11drv_client_func( client_func_dnd_position_event
, ¶ms
, sizeof(params
) );
1794 TRACE( "actionRequested(%ld) chosen(0x%x) at x(%d),y(%d)\n",
1795 event
->data
.l
[4], effect
, (int)params
.point
.x
, (int)params
.point
.y
);
1798 * Let source know if we're accepting the drop by
1799 * sending a status message.
1801 e
.type
= ClientMessage
;
1802 e
.display
= event
->display
;
1803 e
.window
= event
->data
.l
[0];
1804 e
.message_type
= x11drv_atom(XdndStatus
);
1806 e
.data
.l
[0] = event
->window
;
1807 e
.data
.l
[1] = !!effect
;
1808 e
.data
.l
[2] = 0; /* Empty Rect */
1809 e
.data
.l
[3] = 0; /* Empty Rect */
1810 e
.data
.l
[4] = drop_effect_to_xdnd_action( effect
);
1811 XSendEvent( event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
1815 static void handle_xdnd_drop_event( HWND hwnd
, XClientMessageEvent
*event
)
1817 XClientMessageEvent e
;
1820 effect
= x11drv_client_call( client_dnd_drop_event
, HandleToUlong( hwnd
));
1822 /* Tell the target we are finished. */
1823 memset( &e
, 0, sizeof(e
) );
1824 e
.type
= ClientMessage
;
1825 e
.display
= event
->display
;
1826 e
.window
= event
->data
.l
[0];
1827 e
.message_type
= x11drv_atom(XdndFinished
);
1829 e
.data
.l
[0] = event
->window
;
1830 e
.data
.l
[1] = !!effect
;
1831 e
.data
.l
[2] = drop_effect_to_xdnd_action( effect
);
1832 XSendEvent( event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
1836 static void handle_xdnd_leave_event( HWND hwnd
, XClientMessageEvent
*event
)
1838 x11drv_client_call( client_dnd_leave_event
, 0 );
1842 struct client_message_handler
1844 int atom
; /* protocol atom */
1845 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1848 static const struct client_message_handler client_messages
[] =
1850 { XATOM_MANAGER
, handle_manager_message
},
1851 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1852 { XATOM__XEMBED
, handle_xembed_protocol
},
1853 { XATOM_DndProtocol
, handle_dnd_protocol
},
1854 { XATOM_XdndEnter
, handle_xdnd_enter_event
},
1855 { XATOM_XdndPosition
, handle_xdnd_position_event
},
1856 { XATOM_XdndDrop
, handle_xdnd_drop_event
},
1857 { XATOM_XdndLeave
, handle_xdnd_leave_event
}
1861 /**********************************************************************
1862 * X11DRV_ClientMessage
1864 static BOOL
X11DRV_ClientMessage( HWND hwnd
, XEvent
*xev
)
1866 XClientMessageEvent
*event
= &xev
->xclient
;
1869 if (!hwnd
) return FALSE
;
1871 if (event
->format
!= 32)
1873 WARN( "Don't know how to handle format %d\n", event
->format
);
1877 for (i
= 0; i
< ARRAY_SIZE( client_messages
); i
++)
1879 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1881 client_messages
[i
].handler( hwnd
, event
);
1885 TRACE( "no handler found for %ld\n", event
->message_type
);