cmd: DIR command outputs free space for the path.
[wine.git] / dlls / winex11.drv / event.c
blobc3c8d9a40702bf5aa06d668f67d3b09240652519
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
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
22 #if 0
23 #pragma makedep unix
24 #endif
26 #include "config.h"
28 #include <poll.h>
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xresource.h>
33 #include <X11/Xutil.h>
34 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
35 #include <X11/extensions/XInput2.h>
36 #endif
38 #include <assert.h>
39 #include <stdarg.h>
40 #include <string.h>
42 #include "x11drv.h"
43 #include "shlobj.h" /* DROPFILES */
44 #include "shellapi.h"
46 #include "wine/server.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(event);
50 WINE_DECLARE_DEBUG_CHANNEL(xdnd);
52 #define DndNotDnd -1 /* OffiX drag&drop */
53 #define DndUnknown 0
54 #define DndRawData 1
55 #define DndFile 2
56 #define DndFiles 3
57 #define DndText 4
58 #define DndDir 5
59 #define DndLink 6
60 #define DndExe 7
62 #define DndEND 8
64 #define DndURL 128 /* KDE drag&drop */
66 #define XEMBED_EMBEDDED_NOTIFY 0
67 #define XEMBED_WINDOW_ACTIVATE 1
68 #define XEMBED_WINDOW_DEACTIVATE 2
69 #define XEMBED_REQUEST_FOCUS 3
70 #define XEMBED_FOCUS_IN 4
71 #define XEMBED_FOCUS_OUT 5
72 #define XEMBED_FOCUS_NEXT 6
73 #define XEMBED_FOCUS_PREV 7
74 #define XEMBED_MODALITY_ON 10
75 #define XEMBED_MODALITY_OFF 11
76 #define XEMBED_REGISTER_ACCELERATOR 12
77 #define XEMBED_UNREGISTER_ACCELERATOR 13
78 #define XEMBED_ACTIVATE_ACCELERATOR 14
80 Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
81 void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
83 /* Event handlers */
84 static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *event );
85 static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *event );
86 static BOOL X11DRV_Expose( HWND hwnd, XEvent *event );
87 static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event );
88 static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
89 static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
90 static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
91 static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
92 static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *event );
93 static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *event );
95 #define MAX_EVENT_HANDLERS 128
97 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
99 NULL, /* 0 reserved */
100 NULL, /* 1 reserved */
101 X11DRV_KeyEvent, /* 2 KeyPress */
102 X11DRV_KeyEvent, /* 3 KeyRelease */
103 X11DRV_ButtonPress, /* 4 ButtonPress */
104 X11DRV_ButtonRelease, /* 5 ButtonRelease */
105 X11DRV_MotionNotify, /* 6 MotionNotify */
106 X11DRV_EnterNotify, /* 7 EnterNotify */
107 NULL, /* 8 LeaveNotify */
108 X11DRV_FocusIn, /* 9 FocusIn */
109 X11DRV_FocusOut, /* 10 FocusOut */
110 X11DRV_KeymapNotify, /* 11 KeymapNotify */
111 X11DRV_Expose, /* 12 Expose */
112 NULL, /* 13 GraphicsExpose */
113 NULL, /* 14 NoExpose */
114 NULL, /* 15 VisibilityNotify */
115 NULL, /* 16 CreateNotify */
116 X11DRV_DestroyNotify, /* 17 DestroyNotify */
117 X11DRV_UnmapNotify, /* 18 UnmapNotify */
118 X11DRV_MapNotify, /* 19 MapNotify */
119 NULL, /* 20 MapRequest */
120 X11DRV_ReparentNotify, /* 21 ReparentNotify */
121 X11DRV_ConfigureNotify, /* 22 ConfigureNotify */
122 NULL, /* 23 ConfigureRequest */
123 X11DRV_GravityNotify, /* 24 GravityNotify */
124 NULL, /* 25 ResizeRequest */
125 NULL, /* 26 CirculateNotify */
126 NULL, /* 27 CirculateRequest */
127 X11DRV_PropertyNotify, /* 28 PropertyNotify */
128 X11DRV_SelectionClear, /* 29 SelectionClear */
129 X11DRV_SelectionRequest, /* 30 SelectionRequest */
130 NULL, /* 31 SelectionNotify */
131 NULL, /* 32 ColormapNotify */
132 X11DRV_ClientMessage, /* 33 ClientMessage */
133 X11DRV_MappingNotify, /* 34 MappingNotify */
134 X11DRV_GenericEvent /* 35 GenericEvent */
137 static const char * event_names[MAX_EVENT_HANDLERS] =
139 NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
140 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
141 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
142 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
143 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
144 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
145 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
148 /* is someone else grabbing the keyboard, for example the WM, when manipulating the window */
149 BOOL keyboard_grabbed = FALSE;
151 int xinput2_opcode = 0;
153 /* return the name of an X event */
154 static const char *dbgstr_event( int type )
156 if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
157 return wine_dbg_sprintf( "Unknown event %d", type );
160 static inline void get_event_data( XEvent *event )
162 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
163 if (event->xany.type != GenericEvent) return;
164 if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
165 #endif
168 static inline void free_event_data( XEvent *event )
170 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
171 if (event->xany.type != GenericEvent) return;
172 if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
173 #endif
176 /***********************************************************************
177 * xembed_request_focus
179 static void xembed_request_focus( Display *display, Window window, DWORD timestamp )
181 XEvent xev;
183 xev.xclient.type = ClientMessage;
184 xev.xclient.window = window;
185 xev.xclient.message_type = x11drv_atom(_XEMBED);
186 xev.xclient.serial = 0;
187 xev.xclient.display = display;
188 xev.xclient.send_event = True;
189 xev.xclient.format = 32;
191 xev.xclient.data.l[0] = timestamp;
192 xev.xclient.data.l[1] = XEMBED_REQUEST_FOCUS;
193 xev.xclient.data.l[2] = 0;
194 xev.xclient.data.l[3] = 0;
195 xev.xclient.data.l[4] = 0;
197 XSendEvent(display, window, False, NoEventMask, &xev);
198 XFlush( display );
201 /***********************************************************************
202 * X11DRV_register_event_handler
204 * Register a handler for a given event type.
205 * If already registered, overwrite the previous handler.
207 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
209 assert( type < MAX_EVENT_HANDLERS );
210 assert( !handlers[type] || handlers[type] == handler );
211 handlers[type] = handler;
212 event_names[type] = name;
213 TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
217 /***********************************************************************
218 * filter_event
220 static Bool filter_event( Display *display, XEvent *event, char *arg )
222 ULONG_PTR mask = (ULONG_PTR)arg;
224 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
226 switch(event->type)
228 case KeyPress:
229 case KeyRelease:
230 case KeymapNotify:
231 case MappingNotify:
232 return (mask & (QS_KEY|QS_HOTKEY)) != 0;
233 case ButtonPress:
234 case ButtonRelease:
235 return (mask & QS_MOUSEBUTTON) != 0;
236 #ifdef GenericEvent
237 case GenericEvent:
238 #endif
239 case MotionNotify:
240 case EnterNotify:
241 case LeaveNotify:
242 return (mask & QS_MOUSEMOVE) != 0;
243 case Expose:
244 return (mask & QS_PAINT) != 0;
245 case FocusIn:
246 case FocusOut:
247 case MapNotify:
248 case UnmapNotify:
249 case ConfigureNotify:
250 case PropertyNotify:
251 case ClientMessage:
252 return (mask & QS_POSTMESSAGE) != 0;
253 default:
254 return (mask & QS_SENDMESSAGE) != 0;
259 enum event_merge_action
261 MERGE_DISCARD, /* discard the old event */
262 MERGE_HANDLE, /* handle the old event */
263 MERGE_KEEP, /* keep the old event for future merging */
264 MERGE_IGNORE /* ignore the new event, keep the old one */
267 /***********************************************************************
268 * merge_raw_motion_events
270 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
271 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
273 int i, j, k;
274 unsigned char mask;
276 if (!prev->valuators.mask_len) return MERGE_HANDLE;
277 if (!next->valuators.mask_len) return MERGE_HANDLE;
279 mask = prev->valuators.mask[0] | next->valuators.mask[0];
280 if (mask == next->valuators.mask[0]) /* keep next */
282 for (i = j = k = 0; i < 8; i++)
284 if (XIMaskIsSet( prev->valuators.mask, i ))
285 next->valuators.values[j] += prev->valuators.values[k++];
286 if (XIMaskIsSet( next->valuators.mask, i )) j++;
288 TRACE( "merging duplicate GenericEvent\n" );
289 return MERGE_DISCARD;
291 if (mask == prev->valuators.mask[0]) /* keep prev */
293 for (i = j = k = 0; i < 8; i++)
295 if (XIMaskIsSet( next->valuators.mask, i ))
296 prev->valuators.values[j] += next->valuators.values[k++];
297 if (XIMaskIsSet( prev->valuators.mask, i )) j++;
299 TRACE( "merging duplicate GenericEvent\n" );
300 return MERGE_IGNORE;
302 /* can't merge events with disjoint masks */
303 return MERGE_HANDLE;
305 #endif
307 /***********************************************************************
308 * merge_events
310 * Try to merge 2 consecutive events.
312 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
314 switch (prev->type)
316 case ConfigureNotify:
317 switch (next->type)
319 case ConfigureNotify:
320 if (prev->xany.window == next->xany.window)
322 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
323 return MERGE_DISCARD;
325 break;
326 case Expose:
327 case PropertyNotify:
328 return MERGE_KEEP;
330 break;
331 case MotionNotify:
332 switch (next->type)
334 case MotionNotify:
335 if (prev->xany.window == next->xany.window)
337 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
338 return MERGE_DISCARD;
340 break;
341 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
342 case GenericEvent:
343 if (next->xcookie.extension != xinput2_opcode) break;
344 if (next->xcookie.evtype != XI_RawMotion) break;
345 if (x11drv_thread_data()->warp_serial) break;
346 return MERGE_KEEP;
348 break;
349 case GenericEvent:
350 if (prev->xcookie.extension != xinput2_opcode) break;
351 if (prev->xcookie.evtype != XI_RawMotion) break;
352 switch (next->type)
354 case GenericEvent:
355 if (next->xcookie.extension != xinput2_opcode) break;
356 if (next->xcookie.evtype != XI_RawMotion) break;
357 if (x11drv_thread_data()->warp_serial) break;
358 return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
359 #endif
361 break;
363 return MERGE_HANDLE;
367 /***********************************************************************
368 * call_event_handler
370 static inline BOOL call_event_handler( Display *display, XEvent *event )
372 HWND hwnd;
373 XEvent *prev;
374 struct x11drv_thread_data *thread_data;
375 BOOL ret;
377 if (!handlers[event->type])
379 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
380 return FALSE; /* no handler, ignore it */
383 #ifdef GenericEvent
384 if (event->type == GenericEvent) hwnd = 0; else
385 #endif
386 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
387 hwnd = 0; /* not for a registered window */
388 if (!hwnd && event->xany.window == root_window) hwnd = NtUserGetDesktopWindow();
390 TRACE( "%lu %s for hwnd/window %p/%lx\n",
391 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
392 thread_data = x11drv_thread_data();
393 prev = thread_data->current_event;
394 thread_data->current_event = event;
395 ret = handlers[event->type]( hwnd, event );
396 thread_data->current_event = prev;
397 return ret;
401 /***********************************************************************
402 * process_events
404 static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
406 XEvent event, prev_event;
407 int count = 0;
408 BOOL queued = FALSE;
409 enum event_merge_action action = MERGE_DISCARD;
411 prev_event.type = 0;
412 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
414 count++;
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)
428 KeySym keysym = 0;
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 */
442 else
443 continue; /* filtered, ignore it */
445 get_event_data( &event );
446 if (prev_event.type) action = merge_events( &prev_event, &event );
447 switch( action )
449 case MERGE_HANDLE: /* handle prev, keep new */
450 queued |= call_event_handler( display, &prev_event );
451 /* fall through */
452 case MERGE_DISCARD: /* discard prev, keep new */
453 free_event_data( &prev_event );
454 prev_event = event;
455 break;
456 case MERGE_KEEP: /* handle new, keep prev for future merging */
457 queued |= call_event_handler( display, &event );
458 /* fall through */
459 case MERGE_IGNORE: /* ignore new, keep prev for future merging */
460 free_event_data( &event );
461 break;
464 if (prev_event.type) queued |= call_event_handler( display, &prev_event );
465 free_event_data( &prev_event );
466 XFlush( gdi_display );
467 if (count) TRACE( "processed %d events, returning %d\n", count, queued );
468 return queued;
472 /***********************************************************************
473 * ProcessEvents (X11DRV.@)
475 BOOL X11DRV_ProcessEvents( DWORD mask )
477 struct x11drv_thread_data *data = x11drv_thread_data();
479 if (!data) return FALSE;
480 if (data->current_event) mask = 0; /* don't process nested events */
482 return process_events( data->display, filter_event, mask );
485 /***********************************************************************
486 * EVENT_x11_time_to_win32_time
488 * Make our timer and the X timer line up as best we can
489 * Pass 0 to retrieve the current adjustment value (times -1)
491 DWORD EVENT_x11_time_to_win32_time(Time time)
493 static DWORD adjust = 0;
494 DWORD now = NtGetTickCount();
495 DWORD ret;
497 if (! adjust && time != 0)
499 ret = now;
500 adjust = time - now;
502 else
504 /* If we got an event in the 'future', then our clock is clearly wrong.
505 If we got it more than 10000 ms in the future, then it's most likely
506 that the clock has wrapped. */
508 ret = time - adjust;
509 if (ret > now && ((ret - now) < 10000) && time != 0)
511 adjust += ret - now;
512 ret -= ret - now;
516 return ret;
520 /*******************************************************************
521 * can_activate_window
523 * Check if we can activate the specified window.
525 static inline BOOL can_activate_window( HWND hwnd )
527 LONG style = NtUserGetWindowLongW( hwnd, GWL_STYLE );
528 RECT rect;
530 if (!(style & WS_VISIBLE)) return FALSE;
531 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
532 if (style & WS_MINIMIZE) return FALSE;
533 if (NtUserGetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
534 if (hwnd == NtUserGetDesktopWindow()) return FALSE;
535 if (NtUserGetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE;
536 return !(style & WS_DISABLED);
540 /**********************************************************************
541 * set_input_focus
543 * Try to force focus for embedded or non-managed windows.
545 static void set_input_focus( struct x11drv_win_data *data )
547 XWindowChanges changes;
548 DWORD timestamp;
550 if (!data->whole_window) return;
552 if (EVENT_x11_time_to_win32_time(0))
553 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
554 /* FIXME: this is not entirely correct */
555 timestamp = NtUserGetThreadInfo()->message_time - EVENT_x11_time_to_win32_time(0);
556 else
557 timestamp = CurrentTime;
559 /* Set X focus and install colormap */
560 changes.stack_mode = Above;
561 XConfigureWindow( data->display, data->whole_window, CWStackMode, &changes );
563 if (data->embedder)
564 xembed_request_focus( data->display, data->embedder, timestamp );
565 else
566 XSetInputFocus( data->display, data->whole_window, RevertToParent, timestamp );
570 /**********************************************************************
571 * set_focus
573 static void set_focus( Display *display, HWND hwnd, Time time )
575 HWND focus;
576 Window win;
577 GUITHREADINFO threadinfo;
579 TRACE( "setting foreground window to %p\n", hwnd );
580 NtUserSetForegroundWindow( hwnd );
582 threadinfo.cbSize = sizeof(threadinfo);
583 NtUserGetGUIThreadInfo( 0, &threadinfo );
584 focus = threadinfo.hwndFocus;
585 if (!focus) focus = threadinfo.hwndActive;
586 if (focus) focus = NtUserGetAncestor( focus, GA_ROOT );
587 win = X11DRV_get_whole_window(focus);
589 if (win)
591 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
592 XSetInputFocus( display, win, RevertToParent, time );
597 /**********************************************************************
598 * handle_manager_message
600 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
602 if (hwnd != NtUserGetDesktopWindow()) return;
604 if (systray_atom && event->data.l[1] == systray_atom)
606 struct systray_change_owner_params params;
608 TRACE( "new owner %lx\n", event->data.l[2] );
610 params.event_handle = (UINT_PTR)event;
611 x11drv_client_func( client_func_systray_change_owner, &params, sizeof(params) );
616 /**********************************************************************
617 * handle_wm_protocols
619 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
621 Atom protocol = (Atom)event->data.l[0];
622 Time event_time = (Time)event->data.l[1];
624 if (!protocol) return;
626 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
628 update_user_time( event_time );
630 if (hwnd == NtUserGetDesktopWindow())
632 /* The desktop window does not have a close button that we can
633 * pretend to click. Therefore, we simply send it a close command. */
634 send_message( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
635 return;
638 /* Ignore the delete window request if the window has been disabled
639 * and we are in managed mode. This is to disallow applications from
640 * being closed by the window manager while in a modal state.
642 if (NtUserIsWindowEnabled( hwnd ))
644 HMENU hSysMenu;
646 if (NtUserGetClassLongW( hwnd, GCL_STYLE ) & CS_NOCLOSE) return;
647 hSysMenu = NtUserGetSystemMenu( hwnd, FALSE );
648 if (hSysMenu)
650 UINT state = NtUserThunkedMenuItemInfo( hSysMenu, SC_CLOSE, MF_BYCOMMAND,
651 NtUserGetMenuState, NULL, NULL );
652 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
653 return;
655 if (get_active_window() != hwnd)
657 LRESULT ma = send_message( hwnd, WM_MOUSEACTIVATE,
658 (WPARAM)NtUserGetAncestor( hwnd, GA_ROOT ),
659 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
660 switch(ma)
662 case MA_NOACTIVATEANDEAT:
663 case MA_ACTIVATEANDEAT:
664 return;
665 case MA_NOACTIVATE:
666 break;
667 case MA_ACTIVATE:
668 case 0:
669 NtUserSetActiveWindow( hwnd );
670 break;
671 default:
672 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
673 break;
677 NtUserPostMessage( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
680 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
682 HWND last_focus = x11drv_thread_data()->last_focus;
684 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
685 hwnd, NtUserIsWindowEnabled(hwnd), NtUserIsWindowVisible(hwnd),
686 (int)NtUserGetWindowLongW(hwnd, GWL_STYLE),
687 get_focus(), get_active_window(), NtUserGetForegroundWindow(), last_focus );
689 if (can_activate_window(hwnd))
691 /* simulate a mouse click on the menu to find out
692 * whether the window wants to be activated */
693 LRESULT ma = send_message( hwnd, WM_MOUSEACTIVATE,
694 (WPARAM)NtUserGetAncestor( hwnd, GA_ROOT ),
695 MAKELONG( HTMENU, WM_LBUTTONDOWN ) );
696 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
698 set_focus( event->display, hwnd, event_time );
699 return;
702 else if (hwnd == NtUserGetDesktopWindow())
704 hwnd = NtUserGetForegroundWindow();
705 if (!hwnd) hwnd = last_focus;
706 if (!hwnd) hwnd = NtUserGetDesktopWindow();
707 set_focus( event->display, hwnd, event_time );
708 return;
710 /* try to find some other window to give the focus to */
711 hwnd = get_focus();
712 if (hwnd) hwnd = NtUserGetAncestor( hwnd, GA_ROOT );
713 if (!hwnd) hwnd = get_active_window();
714 if (!hwnd) hwnd = last_focus;
715 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
717 else if (protocol == x11drv_atom(_NET_WM_PING))
719 XClientMessageEvent xev;
720 xev = *event;
722 TRACE("NET_WM Ping\n");
723 xev.window = DefaultRootWindow(xev.display);
724 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
729 static const char * const focus_details[] =
731 "NotifyAncestor",
732 "NotifyVirtual",
733 "NotifyInferior",
734 "NotifyNonlinear",
735 "NotifyNonlinearVirtual",
736 "NotifyPointer",
737 "NotifyPointerRoot",
738 "NotifyDetailNone"
741 static const char * const focus_modes[] =
743 "NotifyNormal",
744 "NotifyGrab",
745 "NotifyUngrab",
746 "NotifyWhileGrabbed"
749 BOOL is_current_process_focused(void)
751 Display *display = x11drv_thread_data()->display;
752 Window focus;
753 int revert;
754 HWND hwnd;
756 XGetInputFocus( display, &focus, &revert );
757 if (focus && !XFindContext( display, focus, winContext, (char **)&hwnd )) return TRUE;
758 return FALSE;
761 /**********************************************************************
762 * X11DRV_FocusIn
764 static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
766 XFocusChangeEvent *event = &xev->xfocus;
767 BOOL was_grabbed;
769 if (!hwnd) return FALSE;
771 TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] );
773 if (event->detail == NotifyPointer) return FALSE;
774 /* when focusing in the virtual desktop window, re-apply the cursor clipping rect */
775 if (is_virtual_desktop() && hwnd == NtUserGetDesktopWindow()) retry_grab_clipping_window();
776 if (hwnd == NtUserGetDesktopWindow()) return FALSE;
778 /* when keyboard grab is released, re-apply the cursor clipping rect */
779 was_grabbed = keyboard_grabbed;
780 keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed;
781 if (was_grabbed > keyboard_grabbed) retry_grab_clipping_window();
782 /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
783 if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE;
785 xim_set_focus( hwnd, TRUE );
787 if (use_take_focus) return TRUE;
789 if (!can_activate_window(hwnd))
791 HWND hwnd = get_focus();
792 if (hwnd) hwnd = NtUserGetAncestor( hwnd, GA_ROOT );
793 if (!hwnd) hwnd = get_active_window();
794 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
795 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
797 else NtUserSetForegroundWindow( hwnd );
798 return TRUE;
801 /**********************************************************************
802 * focus_out
804 static void focus_out( Display *display , HWND hwnd )
806 if (xim_in_compose_mode()) return;
808 x11drv_thread_data()->last_focus = hwnd;
809 xim_set_focus( hwnd, FALSE );
811 if (is_virtual_desktop()) return;
812 if (hwnd != NtUserGetForegroundWindow()) return;
813 if (!(NtUserGetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE))
814 send_message( hwnd, WM_CANCELMODE, 0, 0 );
816 /* don't reset the foreground window, if the window which is
817 getting the focus is a Wine window */
819 if (!is_current_process_focused())
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 == NtUserGetForegroundWindow())
827 TRACE( "lost focus, setting fg to desktop\n" );
828 NtUserSetForegroundWindow( NtUserGetDesktopWindow() );
833 /**********************************************************************
834 * X11DRV_FocusOut
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 mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] );
844 if (event->detail == NotifyPointer)
846 if (!hwnd && event->window == x11drv_thread_data()->clip_window) NtUserClipCursor( NULL );
847 return TRUE;
849 if (!hwnd) return FALSE;
851 /* in virtual desktop mode or when keyboard is grabbed, release any cursor grab but keep the clipping rect */
852 keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed;
853 if (is_virtual_desktop() || keyboard_grabbed) ungrab_clipping_window();
854 /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
855 if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE;
857 focus_out( event->display, hwnd );
858 return TRUE;
862 /***********************************************************************
863 * X11DRV_Expose
865 static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev )
867 XExposeEvent *event = &xev->xexpose;
868 RECT rect, abs_rect;
869 POINT pos;
870 struct x11drv_win_data *data;
871 HRGN surface_region = 0;
872 UINT flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN;
874 TRACE( "win %p (%lx) %d,%d %dx%d\n",
875 hwnd, event->window, event->x, event->y, event->width, event->height );
877 if (event->window != root_window)
879 pos.x = event->x;
880 pos.y = event->y;
882 else pos = root_to_virtual_screen( event->x, event->y );
884 if (!(data = get_win_data( hwnd ))) return FALSE;
886 rect.left = pos.x;
887 rect.top = pos.y;
888 rect.right = pos.x + event->width;
889 rect.bottom = pos.y + event->height;
891 if (event->window != data->client_window)
893 if (data->surface)
895 surface_region = expose_surface( data->surface, &rect );
896 if (!surface_region) flags = 0;
897 else NtGdiOffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
898 data->whole_rect.top - data->client_rect.top );
900 if (data->vis.visualid != default_visual.visualid)
901 data->surface->funcs->flush( data->surface );
903 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
904 data->whole_rect.top - data->client_rect.top );
907 if (event->window != root_window)
909 if (NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
910 mirror_rect( &data->client_rect, &rect );
911 abs_rect = rect;
912 NtUserMapWindowPoints( hwnd, 0, (POINT *)&abs_rect, 2 );
914 SERVER_START_REQ( update_window_zorder )
916 req->window = wine_server_user_handle( hwnd );
917 req->rect.left = abs_rect.left;
918 req->rect.top = abs_rect.top;
919 req->rect.right = abs_rect.right;
920 req->rect.bottom = abs_rect.bottom;
921 wine_server_call( req );
923 SERVER_END_REQ;
925 else flags &= ~RDW_ALLCHILDREN;
927 release_win_data( data );
929 if (flags) NtUserRedrawWindow( hwnd, &rect, surface_region, flags );
930 if (surface_region) NtGdiDeleteObjectApp( surface_region );
931 return TRUE;
935 /**********************************************************************
936 * X11DRV_MapNotify
938 static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event )
940 struct x11drv_win_data *data;
942 if (event->xany.window == x11drv_thread_data()->clip_window) return TRUE;
944 if (!(data = get_win_data( hwnd ))) return FALSE;
946 if (!data->managed && !data->embedded && data->mapped)
948 HWND hwndFocus = get_focus();
949 if (hwndFocus && NtUserIsChild( hwnd, hwndFocus ))
950 set_input_focus( data );
952 release_win_data( data );
953 return TRUE;
957 /**********************************************************************
958 * X11DRV_UnmapNotify
960 static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
962 return TRUE;
966 /***********************************************************************
967 * reparent_notify
969 static void reparent_notify( Display *display, HWND hwnd, Window xparent, int x, int y )
971 HWND parent, old_parent;
972 DWORD style;
974 style = NtUserGetWindowLongW( hwnd, GWL_STYLE );
975 if (xparent == root_window)
977 parent = NtUserGetDesktopWindow();
978 style = (style & ~WS_CHILD) | WS_POPUP;
980 else
982 if (!(parent = create_foreign_window( display, xparent ))) return;
983 style = (style & ~WS_POPUP) | WS_CHILD;
986 NtUserShowWindow( hwnd, SW_HIDE );
987 old_parent = NtUserSetParent( hwnd, parent );
988 NtUserSetWindowLong( hwnd, GWL_STYLE, style, FALSE );
989 NtUserSetWindowPos( hwnd, HWND_TOP, x, y, 0, 0,
990 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
991 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
993 /* make old parent destroy itself if it no longer has children */
994 if (old_parent != NtUserGetDesktopWindow()) NtUserPostMessage( old_parent, WM_CLOSE, 0, 0 );
998 /***********************************************************************
999 * X11DRV_ReparentNotify
1001 static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
1003 XReparentEvent *event = &xev->xreparent;
1004 struct x11drv_win_data *data;
1006 if (!(data = get_win_data( hwnd ))) return FALSE;
1008 if (!data->embedded)
1010 release_win_data( data );
1011 return FALSE;
1014 if (data->whole_window)
1016 if (event->parent == root_window)
1018 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
1019 data->embedder = 0;
1020 release_win_data( data );
1021 send_message( hwnd, WM_CLOSE, 0, 0 );
1022 return TRUE;
1024 data->embedder = event->parent;
1027 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
1028 release_win_data( data );
1030 reparent_notify( event->display, hwnd, event->parent, event->x, event->y );
1031 return TRUE;
1035 /***********************************************************************
1036 * X11DRV_ConfigureNotify
1038 static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
1040 XConfigureEvent *event = &xev->xconfigure;
1041 struct x11drv_win_data *data;
1042 RECT rect;
1043 POINT pos;
1044 UINT flags;
1045 HWND parent;
1046 BOOL root_coords;
1047 int cx, cy, x = event->x, y = event->y;
1048 DWORD style;
1050 if (!hwnd) return FALSE;
1051 if (!(data = get_win_data( hwnd ))) return FALSE;
1052 if (!data->mapped || data->iconic) goto done;
1053 if (data->whole_window && !data->managed) goto done;
1054 /* ignore synthetic events on foreign windows */
1055 if (event->send_event && !data->whole_window) goto done;
1056 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
1058 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1059 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
1060 event->serial, data->configure_serial );
1061 goto done;
1064 /* Get geometry */
1066 parent = NtUserGetAncestor( hwnd, GA_PARENT );
1067 root_coords = event->send_event; /* synthetic events are always in root coords */
1069 if (!root_coords && parent == NtUserGetDesktopWindow()) /* normal event, map coordinates to the root */
1071 Window child;
1072 XTranslateCoordinates( event->display, event->window, root_window,
1073 0, 0, &x, &y, &child );
1074 root_coords = TRUE;
1077 if (!root_coords)
1079 pos.x = x;
1080 pos.y = y;
1082 else pos = root_to_virtual_screen( x, y );
1084 X11DRV_X_to_window_rect( data, &rect, pos.x, pos.y, event->width, event->height );
1085 if (root_coords) NtUserMapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1087 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1088 hwnd, data->whole_window, (int)rect.left, (int)rect.top,
1089 (int)(rect.right-rect.left), (int)(rect.bottom-rect.top),
1090 event->x, event->y, event->width, event->height );
1092 /* Compare what has changed */
1094 x = rect.left;
1095 y = rect.top;
1096 cx = rect.right - rect.left;
1097 cy = rect.bottom - rect.top;
1098 flags = SWP_NOACTIVATE | SWP_NOZORDER;
1100 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
1102 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1103 else
1104 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1105 hwnd, (int)data->window_rect.left, (int)data->window_rect.top, x, y );
1107 if ((data->window_rect.right - data->window_rect.left == cx &&
1108 data->window_rect.bottom - data->window_rect.top == cy) ||
1109 IsRectEmpty( &data->window_rect ))
1110 flags |= SWP_NOSIZE;
1111 else
1112 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1113 hwnd, (int)(data->window_rect.right - data->window_rect.left),
1114 (int)(data->window_rect.bottom - data->window_rect.top), cx, cy );
1116 style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
1117 if ((style & WS_CAPTION) == WS_CAPTION || !NtUserIsWindowRectFullScreen( &data->whole_rect ))
1119 read_net_wm_states( event->display, data );
1120 if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1122 if (!(style & WS_MAXIMIZE))
1124 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1125 release_win_data( data );
1126 send_message( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1127 return TRUE;
1130 else if (style & WS_MAXIMIZE)
1132 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1133 release_win_data( data );
1134 send_message( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1135 return TRUE;
1139 if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
1141 release_win_data( data );
1142 NtUserSetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1143 return TRUE;
1146 done:
1147 release_win_data( data );
1148 return FALSE;
1152 /**********************************************************************
1153 * X11DRV_GravityNotify
1155 static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1157 XGravityEvent *event = &xev->xgravity;
1158 struct x11drv_win_data *data = get_win_data( hwnd );
1159 RECT window_rect;
1160 int x, y;
1162 if (!data) return FALSE;
1164 if (data->whole_window) /* only handle this for foreign windows */
1166 release_win_data( data );
1167 return FALSE;
1170 x = event->x + data->window_rect.left - data->whole_rect.left;
1171 y = event->y + data->window_rect.top - data->whole_rect.top;
1173 TRACE( "win %p/%lx new X pos %d,%d (event %d,%d)\n",
1174 hwnd, data->whole_window, x, y, event->x, event->y );
1176 window_rect = data->window_rect;
1177 release_win_data( data );
1179 if (window_rect.left != x || window_rect.top != y)
1180 NtUserSetWindowPos( hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1182 return TRUE;
1186 /***********************************************************************
1187 * get_window_wm_state
1189 static int get_window_wm_state( Display *display, Window window )
1191 struct
1193 CARD32 state;
1194 XID icon;
1195 } *state;
1196 Atom type;
1197 int format, ret = -1;
1198 unsigned long count, remaining;
1200 if (!XGetWindowProperty( display, window, x11drv_atom(WM_STATE), 0,
1201 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1202 &type, &format, &count, &remaining, (unsigned char **)&state ))
1204 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1205 ret = state->state;
1206 XFree( state );
1208 return ret;
1212 /***********************************************************************
1213 * handle_wm_state_notify
1215 * Handle a PropertyNotify for WM_STATE.
1217 static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
1219 struct x11drv_win_data *data = get_win_data( hwnd );
1220 UINT style;
1222 if (!data) return;
1224 switch(event->state)
1226 case PropertyDelete:
1227 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1228 data->wm_state = WithdrawnState;
1229 break;
1230 case PropertyNewValue:
1232 int old_state = data->wm_state;
1233 int new_state = get_window_wm_state( event->display, data->whole_window );
1234 if (new_state != -1 && new_state != data->wm_state)
1236 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1237 data->hwnd, data->whole_window, new_state, old_state );
1238 data->wm_state = new_state;
1239 /* ignore the initial state transition out of withdrawn state */
1240 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1241 if (!old_state) goto done;
1244 break;
1247 if (!update_window || !data->managed || !data->mapped) goto done;
1249 style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
1251 if (data->iconic && data->wm_state == NormalState) /* restore window */
1253 data->iconic = FALSE;
1254 read_net_wm_states( event->display, data );
1255 if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1257 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1259 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1260 release_win_data( data );
1261 send_message( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1262 return;
1264 TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1266 else
1268 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1270 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1271 release_win_data( data );
1272 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
1273 NtUserSetActiveWindow( hwnd );
1274 send_message( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1275 return;
1277 TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1280 else if (!data->iconic && data->wm_state == IconicState)
1282 data->iconic = TRUE;
1283 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1285 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1286 release_win_data( data );
1287 send_message( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1288 return;
1290 TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1292 done:
1293 release_win_data( data );
1297 /***********************************************************************
1298 * X11DRV_PropertyNotify
1300 static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1302 XPropertyEvent *event = &xev->xproperty;
1304 if (!hwnd) return FALSE;
1305 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
1306 return TRUE;
1310 /* event filter to wait for a WM_STATE change notification on a window */
1311 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1313 if (event->xany.window != (Window)arg) return 0;
1314 return (event->type == DestroyNotify ||
1315 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1318 /***********************************************************************
1319 * wait_for_withdrawn_state
1321 void wait_for_withdrawn_state( HWND hwnd, BOOL set )
1323 Display *display = thread_display();
1324 struct x11drv_win_data *data;
1325 DWORD end = NtGetTickCount() + 2000;
1327 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
1329 for (;;)
1331 XEvent event;
1332 Window window;
1333 int count = 0;
1335 if (!(data = get_win_data( hwnd ))) break;
1336 if (!data->managed || data->embedded || data->display != display) break;
1337 if (!(window = data->whole_window)) break;
1338 if (!data->mapped == !set)
1340 TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
1341 break;
1343 if ((data->wm_state == WithdrawnState) != !set)
1345 TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
1346 break;
1348 release_win_data( data );
1350 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
1352 count++;
1353 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1354 if (event.type == DestroyNotify) call_event_handler( display, &event );
1355 else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
1358 if (!count)
1360 struct pollfd pfd;
1361 int timeout = end - NtGetTickCount();
1363 pfd.fd = ConnectionNumber(display);
1364 pfd.events = POLLIN;
1365 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1367 FIXME( "window %p/%lx wait timed out\n", hwnd, window );
1368 return;
1372 release_win_data( data );
1376 /*****************************************************************
1377 * SetFocus (X11DRV.@)
1379 * Set the X focus.
1381 void X11DRV_SetFocus( HWND hwnd )
1383 struct x11drv_win_data *data;
1385 HWND parent;
1387 for (;;)
1389 if (!(data = get_win_data( hwnd ))) return;
1390 if (data->embedded) break;
1391 parent = NtUserGetAncestor( hwnd, GA_PARENT );
1392 if (!parent || parent == NtUserGetDesktopWindow()) break;
1393 release_win_data( data );
1394 hwnd = parent;
1396 if (!data->managed || data->embedder) set_input_focus( data );
1397 release_win_data( data );
1401 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1403 RECT tempRect;
1405 if (!NtUserIsWindowEnabled(hQueryWnd)) return 0;
1407 NtUserGetWindowRect(hQueryWnd, &tempRect);
1409 if(!PtInRect(&tempRect, *lpPt)) return 0;
1411 if (!(NtUserGetWindowLongW( hQueryWnd, GWL_STYLE ) & WS_MINIMIZE))
1413 POINT pt = *lpPt;
1414 NtUserScreenToClient( hQueryWnd, &pt );
1415 NtUserGetClientRect( hQueryWnd, &tempRect );
1417 if (PtInRect( &tempRect, pt))
1419 HWND ret = NtUserChildWindowFromPointEx( hQueryWnd, pt.x, pt.y,
1420 CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1421 if (ret && ret != hQueryWnd)
1423 ret = find_drop_window( ret, lpPt );
1424 if (ret) return ret;
1429 if(!(NtUserGetWindowLongW( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1431 NtUserScreenToClient( hQueryWnd, lpPt );
1433 return hQueryWnd;
1436 static void post_drop( HWND hwnd, DROPFILES *drop, ULONG size )
1438 drop->fWide = HandleToUlong( hwnd ); /* abuse fWide to pass window handle */
1439 x11drv_client_func( client_func_dnd_post_drop, drop, size );
1442 /**********************************************************************
1443 * EVENT_DropFromOffix
1445 * don't know if it still works (last Changelog is from 96/11/04)
1447 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1449 struct x11drv_win_data *data;
1450 POINT pt;
1451 unsigned long data_length;
1452 unsigned long aux_long;
1453 unsigned char* p_data = NULL;
1454 Atom atom_aux;
1455 int x, y, cx, cy, dummy, format;
1456 Window win, w_aux_root, w_aux_child;
1458 if (!(data = get_win_data( hWnd ))) return;
1459 cx = data->whole_rect.right - data->whole_rect.left;
1460 cy = data->whole_rect.bottom - data->whole_rect.top;
1461 win = data->whole_window;
1462 release_win_data( data );
1464 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1465 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1466 pt = root_to_virtual_screen( x, y );
1468 /* find out drop point and drop window */
1469 if (pt.x < 0 || pt.y < 0 || pt.x > cx || pt.y > cy)
1471 if (!(NtUserGetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1472 pt.x = pt.y = 0;
1474 else
1476 if (!find_drop_window( hWnd, &pt )) return;
1479 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1480 x11drv_atom(DndSelection), 0, 65535, FALSE,
1481 AnyPropertyType, &atom_aux, &format,
1482 &data_length, &aux_long, &p_data);
1484 if (!aux_long && p_data) /* don't bother if > 64K */
1486 DROPFILES *drop;
1487 size_t drop_size;
1489 drop = file_list_to_drop_files( p_data, get_property_size( format, data_length ), &drop_size );
1490 if (drop)
1492 post_drop( hWnd, drop, drop_size );
1493 free( drop );
1497 if (p_data) XFree(p_data);
1500 /**********************************************************************
1501 * EVENT_DropURLs
1503 * drop items are separated by \n
1504 * each item is prefixed by its mime type
1506 * event->data.l[3], event->data.l[4] contains drop x,y position
1508 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1510 struct x11drv_win_data *win_data;
1511 unsigned long data_length;
1512 unsigned long aux_long;
1513 unsigned char *p_data = NULL; /* property data */
1514 int x, y;
1515 DROPFILES *drop;
1516 int format;
1517 union {
1518 Atom atom_aux;
1519 int i;
1520 Window w_aux;
1521 unsigned int u;
1522 } u; /* unused */
1524 if (!(NtUserGetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1526 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1527 x11drv_atom(DndSelection), 0, 65535, FALSE,
1528 AnyPropertyType, &u.atom_aux, &format,
1529 &data_length, &aux_long, &p_data);
1530 if (aux_long)
1531 WARN("property too large, truncated!\n");
1532 TRACE("urls=%s\n", p_data);
1534 if (!aux_long && p_data) /* don't bother if > 64K */
1536 size_t drop_size;
1537 drop = uri_list_to_drop_files( p_data, get_property_size( format, data_length ), &drop_size );
1539 if (drop)
1541 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1542 &x, &y, &u.i, &u.i, &u.u);
1543 drop->pt = root_to_virtual_screen( x, y );
1545 if ((win_data = get_win_data( hWnd )))
1547 drop->fNC =
1548 (drop->pt.x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1549 drop->pt.y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1550 drop->pt.x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1551 drop->pt.y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1552 release_win_data( win_data );
1555 post_drop( hWnd, drop, drop_size );
1556 free( drop );
1559 if (p_data) XFree( p_data );
1563 /**********************************************************************
1564 * handle_xembed_protocol
1566 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1568 switch (event->data.l[1])
1570 case XEMBED_EMBEDDED_NOTIFY:
1572 struct x11drv_win_data *data = get_win_data( hwnd );
1573 if (!data) break;
1575 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1576 data->embedder = event->data.l[3];
1578 /* window has been marked as embedded before (e.g. systray) */
1579 if (data->embedded || !data->embedder /* broken QX11EmbedContainer implementation */)
1581 release_win_data( data );
1582 break;
1585 make_window_embedded( data );
1586 release_win_data( data );
1587 reparent_notify( event->display, hwnd, event->data.l[3], 0, 0 );
1589 break;
1591 case XEMBED_WINDOW_DEACTIVATE:
1592 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd, event->window );
1593 focus_out( event->display, NtUserGetAncestor( hwnd, GA_ROOT ) );
1594 break;
1596 case XEMBED_FOCUS_OUT:
1597 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd, event->window );
1598 focus_out( event->display, NtUserGetAncestor( hwnd, GA_ROOT ) );
1599 break;
1601 case XEMBED_MODALITY_ON:
1602 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd, event->window );
1603 NtUserEnableWindow( hwnd, FALSE );
1604 break;
1606 case XEMBED_MODALITY_OFF:
1607 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd, event->window );
1608 NtUserEnableWindow( hwnd, TRUE );
1609 break;
1611 default:
1612 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1613 hwnd, event->window, event->data.l[1], event->data.l[2] );
1614 break;
1619 /**********************************************************************
1620 * handle_dnd_protocol
1622 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1624 Window root, child;
1625 int root_x, root_y, child_x, child_y;
1626 unsigned int u;
1628 /* query window (drag&drop event contains only drag window) */
1629 XQueryPointer( event->display, root_window, &root, &child,
1630 &root_x, &root_y, &child_x, &child_y, &u);
1631 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1632 if (!hwnd) return;
1633 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1634 EVENT_DropFromOffiX(hwnd, event);
1635 else if (event->data.l[0] == DndURL)
1636 EVENT_DropURLs(hwnd, event);
1640 /**************************************************************************
1641 * handle_xdnd_enter_event
1643 * Handle an XdndEnter event.
1645 static void handle_xdnd_enter_event( HWND hWnd, XClientMessageEvent *event )
1647 struct format_entry *data;
1648 unsigned long count = 0;
1649 Atom *xdndtypes;
1650 size_t size;
1651 int version;
1653 version = (event->data.l[1] & 0xFF000000) >> 24;
1655 TRACE( "ver(%d) check-XdndTypeList(%ld) data=%ld,%ld,%ld,%ld,%ld\n",
1656 version, (event->data.l[1] & 1),
1657 event->data.l[0], event->data.l[1], event->data.l[2],
1658 event->data.l[3], event->data.l[4] );
1660 if (version > WINE_XDND_VERSION)
1662 ERR("ignoring unsupported XDND version %d\n", version);
1663 return;
1666 /* If the source supports more than 3 data types we retrieve
1667 * the entire list. */
1668 if (event->data.l[1] & 1)
1670 Atom acttype;
1671 int actfmt;
1672 unsigned long bytesret;
1674 /* Request supported formats from source window */
1675 XGetWindowProperty( event->display, event->data.l[0], x11drv_atom(XdndTypeList),
1676 0, 65535, FALSE, AnyPropertyType, &acttype, &actfmt, &count,
1677 &bytesret, (unsigned char **)&xdndtypes );
1679 else
1681 count = 3;
1682 xdndtypes = (Atom *)&event->data.l[2];
1685 if (TRACE_ON(xdnd))
1687 unsigned int i;
1689 for (i = 0; i < count; i++)
1691 if (xdndtypes[i] != 0)
1693 char * pn = XGetAtomName( event->display, xdndtypes[i] );
1694 TRACE( "XDNDEnterAtom %ld: %s\n", xdndtypes[i], pn );
1695 XFree( pn );
1700 data = import_xdnd_selection( event->display, event->window, x11drv_atom(XdndSelection),
1701 xdndtypes, count, &size );
1702 if (data)
1704 x11drv_client_func( client_func_dnd_enter_event, data, size );
1705 free( data );
1708 if (event->data.l[1] & 1)
1709 XFree(xdndtypes);
1713 static DWORD xdnd_action_to_drop_effect( long action )
1715 /* In Windows, nothing but the given effects is allowed.
1716 * In X the given action is just a hint, and you can always
1717 * XdndActionCopy and XdndActionPrivate, so be more permissive. */
1718 if (action == x11drv_atom(XdndActionCopy))
1719 return DROPEFFECT_COPY;
1720 else if (action == x11drv_atom(XdndActionMove))
1721 return DROPEFFECT_MOVE | DROPEFFECT_COPY;
1722 else if (action == x11drv_atom(XdndActionLink))
1723 return DROPEFFECT_LINK | DROPEFFECT_COPY;
1724 else if (action == x11drv_atom(XdndActionAsk))
1725 /* FIXME: should we somehow ask the user what to do here? */
1726 return DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
1728 FIXME( "unknown action %ld, assuming DROPEFFECT_COPY\n", action );
1729 return DROPEFFECT_COPY;
1733 static long drop_effect_to_xdnd_action( UINT effect )
1735 if (effect == DROPEFFECT_COPY)
1736 return x11drv_atom(XdndActionCopy);
1737 else if (effect == DROPEFFECT_MOVE)
1738 return x11drv_atom(XdndActionMove);
1739 else if (effect == DROPEFFECT_LINK)
1740 return x11drv_atom(XdndActionLink);
1741 else if (effect == DROPEFFECT_NONE)
1742 return None;
1744 FIXME( "unknown drop effect %u, assuming XdndActionCopy\n", effect );
1745 return x11drv_atom(XdndActionCopy);
1749 static void handle_xdnd_position_event( HWND hwnd, XClientMessageEvent *event )
1751 struct dnd_position_event_params params;
1752 XClientMessageEvent e;
1753 UINT effect;
1755 params.hwnd = HandleToUlong( hwnd );
1756 params.point = root_to_virtual_screen( event->data.l[2] >> 16, event->data.l[2] & 0xFFFF );
1757 params.effect = effect = xdnd_action_to_drop_effect( event->data.l[4] );
1759 effect = x11drv_client_func( client_func_dnd_position_event, &params, sizeof(params) );
1761 TRACE( "actionRequested(%ld) chosen(0x%x) at x(%d),y(%d)\n",
1762 event->data.l[4], effect, (int)params.point.x, (int)params.point.y );
1765 * Let source know if we're accepting the drop by
1766 * sending a status message.
1768 e.type = ClientMessage;
1769 e.display = event->display;
1770 e.window = event->data.l[0];
1771 e.message_type = x11drv_atom(XdndStatus);
1772 e.format = 32;
1773 e.data.l[0] = event->window;
1774 e.data.l[1] = !!effect;
1775 e.data.l[2] = 0; /* Empty Rect */
1776 e.data.l[3] = 0; /* Empty Rect */
1777 e.data.l[4] = drop_effect_to_xdnd_action( effect );
1778 XSendEvent( event->display, event->data.l[0], False, NoEventMask, (XEvent *)&e );
1782 static void handle_xdnd_drop_event( HWND hwnd, XClientMessageEvent *event )
1784 XClientMessageEvent e;
1785 DWORD effect;
1787 effect = x11drv_client_call( client_dnd_drop_event, HandleToUlong( hwnd ));
1789 /* Tell the target we are finished. */
1790 memset( &e, 0, sizeof(e) );
1791 e.type = ClientMessage;
1792 e.display = event->display;
1793 e.window = event->data.l[0];
1794 e.message_type = x11drv_atom(XdndFinished);
1795 e.format = 32;
1796 e.data.l[0] = event->window;
1797 e.data.l[1] = !!effect;
1798 e.data.l[2] = drop_effect_to_xdnd_action( effect );
1799 XSendEvent( event->display, event->data.l[0], False, NoEventMask, (XEvent *)&e );
1803 static void handle_xdnd_leave_event( HWND hwnd, XClientMessageEvent *event )
1805 x11drv_client_call( client_dnd_leave_event, 0 );
1809 struct client_message_handler
1811 int atom; /* protocol atom */
1812 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1815 static const struct client_message_handler client_messages[] =
1817 { XATOM_MANAGER, handle_manager_message },
1818 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1819 { XATOM__XEMBED, handle_xembed_protocol },
1820 { XATOM_DndProtocol, handle_dnd_protocol },
1821 { XATOM_XdndEnter, handle_xdnd_enter_event },
1822 { XATOM_XdndPosition, handle_xdnd_position_event },
1823 { XATOM_XdndDrop, handle_xdnd_drop_event },
1824 { XATOM_XdndLeave, handle_xdnd_leave_event }
1828 /**********************************************************************
1829 * X11DRV_ClientMessage
1831 static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1833 XClientMessageEvent *event = &xev->xclient;
1834 unsigned int i;
1836 if (!hwnd) return FALSE;
1838 if (event->format != 32)
1840 WARN( "Don't know how to handle format %d\n", event->format );
1841 return FALSE;
1844 for (i = 0; i < ARRAY_SIZE( client_messages ); i++)
1846 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1848 client_messages[i].handler( hwnd, event );
1849 return TRUE;
1852 TRACE( "no handler found for %ld\n", event->message_type );
1853 return FALSE;