TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / winex11.drv / event.c
blob51ef24b625d480fb6073467047d3d2490ba052b7
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 void X11DRV_FocusIn( HWND hwnd, XEvent *event );
95 static void X11DRV_FocusOut( HWND hwnd, XEvent *event );
96 static void X11DRV_Expose( HWND hwnd, XEvent *event );
97 static void X11DRV_MapNotify( HWND hwnd, XEvent *event );
98 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
99 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
100 static void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
101 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
102 static void X11DRV_ClientMessage( HWND hwnd, XEvent *event );
103 static void X11DRV_GravityNotify( HWND hwnd, XEvent *event );
105 #define MAX_EVENT_HANDLERS 128
107 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
109 NULL, /* 0 reserved */
110 NULL, /* 1 reserved */
111 X11DRV_KeyEvent, /* 2 KeyPress */
112 X11DRV_KeyEvent, /* 3 KeyRelease */
113 X11DRV_ButtonPress, /* 4 ButtonPress */
114 X11DRV_ButtonRelease, /* 5 ButtonRelease */
115 X11DRV_MotionNotify, /* 6 MotionNotify */
116 X11DRV_EnterNotify, /* 7 EnterNotify */
117 NULL, /* 8 LeaveNotify */
118 X11DRV_FocusIn, /* 9 FocusIn */
119 X11DRV_FocusOut, /* 10 FocusOut */
120 X11DRV_KeymapNotify, /* 11 KeymapNotify */
121 X11DRV_Expose, /* 12 Expose */
122 NULL, /* 13 GraphicsExpose */
123 NULL, /* 14 NoExpose */
124 NULL, /* 15 VisibilityNotify */
125 NULL, /* 16 CreateNotify */
126 X11DRV_DestroyNotify, /* 17 DestroyNotify */
127 X11DRV_UnmapNotify, /* 18 UnmapNotify */
128 X11DRV_MapNotify, /* 19 MapNotify */
129 NULL, /* 20 MapRequest */
130 X11DRV_ReparentNotify, /* 21 ReparentNotify */
131 X11DRV_ConfigureNotify, /* 22 ConfigureNotify */
132 NULL, /* 23 ConfigureRequest */
133 X11DRV_GravityNotify, /* 24 GravityNotify */
134 NULL, /* 25 ResizeRequest */
135 NULL, /* 26 CirculateNotify */
136 NULL, /* 27 CirculateRequest */
137 X11DRV_PropertyNotify, /* 28 PropertyNotify */
138 X11DRV_SelectionClear, /* 29 SelectionClear */
139 X11DRV_SelectionRequest, /* 30 SelectionRequest */
140 NULL, /* 31 SelectionNotify */
141 NULL, /* 32 ColormapNotify */
142 X11DRV_ClientMessage, /* 33 ClientMessage */
143 X11DRV_MappingNotify, /* 34 MappingNotify */
144 X11DRV_GenericEvent /* 35 GenericEvent */
147 static const char * event_names[MAX_EVENT_HANDLERS] =
149 NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
150 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
151 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
152 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
153 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
154 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
155 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
158 int xinput2_opcode = 0;
160 /* return the name of an X event */
161 static const char *dbgstr_event( int type )
163 if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
164 return wine_dbg_sprintf( "Unknown event %d", type );
167 static inline void get_event_data( XEvent *event )
169 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
170 if (event->xany.type != GenericEvent) return;
171 if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
172 #endif
175 static inline void free_event_data( XEvent *event )
177 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
178 if (event->xany.type != GenericEvent) return;
179 if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
180 #endif
183 /***********************************************************************
184 * xembed_request_focus
186 static void xembed_request_focus( Display *display, Window window, DWORD timestamp )
188 XEvent xev;
190 xev.xclient.type = ClientMessage;
191 xev.xclient.window = window;
192 xev.xclient.message_type = x11drv_atom(_XEMBED);
193 xev.xclient.serial = 0;
194 xev.xclient.display = display;
195 xev.xclient.send_event = True;
196 xev.xclient.format = 32;
198 xev.xclient.data.l[0] = timestamp;
199 xev.xclient.data.l[1] = XEMBED_REQUEST_FOCUS;
200 xev.xclient.data.l[2] = 0;
201 xev.xclient.data.l[3] = 0;
202 xev.xclient.data.l[4] = 0;
204 XSendEvent(display, window, False, NoEventMask, &xev);
205 XFlush( display );
208 /***********************************************************************
209 * X11DRV_register_event_handler
211 * Register a handler for a given event type.
212 * If already registered, overwrite the previous handler.
214 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
216 assert( type < MAX_EVENT_HANDLERS );
217 assert( !handlers[type] || handlers[type] == handler );
218 handlers[type] = handler;
219 event_names[type] = name;
220 TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
224 /***********************************************************************
225 * filter_event
227 static Bool filter_event( Display *display, XEvent *event, char *arg )
229 ULONG_PTR mask = (ULONG_PTR)arg;
231 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
233 switch(event->type)
235 case KeyPress:
236 case KeyRelease:
237 case KeymapNotify:
238 case MappingNotify:
239 return (mask & (QS_KEY|QS_HOTKEY)) != 0;
240 case ButtonPress:
241 case ButtonRelease:
242 return (mask & QS_MOUSEBUTTON) != 0;
243 #ifdef GenericEvent
244 case GenericEvent:
245 #endif
246 case MotionNotify:
247 case EnterNotify:
248 case LeaveNotify:
249 return (mask & QS_MOUSEMOVE) != 0;
250 case Expose:
251 return (mask & QS_PAINT) != 0;
252 case FocusIn:
253 case FocusOut:
254 case MapNotify:
255 case UnmapNotify:
256 case ConfigureNotify:
257 case PropertyNotify:
258 case ClientMessage:
259 return (mask & QS_POSTMESSAGE) != 0;
260 default:
261 return (mask & QS_SENDMESSAGE) != 0;
266 enum event_merge_action
268 MERGE_DISCARD, /* discard the old event */
269 MERGE_HANDLE, /* handle the old event */
270 MERGE_KEEP, /* keep the old event for future merging */
271 MERGE_IGNORE /* ignore the new event, keep the old one */
274 /***********************************************************************
275 * merge_raw_motion_events
277 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
278 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
280 int i, j, k;
281 unsigned char mask;
283 if (!prev->valuators.mask_len) return MERGE_HANDLE;
284 if (!next->valuators.mask_len) return MERGE_HANDLE;
286 mask = prev->valuators.mask[0] | next->valuators.mask[0];
287 if (mask == next->valuators.mask[0]) /* keep next */
289 for (i = j = k = 0; i < 8; i++)
291 if (XIMaskIsSet( prev->valuators.mask, i ))
292 next->valuators.values[j] += prev->valuators.values[k++];
293 if (XIMaskIsSet( next->valuators.mask, i )) j++;
295 TRACE( "merging duplicate GenericEvent\n" );
296 return MERGE_DISCARD;
298 if (mask == prev->valuators.mask[0]) /* keep prev */
300 for (i = j = k = 0; i < 8; i++)
302 if (XIMaskIsSet( next->valuators.mask, i ))
303 prev->valuators.values[j] += next->valuators.values[k++];
304 if (XIMaskIsSet( prev->valuators.mask, i )) j++;
306 TRACE( "merging duplicate GenericEvent\n" );
307 return MERGE_IGNORE;
309 /* can't merge events with disjoint masks */
310 return MERGE_HANDLE;
312 #endif
314 /***********************************************************************
315 * merge_events
317 * Try to merge 2 consecutive events.
319 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
321 switch (prev->type)
323 case ConfigureNotify:
324 switch (next->type)
326 case ConfigureNotify:
327 if (prev->xany.window == next->xany.window)
329 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
330 return MERGE_DISCARD;
332 break;
333 case Expose:
334 case PropertyNotify:
335 return MERGE_KEEP;
337 break;
338 case MotionNotify:
339 switch (next->type)
341 case MotionNotify:
342 if (prev->xany.window == next->xany.window)
344 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
345 return MERGE_DISCARD;
347 break;
348 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
349 case GenericEvent:
350 if (next->xcookie.extension != xinput2_opcode) break;
351 if (next->xcookie.evtype != XI_RawMotion) break;
352 if (x11drv_thread_data()->warp_serial) break;
353 return MERGE_KEEP;
355 break;
356 case GenericEvent:
357 if (prev->xcookie.extension != xinput2_opcode) break;
358 if (prev->xcookie.evtype != XI_RawMotion) break;
359 switch (next->type)
361 case GenericEvent:
362 if (next->xcookie.extension != xinput2_opcode) break;
363 if (next->xcookie.evtype != XI_RawMotion) break;
364 if (x11drv_thread_data()->warp_serial) break;
365 return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
366 #endif
368 break;
370 return MERGE_HANDLE;
374 /***********************************************************************
375 * call_event_handler
377 static inline void call_event_handler( Display *display, XEvent *event )
379 HWND hwnd;
380 XEvent *prev;
381 struct x11drv_thread_data *thread_data;
383 if (!handlers[event->type])
385 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
386 return; /* no handler, ignore it */
389 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
390 hwnd = 0; /* not for a registered window */
391 if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
393 TRACE( "%lu %s for hwnd/window %p/%lx\n",
394 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
395 thread_data = x11drv_thread_data();
396 prev = thread_data->current_event;
397 thread_data->current_event = event;
398 handlers[event->type]( hwnd, event );
399 thread_data->current_event = prev;
403 /***********************************************************************
404 * process_events
406 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
408 XEvent event, prev_event;
409 int count = 0;
410 enum event_merge_action action = MERGE_DISCARD;
412 prev_event.type = 0;
413 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
415 count++;
416 if (XFilterEvent( &event, None ))
419 * SCIM on linux filters key events strangely. It does not filter the
420 * KeyPress events for these keys however it does filter the
421 * KeyRelease events. This causes wine to become very confused as
422 * to the keyboard state.
424 * We need to let those KeyRelease events be processed so that the
425 * keyboard state is correct.
427 if (event.type == KeyRelease)
429 KeySym keysym = 0;
430 XKeyEvent *keyevent = &event.xkey;
432 XLookupString(keyevent, NULL, 0, &keysym, NULL);
433 if (!(keysym == XK_Shift_L ||
434 keysym == XK_Shift_R ||
435 keysym == XK_Control_L ||
436 keysym == XK_Control_R ||
437 keysym == XK_Alt_R ||
438 keysym == XK_Alt_L ||
439 keysym == XK_Meta_R ||
440 keysym == XK_Meta_L))
441 continue; /* not a key we care about, ignore it */
443 else
444 continue; /* filtered, ignore it */
446 get_event_data( &event );
447 if (prev_event.type) action = merge_events( &prev_event, &event );
448 switch( action )
450 case MERGE_HANDLE: /* handle prev, keep new */
451 call_event_handler( display, &prev_event );
452 /* fall through */
453 case MERGE_DISCARD: /* discard prev, keep new */
454 free_event_data( &prev_event );
455 prev_event = event;
456 break;
457 case MERGE_KEEP: /* handle new, keep prev for future merging */
458 call_event_handler( display, &event );
459 /* fall through */
460 case MERGE_IGNORE: /* ignore new, keep prev for future merging */
461 free_event_data( &event );
462 break;
465 if (prev_event.type) call_event_handler( display, &prev_event );
466 free_event_data( &prev_event );
467 XFlush( gdi_display );
468 if (count) TRACE( "processed %d events\n", count );
469 return count;
473 /***********************************************************************
474 * MsgWaitForMultipleObjectsEx (X11DRV.@)
476 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
477 DWORD timeout, DWORD mask, DWORD flags )
479 DWORD ret;
480 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
482 if (!data)
484 if (!count && !timeout) return WAIT_TIMEOUT;
485 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
486 timeout, flags & MWMO_ALERTABLE );
489 if (data->current_event) mask = 0; /* don't process nested events */
491 if (process_events( data->display, filter_event, mask )) ret = count - 1;
492 else if (count || timeout)
494 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
495 timeout, flags & MWMO_ALERTABLE );
496 if (ret == count - 1) process_events( data->display, filter_event, mask );
498 else ret = WAIT_TIMEOUT;
500 return ret;
503 /***********************************************************************
504 * EVENT_x11_time_to_win32_time
506 * Make our timer and the X timer line up as best we can
507 * Pass 0 to retrieve the current adjustment value (times -1)
509 DWORD EVENT_x11_time_to_win32_time(Time time)
511 static DWORD adjust = 0;
512 DWORD now = GetTickCount();
513 DWORD ret;
515 if (! adjust && time != 0)
517 ret = now;
518 adjust = time - now;
520 else
522 /* If we got an event in the 'future', then our clock is clearly wrong.
523 If we got it more than 10000 ms in the future, then it's most likely
524 that the clock has wrapped. */
526 ret = time - adjust;
527 if (ret > now && ((ret - now) < 10000) && time != 0)
529 adjust += ret - now;
530 ret -= ret - now;
534 return ret;
538 /*******************************************************************
539 * can_activate_window
541 * Check if we can activate the specified window.
543 static inline BOOL can_activate_window( HWND hwnd )
545 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
546 RECT rect;
548 if (!(style & WS_VISIBLE)) return FALSE;
549 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
550 if (style & WS_MINIMIZE) return FALSE;
551 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
552 if (hwnd == GetDesktopWindow()) return FALSE;
553 if (GetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE;
554 return !(style & WS_DISABLED);
558 /**********************************************************************
559 * set_input_focus
561 * Try to force focus for embedded or non-managed windows.
563 static void set_input_focus( struct x11drv_win_data *data )
565 XWindowChanges changes;
566 DWORD timestamp;
568 if (!data->whole_window) return;
570 if (EVENT_x11_time_to_win32_time(0))
571 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
572 /* FIXME: this is not entirely correct */
573 timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
574 else
575 timestamp = CurrentTime;
577 /* Set X focus and install colormap */
578 changes.stack_mode = Above;
579 XConfigureWindow( data->display, data->whole_window, CWStackMode, &changes );
581 if (data->embedder)
582 xembed_request_focus( data->display, data->embedder, timestamp );
583 else
584 XSetInputFocus( data->display, data->whole_window, RevertToParent, timestamp );
588 /**********************************************************************
589 * set_focus
591 static void set_focus( Display *display, HWND hwnd, Time time )
593 HWND focus;
594 Window win;
595 GUITHREADINFO threadinfo;
597 TRACE( "setting foreground window to %p\n", hwnd );
598 SetForegroundWindow( hwnd );
600 threadinfo.cbSize = sizeof(threadinfo);
601 GetGUIThreadInfo(0, &threadinfo);
602 focus = threadinfo.hwndFocus;
603 if (!focus) focus = threadinfo.hwndActive;
604 if (focus) focus = GetAncestor( focus, GA_ROOT );
605 win = X11DRV_get_whole_window(focus);
607 if (win)
609 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
610 XSetInputFocus( display, win, RevertToParent, time );
615 /**********************************************************************
616 * handle_manager_message
618 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
620 if (hwnd != GetDesktopWindow()) return;
621 if (systray_atom && event->data.l[1] == systray_atom)
622 change_systray_owner( event->display, event->data.l[2] );
626 /**********************************************************************
627 * handle_wm_protocols
629 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
631 Atom protocol = (Atom)event->data.l[0];
632 Time event_time = (Time)event->data.l[1];
634 if (!protocol) return;
636 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
638 update_user_time( event_time );
640 if (hwnd == GetDesktopWindow())
642 /* The desktop window does not have a close button that we can
643 * pretend to click. Therefore, we simply send it a close command. */
644 SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
645 return;
648 /* Ignore the delete window request if the window has been disabled
649 * and we are in managed mode. This is to disallow applications from
650 * being closed by the window manager while in a modal state.
652 if (IsWindowEnabled(hwnd))
654 HMENU hSysMenu;
656 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
657 hSysMenu = GetSystemMenu(hwnd, FALSE);
658 if (hSysMenu)
660 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
661 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
662 return;
664 if (GetActiveWindow() != hwnd)
666 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
667 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
668 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
669 switch(ma)
671 case MA_NOACTIVATEANDEAT:
672 case MA_ACTIVATEANDEAT:
673 return;
674 case MA_NOACTIVATE:
675 break;
676 case MA_ACTIVATE:
677 case 0:
678 SetActiveWindow(hwnd);
679 break;
680 default:
681 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
682 break;
686 PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
689 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
691 HWND last_focus = x11drv_thread_data()->last_focus;
693 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
694 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
695 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
697 if (can_activate_window(hwnd))
699 /* simulate a mouse click on the caption to find out
700 * whether the window wants to be activated */
701 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
702 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
703 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
704 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
706 set_focus( event->display, hwnd, event_time );
707 return;
710 else if (hwnd == GetDesktopWindow())
712 hwnd = GetForegroundWindow();
713 if (!hwnd) hwnd = last_focus;
714 if (!hwnd) hwnd = GetDesktopWindow();
715 set_focus( event->display, hwnd, event_time );
716 return;
718 /* try to find some other window to give the focus to */
719 hwnd = GetFocus();
720 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
721 if (!hwnd) hwnd = GetActiveWindow();
722 if (!hwnd) hwnd = last_focus;
723 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
725 else if (protocol == x11drv_atom(_NET_WM_PING))
727 XClientMessageEvent xev;
728 xev = *event;
730 TRACE("NET_WM Ping\n");
731 xev.window = DefaultRootWindow(xev.display);
732 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
737 static const char * const focus_details[] =
739 "NotifyAncestor",
740 "NotifyVirtual",
741 "NotifyInferior",
742 "NotifyNonlinear",
743 "NotifyNonlinearVirtual",
744 "NotifyPointer",
745 "NotifyPointerRoot",
746 "NotifyDetailNone"
749 /**********************************************************************
750 * X11DRV_FocusIn
752 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
754 XFocusChangeEvent *event = &xev->xfocus;
755 XIC xic;
757 if (!hwnd) return;
759 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
761 if (event->detail == NotifyPointer) return;
762 if (hwnd == GetDesktopWindow()) return;
764 if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic );
765 if (use_take_focus)
767 if (hwnd == GetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE );
768 return;
771 if (!can_activate_window(hwnd))
773 HWND hwnd = GetFocus();
774 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
775 if (!hwnd) hwnd = GetActiveWindow();
776 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
777 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
779 else SetForegroundWindow( hwnd );
782 /**********************************************************************
783 * focus_out
785 static void focus_out( Display *display , HWND hwnd )
787 HWND hwnd_tmp;
788 Window focus_win;
789 int revert;
790 XIC xic;
792 if (ximInComposeMode) return;
794 x11drv_thread_data()->last_focus = hwnd;
795 if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
797 if (root_window != DefaultRootWindow(display))
799 if (hwnd == GetDesktopWindow()) reset_clipping_window();
800 return;
802 if (hwnd != GetForegroundWindow()) return;
803 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
805 /* don't reset the foreground window, if the window which is
806 getting the focus is a Wine window */
808 XGetInputFocus( display, &focus_win, &revert );
809 if (focus_win)
811 if (XFindContext( display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
812 focus_win = 0;
815 if (!focus_win)
817 /* Abey : 6-Oct-99. Check again if the focus out window is the
818 Foreground window, because in most cases the messages sent
819 above must have already changed the foreground window, in which
820 case we don't have to change the foreground window to 0 */
821 if (hwnd == GetForegroundWindow())
823 TRACE( "lost focus, setting fg to desktop\n" );
824 SetForegroundWindow( GetDesktopWindow() );
829 /**********************************************************************
830 * X11DRV_FocusOut
832 * Note: only top-level windows get FocusOut events.
834 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
836 XFocusChangeEvent *event = &xev->xfocus;
838 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
840 if (event->detail == NotifyPointer)
842 if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
843 return;
845 if (!hwnd) return;
846 focus_out( event->display, hwnd );
850 /***********************************************************************
851 * X11DRV_Expose
853 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
855 XExposeEvent *event = &xev->xexpose;
856 RECT rect;
857 POINT pos;
858 struct x11drv_win_data *data;
859 HRGN surface_region = 0;
860 UINT flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN;
862 TRACE( "win %p (%lx) %d,%d %dx%d\n",
863 hwnd, event->window, event->x, event->y, event->width, event->height );
865 if (event->window != root_window)
867 pos.x = event->x;
868 pos.y = event->y;
870 else pos = root_to_virtual_screen( event->x, event->y );
872 if (!(data = get_win_data( hwnd ))) return;
874 rect.left = pos.x;
875 rect.top = pos.y;
876 rect.right = pos.x + event->width;
877 rect.bottom = pos.y + event->height;
879 if (event->window != data->client_window)
881 if (data->surface)
883 surface_region = expose_surface( data->surface, &rect );
884 if (!surface_region) flags = 0;
885 else OffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
886 data->whole_rect.top - data->client_rect.top );
888 if (data->vis.visualid != default_visual.visualid)
889 data->surface->funcs->flush( data->surface );
891 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
892 data->whole_rect.top - data->client_rect.top );
895 if (event->window != root_window)
897 if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
898 mirror_rect( &data->client_rect, &rect );
900 SERVER_START_REQ( update_window_zorder )
902 req->window = wine_server_user_handle( hwnd );
903 req->rect.left = rect.left;
904 req->rect.top = rect.top;
905 req->rect.right = rect.right;
906 req->rect.bottom = rect.bottom;
907 wine_server_call( req );
909 SERVER_END_REQ;
911 else flags &= ~RDW_ALLCHILDREN;
913 release_win_data( data );
915 if (flags) RedrawWindow( hwnd, &rect, surface_region, flags );
916 if (surface_region) DeleteObject( surface_region );
920 /**********************************************************************
921 * X11DRV_MapNotify
923 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
925 struct x11drv_win_data *data;
927 if (event->xany.window == x11drv_thread_data()->clip_window)
929 clipping_cursor = TRUE;
930 return;
932 if (!(data = get_win_data( hwnd ))) return;
934 if (!data->managed && !data->embedded && data->mapped)
936 HWND hwndFocus = GetFocus();
937 if (hwndFocus && IsChild( hwnd, hwndFocus ))
938 set_input_focus( data );
940 release_win_data( data );
944 /**********************************************************************
945 * X11DRV_UnmapNotify
947 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
949 if (event->xany.window == x11drv_thread_data()->clip_window)
950 clipping_cursor = FALSE;
954 /***********************************************************************
955 * reparent_notify
957 static void reparent_notify( Display *display, HWND hwnd, Window xparent, int x, int y )
959 HWND parent, old_parent;
960 DWORD style;
962 style = GetWindowLongW( hwnd, GWL_STYLE );
963 if (xparent == root_window)
965 parent = GetDesktopWindow();
966 style = (style & ~WS_CHILD) | WS_POPUP;
968 else
970 if (!(parent = create_foreign_window( display, xparent ))) return;
971 style = (style & ~WS_POPUP) | WS_CHILD;
974 ShowWindow( hwnd, SW_HIDE );
975 old_parent = SetParent( hwnd, parent );
976 SetWindowLongW( hwnd, GWL_STYLE, style );
977 SetWindowPos( hwnd, HWND_TOP, x, y, 0, 0,
978 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
979 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
981 /* make old parent destroy itself if it no longer has children */
982 if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
986 /***********************************************************************
987 * X11DRV_ReparentNotify
989 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
991 XReparentEvent *event = &xev->xreparent;
992 struct x11drv_win_data *data;
994 if (!(data = get_win_data( hwnd ))) return;
996 if (!data->embedded)
998 release_win_data( data );
999 return;
1002 if (data->whole_window)
1004 if (event->parent == root_window)
1006 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
1007 data->embedder = 0;
1008 release_win_data( data );
1009 SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1010 return;
1012 data->embedder = event->parent;
1015 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
1016 release_win_data( data );
1018 reparent_notify( event->display, hwnd, event->parent, event->x, event->y );
1022 /***********************************************************************
1023 * X11DRV_ConfigureNotify
1025 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
1027 XConfigureEvent *event = &xev->xconfigure;
1028 struct x11drv_win_data *data;
1029 RECT rect;
1030 POINT pos;
1031 UINT flags;
1032 HWND parent;
1033 BOOL root_coords;
1034 int cx, cy, x = event->x, y = event->y;
1035 DWORD style;
1037 if (!hwnd) return;
1038 if (!(data = get_win_data( hwnd ))) return;
1039 if (!data->mapped || data->iconic) goto done;
1040 if (data->whole_window && !data->managed) goto done;
1041 /* ignore synthetic events on foreign windows */
1042 if (event->send_event && !data->whole_window) goto done;
1043 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
1045 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1046 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
1047 event->serial, data->configure_serial );
1048 goto done;
1051 /* Get geometry */
1053 parent = GetAncestor( hwnd, GA_PARENT );
1054 root_coords = event->send_event; /* synthetic events are always in root coords */
1056 if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
1058 Window child;
1059 XTranslateCoordinates( event->display, event->window, root_window,
1060 0, 0, &x, &y, &child );
1061 root_coords = TRUE;
1064 if (!root_coords)
1066 pos.x = x;
1067 pos.y = y;
1069 else pos = root_to_virtual_screen( x, y );
1071 rect.left = pos.x;
1072 rect.top = pos.y;
1073 rect.right = pos.x + event->width;
1074 rect.bottom = pos.y + event->height;
1075 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1076 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1077 event->x, event->y, event->width, event->height );
1079 X11DRV_X_to_window_rect( data, &rect );
1080 if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1082 /* Compare what has changed */
1084 x = rect.left;
1085 y = rect.top;
1086 cx = rect.right - rect.left;
1087 cy = rect.bottom - rect.top;
1088 flags = SWP_NOACTIVATE | SWP_NOZORDER;
1090 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
1092 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1093 else
1094 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1095 hwnd, data->window_rect.left, data->window_rect.top, x, y );
1097 if ((data->window_rect.right - data->window_rect.left == cx &&
1098 data->window_rect.bottom - data->window_rect.top == cy) ||
1099 IsRectEmpty( &data->window_rect ))
1100 flags |= SWP_NOSIZE;
1101 else
1102 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1103 hwnd, data->window_rect.right - data->window_rect.left,
1104 data->window_rect.bottom - data->window_rect.top, cx, cy );
1106 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1107 if ((style & WS_CAPTION) == WS_CAPTION)
1109 read_net_wm_states( event->display, data );
1110 if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1112 if (!(style & WS_MAXIMIZE))
1114 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1115 release_win_data( data );
1116 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1117 return;
1120 else if (style & WS_MAXIMIZE)
1122 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1123 release_win_data( data );
1124 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1125 return;
1129 if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
1131 release_win_data( data );
1132 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1133 return;
1136 done:
1137 release_win_data( data );
1141 /**********************************************************************
1142 * X11DRV_GravityNotify
1144 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1146 XGravityEvent *event = &xev->xgravity;
1147 struct x11drv_win_data *data = get_win_data( hwnd );
1148 RECT rect, window_rect;
1150 if (!data) return;
1152 if (data->whole_window) /* only handle this for foreign windows */
1154 release_win_data( data );
1155 return;
1158 rect.left = event->x;
1159 rect.top = event->y;
1160 rect.right = rect.left + data->whole_rect.right - data->whole_rect.left;
1161 rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1163 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1164 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1165 event->x, event->y );
1167 X11DRV_X_to_window_rect( data, &rect );
1168 window_rect = data->window_rect;
1169 release_win_data( data );
1171 if (window_rect.left != rect.left || window_rect.top != rect.top)
1172 SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1173 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1177 /***********************************************************************
1178 * get_window_wm_state
1180 static int get_window_wm_state( Display *display, Window window )
1182 struct
1184 CARD32 state;
1185 XID icon;
1186 } *state;
1187 Atom type;
1188 int format, ret = -1;
1189 unsigned long count, remaining;
1191 if (!XGetWindowProperty( display, window, x11drv_atom(WM_STATE), 0,
1192 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1193 &type, &format, &count, &remaining, (unsigned char **)&state ))
1195 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1196 ret = state->state;
1197 XFree( state );
1199 return ret;
1203 /***********************************************************************
1204 * handle_wm_state_notify
1206 * Handle a PropertyNotify for WM_STATE.
1208 static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
1210 struct x11drv_win_data *data = get_win_data( hwnd );
1211 DWORD style;
1213 if (!data) return;
1215 switch(event->state)
1217 case PropertyDelete:
1218 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1219 data->wm_state = WithdrawnState;
1220 break;
1221 case PropertyNewValue:
1223 int old_state = data->wm_state;
1224 int new_state = get_window_wm_state( event->display, data->whole_window );
1225 if (new_state != -1 && new_state != data->wm_state)
1227 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1228 data->hwnd, data->whole_window, new_state, old_state );
1229 data->wm_state = new_state;
1230 /* ignore the initial state transition out of withdrawn state */
1231 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1232 if (!old_state) goto done;
1235 break;
1238 if (!update_window || !data->managed || !data->mapped) goto done;
1240 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1242 if (data->iconic && data->wm_state == NormalState) /* restore window */
1244 data->iconic = FALSE;
1245 read_net_wm_states( event->display, data );
1246 if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1248 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1250 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1251 release_win_data( data );
1252 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1253 return;
1255 TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1257 else
1259 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1261 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1262 release_win_data( data );
1263 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1264 return;
1266 TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1269 else if (!data->iconic && data->wm_state == IconicState)
1271 data->iconic = TRUE;
1272 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1274 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1275 release_win_data( data );
1276 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1277 return;
1279 TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1281 done:
1282 release_win_data( data );
1286 /***********************************************************************
1287 * X11DRV_PropertyNotify
1289 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1291 XPropertyEvent *event = &xev->xproperty;
1293 if (!hwnd) return;
1294 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
1298 /* event filter to wait for a WM_STATE change notification on a window */
1299 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1301 if (event->xany.window != (Window)arg) return 0;
1302 return (event->type == DestroyNotify ||
1303 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1306 /***********************************************************************
1307 * wait_for_withdrawn_state
1309 void wait_for_withdrawn_state( HWND hwnd, BOOL set )
1311 Display *display = thread_display();
1312 struct x11drv_win_data *data;
1313 DWORD end = GetTickCount() + 2000;
1315 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
1317 for (;;)
1319 XEvent event;
1320 Window window;
1321 int count = 0;
1323 if (!(data = get_win_data( hwnd ))) break;
1324 if (!data->managed || data->embedded || data->display != display) break;
1325 if (!(window = data->whole_window)) break;
1326 if (!data->mapped == !set)
1328 TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
1329 break;
1331 if ((data->wm_state == WithdrawnState) != !set)
1333 TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
1334 break;
1336 release_win_data( data );
1338 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
1340 count++;
1341 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1342 if (event.type == DestroyNotify) call_event_handler( display, &event );
1343 else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
1346 if (!count)
1348 struct pollfd pfd;
1349 int timeout = end - GetTickCount();
1351 pfd.fd = ConnectionNumber(display);
1352 pfd.events = POLLIN;
1353 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1355 FIXME( "window %p/%lx wait timed out\n", hwnd, window );
1356 return;
1360 release_win_data( data );
1364 /*****************************************************************
1365 * SetFocus (X11DRV.@)
1367 * Set the X focus.
1369 void CDECL X11DRV_SetFocus( HWND hwnd )
1371 struct x11drv_win_data *data;
1373 HWND parent;
1375 for (;;)
1377 if (!(data = get_win_data( hwnd ))) return;
1378 if (data->embedded) break;
1379 parent = GetAncestor( hwnd, GA_PARENT );
1380 if (!parent || parent == GetDesktopWindow()) break;
1381 release_win_data( data );
1382 hwnd = parent;
1384 if (!data->managed || data->embedder) set_input_focus( data );
1385 release_win_data( data );
1389 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1391 RECT tempRect;
1393 if (!IsWindowEnabled(hQueryWnd)) return 0;
1395 GetWindowRect(hQueryWnd, &tempRect);
1397 if(!PtInRect(&tempRect, *lpPt)) return 0;
1399 if (!IsIconic( hQueryWnd ))
1401 POINT pt = *lpPt;
1402 ScreenToClient( hQueryWnd, &pt );
1403 GetClientRect( hQueryWnd, &tempRect );
1405 if (PtInRect( &tempRect, pt))
1407 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1408 if (ret && ret != hQueryWnd)
1410 ret = find_drop_window( ret, lpPt );
1411 if (ret) return ret;
1416 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1418 ScreenToClient(hQueryWnd, lpPt);
1420 return hQueryWnd;
1423 /**********************************************************************
1424 * EVENT_DropFromOffix
1426 * don't know if it still works (last Changelog is from 96/11/04)
1428 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1430 struct x11drv_win_data *data;
1431 POINT pt;
1432 unsigned long data_length;
1433 unsigned long aux_long;
1434 unsigned char* p_data = NULL;
1435 Atom atom_aux;
1436 int x, y, cx, cy, dummy;
1437 Window win, w_aux_root, w_aux_child;
1439 if (!(data = get_win_data( hWnd ))) return;
1440 cx = data->whole_rect.right - data->whole_rect.left;
1441 cy = data->whole_rect.bottom - data->whole_rect.top;
1442 win = data->whole_window;
1443 release_win_data( data );
1445 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1446 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1447 pt = root_to_virtual_screen( x, y );
1449 /* find out drop point and drop window */
1450 if (pt.x < 0 || pt.y < 0 || pt.x > cx || pt.y > cy)
1452 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1453 pt.x = pt.y = 0;
1455 else
1457 if (!find_drop_window( hWnd, &pt )) return;
1460 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1461 x11drv_atom(DndSelection), 0, 65535, FALSE,
1462 AnyPropertyType, &atom_aux, &dummy,
1463 &data_length, &aux_long, &p_data);
1465 if( !aux_long && p_data) /* don't bother if > 64K */
1467 char *p = (char *)p_data;
1468 char *p_drop;
1470 aux_long = 0;
1471 while( *p ) /* calculate buffer size */
1473 INT len = GetShortPathNameA( p, NULL, 0 );
1474 if (len) aux_long += len + 1;
1475 p += strlen(p) + 1;
1477 if( aux_long && aux_long < 65535 )
1479 HDROP hDrop;
1480 DROPFILES *lpDrop;
1482 aux_long += sizeof(DROPFILES) + 1;
1483 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1484 lpDrop = GlobalLock( hDrop );
1486 if( lpDrop )
1488 lpDrop->pFiles = sizeof(DROPFILES);
1489 lpDrop->pt = pt;
1490 lpDrop->fNC = FALSE;
1491 lpDrop->fWide = FALSE;
1492 p_drop = (char *)(lpDrop + 1);
1493 p = (char *)p_data;
1494 while(*p)
1496 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1497 p_drop += strlen( p_drop ) + 1;
1498 p += strlen(p) + 1;
1500 *p_drop = '\0';
1501 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1505 if( p_data ) XFree(p_data);
1508 /**********************************************************************
1509 * EVENT_DropURLs
1511 * drop items are separated by \n
1512 * each item is prefixed by its mime type
1514 * event->data.l[3], event->data.l[4] contains drop x,y position
1516 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1518 struct x11drv_win_data *win_data;
1519 unsigned long data_length;
1520 unsigned long aux_long, drop_len = 0;
1521 unsigned char *p_data = NULL; /* property data */
1522 char *p_drop = NULL;
1523 char *p, *next;
1524 int x, y;
1525 POINT pos;
1526 DROPFILES *lpDrop;
1527 HDROP hDrop;
1528 union {
1529 Atom atom_aux;
1530 int i;
1531 Window w_aux;
1532 unsigned int u;
1533 } u; /* unused */
1535 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1537 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1538 x11drv_atom(DndSelection), 0, 65535, FALSE,
1539 AnyPropertyType, &u.atom_aux, &u.i,
1540 &data_length, &aux_long, &p_data);
1541 if (aux_long)
1542 WARN("property too large, truncated!\n");
1543 TRACE("urls=%s\n", p_data);
1545 if( !aux_long && p_data) { /* don't bother if > 64K */
1546 /* calculate length */
1547 p = (char*) p_data;
1548 next = strchr(p, '\n');
1549 while (p) {
1550 if (next) *next=0;
1551 if (strncmp(p,"file:",5) == 0 ) {
1552 INT len = GetShortPathNameA( p+5, NULL, 0 );
1553 if (len) drop_len += len + 1;
1555 if (next) {
1556 *next = '\n';
1557 p = next + 1;
1558 next = strchr(p, '\n');
1559 } else {
1560 p = NULL;
1564 if( drop_len && drop_len < 65535 ) {
1565 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1566 &x, &y, &u.i, &u.i, &u.u);
1567 pos = root_to_virtual_screen( x, y );
1569 drop_len += sizeof(DROPFILES) + 1;
1570 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1571 lpDrop = GlobalLock( hDrop );
1573 if( lpDrop && (win_data = get_win_data( hWnd )))
1575 lpDrop->pFiles = sizeof(DROPFILES);
1576 lpDrop->pt = pos;
1577 lpDrop->fNC =
1578 (pos.x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1579 pos.y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1580 pos.x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1581 pos.y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1582 lpDrop->fWide = FALSE;
1583 p_drop = (char*)(lpDrop + 1);
1584 release_win_data( win_data );
1587 /* create message content */
1588 if (p_drop) {
1589 p = (char*) p_data;
1590 next = strchr(p, '\n');
1591 while (p) {
1592 if (next) *next=0;
1593 if (strncmp(p,"file:",5) == 0 ) {
1594 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1595 if (len) {
1596 TRACE("drop file %s as %s\n", p+5, p_drop);
1597 p_drop += len+1;
1598 } else {
1599 WARN("can't convert file %s to dos name\n", p+5);
1601 } else {
1602 WARN("unknown mime type %s\n", p);
1604 if (next) {
1605 *next = '\n';
1606 p = next + 1;
1607 next = strchr(p, '\n');
1608 } else {
1609 p = NULL;
1611 *p_drop = '\0';
1614 GlobalUnlock(hDrop);
1615 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1618 if( p_data ) XFree(p_data);
1623 /**********************************************************************
1624 * handle_xembed_protocol
1626 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1628 switch (event->data.l[1])
1630 case XEMBED_EMBEDDED_NOTIFY:
1632 struct x11drv_win_data *data = get_win_data( hwnd );
1633 if (!data) break;
1635 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1636 data->embedder = event->data.l[3];
1638 /* window has been marked as embedded before (e.g. systray) */
1639 if (data->embedded || !data->embedder /* broken QX11EmbedContainer implementation */)
1641 release_win_data( data );
1642 break;
1645 make_window_embedded( data );
1646 release_win_data( data );
1647 reparent_notify( event->display, hwnd, event->data.l[3], 0, 0 );
1649 break;
1651 case XEMBED_WINDOW_DEACTIVATE:
1652 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd, event->window );
1653 focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
1654 break;
1656 case XEMBED_FOCUS_OUT:
1657 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd, event->window );
1658 focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
1659 break;
1661 case XEMBED_MODALITY_ON:
1662 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd, event->window );
1663 EnableWindow( hwnd, FALSE );
1664 break;
1666 case XEMBED_MODALITY_OFF:
1667 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd, event->window );
1668 EnableWindow( hwnd, TRUE );
1669 break;
1671 default:
1672 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1673 hwnd, event->window, event->data.l[1], event->data.l[2] );
1674 break;
1679 /**********************************************************************
1680 * handle_dnd_protocol
1682 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1684 Window root, child;
1685 int root_x, root_y, child_x, child_y;
1686 unsigned int u;
1688 /* query window (drag&drop event contains only drag window) */
1689 XQueryPointer( event->display, root_window, &root, &child,
1690 &root_x, &root_y, &child_x, &child_y, &u);
1691 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1692 if (!hwnd) return;
1693 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1694 EVENT_DropFromOffiX(hwnd, event);
1695 else if (event->data.l[0] == DndURL)
1696 EVENT_DropURLs(hwnd, event);
1700 struct client_message_handler
1702 int atom; /* protocol atom */
1703 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1706 static const struct client_message_handler client_messages[] =
1708 { XATOM_MANAGER, handle_manager_message },
1709 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1710 { XATOM__XEMBED, handle_xembed_protocol },
1711 { XATOM_DndProtocol, handle_dnd_protocol },
1712 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1713 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1714 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1715 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1719 /**********************************************************************
1720 * X11DRV_ClientMessage
1722 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1724 XClientMessageEvent *event = &xev->xclient;
1725 unsigned int i;
1727 if (!hwnd) return;
1729 if (event->format != 32)
1731 WARN( "Don't know how to handle format %d\n", event->format );
1732 return;
1735 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1737 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1739 client_messages[i].handler( hwnd, event );
1740 return;
1743 TRACE( "no handler found for %ld\n", event->message_type );