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>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
52 /* avoid conflict with field names in included win32 headers */
54 #include "shlobj.h" /* DROPFILES */
57 #include "wine/server.h"
58 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(event
);
62 extern BOOL ximInComposeMode
;
64 #define DndNotDnd -1 /* OffiX drag&drop */
76 #define DndURL 128 /* KDE drag&drop */
78 #define XEMBED_EMBEDDED_NOTIFY 0
79 #define XEMBED_WINDOW_ACTIVATE 1
80 #define XEMBED_WINDOW_DEACTIVATE 2
81 #define XEMBED_REQUEST_FOCUS 3
82 #define XEMBED_FOCUS_IN 4
83 #define XEMBED_FOCUS_OUT 5
84 #define XEMBED_FOCUS_NEXT 6
85 #define XEMBED_FOCUS_PREV 7
86 #define XEMBED_MODALITY_ON 10
87 #define XEMBED_MODALITY_OFF 11
88 #define XEMBED_REGISTER_ACCELERATOR 12
89 #define XEMBED_UNREGISTER_ACCELERATOR 13
90 #define XEMBED_ACTIVATE_ACCELERATOR 14
92 Bool (*pXGetEventData
)( Display
*display
, XEvent
/*XGenericEventCookie*/ *event
) = NULL
;
93 void (*pXFreeEventData
)( Display
*display
, XEvent
/*XGenericEventCookie*/ *event
) = NULL
;
96 static void X11DRV_FocusIn( HWND hwnd
, XEvent
*event
);
97 static void X11DRV_FocusOut( HWND hwnd
, XEvent
*event
);
98 static void X11DRV_Expose( HWND hwnd
, XEvent
*event
);
99 static void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
);
100 static void X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
);
101 static void X11DRV_ReparentNotify( HWND hwnd
, XEvent
*event
);
102 static void X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*event
);
103 static void X11DRV_PropertyNotify( HWND hwnd
, XEvent
*event
);
104 static void X11DRV_ClientMessage( HWND hwnd
, XEvent
*event
);
105 static void X11DRV_GravityNotify( HWND hwnd
, XEvent
*event
);
107 #define MAX_EVENT_HANDLERS 128
109 static x11drv_event_handler handlers
[MAX_EVENT_HANDLERS
] =
111 NULL
, /* 0 reserved */
112 NULL
, /* 1 reserved */
113 X11DRV_KeyEvent
, /* 2 KeyPress */
114 X11DRV_KeyEvent
, /* 3 KeyRelease */
115 X11DRV_ButtonPress
, /* 4 ButtonPress */
116 X11DRV_ButtonRelease
, /* 5 ButtonRelease */
117 X11DRV_MotionNotify
, /* 6 MotionNotify */
118 X11DRV_EnterNotify
, /* 7 EnterNotify */
119 NULL
, /* 8 LeaveNotify */
120 X11DRV_FocusIn
, /* 9 FocusIn */
121 X11DRV_FocusOut
, /* 10 FocusOut */
122 X11DRV_KeymapNotify
, /* 11 KeymapNotify */
123 X11DRV_Expose
, /* 12 Expose */
124 NULL
, /* 13 GraphicsExpose */
125 NULL
, /* 14 NoExpose */
126 NULL
, /* 15 VisibilityNotify */
127 NULL
, /* 16 CreateNotify */
128 X11DRV_DestroyNotify
, /* 17 DestroyNotify */
129 X11DRV_UnmapNotify
, /* 18 UnmapNotify */
130 X11DRV_MapNotify
, /* 19 MapNotify */
131 NULL
, /* 20 MapRequest */
132 X11DRV_ReparentNotify
, /* 21 ReparentNotify */
133 X11DRV_ConfigureNotify
, /* 22 ConfigureNotify */
134 NULL
, /* 23 ConfigureRequest */
135 X11DRV_GravityNotify
, /* 24 GravityNotify */
136 NULL
, /* 25 ResizeRequest */
137 NULL
, /* 26 CirculateNotify */
138 NULL
, /* 27 CirculateRequest */
139 X11DRV_PropertyNotify
, /* 28 PropertyNotify */
140 X11DRV_SelectionClear
, /* 29 SelectionClear */
141 X11DRV_SelectionRequest
, /* 30 SelectionRequest */
142 NULL
, /* 31 SelectionNotify */
143 NULL
, /* 32 ColormapNotify */
144 X11DRV_ClientMessage
, /* 33 ClientMessage */
145 X11DRV_MappingNotify
, /* 34 MappingNotify */
146 X11DRV_GenericEvent
/* 35 GenericEvent */
149 static const char * event_names
[MAX_EVENT_HANDLERS
] =
151 NULL
, NULL
, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
152 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
153 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
154 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
155 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
156 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
157 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
160 int xinput2_opcode
= 0;
162 /* return the name of an X event */
163 static const char *dbgstr_event( int type
)
165 if (type
< MAX_EVENT_HANDLERS
&& event_names
[type
]) return event_names
[type
];
166 return wine_dbg_sprintf( "Unknown event %d", type
);
169 static inline void get_event_data( XEvent
*event
)
171 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
172 if (event
->xany
.type
!= GenericEvent
) return;
173 if (!pXGetEventData
|| !pXGetEventData( event
->xany
.display
, event
)) event
->xcookie
.data
= NULL
;
177 static inline void free_event_data( XEvent
*event
)
179 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
180 if (event
->xany
.type
!= GenericEvent
) return;
181 if (event
->xcookie
.data
) pXFreeEventData( event
->xany
.display
, event
);
185 /***********************************************************************
186 * xembed_request_focus
188 static void xembed_request_focus( Display
*display
, Window window
, DWORD timestamp
)
192 xev
.xclient
.type
= ClientMessage
;
193 xev
.xclient
.window
= window
;
194 xev
.xclient
.message_type
= x11drv_atom(_XEMBED
);
195 xev
.xclient
.serial
= 0;
196 xev
.xclient
.display
= display
;
197 xev
.xclient
.send_event
= True
;
198 xev
.xclient
.format
= 32;
200 xev
.xclient
.data
.l
[0] = timestamp
;
201 xev
.xclient
.data
.l
[1] = XEMBED_REQUEST_FOCUS
;
202 xev
.xclient
.data
.l
[2] = 0;
203 xev
.xclient
.data
.l
[3] = 0;
204 xev
.xclient
.data
.l
[4] = 0;
206 XSendEvent(display
, window
, False
, NoEventMask
, &xev
);
210 /***********************************************************************
211 * X11DRV_register_event_handler
213 * Register a handler for a given event type.
214 * If already registered, overwrite the previous handler.
216 void X11DRV_register_event_handler( int type
, x11drv_event_handler handler
, const char *name
)
218 assert( type
< MAX_EVENT_HANDLERS
);
219 assert( !handlers
[type
] || handlers
[type
] == handler
);
220 handlers
[type
] = handler
;
221 event_names
[type
] = name
;
222 TRACE("registered handler %p for event %d %s\n", handler
, type
, debugstr_a(name
) );
226 /***********************************************************************
229 static Bool
filter_event( Display
*display
, XEvent
*event
, char *arg
)
231 ULONG_PTR mask
= (ULONG_PTR
)arg
;
233 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return 1;
241 return (mask
& (QS_KEY
|QS_HOTKEY
)) != 0;
244 return (mask
& QS_MOUSEBUTTON
) != 0;
248 return (mask
& QS_MOUSEMOVE
) != 0;
250 return (mask
& QS_PAINT
) != 0;
255 case ConfigureNotify
:
258 return (mask
& QS_POSTMESSAGE
) != 0;
260 return (mask
& QS_SENDMESSAGE
) != 0;
265 enum event_merge_action
267 MERGE_DISCARD
, /* discard the old event */
268 MERGE_HANDLE
, /* handle the old event */
269 MERGE_KEEP
, /* keep the old event for future merging */
270 MERGE_IGNORE
/* ignore the new event, keep the old one */
273 /***********************************************************************
274 * merge_raw_motion_events
276 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
277 static enum event_merge_action
merge_raw_motion_events( XIRawEvent
*prev
, XIRawEvent
*next
)
282 if (!prev
->valuators
.mask_len
) return MERGE_HANDLE
;
283 if (!next
->valuators
.mask_len
) return MERGE_HANDLE
;
285 mask
= prev
->valuators
.mask
[0] | next
->valuators
.mask
[0];
286 if (mask
== next
->valuators
.mask
[0]) /* keep next */
288 for (i
= j
= k
= 0; i
< 8; i
++)
290 if (XIMaskIsSet( prev
->valuators
.mask
, i
))
291 next
->valuators
.values
[j
] += prev
->valuators
.values
[k
++];
292 if (XIMaskIsSet( next
->valuators
.mask
, i
)) j
++;
294 TRACE( "merging duplicate GenericEvent\n" );
295 return MERGE_DISCARD
;
297 if (mask
== prev
->valuators
.mask
[0]) /* keep prev */
299 for (i
= j
= k
= 0; i
< 8; i
++)
301 if (XIMaskIsSet( next
->valuators
.mask
, i
))
302 prev
->valuators
.values
[j
] += next
->valuators
.values
[k
++];
303 if (XIMaskIsSet( prev
->valuators
.mask
, i
)) j
++;
305 TRACE( "merging duplicate GenericEvent\n" );
308 /* can't merge events with disjoint masks */
313 /***********************************************************************
316 * Try to merge 2 consecutive events.
318 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
322 case ConfigureNotify
:
325 case ConfigureNotify
:
326 if (prev
->xany
.window
== next
->xany
.window
)
328 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev
->xany
.window
);
329 return MERGE_DISCARD
;
341 if (prev
->xany
.window
== next
->xany
.window
)
343 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
344 return MERGE_DISCARD
;
347 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
349 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
350 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
351 if (x11drv_thread_data()->warp_serial
) break;
356 if (prev
->xcookie
.extension
!= xinput2_opcode
) break;
357 if (prev
->xcookie
.evtype
!= XI_RawMotion
) break;
361 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
362 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
363 if (x11drv_thread_data()->warp_serial
) break;
364 return merge_raw_motion_events( prev
->xcookie
.data
, next
->xcookie
.data
);
373 /***********************************************************************
376 static inline void call_event_handler( Display
*display
, XEvent
*event
)
380 struct x11drv_thread_data
*thread_data
;
382 if (!handlers
[event
->type
])
384 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
->type
), event
->xany
.window
);
385 return; /* no handler, ignore it */
388 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hwnd
) != 0)
389 hwnd
= 0; /* not for a registered window */
390 if (!hwnd
&& event
->xany
.window
== root_window
) hwnd
= GetDesktopWindow();
392 TRACE( "%lu %s for hwnd/window %p/%lx\n",
393 event
->xany
.serial
, dbgstr_event( event
->type
), hwnd
, event
->xany
.window
);
394 thread_data
= x11drv_thread_data();
395 prev
= thread_data
->current_event
;
396 thread_data
->current_event
= event
;
397 handlers
[event
->type
]( hwnd
, event
);
398 thread_data
->current_event
= prev
;
402 /***********************************************************************
405 static int process_events( Display
*display
, Bool (*filter
)(Display
*, XEvent
*,XPointer
), ULONG_PTR arg
)
407 XEvent event
, prev_event
;
409 enum event_merge_action action
= MERGE_DISCARD
;
412 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
415 if (XFilterEvent( &event
, None
))
418 * SCIM on linux filters key events strangely. It does not filter the
419 * KeyPress events for these keys however it does filter the
420 * KeyRelease events. This causes wine to become very confused as
421 * to the keyboard state.
423 * We need to let those KeyRelease events be processed so that the
424 * keyboard state is correct.
426 if (event
.type
== KeyRelease
)
429 XKeyEvent
*keyevent
= &event
.xkey
;
431 XLookupString(keyevent
, NULL
, 0, &keysym
, NULL
);
432 if (!(keysym
== XK_Shift_L
||
433 keysym
== XK_Shift_R
||
434 keysym
== XK_Control_L
||
435 keysym
== XK_Control_R
||
436 keysym
== XK_Alt_R
||
437 keysym
== XK_Alt_L
||
438 keysym
== XK_Meta_R
||
439 keysym
== XK_Meta_L
))
440 continue; /* not a key we care about, ignore it */
443 continue; /* filtered, ignore it */
445 get_event_data( &event
);
446 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
449 case MERGE_HANDLE
: /* handle prev, keep new */
450 call_event_handler( display
, &prev_event
);
452 case MERGE_DISCARD
: /* discard prev, keep new */
453 free_event_data( &prev_event
);
456 case MERGE_KEEP
: /* handle new, keep prev for future merging */
457 call_event_handler( display
, &event
);
459 case MERGE_IGNORE
: /* ignore new, keep prev for future merging */
460 free_event_data( &event
);
464 if (prev_event
.type
) call_event_handler( display
, &prev_event
);
465 free_event_data( &prev_event
);
466 XFlush( gdi_display
);
467 if (count
) TRACE( "processed %d events\n", count
);
472 /***********************************************************************
473 * MsgWaitForMultipleObjectsEx (X11DRV.@)
475 DWORD CDECL
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
476 DWORD timeout
, DWORD mask
, DWORD flags
)
479 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
483 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
484 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
485 timeout
, flags
& MWMO_ALERTABLE
);
488 if (data
->current_event
) mask
= 0; /* don't process nested events */
490 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
491 else if (count
|| timeout
)
493 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
494 timeout
, flags
& MWMO_ALERTABLE
);
495 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
497 else ret
= WAIT_TIMEOUT
;
502 /***********************************************************************
503 * EVENT_x11_time_to_win32_time
505 * Make our timer and the X timer line up as best we can
506 * Pass 0 to retrieve the current adjustment value (times -1)
508 DWORD
EVENT_x11_time_to_win32_time(Time time
)
510 static DWORD adjust
= 0;
511 DWORD now
= GetTickCount();
514 if (! adjust
&& time
!= 0)
521 /* If we got an event in the 'future', then our clock is clearly wrong.
522 If we got it more than 10000 ms in the future, then it's most likely
523 that the clock has wrapped. */
526 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
537 /*******************************************************************
538 * can_activate_window
540 * Check if we can activate the specified window.
542 static inline BOOL
can_activate_window( HWND hwnd
)
544 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
547 if (!(style
& WS_VISIBLE
)) return FALSE
;
548 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
549 if (style
& WS_MINIMIZE
) return FALSE
;
550 if (GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_NOACTIVATE
) return FALSE
;
551 if (hwnd
== GetDesktopWindow()) return FALSE
;
552 if (GetWindowRect( hwnd
, &rect
) && IsRectEmpty( &rect
)) return FALSE
;
553 return !(style
& WS_DISABLED
);
557 /**********************************************************************
560 * Try to force focus for embedded or non-managed windows.
562 static void set_input_focus( struct x11drv_win_data
*data
)
564 XWindowChanges changes
;
567 if (!data
->whole_window
) return;
569 if (EVENT_x11_time_to_win32_time(0))
570 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
571 /* FIXME: this is not entirely correct */
572 timestamp
= GetMessageTime() - EVENT_x11_time_to_win32_time(0);
574 timestamp
= CurrentTime
;
576 /* Set X focus and install colormap */
577 changes
.stack_mode
= Above
;
578 XConfigureWindow( data
->display
, data
->whole_window
, CWStackMode
, &changes
);
581 xembed_request_focus( data
->display
, data
->embedder
, timestamp
);
583 XSetInputFocus( data
->display
, data
->whole_window
, RevertToParent
, timestamp
);
587 /**********************************************************************
590 static void set_focus( Display
*display
, HWND hwnd
, Time time
)
594 GUITHREADINFO threadinfo
;
596 TRACE( "setting foreground window to %p\n", hwnd
);
597 SetForegroundWindow( hwnd
);
599 threadinfo
.cbSize
= sizeof(threadinfo
);
600 GetGUIThreadInfo(0, &threadinfo
);
601 focus
= threadinfo
.hwndFocus
;
602 if (!focus
) focus
= threadinfo
.hwndActive
;
603 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
604 win
= X11DRV_get_whole_window(focus
);
608 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
609 XSetInputFocus( display
, win
, RevertToParent
, time
);
614 /**********************************************************************
615 * handle_manager_message
617 static void handle_manager_message( HWND hwnd
, XClientMessageEvent
*event
)
619 if (hwnd
!= GetDesktopWindow()) return;
620 if (systray_atom
&& event
->data
.l
[1] == systray_atom
)
621 change_systray_owner( event
->display
, event
->data
.l
[2] );
625 /**********************************************************************
626 * handle_wm_protocols
628 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
630 Atom protocol
= (Atom
)event
->data
.l
[0];
631 Time event_time
= (Time
)event
->data
.l
[1];
633 if (!protocol
) return;
635 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
637 update_user_time( event_time
);
639 if (hwnd
== GetDesktopWindow())
641 /* The desktop window does not have a close button that we can
642 * pretend to click. Therefore, we simply send it a close command. */
643 SendMessageW(hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0);
647 /* Ignore the delete window request if the window has been disabled
648 * and we are in managed mode. This is to disallow applications from
649 * being closed by the window manager while in a modal state.
651 if (IsWindowEnabled(hwnd
))
655 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
656 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
659 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
660 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
663 if (GetActiveWindow() != hwnd
)
665 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
666 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
667 MAKELPARAM( HTCLOSE
, WM_NCLBUTTONDOWN
) );
670 case MA_NOACTIVATEANDEAT
:
671 case MA_ACTIVATEANDEAT
:
677 SetActiveWindow(hwnd
);
680 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
685 PostMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
688 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
690 HWND last_focus
= x11drv_thread_data()->last_focus
;
692 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
693 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
694 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
696 if (can_activate_window(hwnd
))
698 /* simulate a mouse click on the caption to find out
699 * whether the window wants to be activated */
700 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
701 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
702 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
703 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
705 set_focus( event
->display
, hwnd
, event_time
);
709 else if (hwnd
== GetDesktopWindow())
711 hwnd
= GetForegroundWindow();
712 if (!hwnd
) hwnd
= last_focus
;
713 if (!hwnd
) hwnd
= GetDesktopWindow();
714 set_focus( event
->display
, hwnd
, event_time
);
717 /* try to find some other window to give the focus to */
719 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
720 if (!hwnd
) hwnd
= GetActiveWindow();
721 if (!hwnd
) hwnd
= last_focus
;
722 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, event_time
);
724 else if (protocol
== x11drv_atom(_NET_WM_PING
))
726 XClientMessageEvent xev
;
729 TRACE("NET_WM Ping\n");
730 xev
.window
= DefaultRootWindow(xev
.display
);
731 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
736 static const char * const focus_details
[] =
742 "NotifyNonlinearVirtual",
748 /**********************************************************************
751 static void X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
753 XFocusChangeEvent
*event
= &xev
->xfocus
;
758 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
760 if (event
->detail
== NotifyPointer
) return;
761 if (hwnd
== GetDesktopWindow()) return;
763 if ((xic
= X11DRV_get_ic( hwnd
))) XSetICFocus( xic
);
766 if (hwnd
== GetForegroundWindow()) clip_fullscreen_window( hwnd
, FALSE
);
770 if (!can_activate_window(hwnd
))
772 HWND hwnd
= GetFocus();
773 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
774 if (!hwnd
) hwnd
= GetActiveWindow();
775 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
776 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, CurrentTime
);
778 else SetForegroundWindow( hwnd
);
781 /**********************************************************************
784 static void focus_out( Display
*display
, HWND hwnd
)
791 if (ximInComposeMode
) return;
793 x11drv_thread_data()->last_focus
= hwnd
;
794 if ((xic
= X11DRV_get_ic( hwnd
))) XUnsetICFocus( xic
);
796 if (root_window
!= DefaultRootWindow(display
))
798 if (hwnd
== GetDesktopWindow()) reset_clipping_window();
801 if (hwnd
!= GetForegroundWindow()) return;
802 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
804 /* don't reset the foreground window, if the window which is
805 getting the focus is a Wine window */
807 XGetInputFocus( display
, &focus_win
, &revert
);
810 if (XFindContext( display
, focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
816 /* Abey : 6-Oct-99. Check again if the focus out window is the
817 Foreground window, because in most cases the messages sent
818 above must have already changed the foreground window, in which
819 case we don't have to change the foreground window to 0 */
820 if (hwnd
== GetForegroundWindow())
822 TRACE( "lost focus, setting fg to desktop\n" );
823 SetForegroundWindow( GetDesktopWindow() );
828 /**********************************************************************
831 * Note: only top-level windows get FocusOut events.
833 static void X11DRV_FocusOut( HWND hwnd
, XEvent
*xev
)
835 XFocusChangeEvent
*event
= &xev
->xfocus
;
837 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
839 if (event
->detail
== NotifyPointer
)
841 if (!hwnd
&& event
->window
== x11drv_thread_data()->clip_window
) reset_clipping_window();
845 focus_out( event
->display
, hwnd
);
849 /***********************************************************************
852 static void X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
854 XExposeEvent
*event
= &xev
->xexpose
;
857 struct x11drv_win_data
*data
;
858 HRGN surface_region
= 0;
859 UINT flags
= RDW_INVALIDATE
| RDW_ERASE
| RDW_FRAME
| RDW_ALLCHILDREN
;
861 TRACE( "win %p (%lx) %d,%d %dx%d\n",
862 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
864 if (event
->window
!= root_window
)
869 else pos
= root_to_virtual_screen( event
->x
, event
->y
);
871 if (!(data
= get_win_data( hwnd
))) return;
875 rect
.right
= pos
.x
+ event
->width
;
876 rect
.bottom
= pos
.y
+ event
->height
;
878 if (event
->window
!= data
->client_window
)
882 surface_region
= expose_surface( data
->surface
, &rect
);
883 if (!surface_region
) flags
= 0;
884 else OffsetRgn( surface_region
, data
->whole_rect
.left
- data
->client_rect
.left
,
885 data
->whole_rect
.top
- data
->client_rect
.top
);
887 if (data
->vis
.visualid
!= default_visual
.visualid
)
888 data
->surface
->funcs
->flush( data
->surface
);
890 OffsetRect( &rect
, data
->whole_rect
.left
- data
->client_rect
.left
,
891 data
->whole_rect
.top
- data
->client_rect
.top
);
894 if (event
->window
!= root_window
)
896 if (GetWindowLongW( data
->hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
897 mirror_rect( &data
->client_rect
, &rect
);
899 SERVER_START_REQ( update_window_zorder
)
901 req
->window
= wine_server_user_handle( hwnd
);
902 req
->rect
.left
= rect
.left
;
903 req
->rect
.top
= rect
.top
;
904 req
->rect
.right
= rect
.right
;
905 req
->rect
.bottom
= rect
.bottom
;
906 wine_server_call( req
);
910 else flags
&= ~RDW_ALLCHILDREN
;
912 release_win_data( data
);
914 if (flags
) RedrawWindow( hwnd
, &rect
, surface_region
, flags
);
915 if (surface_region
) DeleteObject( surface_region
);
919 /**********************************************************************
922 static void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
924 struct x11drv_win_data
*data
;
926 if (event
->xany
.window
== x11drv_thread_data()->clip_window
)
928 clipping_cursor
= TRUE
;
931 if (!(data
= get_win_data( hwnd
))) return;
933 if (!data
->managed
&& !data
->embedded
&& data
->mapped
)
935 HWND hwndFocus
= GetFocus();
936 if (hwndFocus
&& IsChild( hwnd
, hwndFocus
))
937 set_input_focus( data
);
939 release_win_data( data
);
943 /**********************************************************************
946 static void X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
)
948 if (event
->xany
.window
== x11drv_thread_data()->clip_window
)
949 clipping_cursor
= FALSE
;
953 /***********************************************************************
954 * is_net_wm_state_maximized
956 static BOOL
is_net_wm_state_maximized( Display
*display
, struct x11drv_win_data
*data
)
960 unsigned long i
, count
, remaining
;
962 if (!data
->whole_window
) return FALSE
;
964 if (!XGetWindowProperty( display
, data
->whole_window
, x11drv_atom(_NET_WM_STATE
), 0,
965 65536/sizeof(CARD32
), False
, XA_ATOM
, &type
, &format
, &count
,
966 &remaining
, (unsigned char **)&state
))
968 if (type
== XA_ATOM
&& format
== 32)
970 for (i
= 0; i
< count
; i
++)
972 if (state
[i
] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT
) ||
973 state
[i
] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ
))
982 /***********************************************************************
985 static void reparent_notify( Display
*display
, HWND hwnd
, Window xparent
, int x
, int y
)
987 HWND parent
, old_parent
;
990 style
= GetWindowLongW( hwnd
, GWL_STYLE
);
991 if (xparent
== root_window
)
993 parent
= GetDesktopWindow();
994 style
= (style
& ~WS_CHILD
) | WS_POPUP
;
998 if (!(parent
= create_foreign_window( display
, xparent
))) return;
999 style
= (style
& ~WS_POPUP
) | WS_CHILD
;
1002 ShowWindow( hwnd
, SW_HIDE
);
1003 old_parent
= SetParent( hwnd
, parent
);
1004 SetWindowLongW( hwnd
, GWL_STYLE
, style
);
1005 SetWindowPos( hwnd
, HWND_TOP
, x
, y
, 0, 0,
1006 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOCOPYBITS
|
1007 ((style
& WS_VISIBLE
) ? SWP_SHOWWINDOW
: 0) );
1009 /* make old parent destroy itself if it no longer has children */
1010 if (old_parent
!= GetDesktopWindow()) PostMessageW( old_parent
, WM_CLOSE
, 0, 0 );
1014 /***********************************************************************
1015 * X11DRV_ReparentNotify
1017 static void X11DRV_ReparentNotify( HWND hwnd
, XEvent
*xev
)
1019 XReparentEvent
*event
= &xev
->xreparent
;
1020 struct x11drv_win_data
*data
;
1022 if (!(data
= get_win_data( hwnd
))) return;
1024 if (!data
->embedded
)
1026 release_win_data( data
);
1030 if (data
->whole_window
)
1032 if (event
->parent
== root_window
)
1034 TRACE( "%p/%lx reparented to root\n", hwnd
, data
->whole_window
);
1036 release_win_data( data
);
1037 SendMessageW( hwnd
, WM_CLOSE
, 0, 0 );
1040 data
->embedder
= event
->parent
;
1043 TRACE( "%p/%lx reparented to %lx\n", hwnd
, data
->whole_window
, event
->parent
);
1044 release_win_data( data
);
1046 reparent_notify( event
->display
, hwnd
, event
->parent
, event
->x
, event
->y
);
1050 /***********************************************************************
1051 * X11DRV_ConfigureNotify
1053 void X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
1055 XConfigureEvent
*event
= &xev
->xconfigure
;
1056 struct x11drv_win_data
*data
;
1062 int cx
, cy
, x
= event
->x
, y
= event
->y
;
1066 if (!(data
= get_win_data( hwnd
))) return;
1067 if (!data
->mapped
|| data
->iconic
) goto done
;
1068 if (data
->whole_window
&& !data
->managed
) goto done
;
1069 /* ignore synthetic events on foreign windows */
1070 if (event
->send_event
&& !data
->whole_window
) goto done
;
1071 if (data
->configure_serial
&& (long)(data
->configure_serial
- event
->serial
) > 0)
1073 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1074 hwnd
, data
->whole_window
, event
->x
, event
->y
, event
->width
, event
->height
,
1075 event
->serial
, data
->configure_serial
);
1081 parent
= GetAncestor( hwnd
, GA_PARENT
);
1082 root_coords
= event
->send_event
; /* synthetic events are always in root coords */
1084 if (!root_coords
&& parent
== GetDesktopWindow()) /* normal event, map coordinates to the root */
1087 XTranslateCoordinates( event
->display
, event
->window
, root_window
,
1088 0, 0, &x
, &y
, &child
);
1097 else pos
= root_to_virtual_screen( x
, y
);
1101 rect
.right
= pos
.x
+ event
->width
;
1102 rect
.bottom
= pos
.y
+ event
->height
;
1103 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1104 hwnd
, data
->whole_window
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
1105 event
->x
, event
->y
, event
->width
, event
->height
);
1107 X11DRV_X_to_window_rect( data
, &rect
);
1108 if (root_coords
) MapWindowPoints( 0, parent
, (POINT
*)&rect
, 2 );
1110 /* Compare what has changed */
1114 cx
= rect
.right
- rect
.left
;
1115 cy
= rect
.bottom
- rect
.top
;
1116 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
1118 if (!data
->whole_window
) flags
|= SWP_NOCOPYBITS
; /* we can't copy bits of foreign windows */
1120 if (data
->window_rect
.left
== x
&& data
->window_rect
.top
== y
) flags
|= SWP_NOMOVE
;
1122 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1123 hwnd
, data
->window_rect
.left
, data
->window_rect
.top
, x
, y
);
1125 if ((data
->window_rect
.right
- data
->window_rect
.left
== cx
&&
1126 data
->window_rect
.bottom
- data
->window_rect
.top
== cy
) ||
1127 (IsRectEmpty( &data
->window_rect
) && event
->width
== 1 && event
->height
== 1))
1128 flags
|= SWP_NOSIZE
;
1130 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1131 hwnd
, data
->window_rect
.right
- data
->window_rect
.left
,
1132 data
->window_rect
.bottom
- data
->window_rect
.top
, cx
, cy
);
1134 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
1135 if ((style
& WS_CAPTION
) == WS_CAPTION
)
1137 if (is_net_wm_state_maximized( event
->display
, data
))
1139 if (!(style
& WS_MAXIMIZE
))
1141 TRACE( "win %p/%lx is maximized\n", data
->hwnd
, data
->whole_window
);
1142 release_win_data( data
);
1143 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1147 else if (style
& WS_MAXIMIZE
)
1149 TRACE( "window %p/%lx is no longer maximized\n", data
->hwnd
, data
->whole_window
);
1150 release_win_data( data
);
1151 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1156 if ((flags
& (SWP_NOSIZE
| SWP_NOMOVE
)) != (SWP_NOSIZE
| SWP_NOMOVE
))
1158 release_win_data( data
);
1159 SetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
1164 release_win_data( data
);
1168 /**********************************************************************
1169 * X11DRV_GravityNotify
1171 static void X11DRV_GravityNotify( HWND hwnd
, XEvent
*xev
)
1173 XGravityEvent
*event
= &xev
->xgravity
;
1174 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1175 RECT rect
, window_rect
;
1179 if (data
->whole_window
) /* only handle this for foreign windows */
1181 release_win_data( data
);
1185 rect
.left
= event
->x
;
1186 rect
.top
= event
->y
;
1187 rect
.right
= rect
.left
+ data
->whole_rect
.right
- data
->whole_rect
.left
;
1188 rect
.bottom
= rect
.top
+ data
->whole_rect
.bottom
- data
->whole_rect
.top
;
1190 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1191 hwnd
, data
->whole_window
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
1192 event
->x
, event
->y
);
1194 X11DRV_X_to_window_rect( data
, &rect
);
1195 window_rect
= data
->window_rect
;
1196 release_win_data( data
);
1198 if (window_rect
.left
!= rect
.left
|| window_rect
.top
!= rect
.top
)
1199 SetWindowPos( hwnd
, 0, rect
.left
, rect
.top
, 0, 0,
1200 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
1204 /***********************************************************************
1205 * get_window_wm_state
1207 static int get_window_wm_state( Display
*display
, Window window
)
1215 int format
, ret
= -1;
1216 unsigned long count
, remaining
;
1218 if (!XGetWindowProperty( display
, window
, x11drv_atom(WM_STATE
), 0,
1219 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
1220 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
1222 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
1230 /***********************************************************************
1231 * handle_wm_state_notify
1233 * Handle a PropertyNotify for WM_STATE.
1235 static void handle_wm_state_notify( HWND hwnd
, XPropertyEvent
*event
, BOOL update_window
)
1237 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1242 switch(event
->state
)
1244 case PropertyDelete
:
1245 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
1246 data
->wm_state
= WithdrawnState
;
1248 case PropertyNewValue
:
1250 int old_state
= data
->wm_state
;
1251 int new_state
= get_window_wm_state( event
->display
, data
->whole_window
);
1252 if (new_state
!= -1 && new_state
!= data
->wm_state
)
1254 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1255 data
->hwnd
, data
->whole_window
, new_state
, old_state
);
1256 data
->wm_state
= new_state
;
1257 /* ignore the initial state transition out of withdrawn state */
1258 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1259 if (!old_state
) goto done
;
1265 if (!update_window
|| !data
->managed
|| !data
->mapped
) goto done
;
1267 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
1269 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
1271 data
->iconic
= FALSE
;
1272 if ((style
& WS_CAPTION
) == WS_CAPTION
&& is_net_wm_state_maximized( event
->display
, data
))
1274 if ((style
& WS_MAXIMIZEBOX
) && !(style
& WS_DISABLED
))
1276 TRACE( "restoring to max %p/%lx\n", data
->hwnd
, data
->whole_window
);
1277 release_win_data( data
);
1278 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1281 TRACE( "not restoring to max win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1285 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1287 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1288 release_win_data( data
);
1289 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1292 TRACE( "not restoring win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1295 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
1297 data
->iconic
= TRUE
;
1298 if ((style
& WS_MINIMIZEBOX
) && !(style
& WS_DISABLED
))
1300 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1301 release_win_data( data
);
1302 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0 );
1305 TRACE( "not minimizing win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1308 release_win_data( data
);
1312 /***********************************************************************
1313 * X11DRV_PropertyNotify
1315 static void X11DRV_PropertyNotify( HWND hwnd
, XEvent
*xev
)
1317 XPropertyEvent
*event
= &xev
->xproperty
;
1320 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( hwnd
, event
, TRUE
);
1324 /* event filter to wait for a WM_STATE change notification on a window */
1325 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
1327 if (event
->xany
.window
!= (Window
)arg
) return 0;
1328 return (event
->type
== DestroyNotify
||
1329 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
1332 /***********************************************************************
1333 * wait_for_withdrawn_state
1335 void wait_for_withdrawn_state( HWND hwnd
, BOOL set
)
1337 Display
*display
= thread_display();
1338 struct x11drv_win_data
*data
;
1339 DWORD end
= GetTickCount() + 2000;
1341 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd
, set
? "" : "not " );
1349 if (!(data
= get_win_data( hwnd
))) break;
1350 if (!data
->managed
|| data
->embedded
|| data
->display
!= display
) break;
1351 if (!(window
= data
->whole_window
)) break;
1352 if (!data
->mapped
== !set
)
1354 TRACE( "window %p/%lx now %smapped\n", hwnd
, window
, data
->mapped
? "" : "un" );
1357 if ((data
->wm_state
== WithdrawnState
) != !set
)
1359 TRACE( "window %p/%lx state now %d\n", hwnd
, window
, data
->wm_state
);
1362 release_win_data( data
);
1364 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)window
))
1367 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
1368 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
1369 else handle_wm_state_notify( hwnd
, &event
.xproperty
, FALSE
);
1375 int timeout
= end
- GetTickCount();
1377 pfd
.fd
= ConnectionNumber(display
);
1378 pfd
.events
= POLLIN
;
1379 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
1381 FIXME( "window %p/%lx wait timed out\n", hwnd
, window
);
1386 release_win_data( data
);
1390 /*****************************************************************
1391 * SetFocus (X11DRV.@)
1395 void CDECL
X11DRV_SetFocus( HWND hwnd
)
1397 struct x11drv_win_data
*data
;
1403 if (!(data
= get_win_data( hwnd
))) return;
1404 if (data
->embedded
) break;
1405 parent
= GetAncestor( hwnd
, GA_PARENT
);
1406 if (!parent
|| parent
== GetDesktopWindow()) break;
1407 release_win_data( data
);
1410 if (!data
->managed
|| data
->embedder
) set_input_focus( data
);
1411 release_win_data( data
);
1415 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
1419 if (!IsWindowEnabled(hQueryWnd
)) return 0;
1421 GetWindowRect(hQueryWnd
, &tempRect
);
1423 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
1425 if (!IsIconic( hQueryWnd
))
1428 ScreenToClient( hQueryWnd
, &pt
);
1429 GetClientRect( hQueryWnd
, &tempRect
);
1431 if (PtInRect( &tempRect
, pt
))
1433 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
1434 if (ret
&& ret
!= hQueryWnd
)
1436 ret
= find_drop_window( ret
, lpPt
);
1437 if (ret
) return ret
;
1442 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
1444 ScreenToClient(hQueryWnd
, lpPt
);
1449 /**********************************************************************
1450 * EVENT_DropFromOffix
1452 * don't know if it still works (last Changelog is from 96/11/04)
1454 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1456 struct x11drv_win_data
*data
;
1458 unsigned long data_length
;
1459 unsigned long aux_long
;
1460 unsigned char* p_data
= NULL
;
1462 int x
, y
, cx
, cy
, dummy
;
1463 Window win
, w_aux_root
, w_aux_child
;
1465 if (!(data
= get_win_data( hWnd
))) return;
1466 cx
= data
->whole_rect
.right
- data
->whole_rect
.left
;
1467 cy
= data
->whole_rect
.bottom
- data
->whole_rect
.top
;
1468 win
= data
->whole_window
;
1469 release_win_data( data
);
1471 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
1472 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
1473 pt
= root_to_virtual_screen( x
, y
);
1475 /* find out drop point and drop window */
1476 if (pt
.x
< 0 || pt
.y
< 0 || pt
.x
> cx
|| pt
.y
> cy
)
1478 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1483 if (!find_drop_window( hWnd
, &pt
)) return;
1486 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1487 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1488 AnyPropertyType
, &atom_aux
, &dummy
,
1489 &data_length
, &aux_long
, &p_data
);
1491 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1493 char *p
= (char *)p_data
;
1497 while( *p
) /* calculate buffer size */
1499 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1500 if (len
) aux_long
+= len
+ 1;
1503 if( aux_long
&& aux_long
< 65535 )
1508 aux_long
+= sizeof(DROPFILES
) + 1;
1509 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1510 lpDrop
= GlobalLock( hDrop
);
1514 lpDrop
->pFiles
= sizeof(DROPFILES
);
1516 lpDrop
->fNC
= FALSE
;
1517 lpDrop
->fWide
= FALSE
;
1518 p_drop
= (char *)(lpDrop
+ 1);
1522 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
1523 p_drop
+= strlen( p_drop
) + 1;
1527 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1531 if( p_data
) XFree(p_data
);
1534 /**********************************************************************
1537 * drop items are separated by \n
1538 * each item is prefixed by its mime type
1540 * event->data.l[3], event->data.l[4] contains drop x,y position
1542 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1544 struct x11drv_win_data
*win_data
;
1545 unsigned long data_length
;
1546 unsigned long aux_long
, drop_len
= 0;
1547 unsigned char *p_data
= NULL
; /* property data */
1548 char *p_drop
= NULL
;
1561 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1563 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1564 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1565 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1566 &data_length
, &aux_long
, &p_data
);
1568 WARN("property too large, truncated!\n");
1569 TRACE("urls=%s\n", p_data
);
1571 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1572 /* calculate length */
1574 next
= strchr(p
, '\n');
1577 if (strncmp(p
,"file:",5) == 0 ) {
1578 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1579 if (len
) drop_len
+= len
+ 1;
1584 next
= strchr(p
, '\n');
1590 if( drop_len
&& drop_len
< 65535 ) {
1591 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1592 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1593 pos
= root_to_virtual_screen( x
, y
);
1595 drop_len
+= sizeof(DROPFILES
) + 1;
1596 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1597 lpDrop
= GlobalLock( hDrop
);
1599 if( lpDrop
&& (win_data
= get_win_data( hWnd
)))
1601 lpDrop
->pFiles
= sizeof(DROPFILES
);
1604 (pos
.x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1605 pos
.y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1606 pos
.x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1607 pos
.y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1608 lpDrop
->fWide
= FALSE
;
1609 p_drop
= (char*)(lpDrop
+ 1);
1610 release_win_data( win_data
);
1613 /* create message content */
1616 next
= strchr(p
, '\n');
1619 if (strncmp(p
,"file:",5) == 0 ) {
1620 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1622 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1625 WARN("can't convert file %s to dos name\n", p
+5);
1628 WARN("unknown mime type %s\n", p
);
1633 next
= strchr(p
, '\n');
1640 GlobalUnlock(hDrop
);
1641 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1644 if( p_data
) XFree(p_data
);
1649 /**********************************************************************
1650 * handle_xembed_protocol
1652 static void handle_xembed_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1654 switch (event
->data
.l
[1])
1656 case XEMBED_EMBEDDED_NOTIFY
:
1658 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1661 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd
, event
->window
, event
->data
.l
[3] );
1662 data
->embedder
= event
->data
.l
[3];
1664 /* window has been marked as embedded before (e.g. systray) */
1665 if (data
->embedded
|| !data
->embedder
/* broken QX11EmbedContainer implementation */)
1667 release_win_data( data
);
1671 make_window_embedded( data
);
1672 release_win_data( data
);
1673 reparent_notify( event
->display
, hwnd
, event
->data
.l
[3], 0, 0 );
1677 case XEMBED_WINDOW_DEACTIVATE
:
1678 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd
, event
->window
);
1679 focus_out( event
->display
, GetAncestor( hwnd
, GA_ROOT
) );
1682 case XEMBED_FOCUS_OUT
:
1683 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd
, event
->window
);
1684 focus_out( event
->display
, GetAncestor( hwnd
, GA_ROOT
) );
1687 case XEMBED_MODALITY_ON
:
1688 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd
, event
->window
);
1689 EnableWindow( hwnd
, FALSE
);
1692 case XEMBED_MODALITY_OFF
:
1693 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd
, event
->window
);
1694 EnableWindow( hwnd
, TRUE
);
1698 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1699 hwnd
, event
->window
, event
->data
.l
[1], event
->data
.l
[2] );
1705 /**********************************************************************
1706 * handle_dnd_protocol
1708 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1711 int root_x
, root_y
, child_x
, child_y
;
1714 /* query window (drag&drop event contains only drag window) */
1715 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1716 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1717 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1719 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1720 EVENT_DropFromOffiX(hwnd
, event
);
1721 else if (event
->data
.l
[0] == DndURL
)
1722 EVENT_DropURLs(hwnd
, event
);
1726 struct client_message_handler
1728 int atom
; /* protocol atom */
1729 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1732 static const struct client_message_handler client_messages
[] =
1734 { XATOM_MANAGER
, handle_manager_message
},
1735 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1736 { XATOM__XEMBED
, handle_xembed_protocol
},
1737 { XATOM_DndProtocol
, handle_dnd_protocol
},
1738 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
1739 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
1740 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
1741 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
1745 /**********************************************************************
1746 * X11DRV_ClientMessage
1748 static void X11DRV_ClientMessage( HWND hwnd
, XEvent
*xev
)
1750 XClientMessageEvent
*event
= &xev
->xclient
;
1755 if (event
->format
!= 32)
1757 WARN( "Don't know how to handle format %d\n", event
->format
);
1761 for (i
= 0; i
< sizeof(client_messages
)/sizeof(client_messages
[0]); i
++)
1763 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1765 client_messages
[i
].handler( hwnd
, event
);
1769 TRACE( "no handler found for %ld\n", event
->message_type
);