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
27 #ifdef HAVE_SYS_POLL_H
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
35 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
36 #include <X11/extensions/XInput2.h>
50 /* avoid conflict with field names in included win32 headers */
52 #include "shlobj.h" /* DROPFILES */
55 #include "wine/server.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(event
);
60 extern BOOL ximInComposeMode
;
62 #define DndNotDnd -1 /* OffiX drag&drop */
74 #define DndURL 128 /* KDE drag&drop */
76 #define XEMBED_EMBEDDED_NOTIFY 0
77 #define XEMBED_WINDOW_ACTIVATE 1
78 #define XEMBED_WINDOW_DEACTIVATE 2
79 #define XEMBED_REQUEST_FOCUS 3
80 #define XEMBED_FOCUS_IN 4
81 #define XEMBED_FOCUS_OUT 5
82 #define XEMBED_FOCUS_NEXT 6
83 #define XEMBED_FOCUS_PREV 7
84 #define XEMBED_MODALITY_ON 10
85 #define XEMBED_MODALITY_OFF 11
86 #define XEMBED_REGISTER_ACCELERATOR 12
87 #define XEMBED_UNREGISTER_ACCELERATOR 13
88 #define XEMBED_ACTIVATE_ACCELERATOR 14
90 Bool (*pXGetEventData
)( Display
*display
, XEvent
/*XGenericEventCookie*/ *event
) = NULL
;
91 void (*pXFreeEventData
)( Display
*display
, XEvent
/*XGenericEventCookie*/ *event
) = NULL
;
94 static BOOL
X11DRV_FocusIn( HWND hwnd
, XEvent
*event
);
95 static BOOL
X11DRV_FocusOut( HWND hwnd
, XEvent
*event
);
96 static BOOL
X11DRV_Expose( HWND hwnd
, XEvent
*event
);
97 static BOOL
X11DRV_MapNotify( HWND hwnd
, XEvent
*event
);
98 static BOOL
X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
);
99 static BOOL
X11DRV_ReparentNotify( HWND hwnd
, XEvent
*event
);
100 static BOOL
X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*event
);
101 static BOOL
X11DRV_PropertyNotify( HWND hwnd
, XEvent
*event
);
102 static BOOL
X11DRV_ClientMessage( HWND hwnd
, XEvent
*event
);
103 static BOOL
X11DRV_GravityNotify( HWND hwnd
, XEvent
*event
);
105 #define MAX_EVENT_HANDLERS 128
107 static x11drv_event_handler handlers
[MAX_EVENT_HANDLERS
] =
109 NULL
, /* 0 reserved */
110 NULL
, /* 1 reserved */
111 X11DRV_KeyEvent
, /* 2 KeyPress */
112 X11DRV_KeyEvent
, /* 3 KeyRelease */
113 X11DRV_ButtonPress
, /* 4 ButtonPress */
114 X11DRV_ButtonRelease
, /* 5 ButtonRelease */
115 X11DRV_MotionNotify
, /* 6 MotionNotify */
116 X11DRV_EnterNotify
, /* 7 EnterNotify */
117 NULL
, /* 8 LeaveNotify */
118 X11DRV_FocusIn
, /* 9 FocusIn */
119 X11DRV_FocusOut
, /* 10 FocusOut */
120 X11DRV_KeymapNotify
, /* 11 KeymapNotify */
121 X11DRV_Expose
, /* 12 Expose */
122 NULL
, /* 13 GraphicsExpose */
123 NULL
, /* 14 NoExpose */
124 NULL
, /* 15 VisibilityNotify */
125 NULL
, /* 16 CreateNotify */
126 X11DRV_DestroyNotify
, /* 17 DestroyNotify */
127 X11DRV_UnmapNotify
, /* 18 UnmapNotify */
128 X11DRV_MapNotify
, /* 19 MapNotify */
129 NULL
, /* 20 MapRequest */
130 X11DRV_ReparentNotify
, /* 21 ReparentNotify */
131 X11DRV_ConfigureNotify
, /* 22 ConfigureNotify */
132 NULL
, /* 23 ConfigureRequest */
133 X11DRV_GravityNotify
, /* 24 GravityNotify */
134 NULL
, /* 25 ResizeRequest */
135 NULL
, /* 26 CirculateNotify */
136 NULL
, /* 27 CirculateRequest */
137 X11DRV_PropertyNotify
, /* 28 PropertyNotify */
138 X11DRV_SelectionClear
, /* 29 SelectionClear */
139 X11DRV_SelectionRequest
, /* 30 SelectionRequest */
140 NULL
, /* 31 SelectionNotify */
141 NULL
, /* 32 ColormapNotify */
142 X11DRV_ClientMessage
, /* 33 ClientMessage */
143 X11DRV_MappingNotify
, /* 34 MappingNotify */
144 X11DRV_GenericEvent
/* 35 GenericEvent */
147 static const char * event_names
[MAX_EVENT_HANDLERS
] =
149 NULL
, NULL
, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
150 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
151 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
152 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
153 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
154 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
155 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
158 /* is someone else grabbing the keyboard, for example the WM, when manipulating the window */
159 BOOL keyboard_grabbed
= FALSE
;
161 int xinput2_opcode
= 0;
163 /* return the name of an X event */
164 static const char *dbgstr_event( int type
)
166 if (type
< MAX_EVENT_HANDLERS
&& event_names
[type
]) return event_names
[type
];
167 return wine_dbg_sprintf( "Unknown event %d", type
);
170 static inline void get_event_data( XEvent
*event
)
172 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
173 if (event
->xany
.type
!= GenericEvent
) return;
174 if (!pXGetEventData
|| !pXGetEventData( event
->xany
.display
, event
)) event
->xcookie
.data
= NULL
;
178 static inline void free_event_data( XEvent
*event
)
180 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
181 if (event
->xany
.type
!= GenericEvent
) return;
182 if (event
->xcookie
.data
) pXFreeEventData( event
->xany
.display
, event
);
186 /***********************************************************************
187 * xembed_request_focus
189 static void xembed_request_focus( Display
*display
, Window window
, DWORD timestamp
)
193 xev
.xclient
.type
= ClientMessage
;
194 xev
.xclient
.window
= window
;
195 xev
.xclient
.message_type
= x11drv_atom(_XEMBED
);
196 xev
.xclient
.serial
= 0;
197 xev
.xclient
.display
= display
;
198 xev
.xclient
.send_event
= True
;
199 xev
.xclient
.format
= 32;
201 xev
.xclient
.data
.l
[0] = timestamp
;
202 xev
.xclient
.data
.l
[1] = XEMBED_REQUEST_FOCUS
;
203 xev
.xclient
.data
.l
[2] = 0;
204 xev
.xclient
.data
.l
[3] = 0;
205 xev
.xclient
.data
.l
[4] = 0;
207 XSendEvent(display
, window
, False
, NoEventMask
, &xev
);
211 /***********************************************************************
212 * X11DRV_register_event_handler
214 * Register a handler for a given event type.
215 * If already registered, overwrite the previous handler.
217 void X11DRV_register_event_handler( int type
, x11drv_event_handler handler
, const char *name
)
219 assert( type
< MAX_EVENT_HANDLERS
);
220 assert( !handlers
[type
] || handlers
[type
] == handler
);
221 handlers
[type
] = handler
;
222 event_names
[type
] = name
;
223 TRACE("registered handler %p for event %d %s\n", handler
, type
, debugstr_a(name
) );
227 /***********************************************************************
230 static Bool
filter_event( Display
*display
, XEvent
*event
, char *arg
)
232 ULONG_PTR mask
= (ULONG_PTR
)arg
;
234 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return 1;
242 return (mask
& (QS_KEY
|QS_HOTKEY
)) != 0;
245 return (mask
& QS_MOUSEBUTTON
) != 0;
252 return (mask
& QS_MOUSEMOVE
) != 0;
254 return (mask
& QS_PAINT
) != 0;
259 case ConfigureNotify
:
262 return (mask
& QS_POSTMESSAGE
) != 0;
264 return (mask
& QS_SENDMESSAGE
) != 0;
269 enum event_merge_action
271 MERGE_DISCARD
, /* discard the old event */
272 MERGE_HANDLE
, /* handle the old event */
273 MERGE_KEEP
, /* keep the old event for future merging */
274 MERGE_IGNORE
/* ignore the new event, keep the old one */
277 /***********************************************************************
278 * merge_raw_motion_events
280 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
281 static enum event_merge_action
merge_raw_motion_events( XIRawEvent
*prev
, XIRawEvent
*next
)
286 if (!prev
->valuators
.mask_len
) return MERGE_HANDLE
;
287 if (!next
->valuators
.mask_len
) return MERGE_HANDLE
;
289 mask
= prev
->valuators
.mask
[0] | next
->valuators
.mask
[0];
290 if (mask
== next
->valuators
.mask
[0]) /* keep next */
292 for (i
= j
= k
= 0; i
< 8; i
++)
294 if (XIMaskIsSet( prev
->valuators
.mask
, i
))
295 next
->valuators
.values
[j
] += prev
->valuators
.values
[k
++];
296 if (XIMaskIsSet( next
->valuators
.mask
, i
)) j
++;
298 TRACE( "merging duplicate GenericEvent\n" );
299 return MERGE_DISCARD
;
301 if (mask
== prev
->valuators
.mask
[0]) /* keep prev */
303 for (i
= j
= k
= 0; i
< 8; i
++)
305 if (XIMaskIsSet( next
->valuators
.mask
, i
))
306 prev
->valuators
.values
[j
] += next
->valuators
.values
[k
++];
307 if (XIMaskIsSet( prev
->valuators
.mask
, i
)) j
++;
309 TRACE( "merging duplicate GenericEvent\n" );
312 /* can't merge events with disjoint masks */
317 /***********************************************************************
320 * Try to merge 2 consecutive events.
322 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
326 case ConfigureNotify
:
329 case ConfigureNotify
:
330 if (prev
->xany
.window
== next
->xany
.window
)
332 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev
->xany
.window
);
333 return MERGE_DISCARD
;
345 if (prev
->xany
.window
== next
->xany
.window
)
347 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
348 return MERGE_DISCARD
;
351 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
353 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
354 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
355 if (x11drv_thread_data()->warp_serial
) break;
360 if (prev
->xcookie
.extension
!= xinput2_opcode
) break;
361 if (prev
->xcookie
.evtype
!= XI_RawMotion
) break;
365 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
366 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
367 if (x11drv_thread_data()->warp_serial
) break;
368 return merge_raw_motion_events( prev
->xcookie
.data
, next
->xcookie
.data
);
377 /***********************************************************************
380 static inline BOOL
call_event_handler( Display
*display
, XEvent
*event
)
384 struct x11drv_thread_data
*thread_data
;
387 if (!handlers
[event
->type
])
389 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
->type
), event
->xany
.window
);
390 return FALSE
; /* no handler, ignore it */
394 if (event
->type
== GenericEvent
) hwnd
= 0; else
396 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hwnd
) != 0)
397 hwnd
= 0; /* not for a registered window */
398 if (!hwnd
&& event
->xany
.window
== root_window
) hwnd
= GetDesktopWindow();
400 TRACE( "%lu %s for hwnd/window %p/%lx\n",
401 event
->xany
.serial
, dbgstr_event( event
->type
), hwnd
, event
->xany
.window
);
402 thread_data
= x11drv_thread_data();
403 prev
= thread_data
->current_event
;
404 thread_data
->current_event
= event
;
405 ret
= handlers
[event
->type
]( hwnd
, event
);
406 thread_data
->current_event
= prev
;
411 /***********************************************************************
414 static BOOL
process_events( Display
*display
, Bool (*filter
)(Display
*, XEvent
*,XPointer
), ULONG_PTR arg
)
416 XEvent event
, prev_event
;
419 enum event_merge_action action
= MERGE_DISCARD
;
422 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
425 if (XFilterEvent( &event
, None
))
428 * SCIM on linux filters key events strangely. It does not filter the
429 * KeyPress events for these keys however it does filter the
430 * KeyRelease events. This causes wine to become very confused as
431 * to the keyboard state.
433 * We need to let those KeyRelease events be processed so that the
434 * keyboard state is correct.
436 if (event
.type
== KeyRelease
)
439 XKeyEvent
*keyevent
= &event
.xkey
;
441 XLookupString(keyevent
, NULL
, 0, &keysym
, NULL
);
442 if (!(keysym
== XK_Shift_L
||
443 keysym
== XK_Shift_R
||
444 keysym
== XK_Control_L
||
445 keysym
== XK_Control_R
||
446 keysym
== XK_Alt_R
||
447 keysym
== XK_Alt_L
||
448 keysym
== XK_Meta_R
||
449 keysym
== XK_Meta_L
))
450 continue; /* not a key we care about, ignore it */
453 continue; /* filtered, ignore it */
455 get_event_data( &event
);
456 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
459 case MERGE_HANDLE
: /* handle prev, keep new */
460 queued
|= call_event_handler( display
, &prev_event
);
462 case MERGE_DISCARD
: /* discard prev, keep new */
463 free_event_data( &prev_event
);
466 case MERGE_KEEP
: /* handle new, keep prev for future merging */
467 queued
|= call_event_handler( display
, &event
);
469 case MERGE_IGNORE
: /* ignore new, keep prev for future merging */
470 free_event_data( &event
);
474 if (prev_event
.type
) queued
|= call_event_handler( display
, &prev_event
);
475 free_event_data( &prev_event
);
476 XFlush( gdi_display
);
477 if (count
) TRACE( "processed %d events, returning %d\n", count
, queued
);
482 /***********************************************************************
483 * MsgWaitForMultipleObjectsEx (X11DRV.@)
485 DWORD CDECL
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
486 DWORD timeout
, DWORD mask
, DWORD flags
)
489 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
493 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
494 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
495 timeout
, flags
& MWMO_ALERTABLE
);
498 if (data
->current_event
) mask
= 0; /* don't process nested events */
500 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
501 else if (count
|| timeout
)
503 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
504 timeout
, flags
& MWMO_ALERTABLE
);
505 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
507 else ret
= WAIT_TIMEOUT
;
512 /***********************************************************************
513 * EVENT_x11_time_to_win32_time
515 * Make our timer and the X timer line up as best we can
516 * Pass 0 to retrieve the current adjustment value (times -1)
518 DWORD
EVENT_x11_time_to_win32_time(Time time
)
520 static DWORD adjust
= 0;
521 DWORD now
= GetTickCount();
524 if (! adjust
&& time
!= 0)
531 /* If we got an event in the 'future', then our clock is clearly wrong.
532 If we got it more than 10000 ms in the future, then it's most likely
533 that the clock has wrapped. */
536 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
547 /*******************************************************************
548 * can_activate_window
550 * Check if we can activate the specified window.
552 static inline BOOL
can_activate_window( HWND hwnd
)
554 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
557 if (!(style
& WS_VISIBLE
)) return FALSE
;
558 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
559 if (style
& WS_MINIMIZE
) return FALSE
;
560 if (GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_NOACTIVATE
) return FALSE
;
561 if (hwnd
== GetDesktopWindow()) return FALSE
;
562 if (GetWindowRect( hwnd
, &rect
) && IsRectEmpty( &rect
)) return FALSE
;
563 return !(style
& WS_DISABLED
);
567 /**********************************************************************
570 * Try to force focus for embedded or non-managed windows.
572 static void set_input_focus( struct x11drv_win_data
*data
)
574 XWindowChanges changes
;
577 if (!data
->whole_window
) return;
579 if (EVENT_x11_time_to_win32_time(0))
580 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
581 /* FIXME: this is not entirely correct */
582 timestamp
= GetMessageTime() - EVENT_x11_time_to_win32_time(0);
584 timestamp
= CurrentTime
;
586 /* Set X focus and install colormap */
587 changes
.stack_mode
= Above
;
588 XConfigureWindow( data
->display
, data
->whole_window
, CWStackMode
, &changes
);
591 xembed_request_focus( data
->display
, data
->embedder
, timestamp
);
593 XSetInputFocus( data
->display
, data
->whole_window
, RevertToParent
, timestamp
);
597 /**********************************************************************
600 static void set_focus( Display
*display
, HWND hwnd
, Time time
)
604 GUITHREADINFO threadinfo
;
606 TRACE( "setting foreground window to %p\n", hwnd
);
607 SetForegroundWindow( hwnd
);
609 threadinfo
.cbSize
= sizeof(threadinfo
);
610 GetGUIThreadInfo(0, &threadinfo
);
611 focus
= threadinfo
.hwndFocus
;
612 if (!focus
) focus
= threadinfo
.hwndActive
;
613 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
614 win
= X11DRV_get_whole_window(focus
);
618 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
619 XSetInputFocus( display
, win
, RevertToParent
, time
);
624 /**********************************************************************
625 * handle_manager_message
627 static void handle_manager_message( HWND hwnd
, XClientMessageEvent
*event
)
629 if (hwnd
!= GetDesktopWindow()) return;
630 if (systray_atom
&& event
->data
.l
[1] == systray_atom
)
631 change_systray_owner( event
->display
, event
->data
.l
[2] );
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
== GetDesktopWindow())
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 SendMessageW(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 (IsWindowEnabled(hwnd
))
665 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
666 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
669 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
670 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
673 if (GetActiveWindow() != hwnd
)
675 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
676 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
677 MAKELPARAM( HTCLOSE
, WM_NCLBUTTONDOWN
) );
680 case MA_NOACTIVATEANDEAT
:
681 case MA_ACTIVATEANDEAT
:
687 SetActiveWindow(hwnd
);
690 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
695 PostMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
698 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
700 HWND last_focus
= x11drv_thread_data()->last_focus
;
702 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
703 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
704 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
706 if (can_activate_window(hwnd
))
708 /* simulate a mouse click on the menu to find out
709 * whether the window wants to be activated */
710 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
711 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
712 MAKELONG( HTMENU
, WM_LBUTTONDOWN
) );
713 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
715 set_focus( event
->display
, hwnd
, event_time
);
719 else if (hwnd
== GetDesktopWindow())
721 hwnd
= GetForegroundWindow();
722 if (!hwnd
) hwnd
= last_focus
;
723 if (!hwnd
) hwnd
= GetDesktopWindow();
724 set_focus( event
->display
, hwnd
, event_time
);
727 /* try to find some other window to give the focus to */
729 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
730 if (!hwnd
) hwnd
= GetActiveWindow();
731 if (!hwnd
) hwnd
= last_focus
;
732 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, event_time
);
734 else if (protocol
== x11drv_atom(_NET_WM_PING
))
736 XClientMessageEvent xev
;
739 TRACE("NET_WM Ping\n");
740 xev
.window
= DefaultRootWindow(xev
.display
);
741 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
746 static const char * const focus_details
[] =
752 "NotifyNonlinearVirtual",
758 static const char * const focus_modes
[] =
766 /**********************************************************************
769 static BOOL
X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
771 XFocusChangeEvent
*event
= &xev
->xfocus
;
774 if (!hwnd
) return FALSE
;
776 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
], focus_modes
[event
->mode
] );
778 if (event
->detail
== NotifyPointer
) return FALSE
;
779 if (hwnd
== GetDesktopWindow()) return FALSE
;
784 /* these are received when moving undecorated managed windows on mutter */
785 keyboard_grabbed
= TRUE
;
787 case NotifyWhileGrabbed
:
788 keyboard_grabbed
= TRUE
;
791 keyboard_grabbed
= FALSE
;
794 keyboard_grabbed
= FALSE
;
795 retry_grab_clipping_window();
796 return TRUE
; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
799 if ((xic
= X11DRV_get_ic( hwnd
))) XSetICFocus( xic
);
802 if (hwnd
== GetForegroundWindow()) clip_fullscreen_window( hwnd
, FALSE
);
806 if (!can_activate_window(hwnd
))
808 HWND hwnd
= GetFocus();
809 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
810 if (!hwnd
) hwnd
= GetActiveWindow();
811 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
812 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, CurrentTime
);
814 else SetForegroundWindow( hwnd
);
818 /**********************************************************************
821 static void focus_out( Display
*display
, HWND hwnd
)
828 if (ximInComposeMode
) return;
830 x11drv_thread_data()->last_focus
= hwnd
;
831 if ((xic
= X11DRV_get_ic( hwnd
))) XUnsetICFocus( xic
);
833 if (is_virtual_desktop())
835 if (hwnd
== GetDesktopWindow()) reset_clipping_window();
838 if (hwnd
!= GetForegroundWindow()) return;
839 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
841 /* don't reset the foreground window, if the window which is
842 getting the focus is a Wine window */
844 XGetInputFocus( display
, &focus_win
, &revert
);
847 if (XFindContext( display
, focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
853 /* Abey : 6-Oct-99. Check again if the focus out window is the
854 Foreground window, because in most cases the messages sent
855 above must have already changed the foreground window, in which
856 case we don't have to change the foreground window to 0 */
857 if (hwnd
== GetForegroundWindow())
859 TRACE( "lost focus, setting fg to desktop\n" );
860 SetForegroundWindow( GetDesktopWindow() );
865 /**********************************************************************
868 * Note: only top-level windows get FocusOut events.
870 static BOOL
X11DRV_FocusOut( HWND hwnd
, XEvent
*xev
)
872 XFocusChangeEvent
*event
= &xev
->xfocus
;
874 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
], focus_modes
[event
->mode
] );
876 if (event
->detail
== NotifyPointer
)
878 if (!hwnd
&& event
->window
== x11drv_thread_data()->clip_window
) reset_clipping_window();
881 if (!hwnd
) return FALSE
;
886 /* these are received when moving undecorated managed windows on mutter */
887 keyboard_grabbed
= FALSE
;
890 keyboard_grabbed
= FALSE
;
892 case NotifyWhileGrabbed
:
893 keyboard_grabbed
= TRUE
;
896 keyboard_grabbed
= TRUE
;
898 /* This will do nothing due to keyboard_grabbed == TRUE, but it
899 * will save the current clipping rect so we can restore it on
900 * FocusIn with NotifyUngrab mode.
902 retry_grab_clipping_window();
904 return TRUE
; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
907 focus_out( event
->display
, hwnd
);
912 /***********************************************************************
915 static BOOL
X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
917 XExposeEvent
*event
= &xev
->xexpose
;
920 struct x11drv_win_data
*data
;
921 HRGN surface_region
= 0;
922 UINT flags
= RDW_INVALIDATE
| RDW_ERASE
| RDW_FRAME
| RDW_ALLCHILDREN
;
924 TRACE( "win %p (%lx) %d,%d %dx%d\n",
925 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
927 if (event
->window
!= root_window
)
932 else pos
= root_to_virtual_screen( event
->x
, event
->y
);
934 if (!(data
= get_win_data( hwnd
))) return FALSE
;
938 rect
.right
= pos
.x
+ event
->width
;
939 rect
.bottom
= pos
.y
+ event
->height
;
941 if (event
->window
!= data
->client_window
)
945 surface_region
= expose_surface( data
->surface
, &rect
);
946 if (!surface_region
) flags
= 0;
947 else OffsetRgn( surface_region
, data
->whole_rect
.left
- data
->client_rect
.left
,
948 data
->whole_rect
.top
- data
->client_rect
.top
);
950 if (data
->vis
.visualid
!= default_visual
.visualid
)
951 data
->surface
->funcs
->flush( data
->surface
);
953 OffsetRect( &rect
, data
->whole_rect
.left
- data
->client_rect
.left
,
954 data
->whole_rect
.top
- data
->client_rect
.top
);
957 if (event
->window
!= root_window
)
959 if (GetWindowLongW( data
->hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
960 mirror_rect( &data
->client_rect
, &rect
);
962 MapWindowPoints( hwnd
, 0, (POINT
*)&abs_rect
, 2 );
964 SERVER_START_REQ( update_window_zorder
)
966 req
->window
= wine_server_user_handle( hwnd
);
967 req
->rect
.left
= abs_rect
.left
;
968 req
->rect
.top
= abs_rect
.top
;
969 req
->rect
.right
= abs_rect
.right
;
970 req
->rect
.bottom
= abs_rect
.bottom
;
971 wine_server_call( req
);
975 else flags
&= ~RDW_ALLCHILDREN
;
977 release_win_data( data
);
979 if (flags
) RedrawWindow( hwnd
, &rect
, surface_region
, flags
);
980 if (surface_region
) DeleteObject( surface_region
);
985 /**********************************************************************
988 static BOOL
X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
990 struct x11drv_win_data
*data
;
992 if (event
->xany
.window
== x11drv_thread_data()->clip_window
) return TRUE
;
994 if (!(data
= get_win_data( hwnd
))) return FALSE
;
996 if (!data
->managed
&& !data
->embedded
&& data
->mapped
)
998 HWND hwndFocus
= GetFocus();
999 if (hwndFocus
&& IsChild( hwnd
, hwndFocus
))
1000 set_input_focus( data
);
1002 release_win_data( data
);
1007 /**********************************************************************
1008 * X11DRV_UnmapNotify
1010 static BOOL
X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
)
1016 /***********************************************************************
1019 static void reparent_notify( Display
*display
, HWND hwnd
, Window xparent
, int x
, int y
)
1021 HWND parent
, old_parent
;
1024 style
= GetWindowLongW( hwnd
, GWL_STYLE
);
1025 if (xparent
== root_window
)
1027 parent
= GetDesktopWindow();
1028 style
= (style
& ~WS_CHILD
) | WS_POPUP
;
1032 if (!(parent
= create_foreign_window( display
, xparent
))) return;
1033 style
= (style
& ~WS_POPUP
) | WS_CHILD
;
1036 ShowWindow( hwnd
, SW_HIDE
);
1037 old_parent
= SetParent( hwnd
, parent
);
1038 SetWindowLongW( hwnd
, GWL_STYLE
, style
);
1039 SetWindowPos( hwnd
, HWND_TOP
, x
, y
, 0, 0,
1040 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOCOPYBITS
|
1041 ((style
& WS_VISIBLE
) ? SWP_SHOWWINDOW
: 0) );
1043 /* make old parent destroy itself if it no longer has children */
1044 if (old_parent
!= GetDesktopWindow()) PostMessageW( old_parent
, WM_CLOSE
, 0, 0 );
1048 /***********************************************************************
1049 * X11DRV_ReparentNotify
1051 static BOOL
X11DRV_ReparentNotify( HWND hwnd
, XEvent
*xev
)
1053 XReparentEvent
*event
= &xev
->xreparent
;
1054 struct x11drv_win_data
*data
;
1056 if (!(data
= get_win_data( hwnd
))) return FALSE
;
1058 if (!data
->embedded
)
1060 release_win_data( data
);
1064 if (data
->whole_window
)
1066 if (event
->parent
== root_window
)
1068 TRACE( "%p/%lx reparented to root\n", hwnd
, data
->whole_window
);
1070 release_win_data( data
);
1071 SendMessageW( hwnd
, WM_CLOSE
, 0, 0 );
1074 data
->embedder
= event
->parent
;
1077 TRACE( "%p/%lx reparented to %lx\n", hwnd
, data
->whole_window
, event
->parent
);
1078 release_win_data( data
);
1080 reparent_notify( event
->display
, hwnd
, event
->parent
, event
->x
, event
->y
);
1085 /***********************************************************************
1086 * X11DRV_ConfigureNotify
1088 static BOOL
X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
1090 XConfigureEvent
*event
= &xev
->xconfigure
;
1091 struct x11drv_win_data
*data
;
1097 int cx
, cy
, x
= event
->x
, y
= event
->y
;
1100 if (!hwnd
) return FALSE
;
1101 if (!(data
= get_win_data( hwnd
))) return FALSE
;
1102 if (!data
->mapped
|| data
->iconic
) goto done
;
1103 if (data
->whole_window
&& !data
->managed
) goto done
;
1104 /* ignore synthetic events on foreign windows */
1105 if (event
->send_event
&& !data
->whole_window
) goto done
;
1106 if (data
->configure_serial
&& (long)(data
->configure_serial
- event
->serial
) > 0)
1108 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1109 hwnd
, data
->whole_window
, event
->x
, event
->y
, event
->width
, event
->height
,
1110 event
->serial
, data
->configure_serial
);
1116 parent
= GetAncestor( hwnd
, GA_PARENT
);
1117 root_coords
= event
->send_event
; /* synthetic events are always in root coords */
1119 if (!root_coords
&& parent
== GetDesktopWindow()) /* normal event, map coordinates to the root */
1122 XTranslateCoordinates( event
->display
, event
->window
, root_window
,
1123 0, 0, &x
, &y
, &child
);
1132 else pos
= root_to_virtual_screen( x
, y
);
1134 X11DRV_X_to_window_rect( data
, &rect
, pos
.x
, pos
.y
, event
->width
, event
->height
);
1135 if (root_coords
) MapWindowPoints( 0, parent
, (POINT
*)&rect
, 2 );
1137 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1138 hwnd
, data
->whole_window
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
1139 event
->x
, event
->y
, event
->width
, event
->height
);
1141 /* Compare what has changed */
1145 cx
= rect
.right
- rect
.left
;
1146 cy
= rect
.bottom
- rect
.top
;
1147 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
1149 if (!data
->whole_window
) flags
|= SWP_NOCOPYBITS
; /* we can't copy bits of foreign windows */
1151 if (data
->window_rect
.left
== x
&& data
->window_rect
.top
== y
) flags
|= SWP_NOMOVE
;
1153 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1154 hwnd
, data
->window_rect
.left
, data
->window_rect
.top
, x
, y
);
1156 if ((data
->window_rect
.right
- data
->window_rect
.left
== cx
&&
1157 data
->window_rect
.bottom
- data
->window_rect
.top
== cy
) ||
1158 IsRectEmpty( &data
->window_rect
))
1159 flags
|= SWP_NOSIZE
;
1161 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1162 hwnd
, data
->window_rect
.right
- data
->window_rect
.left
,
1163 data
->window_rect
.bottom
- data
->window_rect
.top
, cx
, cy
);
1165 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
1166 if ((style
& WS_CAPTION
) == WS_CAPTION
|| !is_window_rect_full_screen( &data
->whole_rect
))
1168 read_net_wm_states( event
->display
, data
);
1169 if ((data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1171 if (!(style
& WS_MAXIMIZE
))
1173 TRACE( "win %p/%lx is maximized\n", data
->hwnd
, data
->whole_window
);
1174 release_win_data( data
);
1175 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1179 else if (style
& WS_MAXIMIZE
)
1181 TRACE( "window %p/%lx is no longer maximized\n", data
->hwnd
, data
->whole_window
);
1182 release_win_data( data
);
1183 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1188 if ((flags
& (SWP_NOSIZE
| SWP_NOMOVE
)) != (SWP_NOSIZE
| SWP_NOMOVE
))
1190 release_win_data( data
);
1191 SetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
1196 release_win_data( data
);
1201 /**********************************************************************
1202 * X11DRV_GravityNotify
1204 static BOOL
X11DRV_GravityNotify( HWND hwnd
, XEvent
*xev
)
1206 XGravityEvent
*event
= &xev
->xgravity
;
1207 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1211 if (!data
) return FALSE
;
1213 if (data
->whole_window
) /* only handle this for foreign windows */
1215 release_win_data( data
);
1219 x
= event
->x
+ data
->window_rect
.left
- data
->whole_rect
.left
;
1220 y
= event
->y
+ data
->window_rect
.top
- data
->whole_rect
.top
;
1222 TRACE( "win %p/%lx new X pos %d,%d (event %d,%d)\n",
1223 hwnd
, data
->whole_window
, x
, y
, event
->x
, event
->y
);
1225 window_rect
= data
->window_rect
;
1226 release_win_data( data
);
1228 if (window_rect
.left
!= x
|| window_rect
.top
!= y
)
1229 SetWindowPos( hwnd
, 0, x
, y
, 0, 0, SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
1235 /***********************************************************************
1236 * get_window_wm_state
1238 static int get_window_wm_state( Display
*display
, Window window
)
1246 int format
, ret
= -1;
1247 unsigned long count
, remaining
;
1249 if (!XGetWindowProperty( display
, window
, x11drv_atom(WM_STATE
), 0,
1250 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
1251 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
1253 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
1261 /***********************************************************************
1262 * handle_wm_state_notify
1264 * Handle a PropertyNotify for WM_STATE.
1266 static void handle_wm_state_notify( HWND hwnd
, XPropertyEvent
*event
, BOOL update_window
)
1268 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1273 switch(event
->state
)
1275 case PropertyDelete
:
1276 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
1277 data
->wm_state
= WithdrawnState
;
1279 case PropertyNewValue
:
1281 int old_state
= data
->wm_state
;
1282 int new_state
= get_window_wm_state( event
->display
, data
->whole_window
);
1283 if (new_state
!= -1 && new_state
!= data
->wm_state
)
1285 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1286 data
->hwnd
, data
->whole_window
, new_state
, old_state
);
1287 data
->wm_state
= new_state
;
1288 /* ignore the initial state transition out of withdrawn state */
1289 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1290 if (!old_state
) goto done
;
1296 if (!update_window
|| !data
->managed
|| !data
->mapped
) goto done
;
1298 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
1300 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
1302 data
->iconic
= FALSE
;
1303 read_net_wm_states( event
->display
, data
);
1304 if ((style
& WS_CAPTION
) == WS_CAPTION
&& (data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1306 if ((style
& WS_MAXIMIZEBOX
) && !(style
& WS_DISABLED
))
1308 TRACE( "restoring to max %p/%lx\n", data
->hwnd
, data
->whole_window
);
1309 release_win_data( data
);
1310 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1313 TRACE( "not restoring to max win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1317 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1319 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1320 release_win_data( data
);
1321 if ((style
& (WS_MINIMIZE
| WS_VISIBLE
)) == (WS_MINIMIZE
| WS_VISIBLE
))
1322 SetActiveWindow( hwnd
);
1323 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1326 TRACE( "not restoring win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1329 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
1331 data
->iconic
= TRUE
;
1332 if ((style
& WS_MINIMIZEBOX
) && !(style
& WS_DISABLED
))
1334 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1335 release_win_data( data
);
1336 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0 );
1339 TRACE( "not minimizing win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1342 release_win_data( data
);
1346 /***********************************************************************
1347 * X11DRV_PropertyNotify
1349 static BOOL
X11DRV_PropertyNotify( HWND hwnd
, XEvent
*xev
)
1351 XPropertyEvent
*event
= &xev
->xproperty
;
1353 if (!hwnd
) return FALSE
;
1354 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( hwnd
, event
, TRUE
);
1359 /* event filter to wait for a WM_STATE change notification on a window */
1360 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
1362 if (event
->xany
.window
!= (Window
)arg
) return 0;
1363 return (event
->type
== DestroyNotify
||
1364 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
1367 /***********************************************************************
1368 * wait_for_withdrawn_state
1370 void wait_for_withdrawn_state( HWND hwnd
, BOOL set
)
1372 Display
*display
= thread_display();
1373 struct x11drv_win_data
*data
;
1374 DWORD end
= GetTickCount() + 2000;
1376 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd
, set
? "" : "not " );
1384 if (!(data
= get_win_data( hwnd
))) break;
1385 if (!data
->managed
|| data
->embedded
|| data
->display
!= display
) break;
1386 if (!(window
= data
->whole_window
)) break;
1387 if (!data
->mapped
== !set
)
1389 TRACE( "window %p/%lx now %smapped\n", hwnd
, window
, data
->mapped
? "" : "un" );
1392 if ((data
->wm_state
== WithdrawnState
) != !set
)
1394 TRACE( "window %p/%lx state now %d\n", hwnd
, window
, data
->wm_state
);
1397 release_win_data( data
);
1399 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)window
))
1402 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
1403 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
1404 else handle_wm_state_notify( hwnd
, &event
.xproperty
, FALSE
);
1410 int timeout
= end
- GetTickCount();
1412 pfd
.fd
= ConnectionNumber(display
);
1413 pfd
.events
= POLLIN
;
1414 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
1416 FIXME( "window %p/%lx wait timed out\n", hwnd
, window
);
1421 release_win_data( data
);
1425 /*****************************************************************
1426 * SetFocus (X11DRV.@)
1430 void CDECL
X11DRV_SetFocus( HWND hwnd
)
1432 struct x11drv_win_data
*data
;
1438 if (!(data
= get_win_data( hwnd
))) return;
1439 if (data
->embedded
) break;
1440 parent
= GetAncestor( hwnd
, GA_PARENT
);
1441 if (!parent
|| parent
== GetDesktopWindow()) break;
1442 release_win_data( data
);
1445 if (!data
->managed
|| data
->embedder
) set_input_focus( data
);
1446 release_win_data( data
);
1450 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
1454 if (!IsWindowEnabled(hQueryWnd
)) return 0;
1456 GetWindowRect(hQueryWnd
, &tempRect
);
1458 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
1460 if (!IsIconic( hQueryWnd
))
1463 ScreenToClient( hQueryWnd
, &pt
);
1464 GetClientRect( hQueryWnd
, &tempRect
);
1466 if (PtInRect( &tempRect
, pt
))
1468 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
1469 if (ret
&& ret
!= hQueryWnd
)
1471 ret
= find_drop_window( ret
, lpPt
);
1472 if (ret
) return ret
;
1477 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
1479 ScreenToClient(hQueryWnd
, lpPt
);
1484 /**********************************************************************
1485 * EVENT_DropFromOffix
1487 * don't know if it still works (last Changelog is from 96/11/04)
1489 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1491 struct x11drv_win_data
*data
;
1493 unsigned long data_length
;
1494 unsigned long aux_long
;
1495 unsigned char* p_data
= NULL
;
1497 int x
, y
, cx
, cy
, dummy
;
1498 Window win
, w_aux_root
, w_aux_child
;
1500 if (!(data
= get_win_data( hWnd
))) return;
1501 cx
= data
->whole_rect
.right
- data
->whole_rect
.left
;
1502 cy
= data
->whole_rect
.bottom
- data
->whole_rect
.top
;
1503 win
= data
->whole_window
;
1504 release_win_data( data
);
1506 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
1507 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
1508 pt
= root_to_virtual_screen( x
, y
);
1510 /* find out drop point and drop window */
1511 if (pt
.x
< 0 || pt
.y
< 0 || pt
.x
> cx
|| pt
.y
> cy
)
1513 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1518 if (!find_drop_window( hWnd
, &pt
)) return;
1521 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1522 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1523 AnyPropertyType
, &atom_aux
, &dummy
,
1524 &data_length
, &aux_long
, &p_data
);
1526 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1528 char *p
= (char *)p_data
;
1532 while( *p
) /* calculate buffer size */
1534 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1535 if (len
) aux_long
+= len
+ 1;
1538 if( aux_long
&& aux_long
< 65535 )
1543 aux_long
+= sizeof(DROPFILES
) + 1;
1544 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1545 lpDrop
= GlobalLock( hDrop
);
1549 lpDrop
->pFiles
= sizeof(DROPFILES
);
1551 lpDrop
->fNC
= FALSE
;
1552 lpDrop
->fWide
= FALSE
;
1553 p_drop
= (char *)(lpDrop
+ 1);
1557 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
1558 p_drop
+= strlen( p_drop
) + 1;
1562 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1566 if( p_data
) XFree(p_data
);
1569 /**********************************************************************
1572 * drop items are separated by \n
1573 * each item is prefixed by its mime type
1575 * event->data.l[3], event->data.l[4] contains drop x,y position
1577 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1579 struct x11drv_win_data
*win_data
;
1580 unsigned long data_length
;
1581 unsigned long aux_long
, drop_len
= 0;
1582 unsigned char *p_data
= NULL
; /* property data */
1583 char *p_drop
= NULL
;
1596 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1598 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1599 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1600 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1601 &data_length
, &aux_long
, &p_data
);
1603 WARN("property too large, truncated!\n");
1604 TRACE("urls=%s\n", p_data
);
1606 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1607 /* calculate length */
1609 next
= strchr(p
, '\n');
1612 if (strncmp(p
,"file:",5) == 0 ) {
1613 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1614 if (len
) drop_len
+= len
+ 1;
1619 next
= strchr(p
, '\n');
1625 if( drop_len
&& drop_len
< 65535 ) {
1626 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1627 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1628 pos
= root_to_virtual_screen( x
, y
);
1630 drop_len
+= sizeof(DROPFILES
) + 1;
1631 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1632 lpDrop
= GlobalLock( hDrop
);
1634 if( lpDrop
&& (win_data
= get_win_data( hWnd
)))
1636 lpDrop
->pFiles
= sizeof(DROPFILES
);
1639 (pos
.x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1640 pos
.y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1641 pos
.x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1642 pos
.y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1643 lpDrop
->fWide
= FALSE
;
1644 p_drop
= (char*)(lpDrop
+ 1);
1645 release_win_data( win_data
);
1648 /* create message content */
1651 next
= strchr(p
, '\n');
1654 if (strncmp(p
,"file:",5) == 0 ) {
1655 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1657 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1660 WARN("can't convert file %s to dos name\n", p
+5);
1663 WARN("unknown mime type %s\n", p
);
1668 next
= strchr(p
, '\n');
1675 GlobalUnlock(hDrop
);
1676 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1680 if( p_data
) XFree(p_data
);
1684 /**********************************************************************
1685 * handle_xembed_protocol
1687 static void handle_xembed_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1689 switch (event
->data
.l
[1])
1691 case XEMBED_EMBEDDED_NOTIFY
:
1693 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1696 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd
, event
->window
, event
->data
.l
[3] );
1697 data
->embedder
= event
->data
.l
[3];
1699 /* window has been marked as embedded before (e.g. systray) */
1700 if (data
->embedded
|| !data
->embedder
/* broken QX11EmbedContainer implementation */)
1702 release_win_data( data
);
1706 make_window_embedded( data
);
1707 release_win_data( data
);
1708 reparent_notify( event
->display
, hwnd
, event
->data
.l
[3], 0, 0 );
1712 case XEMBED_WINDOW_DEACTIVATE
:
1713 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd
, event
->window
);
1714 focus_out( event
->display
, GetAncestor( hwnd
, GA_ROOT
) );
1717 case XEMBED_FOCUS_OUT
:
1718 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd
, event
->window
);
1719 focus_out( event
->display
, GetAncestor( hwnd
, GA_ROOT
) );
1722 case XEMBED_MODALITY_ON
:
1723 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd
, event
->window
);
1724 EnableWindow( hwnd
, FALSE
);
1727 case XEMBED_MODALITY_OFF
:
1728 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd
, event
->window
);
1729 EnableWindow( hwnd
, TRUE
);
1733 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1734 hwnd
, event
->window
, event
->data
.l
[1], event
->data
.l
[2] );
1740 /**********************************************************************
1741 * handle_dnd_protocol
1743 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1746 int root_x
, root_y
, child_x
, child_y
;
1749 /* query window (drag&drop event contains only drag window) */
1750 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1751 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1752 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1754 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1755 EVENT_DropFromOffiX(hwnd
, event
);
1756 else if (event
->data
.l
[0] == DndURL
)
1757 EVENT_DropURLs(hwnd
, event
);
1761 struct client_message_handler
1763 int atom
; /* protocol atom */
1764 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1767 static const struct client_message_handler client_messages
[] =
1769 { XATOM_MANAGER
, handle_manager_message
},
1770 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1771 { XATOM__XEMBED
, handle_xembed_protocol
},
1772 { XATOM_DndProtocol
, handle_dnd_protocol
},
1773 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
1774 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
1775 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
1776 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
1780 /**********************************************************************
1781 * X11DRV_ClientMessage
1783 static BOOL
X11DRV_ClientMessage( HWND hwnd
, XEvent
*xev
)
1785 XClientMessageEvent
*event
= &xev
->xclient
;
1788 if (!hwnd
) return FALSE
;
1790 if (event
->format
!= 32)
1792 WARN( "Don't know how to handle format %d\n", event
->format
);
1796 for (i
= 0; i
< ARRAY_SIZE( client_messages
); i
++)
1798 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1800 client_messages
[i
].handler( hwnd
, event
);
1804 TRACE( "no handler found for %ld\n", event
->message_type
);