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