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 int xinput2_opcode
= 0;
160 /* return the name of an X event */
161 static const char *dbgstr_event( int type
)
163 if (type
< MAX_EVENT_HANDLERS
&& event_names
[type
]) return event_names
[type
];
164 return wine_dbg_sprintf( "Unknown event %d", type
);
167 static inline void get_event_data( XEvent
*event
)
169 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
170 if (event
->xany
.type
!= GenericEvent
) return;
171 if (!pXGetEventData
|| !pXGetEventData( event
->xany
.display
, event
)) event
->xcookie
.data
= NULL
;
175 static inline void free_event_data( XEvent
*event
)
177 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
178 if (event
->xany
.type
!= GenericEvent
) return;
179 if (event
->xcookie
.data
) pXFreeEventData( event
->xany
.display
, event
);
183 /***********************************************************************
184 * xembed_request_focus
186 static void xembed_request_focus( Display
*display
, Window window
, DWORD timestamp
)
190 xev
.xclient
.type
= ClientMessage
;
191 xev
.xclient
.window
= window
;
192 xev
.xclient
.message_type
= x11drv_atom(_XEMBED
);
193 xev
.xclient
.serial
= 0;
194 xev
.xclient
.display
= display
;
195 xev
.xclient
.send_event
= True
;
196 xev
.xclient
.format
= 32;
198 xev
.xclient
.data
.l
[0] = timestamp
;
199 xev
.xclient
.data
.l
[1] = XEMBED_REQUEST_FOCUS
;
200 xev
.xclient
.data
.l
[2] = 0;
201 xev
.xclient
.data
.l
[3] = 0;
202 xev
.xclient
.data
.l
[4] = 0;
204 XSendEvent(display
, window
, False
, NoEventMask
, &xev
);
208 /***********************************************************************
209 * X11DRV_register_event_handler
211 * Register a handler for a given event type.
212 * If already registered, overwrite the previous handler.
214 void X11DRV_register_event_handler( int type
, x11drv_event_handler handler
, const char *name
)
216 assert( type
< MAX_EVENT_HANDLERS
);
217 assert( !handlers
[type
] || handlers
[type
] == handler
);
218 handlers
[type
] = handler
;
219 event_names
[type
] = name
;
220 TRACE("registered handler %p for event %d %s\n", handler
, type
, debugstr_a(name
) );
224 /***********************************************************************
227 static Bool
filter_event( Display
*display
, XEvent
*event
, char *arg
)
229 ULONG_PTR mask
= (ULONG_PTR
)arg
;
231 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return 1;
239 return (mask
& (QS_KEY
|QS_HOTKEY
)) != 0;
242 return (mask
& QS_MOUSEBUTTON
) != 0;
249 return (mask
& QS_MOUSEMOVE
) != 0;
251 return (mask
& QS_PAINT
) != 0;
256 case ConfigureNotify
:
259 return (mask
& QS_POSTMESSAGE
) != 0;
261 return (mask
& QS_SENDMESSAGE
) != 0;
266 enum event_merge_action
268 MERGE_DISCARD
, /* discard the old event */
269 MERGE_HANDLE
, /* handle the old event */
270 MERGE_KEEP
, /* keep the old event for future merging */
271 MERGE_IGNORE
/* ignore the new event, keep the old one */
274 /***********************************************************************
275 * merge_raw_motion_events
277 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
278 static enum event_merge_action
merge_raw_motion_events( XIRawEvent
*prev
, XIRawEvent
*next
)
283 if (!prev
->valuators
.mask_len
) return MERGE_HANDLE
;
284 if (!next
->valuators
.mask_len
) return MERGE_HANDLE
;
286 mask
= prev
->valuators
.mask
[0] | next
->valuators
.mask
[0];
287 if (mask
== next
->valuators
.mask
[0]) /* keep next */
289 for (i
= j
= k
= 0; i
< 8; i
++)
291 if (XIMaskIsSet( prev
->valuators
.mask
, i
))
292 next
->valuators
.values
[j
] += prev
->valuators
.values
[k
++];
293 if (XIMaskIsSet( next
->valuators
.mask
, i
)) j
++;
295 TRACE( "merging duplicate GenericEvent\n" );
296 return MERGE_DISCARD
;
298 if (mask
== prev
->valuators
.mask
[0]) /* keep prev */
300 for (i
= j
= k
= 0; i
< 8; i
++)
302 if (XIMaskIsSet( next
->valuators
.mask
, i
))
303 prev
->valuators
.values
[j
] += next
->valuators
.values
[k
++];
304 if (XIMaskIsSet( prev
->valuators
.mask
, i
)) j
++;
306 TRACE( "merging duplicate GenericEvent\n" );
309 /* can't merge events with disjoint masks */
314 /***********************************************************************
317 * Try to merge 2 consecutive events.
319 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
323 case ConfigureNotify
:
326 case ConfigureNotify
:
327 if (prev
->xany
.window
== next
->xany
.window
)
329 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev
->xany
.window
);
330 return MERGE_DISCARD
;
342 if (prev
->xany
.window
== next
->xany
.window
)
344 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
345 return MERGE_DISCARD
;
348 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
350 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
351 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
352 if (x11drv_thread_data()->warp_serial
) break;
357 if (prev
->xcookie
.extension
!= xinput2_opcode
) break;
358 if (prev
->xcookie
.evtype
!= XI_RawMotion
) break;
362 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
363 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
364 if (x11drv_thread_data()->warp_serial
) break;
365 return merge_raw_motion_events( prev
->xcookie
.data
, next
->xcookie
.data
);
374 /***********************************************************************
377 static inline BOOL
call_event_handler( Display
*display
, XEvent
*event
)
381 struct x11drv_thread_data
*thread_data
;
384 if (!handlers
[event
->type
])
386 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
->type
), event
->xany
.window
);
387 return FALSE
; /* no handler, ignore it */
390 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hwnd
) != 0)
391 hwnd
= 0; /* not for a registered window */
392 if (!hwnd
&& event
->xany
.window
== root_window
) hwnd
= GetDesktopWindow();
394 TRACE( "%lu %s for hwnd/window %p/%lx\n",
395 event
->xany
.serial
, dbgstr_event( event
->type
), hwnd
, event
->xany
.window
);
396 thread_data
= x11drv_thread_data();
397 prev
= thread_data
->current_event
;
398 thread_data
->current_event
= event
;
399 ret
= handlers
[event
->type
]( hwnd
, event
);
400 thread_data
->current_event
= prev
;
405 /***********************************************************************
408 static BOOL
process_events( Display
*display
, Bool (*filter
)(Display
*, XEvent
*,XPointer
), ULONG_PTR arg
)
410 XEvent event
, prev_event
;
413 enum event_merge_action action
= MERGE_DISCARD
;
416 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
419 if (XFilterEvent( &event
, None
))
422 * SCIM on linux filters key events strangely. It does not filter the
423 * KeyPress events for these keys however it does filter the
424 * KeyRelease events. This causes wine to become very confused as
425 * to the keyboard state.
427 * We need to let those KeyRelease events be processed so that the
428 * keyboard state is correct.
430 if (event
.type
== KeyRelease
)
433 XKeyEvent
*keyevent
= &event
.xkey
;
435 XLookupString(keyevent
, NULL
, 0, &keysym
, NULL
);
436 if (!(keysym
== XK_Shift_L
||
437 keysym
== XK_Shift_R
||
438 keysym
== XK_Control_L
||
439 keysym
== XK_Control_R
||
440 keysym
== XK_Alt_R
||
441 keysym
== XK_Alt_L
||
442 keysym
== XK_Meta_R
||
443 keysym
== XK_Meta_L
))
444 continue; /* not a key we care about, ignore it */
447 continue; /* filtered, ignore it */
449 get_event_data( &event
);
450 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
453 case MERGE_HANDLE
: /* handle prev, keep new */
454 queued
|= call_event_handler( display
, &prev_event
);
456 case MERGE_DISCARD
: /* discard prev, keep new */
457 free_event_data( &prev_event
);
460 case MERGE_KEEP
: /* handle new, keep prev for future merging */
461 queued
|= call_event_handler( display
, &event
);
463 case MERGE_IGNORE
: /* ignore new, keep prev for future merging */
464 free_event_data( &event
);
468 if (prev_event
.type
) queued
|= call_event_handler( display
, &prev_event
);
469 free_event_data( &prev_event
);
470 XFlush( gdi_display
);
471 if (count
) TRACE( "processed %d events, returning %d\n", count
, queued
);
476 /***********************************************************************
477 * MsgWaitForMultipleObjectsEx (X11DRV.@)
479 DWORD CDECL
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
480 DWORD timeout
, DWORD mask
, DWORD flags
)
483 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
487 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
488 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
489 timeout
, flags
& MWMO_ALERTABLE
);
492 if (data
->current_event
) mask
= 0; /* don't process nested events */
494 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
495 else if (count
|| timeout
)
497 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
498 timeout
, flags
& MWMO_ALERTABLE
);
499 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
501 else ret
= WAIT_TIMEOUT
;
506 /***********************************************************************
507 * EVENT_x11_time_to_win32_time
509 * Make our timer and the X timer line up as best we can
510 * Pass 0 to retrieve the current adjustment value (times -1)
512 DWORD
EVENT_x11_time_to_win32_time(Time time
)
514 static DWORD adjust
= 0;
515 DWORD now
= GetTickCount();
518 if (! adjust
&& time
!= 0)
525 /* If we got an event in the 'future', then our clock is clearly wrong.
526 If we got it more than 10000 ms in the future, then it's most likely
527 that the clock has wrapped. */
530 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
541 /*******************************************************************
542 * can_activate_window
544 * Check if we can activate the specified window.
546 static inline BOOL
can_activate_window( HWND hwnd
)
548 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
551 if (!(style
& WS_VISIBLE
)) return FALSE
;
552 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
553 if (style
& WS_MINIMIZE
) return FALSE
;
554 if (GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_NOACTIVATE
) return FALSE
;
555 if (hwnd
== GetDesktopWindow()) return FALSE
;
556 if (GetWindowRect( hwnd
, &rect
) && IsRectEmpty( &rect
)) return FALSE
;
557 return !(style
& WS_DISABLED
);
561 /**********************************************************************
564 * Try to force focus for embedded or non-managed windows.
566 static void set_input_focus( struct x11drv_win_data
*data
)
568 XWindowChanges changes
;
571 if (!data
->whole_window
) return;
573 if (EVENT_x11_time_to_win32_time(0))
574 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
575 /* FIXME: this is not entirely correct */
576 timestamp
= GetMessageTime() - EVENT_x11_time_to_win32_time(0);
578 timestamp
= CurrentTime
;
580 /* Set X focus and install colormap */
581 changes
.stack_mode
= Above
;
582 XConfigureWindow( data
->display
, data
->whole_window
, CWStackMode
, &changes
);
585 xembed_request_focus( data
->display
, data
->embedder
, timestamp
);
587 XSetInputFocus( data
->display
, data
->whole_window
, RevertToParent
, timestamp
);
591 /**********************************************************************
594 static void set_focus( Display
*display
, HWND hwnd
, Time time
)
598 GUITHREADINFO threadinfo
;
600 TRACE( "setting foreground window to %p\n", hwnd
);
601 SetForegroundWindow( hwnd
);
603 threadinfo
.cbSize
= sizeof(threadinfo
);
604 GetGUIThreadInfo(0, &threadinfo
);
605 focus
= threadinfo
.hwndFocus
;
606 if (!focus
) focus
= threadinfo
.hwndActive
;
607 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
608 win
= X11DRV_get_whole_window(focus
);
612 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
613 XSetInputFocus( display
, win
, RevertToParent
, time
);
618 /**********************************************************************
619 * handle_manager_message
621 static void handle_manager_message( HWND hwnd
, XClientMessageEvent
*event
)
623 if (hwnd
!= GetDesktopWindow()) return;
624 if (systray_atom
&& event
->data
.l
[1] == systray_atom
)
625 change_systray_owner( event
->display
, event
->data
.l
[2] );
629 /**********************************************************************
630 * handle_wm_protocols
632 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
634 Atom protocol
= (Atom
)event
->data
.l
[0];
635 Time event_time
= (Time
)event
->data
.l
[1];
637 if (!protocol
) return;
639 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
641 update_user_time( event_time
);
643 if (hwnd
== GetDesktopWindow())
645 /* The desktop window does not have a close button that we can
646 * pretend to click. Therefore, we simply send it a close command. */
647 SendMessageW(hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0);
651 /* Ignore the delete window request if the window has been disabled
652 * and we are in managed mode. This is to disallow applications from
653 * being closed by the window manager while in a modal state.
655 if (IsWindowEnabled(hwnd
))
659 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
660 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
663 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
664 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
667 if (GetActiveWindow() != hwnd
)
669 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
670 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
671 MAKELPARAM( HTCLOSE
, WM_NCLBUTTONDOWN
) );
674 case MA_NOACTIVATEANDEAT
:
675 case MA_ACTIVATEANDEAT
:
681 SetActiveWindow(hwnd
);
684 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
689 PostMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
692 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
694 HWND last_focus
= x11drv_thread_data()->last_focus
;
696 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
697 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
698 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
700 if (can_activate_window(hwnd
))
702 /* simulate a mouse click on the caption to find out
703 * whether the window wants to be activated */
704 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
705 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
706 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
707 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
709 set_focus( event
->display
, hwnd
, event_time
);
713 else if (hwnd
== GetDesktopWindow())
715 hwnd
= GetForegroundWindow();
716 if (!hwnd
) hwnd
= last_focus
;
717 if (!hwnd
) hwnd
= GetDesktopWindow();
718 set_focus( event
->display
, hwnd
, event_time
);
721 /* try to find some other window to give the focus to */
723 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
724 if (!hwnd
) hwnd
= GetActiveWindow();
725 if (!hwnd
) hwnd
= last_focus
;
726 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, event_time
);
728 else if (protocol
== x11drv_atom(_NET_WM_PING
))
730 XClientMessageEvent xev
;
733 TRACE("NET_WM Ping\n");
734 xev
.window
= DefaultRootWindow(xev
.display
);
735 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
740 static const char * const focus_details
[] =
746 "NotifyNonlinearVirtual",
752 /**********************************************************************
755 static BOOL
X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
757 XFocusChangeEvent
*event
= &xev
->xfocus
;
760 if (!hwnd
) return FALSE
;
762 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
764 if (event
->detail
== NotifyPointer
) return FALSE
;
765 if (hwnd
== GetDesktopWindow()) return FALSE
;
767 if ((xic
= X11DRV_get_ic( hwnd
))) XSetICFocus( xic
);
770 if (hwnd
== GetForegroundWindow()) clip_fullscreen_window( hwnd
, FALSE
);
774 if (!can_activate_window(hwnd
))
776 HWND hwnd
= GetFocus();
777 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
778 if (!hwnd
) hwnd
= GetActiveWindow();
779 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
780 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, CurrentTime
);
782 else SetForegroundWindow( hwnd
);
786 /**********************************************************************
789 static void focus_out( Display
*display
, HWND hwnd
)
796 if (ximInComposeMode
) return;
798 x11drv_thread_data()->last_focus
= hwnd
;
799 if ((xic
= X11DRV_get_ic( hwnd
))) XUnsetICFocus( xic
);
801 if (root_window
!= DefaultRootWindow(display
))
803 if (hwnd
== GetDesktopWindow()) reset_clipping_window();
806 if (hwnd
!= GetForegroundWindow()) return;
807 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
809 /* don't reset the foreground window, if the window which is
810 getting the focus is a Wine window */
812 XGetInputFocus( display
, &focus_win
, &revert
);
815 if (XFindContext( display
, focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
821 /* Abey : 6-Oct-99. Check again if the focus out window is the
822 Foreground window, because in most cases the messages sent
823 above must have already changed the foreground window, in which
824 case we don't have to change the foreground window to 0 */
825 if (hwnd
== GetForegroundWindow())
827 TRACE( "lost focus, setting fg to desktop\n" );
828 SetForegroundWindow( GetDesktopWindow() );
833 /**********************************************************************
836 * Note: only top-level windows get FocusOut events.
838 static BOOL
X11DRV_FocusOut( HWND hwnd
, XEvent
*xev
)
840 XFocusChangeEvent
*event
= &xev
->xfocus
;
842 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
844 if (event
->detail
== NotifyPointer
)
846 if (!hwnd
&& event
->window
== x11drv_thread_data()->clip_window
) reset_clipping_window();
849 if (!hwnd
) return FALSE
;
850 focus_out( event
->display
, hwnd
);
855 /***********************************************************************
858 static BOOL
X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
860 XExposeEvent
*event
= &xev
->xexpose
;
863 struct x11drv_win_data
*data
;
864 HRGN surface_region
= 0;
865 UINT flags
= RDW_INVALIDATE
| RDW_ERASE
| RDW_FRAME
| RDW_ALLCHILDREN
;
867 TRACE( "win %p (%lx) %d,%d %dx%d\n",
868 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
870 if (event
->window
!= root_window
)
875 else pos
= root_to_virtual_screen( event
->x
, event
->y
);
877 if (!(data
= get_win_data( hwnd
))) return FALSE
;
881 rect
.right
= pos
.x
+ event
->width
;
882 rect
.bottom
= pos
.y
+ event
->height
;
884 if (event
->window
!= data
->client_window
)
888 surface_region
= expose_surface( data
->surface
, &rect
);
889 if (!surface_region
) flags
= 0;
890 else OffsetRgn( surface_region
, data
->whole_rect
.left
- data
->client_rect
.left
,
891 data
->whole_rect
.top
- data
->client_rect
.top
);
893 if (data
->vis
.visualid
!= default_visual
.visualid
)
894 data
->surface
->funcs
->flush( data
->surface
);
896 OffsetRect( &rect
, data
->whole_rect
.left
- data
->client_rect
.left
,
897 data
->whole_rect
.top
- data
->client_rect
.top
);
900 if (event
->window
!= root_window
)
902 if (GetWindowLongW( data
->hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
903 mirror_rect( &data
->client_rect
, &rect
);
905 MapWindowPoints( hwnd
, 0, (POINT
*)&abs_rect
, 2 );
907 SERVER_START_REQ( update_window_zorder
)
909 req
->window
= wine_server_user_handle( hwnd
);
910 req
->rect
.left
= abs_rect
.left
;
911 req
->rect
.top
= abs_rect
.top
;
912 req
->rect
.right
= abs_rect
.right
;
913 req
->rect
.bottom
= abs_rect
.bottom
;
914 wine_server_call( req
);
918 else flags
&= ~RDW_ALLCHILDREN
;
920 release_win_data( data
);
922 if (flags
) RedrawWindow( hwnd
, &rect
, surface_region
, flags
);
923 if (surface_region
) DeleteObject( surface_region
);
928 /**********************************************************************
931 static BOOL
X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
933 struct x11drv_win_data
*data
;
935 if (event
->xany
.window
== x11drv_thread_data()->clip_window
)
937 clipping_cursor
= TRUE
;
940 if (!(data
= get_win_data( hwnd
))) return FALSE
;
942 if (!data
->managed
&& !data
->embedded
&& data
->mapped
)
944 HWND hwndFocus
= GetFocus();
945 if (hwndFocus
&& IsChild( hwnd
, hwndFocus
))
946 set_input_focus( data
);
948 release_win_data( data
);
953 /**********************************************************************
956 static BOOL
X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
)
958 if (event
->xany
.window
== x11drv_thread_data()->clip_window
)
959 clipping_cursor
= FALSE
;
964 /***********************************************************************
967 static void reparent_notify( Display
*display
, HWND hwnd
, Window xparent
, int x
, int y
)
969 HWND parent
, old_parent
;
972 style
= GetWindowLongW( hwnd
, GWL_STYLE
);
973 if (xparent
== root_window
)
975 parent
= GetDesktopWindow();
976 style
= (style
& ~WS_CHILD
) | WS_POPUP
;
980 if (!(parent
= create_foreign_window( display
, xparent
))) return;
981 style
= (style
& ~WS_POPUP
) | WS_CHILD
;
984 ShowWindow( hwnd
, SW_HIDE
);
985 old_parent
= SetParent( hwnd
, parent
);
986 SetWindowLongW( hwnd
, GWL_STYLE
, style
);
987 SetWindowPos( hwnd
, HWND_TOP
, x
, y
, 0, 0,
988 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOCOPYBITS
|
989 ((style
& WS_VISIBLE
) ? SWP_SHOWWINDOW
: 0) );
991 /* make old parent destroy itself if it no longer has children */
992 if (old_parent
!= GetDesktopWindow()) PostMessageW( old_parent
, WM_CLOSE
, 0, 0 );
996 /***********************************************************************
997 * X11DRV_ReparentNotify
999 static BOOL
X11DRV_ReparentNotify( HWND hwnd
, XEvent
*xev
)
1001 XReparentEvent
*event
= &xev
->xreparent
;
1002 struct x11drv_win_data
*data
;
1004 if (!(data
= get_win_data( hwnd
))) return FALSE
;
1006 if (!data
->embedded
)
1008 release_win_data( data
);
1012 if (data
->whole_window
)
1014 if (event
->parent
== root_window
)
1016 TRACE( "%p/%lx reparented to root\n", hwnd
, data
->whole_window
);
1018 release_win_data( data
);
1019 SendMessageW( hwnd
, WM_CLOSE
, 0, 0 );
1022 data
->embedder
= event
->parent
;
1025 TRACE( "%p/%lx reparented to %lx\n", hwnd
, data
->whole_window
, event
->parent
);
1026 release_win_data( data
);
1028 reparent_notify( event
->display
, hwnd
, event
->parent
, event
->x
, event
->y
);
1033 /***********************************************************************
1034 * X11DRV_ConfigureNotify
1036 static BOOL
X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
1038 XConfigureEvent
*event
= &xev
->xconfigure
;
1039 struct x11drv_win_data
*data
;
1045 int cx
, cy
, x
= event
->x
, y
= event
->y
;
1048 if (!hwnd
) return FALSE
;
1049 if (!(data
= get_win_data( hwnd
))) return FALSE
;
1050 if (!data
->mapped
|| data
->iconic
) goto done
;
1051 if (data
->whole_window
&& !data
->managed
) goto done
;
1052 /* ignore synthetic events on foreign windows */
1053 if (event
->send_event
&& !data
->whole_window
) goto done
;
1054 if (data
->configure_serial
&& (long)(data
->configure_serial
- event
->serial
) > 0)
1056 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1057 hwnd
, data
->whole_window
, event
->x
, event
->y
, event
->width
, event
->height
,
1058 event
->serial
, data
->configure_serial
);
1064 parent
= GetAncestor( hwnd
, GA_PARENT
);
1065 root_coords
= event
->send_event
; /* synthetic events are always in root coords */
1067 if (!root_coords
&& parent
== GetDesktopWindow()) /* normal event, map coordinates to the root */
1070 XTranslateCoordinates( event
->display
, event
->window
, root_window
,
1071 0, 0, &x
, &y
, &child
);
1080 else pos
= root_to_virtual_screen( x
, y
);
1082 X11DRV_X_to_window_rect( data
, &rect
, pos
.x
, pos
.y
, event
->width
, event
->height
);
1083 if (root_coords
) MapWindowPoints( 0, parent
, (POINT
*)&rect
, 2 );
1085 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1086 hwnd
, data
->whole_window
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
1087 event
->x
, event
->y
, event
->width
, event
->height
);
1089 /* Compare what has changed */
1093 cx
= rect
.right
- rect
.left
;
1094 cy
= rect
.bottom
- rect
.top
;
1095 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
1097 if (!data
->whole_window
) flags
|= SWP_NOCOPYBITS
; /* we can't copy bits of foreign windows */
1099 if (data
->window_rect
.left
== x
&& data
->window_rect
.top
== y
) flags
|= SWP_NOMOVE
;
1101 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1102 hwnd
, data
->window_rect
.left
, data
->window_rect
.top
, x
, y
);
1104 if ((data
->window_rect
.right
- data
->window_rect
.left
== cx
&&
1105 data
->window_rect
.bottom
- data
->window_rect
.top
== cy
) ||
1106 IsRectEmpty( &data
->window_rect
))
1107 flags
|= SWP_NOSIZE
;
1109 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1110 hwnd
, data
->window_rect
.right
- data
->window_rect
.left
,
1111 data
->window_rect
.bottom
- data
->window_rect
.top
, cx
, cy
);
1113 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
1114 if ((style
& WS_CAPTION
) == WS_CAPTION
)
1116 read_net_wm_states( event
->display
, data
);
1117 if ((data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1119 if (!(style
& WS_MAXIMIZE
))
1121 TRACE( "win %p/%lx is maximized\n", data
->hwnd
, data
->whole_window
);
1122 release_win_data( data
);
1123 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1127 else if (style
& WS_MAXIMIZE
)
1129 TRACE( "window %p/%lx is no longer maximized\n", data
->hwnd
, data
->whole_window
);
1130 release_win_data( data
);
1131 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1136 if ((flags
& (SWP_NOSIZE
| SWP_NOMOVE
)) != (SWP_NOSIZE
| SWP_NOMOVE
))
1138 release_win_data( data
);
1139 SetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
1144 release_win_data( data
);
1149 /**********************************************************************
1150 * X11DRV_GravityNotify
1152 static BOOL
X11DRV_GravityNotify( HWND hwnd
, XEvent
*xev
)
1154 XGravityEvent
*event
= &xev
->xgravity
;
1155 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1159 if (!data
) return FALSE
;
1161 if (data
->whole_window
) /* only handle this for foreign windows */
1163 release_win_data( data
);
1167 x
= event
->x
+ data
->window_rect
.left
- data
->whole_rect
.left
;
1168 y
= event
->y
+ data
->window_rect
.top
- data
->whole_rect
.top
;
1170 TRACE( "win %p/%lx new X pos %d,%d (event %d,%d)\n",
1171 hwnd
, data
->whole_window
, x
, y
, event
->x
, event
->y
);
1173 window_rect
= data
->window_rect
;
1174 release_win_data( data
);
1176 if (window_rect
.left
!= x
|| window_rect
.top
!= y
)
1177 SetWindowPos( hwnd
, 0, x
, y
, 0, 0, SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
1183 /***********************************************************************
1184 * get_window_wm_state
1186 static int get_window_wm_state( Display
*display
, Window window
)
1194 int format
, ret
= -1;
1195 unsigned long count
, remaining
;
1197 if (!XGetWindowProperty( display
, window
, x11drv_atom(WM_STATE
), 0,
1198 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
1199 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
1201 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
1209 /***********************************************************************
1210 * handle_wm_state_notify
1212 * Handle a PropertyNotify for WM_STATE.
1214 static void handle_wm_state_notify( HWND hwnd
, XPropertyEvent
*event
, BOOL update_window
)
1216 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1221 switch(event
->state
)
1223 case PropertyDelete
:
1224 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
1225 data
->wm_state
= WithdrawnState
;
1227 case PropertyNewValue
:
1229 int old_state
= data
->wm_state
;
1230 int new_state
= get_window_wm_state( event
->display
, data
->whole_window
);
1231 if (new_state
!= -1 && new_state
!= data
->wm_state
)
1233 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1234 data
->hwnd
, data
->whole_window
, new_state
, old_state
);
1235 data
->wm_state
= new_state
;
1236 /* ignore the initial state transition out of withdrawn state */
1237 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1238 if (!old_state
) goto done
;
1244 if (!update_window
|| !data
->managed
|| !data
->mapped
) goto done
;
1246 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
1248 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
1250 data
->iconic
= FALSE
;
1251 read_net_wm_states( event
->display
, data
);
1252 if ((style
& WS_CAPTION
) == WS_CAPTION
&& (data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1254 if ((style
& WS_MAXIMIZEBOX
) && !(style
& WS_DISABLED
))
1256 TRACE( "restoring to max %p/%lx\n", data
->hwnd
, data
->whole_window
);
1257 release_win_data( data
);
1258 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1261 TRACE( "not restoring to max win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1265 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1267 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1268 release_win_data( data
);
1269 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1272 TRACE( "not restoring win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1275 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
1277 data
->iconic
= TRUE
;
1278 if ((style
& WS_MINIMIZEBOX
) && !(style
& WS_DISABLED
))
1280 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1281 release_win_data( data
);
1282 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0 );
1285 TRACE( "not minimizing win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1288 release_win_data( data
);
1292 /***********************************************************************
1293 * X11DRV_PropertyNotify
1295 static BOOL
X11DRV_PropertyNotify( HWND hwnd
, XEvent
*xev
)
1297 XPropertyEvent
*event
= &xev
->xproperty
;
1299 if (!hwnd
) return FALSE
;
1300 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( hwnd
, event
, TRUE
);
1305 /* event filter to wait for a WM_STATE change notification on a window */
1306 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
1308 if (event
->xany
.window
!= (Window
)arg
) return 0;
1309 return (event
->type
== DestroyNotify
||
1310 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
1313 /***********************************************************************
1314 * wait_for_withdrawn_state
1316 void wait_for_withdrawn_state( HWND hwnd
, BOOL set
)
1318 Display
*display
= thread_display();
1319 struct x11drv_win_data
*data
;
1320 DWORD end
= GetTickCount() + 2000;
1322 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd
, set
? "" : "not " );
1330 if (!(data
= get_win_data( hwnd
))) break;
1331 if (!data
->managed
|| data
->embedded
|| data
->display
!= display
) break;
1332 if (!(window
= data
->whole_window
)) break;
1333 if (!data
->mapped
== !set
)
1335 TRACE( "window %p/%lx now %smapped\n", hwnd
, window
, data
->mapped
? "" : "un" );
1338 if ((data
->wm_state
== WithdrawnState
) != !set
)
1340 TRACE( "window %p/%lx state now %d\n", hwnd
, window
, data
->wm_state
);
1343 release_win_data( data
);
1345 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)window
))
1348 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
1349 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
1350 else handle_wm_state_notify( hwnd
, &event
.xproperty
, FALSE
);
1356 int timeout
= end
- GetTickCount();
1358 pfd
.fd
= ConnectionNumber(display
);
1359 pfd
.events
= POLLIN
;
1360 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
1362 FIXME( "window %p/%lx wait timed out\n", hwnd
, window
);
1367 release_win_data( data
);
1371 /*****************************************************************
1372 * SetFocus (X11DRV.@)
1376 void CDECL
X11DRV_SetFocus( HWND hwnd
)
1378 struct x11drv_win_data
*data
;
1384 if (!(data
= get_win_data( hwnd
))) return;
1385 if (data
->embedded
) break;
1386 parent
= GetAncestor( hwnd
, GA_PARENT
);
1387 if (!parent
|| parent
== GetDesktopWindow()) break;
1388 release_win_data( data
);
1391 if (!data
->managed
|| data
->embedder
) set_input_focus( data
);
1392 release_win_data( data
);
1396 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
1400 if (!IsWindowEnabled(hQueryWnd
)) return 0;
1402 GetWindowRect(hQueryWnd
, &tempRect
);
1404 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
1406 if (!IsIconic( hQueryWnd
))
1409 ScreenToClient( hQueryWnd
, &pt
);
1410 GetClientRect( hQueryWnd
, &tempRect
);
1412 if (PtInRect( &tempRect
, pt
))
1414 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
1415 if (ret
&& ret
!= hQueryWnd
)
1417 ret
= find_drop_window( ret
, lpPt
);
1418 if (ret
) return ret
;
1423 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
1425 ScreenToClient(hQueryWnd
, lpPt
);
1430 /**********************************************************************
1431 * EVENT_DropFromOffix
1433 * don't know if it still works (last Changelog is from 96/11/04)
1435 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1437 struct x11drv_win_data
*data
;
1439 unsigned long data_length
;
1440 unsigned long aux_long
;
1441 unsigned char* p_data
= NULL
;
1443 int x
, y
, cx
, cy
, dummy
;
1444 Window win
, w_aux_root
, w_aux_child
;
1446 if (!(data
= get_win_data( hWnd
))) return;
1447 cx
= data
->whole_rect
.right
- data
->whole_rect
.left
;
1448 cy
= data
->whole_rect
.bottom
- data
->whole_rect
.top
;
1449 win
= data
->whole_window
;
1450 release_win_data( data
);
1452 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
1453 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
1454 pt
= root_to_virtual_screen( x
, y
);
1456 /* find out drop point and drop window */
1457 if (pt
.x
< 0 || pt
.y
< 0 || pt
.x
> cx
|| pt
.y
> cy
)
1459 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1464 if (!find_drop_window( hWnd
, &pt
)) return;
1467 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1468 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1469 AnyPropertyType
, &atom_aux
, &dummy
,
1470 &data_length
, &aux_long
, &p_data
);
1472 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1474 char *p
= (char *)p_data
;
1478 while( *p
) /* calculate buffer size */
1480 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1481 if (len
) aux_long
+= len
+ 1;
1484 if( aux_long
&& aux_long
< 65535 )
1489 aux_long
+= sizeof(DROPFILES
) + 1;
1490 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1491 lpDrop
= GlobalLock( hDrop
);
1495 lpDrop
->pFiles
= sizeof(DROPFILES
);
1497 lpDrop
->fNC
= FALSE
;
1498 lpDrop
->fWide
= FALSE
;
1499 p_drop
= (char *)(lpDrop
+ 1);
1503 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
1504 p_drop
+= strlen( p_drop
) + 1;
1508 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1512 if( p_data
) XFree(p_data
);
1515 /**********************************************************************
1518 * drop items are separated by \n
1519 * each item is prefixed by its mime type
1521 * event->data.l[3], event->data.l[4] contains drop x,y position
1523 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1525 struct x11drv_win_data
*win_data
;
1526 unsigned long data_length
;
1527 unsigned long aux_long
, drop_len
= 0;
1528 unsigned char *p_data
= NULL
; /* property data */
1529 char *p_drop
= NULL
;
1542 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1544 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1545 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1546 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1547 &data_length
, &aux_long
, &p_data
);
1549 WARN("property too large, truncated!\n");
1550 TRACE("urls=%s\n", p_data
);
1552 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1553 /* calculate length */
1555 next
= strchr(p
, '\n');
1558 if (strncmp(p
,"file:",5) == 0 ) {
1559 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1560 if (len
) drop_len
+= len
+ 1;
1565 next
= strchr(p
, '\n');
1571 if( drop_len
&& drop_len
< 65535 ) {
1572 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1573 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1574 pos
= root_to_virtual_screen( x
, y
);
1576 drop_len
+= sizeof(DROPFILES
) + 1;
1577 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1578 lpDrop
= GlobalLock( hDrop
);
1580 if( lpDrop
&& (win_data
= get_win_data( hWnd
)))
1582 lpDrop
->pFiles
= sizeof(DROPFILES
);
1585 (pos
.x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1586 pos
.y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1587 pos
.x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1588 pos
.y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1589 lpDrop
->fWide
= FALSE
;
1590 p_drop
= (char*)(lpDrop
+ 1);
1591 release_win_data( win_data
);
1594 /* create message content */
1597 next
= strchr(p
, '\n');
1600 if (strncmp(p
,"file:",5) == 0 ) {
1601 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1603 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1606 WARN("can't convert file %s to dos name\n", p
+5);
1609 WARN("unknown mime type %s\n", p
);
1614 next
= strchr(p
, '\n');
1621 GlobalUnlock(hDrop
);
1622 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1626 if( p_data
) XFree(p_data
);
1630 /**********************************************************************
1631 * handle_xembed_protocol
1633 static void handle_xembed_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1635 switch (event
->data
.l
[1])
1637 case XEMBED_EMBEDDED_NOTIFY
:
1639 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1642 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd
, event
->window
, event
->data
.l
[3] );
1643 data
->embedder
= event
->data
.l
[3];
1645 /* window has been marked as embedded before (e.g. systray) */
1646 if (data
->embedded
|| !data
->embedder
/* broken QX11EmbedContainer implementation */)
1648 release_win_data( data
);
1652 make_window_embedded( data
);
1653 release_win_data( data
);
1654 reparent_notify( event
->display
, hwnd
, event
->data
.l
[3], 0, 0 );
1658 case XEMBED_WINDOW_DEACTIVATE
:
1659 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd
, event
->window
);
1660 focus_out( event
->display
, GetAncestor( hwnd
, GA_ROOT
) );
1663 case XEMBED_FOCUS_OUT
:
1664 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd
, event
->window
);
1665 focus_out( event
->display
, GetAncestor( hwnd
, GA_ROOT
) );
1668 case XEMBED_MODALITY_ON
:
1669 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd
, event
->window
);
1670 EnableWindow( hwnd
, FALSE
);
1673 case XEMBED_MODALITY_OFF
:
1674 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd
, event
->window
);
1675 EnableWindow( hwnd
, TRUE
);
1679 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1680 hwnd
, event
->window
, event
->data
.l
[1], event
->data
.l
[2] );
1686 /**********************************************************************
1687 * handle_dnd_protocol
1689 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1692 int root_x
, root_y
, child_x
, child_y
;
1695 /* query window (drag&drop event contains only drag window) */
1696 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1697 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1698 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1700 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1701 EVENT_DropFromOffiX(hwnd
, event
);
1702 else if (event
->data
.l
[0] == DndURL
)
1703 EVENT_DropURLs(hwnd
, event
);
1707 struct client_message_handler
1709 int atom
; /* protocol atom */
1710 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1713 static const struct client_message_handler client_messages
[] =
1715 { XATOM_MANAGER
, handle_manager_message
},
1716 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1717 { XATOM__XEMBED
, handle_xembed_protocol
},
1718 { XATOM_DndProtocol
, handle_dnd_protocol
},
1719 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
1720 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
1721 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
1722 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
1726 /**********************************************************************
1727 * X11DRV_ClientMessage
1729 static BOOL
X11DRV_ClientMessage( HWND hwnd
, XEvent
*xev
)
1731 XClientMessageEvent
*event
= &xev
->xclient
;
1734 if (!hwnd
) return FALSE
;
1736 if (event
->format
!= 32)
1738 WARN( "Don't know how to handle format %d\n", event
->format
);
1742 for (i
= 0; i
< ARRAY_SIZE( client_messages
); i
++)
1744 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1746 client_messages
[i
].handler( hwnd
, event
);
1750 TRACE( "no handler found for %ld\n", event
->message_type
);