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