mshtml: Added IHTMLElement2::blur implementation.
[wine/multimedia.git] / dlls / winex11.drv / event.c
blob7f9f0bf8d868259ac617a6b2fa03e0a8b6e0fe12
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 * X11DRV_register_event_handler
188 * Register a handler for a given event type.
189 * If already registered, overwrite the previous handler.
191 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
193 assert( type < MAX_EVENT_HANDLERS );
194 assert( !handlers[type] || handlers[type] == handler );
195 handlers[type] = handler;
196 event_names[type] = name;
197 TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
201 /***********************************************************************
202 * filter_event
204 static Bool filter_event( Display *display, XEvent *event, char *arg )
206 ULONG_PTR mask = (ULONG_PTR)arg;
208 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
210 switch(event->type)
212 case KeyPress:
213 case KeyRelease:
214 case KeymapNotify:
215 case MappingNotify:
216 return (mask & (QS_KEY|QS_HOTKEY)) != 0;
217 case ButtonPress:
218 case ButtonRelease:
219 return (mask & QS_MOUSEBUTTON) != 0;
220 case MotionNotify:
221 case EnterNotify:
222 case LeaveNotify:
223 return (mask & QS_MOUSEMOVE) != 0;
224 case Expose:
225 return (mask & QS_PAINT) != 0;
226 case FocusIn:
227 case FocusOut:
228 case MapNotify:
229 case UnmapNotify:
230 case ConfigureNotify:
231 case PropertyNotify:
232 case ClientMessage:
233 return (mask & QS_POSTMESSAGE) != 0;
234 default:
235 return (mask & QS_SENDMESSAGE) != 0;
240 enum event_merge_action
242 MERGE_DISCARD, /* discard the old event */
243 MERGE_HANDLE, /* handle the old event */
244 MERGE_KEEP, /* keep the old event for future merging */
245 MERGE_IGNORE /* ignore the new event, keep the old one */
248 /***********************************************************************
249 * merge_raw_motion_events
251 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
252 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
254 int i, j, k;
255 unsigned char mask;
257 if (!prev->valuators.mask_len) return MERGE_HANDLE;
258 if (!next->valuators.mask_len) return MERGE_HANDLE;
260 mask = prev->valuators.mask[0] | next->valuators.mask[0];
261 if (mask == next->valuators.mask[0]) /* keep next */
263 for (i = j = k = 0; i < 8; i++)
265 if (XIMaskIsSet( prev->valuators.mask, i ))
266 next->valuators.values[j] += prev->valuators.values[k++];
267 if (XIMaskIsSet( next->valuators.mask, i )) j++;
269 TRACE( "merging duplicate GenericEvent\n" );
270 return MERGE_DISCARD;
272 if (mask == prev->valuators.mask[0]) /* keep prev */
274 for (i = j = k = 0; i < 8; i++)
276 if (XIMaskIsSet( next->valuators.mask, i ))
277 prev->valuators.values[j] += next->valuators.values[k++];
278 if (XIMaskIsSet( prev->valuators.mask, i )) j++;
280 TRACE( "merging duplicate GenericEvent\n" );
281 return MERGE_IGNORE;
283 /* can't merge events with disjoint masks */
284 return MERGE_HANDLE;
286 #endif
288 /***********************************************************************
289 * merge_events
291 * Try to merge 2 consecutive events.
293 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
295 switch (prev->type)
297 case ConfigureNotify:
298 switch (next->type)
300 case ConfigureNotify:
301 if (prev->xany.window == next->xany.window)
303 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
304 return MERGE_DISCARD;
306 break;
307 case Expose:
308 case PropertyNotify:
309 return MERGE_KEEP;
311 break;
312 case MotionNotify:
313 switch (next->type)
315 case MotionNotify:
316 if (prev->xany.window == next->xany.window)
318 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
319 return MERGE_DISCARD;
321 break;
322 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
323 case GenericEvent:
324 if (next->xcookie.extension != xinput2_opcode) break;
325 if (next->xcookie.evtype != XI_RawMotion) break;
326 if (x11drv_thread_data()->warp_serial) break;
327 return MERGE_KEEP;
329 break;
330 case GenericEvent:
331 if (prev->xcookie.extension != xinput2_opcode) break;
332 if (prev->xcookie.evtype != XI_RawMotion) break;
333 switch (next->type)
335 case GenericEvent:
336 if (next->xcookie.extension != xinput2_opcode) break;
337 if (next->xcookie.evtype != XI_RawMotion) break;
338 if (x11drv_thread_data()->warp_serial) break;
339 return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
340 #endif
342 break;
344 return MERGE_HANDLE;
348 /***********************************************************************
349 * call_event_handler
351 static inline void call_event_handler( Display *display, XEvent *event )
353 HWND hwnd;
354 XEvent *prev;
355 struct x11drv_thread_data *thread_data;
357 if (!handlers[event->type])
359 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
360 return; /* no handler, ignore it */
363 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
364 hwnd = 0; /* not for a registered window */
365 if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
367 TRACE( "%lu %s for hwnd/window %p/%lx\n",
368 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
369 wine_tsx11_unlock();
370 thread_data = x11drv_thread_data();
371 prev = thread_data->current_event;
372 thread_data->current_event = event;
373 handlers[event->type]( hwnd, event );
374 thread_data->current_event = prev;
375 wine_tsx11_lock();
379 /***********************************************************************
380 * process_events
382 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
384 XEvent event, prev_event;
385 int count = 0;
386 enum event_merge_action action = MERGE_DISCARD;
388 prev_event.type = 0;
389 wine_tsx11_lock();
390 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
392 count++;
393 if (XFilterEvent( &event, None ))
396 * SCIM on linux filters key events strangely. It does not filter the
397 * KeyPress events for these keys however it does filter the
398 * KeyRelease events. This causes wine to become very confused as
399 * to the keyboard state.
401 * We need to let those KeyRelease events be processed so that the
402 * keyboard state is correct.
404 if (event.type == KeyRelease)
406 KeySym keysym = 0;
407 XKeyEvent *keyevent = &event.xkey;
409 XLookupString(keyevent, NULL, 0, &keysym, NULL);
410 if (!(keysym == XK_Shift_L ||
411 keysym == XK_Shift_R ||
412 keysym == XK_Control_L ||
413 keysym == XK_Control_R ||
414 keysym == XK_Alt_R ||
415 keysym == XK_Alt_L ||
416 keysym == XK_Meta_R ||
417 keysym == XK_Meta_L))
418 continue; /* not a key we care about, ignore it */
420 else
421 continue; /* filtered, ignore it */
423 get_event_data( &event );
424 if (prev_event.type) action = merge_events( &prev_event, &event );
425 switch( action )
427 case MERGE_HANDLE: /* handle prev, keep new */
428 call_event_handler( display, &prev_event );
429 /* fall through */
430 case MERGE_DISCARD: /* discard prev, keep new */
431 free_event_data( &prev_event );
432 prev_event = event;
433 break;
434 case MERGE_KEEP: /* handle new, keep prev for future merging */
435 call_event_handler( display, &event );
436 /* fall through */
437 case MERGE_IGNORE: /* ignore new, keep prev for future merging */
438 free_event_data( &event );
439 break;
442 if (prev_event.type) call_event_handler( display, &prev_event );
443 free_event_data( &prev_event );
444 XFlush( gdi_display );
445 wine_tsx11_unlock();
446 if (count) TRACE( "processed %d events\n", count );
447 return count;
451 /***********************************************************************
452 * MsgWaitForMultipleObjectsEx (X11DRV.@)
454 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
455 DWORD timeout, DWORD mask, DWORD flags )
457 DWORD ret;
458 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
460 if (!data)
462 if (!count && !timeout) return WAIT_TIMEOUT;
463 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
464 timeout, flags & MWMO_ALERTABLE );
467 if (data->current_event) mask = 0; /* don't process nested events */
469 if (process_events( data->display, filter_event, mask )) ret = count - 1;
470 else if (count || timeout)
472 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
473 timeout, flags & MWMO_ALERTABLE );
474 if (ret == count - 1) process_events( data->display, filter_event, mask );
476 else ret = WAIT_TIMEOUT;
478 return ret;
481 /***********************************************************************
482 * EVENT_x11_time_to_win32_time
484 * Make our timer and the X timer line up as best we can
485 * Pass 0 to retrieve the current adjustment value (times -1)
487 DWORD EVENT_x11_time_to_win32_time(Time time)
489 static DWORD adjust = 0;
490 DWORD now = GetTickCount();
491 DWORD ret;
493 if (! adjust && time != 0)
495 ret = now;
496 adjust = time - now;
498 else
500 /* If we got an event in the 'future', then our clock is clearly wrong.
501 If we got it more than 10000 ms in the future, then it's most likely
502 that the clock has wrapped. */
504 ret = time - adjust;
505 if (ret > now && ((ret - now) < 10000) && time != 0)
507 adjust += ret - now;
508 ret -= ret - now;
512 return ret;
516 /*******************************************************************
517 * can_activate_window
519 * Check if we can activate the specified window.
521 static inline BOOL can_activate_window( HWND hwnd )
523 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
524 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
526 if (!(style & WS_VISIBLE)) return FALSE;
527 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
528 if (style & WS_MINIMIZE) return FALSE;
529 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
530 if (hwnd == GetDesktopWindow()) return FALSE;
531 if (data && IsRectEmpty( &data->window_rect )) return FALSE;
532 return !(style & WS_DISABLED);
536 /**********************************************************************
537 * set_focus
539 static void set_focus( Display *display, HWND hwnd, Time time )
541 HWND focus;
542 Window win;
543 GUITHREADINFO threadinfo;
545 TRACE( "setting foreground window to %p\n", hwnd );
546 SetForegroundWindow( hwnd );
548 threadinfo.cbSize = sizeof(threadinfo);
549 GetGUIThreadInfo(0, &threadinfo);
550 focus = threadinfo.hwndFocus;
551 if (!focus) focus = threadinfo.hwndActive;
552 if (focus) focus = GetAncestor( focus, GA_ROOT );
553 win = X11DRV_get_whole_window(focus);
555 if (win)
557 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
558 wine_tsx11_lock();
559 XSetInputFocus( display, win, RevertToParent, time );
560 wine_tsx11_unlock();
565 /**********************************************************************
566 * handle_manager_message
568 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
570 if (hwnd != GetDesktopWindow()) return;
571 if (systray_atom && event->data.l[1] == systray_atom)
572 change_systray_owner( event->display, event->data.l[2] );
576 /**********************************************************************
577 * handle_wm_protocols
579 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
581 Atom protocol = (Atom)event->data.l[0];
582 Time event_time = (Time)event->data.l[1];
584 if (!protocol) return;
586 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
588 update_user_time( event_time );
590 if (hwnd == GetDesktopWindow())
592 /* The desktop window does not have a close button that we can
593 * pretend to click. Therefore, we simply send it a close command. */
594 SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
595 return;
598 /* Ignore the delete window request if the window has been disabled
599 * and we are in managed mode. This is to disallow applications from
600 * being closed by the window manager while in a modal state.
602 if (IsWindowEnabled(hwnd))
604 HMENU hSysMenu;
606 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
607 hSysMenu = GetSystemMenu(hwnd, FALSE);
608 if (hSysMenu)
610 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
611 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
612 return;
614 if (GetActiveWindow() != hwnd)
616 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
617 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
618 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
619 switch(ma)
621 case MA_NOACTIVATEANDEAT:
622 case MA_ACTIVATEANDEAT:
623 return;
624 case MA_NOACTIVATE:
625 break;
626 case MA_ACTIVATE:
627 case 0:
628 SetActiveWindow(hwnd);
629 break;
630 default:
631 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
632 break;
636 PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
639 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
641 HWND last_focus = x11drv_thread_data()->last_focus;
643 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
644 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
645 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
647 if (can_activate_window(hwnd))
649 /* simulate a mouse click on the caption to find out
650 * whether the window wants to be activated */
651 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
652 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
653 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
654 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
656 set_focus( event->display, hwnd, event_time );
657 return;
660 else if (hwnd == GetDesktopWindow())
662 hwnd = GetForegroundWindow();
663 if (!hwnd) hwnd = last_focus;
664 if (!hwnd) hwnd = GetDesktopWindow();
665 set_focus( event->display, hwnd, event_time );
666 return;
668 /* try to find some other window to give the focus to */
669 hwnd = GetFocus();
670 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
671 if (!hwnd) hwnd = GetActiveWindow();
672 if (!hwnd) hwnd = last_focus;
673 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
675 else if (protocol == x11drv_atom(_NET_WM_PING))
677 XClientMessageEvent xev;
678 xev = *event;
680 TRACE("NET_WM Ping\n");
681 wine_tsx11_lock();
682 xev.window = DefaultRootWindow(xev.display);
683 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
684 wine_tsx11_unlock();
685 /* this line is semi-stolen from gtk2 */
686 TRACE("NET_WM Pong\n");
691 static const char * const focus_details[] =
693 "NotifyAncestor",
694 "NotifyVirtual",
695 "NotifyInferior",
696 "NotifyNonlinear",
697 "NotifyNonlinearVirtual",
698 "NotifyPointer",
699 "NotifyPointerRoot",
700 "NotifyDetailNone"
703 /**********************************************************************
704 * X11DRV_FocusIn
706 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
708 XFocusChangeEvent *event = &xev->xfocus;
709 XIC xic;
711 if (!hwnd) return;
713 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
715 if (event->detail == NotifyPointer) return;
716 if (hwnd == GetDesktopWindow()) return;
718 if ((xic = X11DRV_get_ic( hwnd )))
720 wine_tsx11_lock();
721 XSetICFocus( xic );
722 wine_tsx11_unlock();
724 if (use_take_focus)
726 if (hwnd == GetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE );
727 return;
730 if (!can_activate_window(hwnd))
732 HWND hwnd = GetFocus();
733 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
734 if (!hwnd) hwnd = GetActiveWindow();
735 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
736 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
738 else SetForegroundWindow( hwnd );
742 /**********************************************************************
743 * X11DRV_FocusOut
745 * Note: only top-level windows get FocusOut events.
747 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
749 XFocusChangeEvent *event = &xev->xfocus;
750 HWND hwnd_tmp;
751 Window focus_win;
752 int revert;
753 XIC xic;
755 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
757 if (event->detail == NotifyPointer)
759 if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
760 return;
762 if (!hwnd) return;
763 if (ximInComposeMode) return;
765 x11drv_thread_data()->last_focus = hwnd;
766 if ((xic = X11DRV_get_ic( hwnd )))
768 wine_tsx11_lock();
769 XUnsetICFocus( xic );
770 wine_tsx11_unlock();
772 if (root_window != DefaultRootWindow(event->display))
774 if (hwnd == GetDesktopWindow()) reset_clipping_window();
775 return;
777 if (hwnd != GetForegroundWindow()) return;
778 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
780 /* don't reset the foreground window, if the window which is
781 getting the focus is a Wine window */
783 wine_tsx11_lock();
784 XGetInputFocus( event->display, &focus_win, &revert );
785 if (focus_win)
787 if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
788 focus_win = 0;
790 wine_tsx11_unlock();
792 if (!focus_win)
794 /* Abey : 6-Oct-99. Check again if the focus out window is the
795 Foreground window, because in most cases the messages sent
796 above must have already changed the foreground window, in which
797 case we don't have to change the foreground window to 0 */
798 if (hwnd == GetForegroundWindow())
800 TRACE( "lost focus, setting fg to desktop\n" );
801 SetForegroundWindow( GetDesktopWindow() );
807 /***********************************************************************
808 * X11DRV_Expose
810 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
812 XExposeEvent *event = &xev->xexpose;
813 RECT rect;
814 struct x11drv_win_data *data;
815 int flags = RDW_INVALIDATE | RDW_ERASE;
817 TRACE( "win %p (%lx) %d,%d %dx%d\n",
818 hwnd, event->window, event->x, event->y, event->width, event->height );
820 if (!(data = X11DRV_get_win_data( hwnd ))) return;
822 rect.left = event->x;
823 rect.top = event->y;
824 rect.right = event->x + event->width;
825 rect.bottom = event->y + event->height;
826 if (event->window == data->whole_window)
828 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
829 data->whole_rect.top - data->client_rect.top );
830 flags |= RDW_FRAME;
833 if (event->window != root_window)
835 if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
836 mirror_rect( &data->client_rect, &rect );
838 SERVER_START_REQ( update_window_zorder )
840 req->window = wine_server_user_handle( hwnd );
841 req->rect.left = rect.left;
842 req->rect.top = rect.top;
843 req->rect.right = rect.right;
844 req->rect.bottom = rect.bottom;
845 wine_server_call( req );
847 SERVER_END_REQ;
849 flags |= RDW_ALLCHILDREN;
851 else OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
853 RedrawWindow( hwnd, &rect, 0, flags );
857 /**********************************************************************
858 * X11DRV_MapNotify
860 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
862 struct x11drv_win_data *data;
864 if (event->xany.window == x11drv_thread_data()->clip_window)
866 clipping_cursor = 1;
867 return;
869 if (!(data = X11DRV_get_win_data( hwnd ))) return;
870 if (!data->mapped || data->embedded) return;
872 if (!data->managed)
874 HWND hwndFocus = GetFocus();
875 if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus); /* FIXME */
880 /**********************************************************************
881 * X11DRV_UnmapNotify
883 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
885 if (event->xany.window == x11drv_thread_data()->clip_window) clipping_cursor = 0;
889 /***********************************************************************
890 * is_net_wm_state_maximized
892 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
894 Atom type, *state;
895 int format, ret = 0;
896 unsigned long i, count, remaining;
898 if (!data->whole_window) return FALSE;
900 wine_tsx11_lock();
901 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
902 65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
903 &remaining, (unsigned char **)&state ))
905 if (type == XA_ATOM && format == 32)
907 for (i = 0; i < count; i++)
909 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
910 state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
911 ret++;
914 XFree( state );
916 wine_tsx11_unlock();
917 return (ret == 2);
921 /***********************************************************************
922 * X11DRV_ReparentNotify
924 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
926 XReparentEvent *event = &xev->xreparent;
927 struct x11drv_win_data *data;
928 HWND parent, old_parent;
929 DWORD style;
931 if (!(data = X11DRV_get_win_data( hwnd ))) return;
932 if (!data->embedded) return;
934 if (data->whole_window)
936 if (event->parent == root_window)
938 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
939 data->embedder = 0;
940 SendMessageW( hwnd, WM_CLOSE, 0, 0 );
941 return;
943 data->embedder = event->parent;
946 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
948 style = GetWindowLongW( hwnd, GWL_STYLE );
949 if (event->parent == root_window)
951 parent = GetDesktopWindow();
952 style = (style & ~WS_CHILD) | WS_POPUP;
954 else
956 if (!(parent = create_foreign_window( event->display, event->parent ))) return;
957 style = (style & ~WS_POPUP) | WS_CHILD;
960 ShowWindow( hwnd, SW_HIDE );
961 old_parent = SetParent( hwnd, parent );
962 SetWindowLongW( hwnd, GWL_STYLE, style );
963 SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
964 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
965 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
967 /* make old parent destroy itself if it no longer has children */
968 if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
972 /***********************************************************************
973 * X11DRV_ConfigureNotify
975 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
977 XConfigureEvent *event = &xev->xconfigure;
978 struct x11drv_win_data *data;
979 RECT rect;
980 UINT flags;
981 HWND parent;
982 BOOL root_coords;
983 int cx, cy, x = event->x, y = event->y;
985 if (!hwnd) return;
986 if (!(data = X11DRV_get_win_data( hwnd ))) return;
987 if (!data->mapped || data->iconic) return;
988 if (data->whole_window && !data->managed) return;
989 /* ignore synthetic events on foreign windows */
990 if (event->send_event && !data->whole_window) return;
991 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
993 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
994 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
995 event->serial, data->configure_serial );
996 return;
999 /* Get geometry */
1001 parent = GetAncestor( hwnd, GA_PARENT );
1002 root_coords = event->send_event; /* synthetic events are always in root coords */
1004 if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
1006 Window child;
1007 wine_tsx11_lock();
1008 XTranslateCoordinates( event->display, event->window, root_window,
1009 0, 0, &x, &y, &child );
1010 wine_tsx11_unlock();
1011 root_coords = TRUE;
1013 rect.left = x;
1014 rect.top = y;
1015 rect.right = x + event->width;
1016 rect.bottom = y + event->height;
1017 if (root_coords) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
1018 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1019 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1020 event->x, event->y, event->width, event->height );
1022 X11DRV_X_to_window_rect( data, &rect );
1023 if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1025 /* Compare what has changed */
1027 x = rect.left;
1028 y = rect.top;
1029 cx = rect.right - rect.left;
1030 cy = rect.bottom - rect.top;
1031 flags = SWP_NOACTIVATE | SWP_NOZORDER;
1033 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
1035 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1036 else
1037 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1038 hwnd, data->window_rect.left, data->window_rect.top, x, y );
1040 if ((data->window_rect.right - data->window_rect.left == cx &&
1041 data->window_rect.bottom - data->window_rect.top == cy) ||
1042 (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
1044 if (flags & SWP_NOMOVE) /* if nothing changed, don't do anything */
1046 TRACE( "Nothing has changed, ignoring event\n" );
1047 return;
1049 flags |= SWP_NOSIZE;
1051 else
1052 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1053 hwnd, data->window_rect.right - data->window_rect.left,
1054 data->window_rect.bottom - data->window_rect.top, cx, cy );
1056 if (is_net_wm_state_maximized( event->display, data ))
1058 if (!IsZoomed( data->hwnd ))
1060 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1061 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1062 return;
1065 else
1067 if (IsZoomed( data->hwnd ))
1069 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1070 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1071 return;
1075 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1079 /**********************************************************************
1080 * X11DRV_GravityNotify
1082 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1084 XGravityEvent *event = &xev->xgravity;
1085 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1086 RECT rect;
1088 if (!data || data->whole_window) return; /* only handle this for foreign windows */
1090 rect.left = event->x;
1091 rect.top = event->y;
1092 rect.right = rect.left + data->whole_rect.right - data->whole_rect.left;
1093 rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1095 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1096 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1097 event->x, event->y );
1099 X11DRV_X_to_window_rect( data, &rect );
1101 if (data->window_rect.left != rect.left || data ->window_rect.top != rect.top)
1102 SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1103 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1107 /***********************************************************************
1108 * get_window_wm_state
1110 static int get_window_wm_state( Display *display, struct x11drv_win_data *data )
1112 struct
1114 CARD32 state;
1115 XID icon;
1116 } *state;
1117 Atom type;
1118 int format, ret = -1;
1119 unsigned long count, remaining;
1121 wine_tsx11_lock();
1122 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
1123 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1124 &type, &format, &count, &remaining, (unsigned char **)&state ))
1126 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1127 ret = state->state;
1128 XFree( state );
1130 wine_tsx11_unlock();
1131 return ret;
1135 /***********************************************************************
1136 * handle_wm_state_notify
1138 * Handle a PropertyNotify for WM_STATE.
1140 static void handle_wm_state_notify( struct x11drv_win_data *data, XPropertyEvent *event,
1141 BOOL update_window )
1143 DWORD style;
1145 switch(event->state)
1147 case PropertyDelete:
1148 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1149 data->wm_state = WithdrawnState;
1150 break;
1151 case PropertyNewValue:
1153 int old_state = data->wm_state;
1154 int new_state = get_window_wm_state( event->display, data );
1155 if (new_state != -1 && new_state != data->wm_state)
1157 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1158 data->hwnd, data->whole_window, new_state, old_state );
1159 data->wm_state = new_state;
1160 /* ignore the initial state transition out of withdrawn state */
1161 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1162 if (!old_state) return;
1165 break;
1168 if (!update_window || !data->managed || !data->mapped) return;
1170 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1172 if (data->iconic && data->wm_state == NormalState) /* restore window */
1174 data->iconic = FALSE;
1175 if (is_net_wm_state_maximized( event->display, data ))
1177 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1179 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1180 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1182 else TRACE( "not restoring to max win %p/%lx style %08x\n",
1183 data->hwnd, data->whole_window, style );
1185 else if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1187 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1188 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1190 else TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1192 else if (!data->iconic && data->wm_state == IconicState)
1194 data->iconic = TRUE;
1195 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1197 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1198 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1200 else TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1205 /***********************************************************************
1206 * X11DRV_PropertyNotify
1208 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1210 XPropertyEvent *event = &xev->xproperty;
1211 struct x11drv_win_data *data;
1213 if (!hwnd) return;
1214 if (!(data = X11DRV_get_win_data( hwnd ))) return;
1216 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( data, event, TRUE );
1220 /* event filter to wait for a WM_STATE change notification on a window */
1221 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1223 if (event->xany.window != (Window)arg) return 0;
1224 return (event->type == DestroyNotify ||
1225 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1228 /***********************************************************************
1229 * wait_for_withdrawn_state
1231 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data, BOOL set )
1233 DWORD end = GetTickCount() + 2000;
1235 if (!data->managed) return;
1237 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
1238 data->hwnd, data->whole_window, set ? "" : "not " );
1240 while (data->whole_window && ((data->wm_state == WithdrawnState) == !set))
1242 XEvent event;
1243 int count = 0;
1245 wine_tsx11_lock();
1246 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)data->whole_window ))
1248 count++;
1249 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1250 if (event.type == DestroyNotify) call_event_handler( display, &event );
1251 else
1253 wine_tsx11_unlock();
1254 handle_wm_state_notify( data, &event.xproperty, FALSE );
1255 wine_tsx11_lock();
1258 wine_tsx11_unlock();
1260 if (!count)
1262 struct pollfd pfd;
1263 int timeout = end - GetTickCount();
1265 pfd.fd = ConnectionNumber(display);
1266 pfd.events = POLLIN;
1267 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1269 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
1270 break;
1274 TRACE( "window %p/%lx state now %d\n", data->hwnd, data->whole_window, data->wm_state );
1278 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1280 RECT tempRect;
1282 if (!IsWindowEnabled(hQueryWnd)) return 0;
1284 GetWindowRect(hQueryWnd, &tempRect);
1286 if(!PtInRect(&tempRect, *lpPt)) return 0;
1288 if (!IsIconic( hQueryWnd ))
1290 POINT pt = *lpPt;
1291 ScreenToClient( hQueryWnd, &pt );
1292 GetClientRect( hQueryWnd, &tempRect );
1294 if (PtInRect( &tempRect, pt))
1296 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1297 if (ret && ret != hQueryWnd)
1299 ret = find_drop_window( ret, lpPt );
1300 if (ret) return ret;
1305 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1307 ScreenToClient(hQueryWnd, lpPt);
1309 return hQueryWnd;
1312 /**********************************************************************
1313 * EVENT_DropFromOffix
1315 * don't know if it still works (last Changelog is from 96/11/04)
1317 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1319 struct x11drv_win_data *data;
1320 unsigned long data_length;
1321 unsigned long aux_long;
1322 unsigned char* p_data = NULL;
1323 Atom atom_aux;
1324 int x, y, dummy;
1325 BOOL bAccept;
1326 Window win, w_aux_root, w_aux_child;
1328 win = X11DRV_get_whole_window(hWnd);
1329 wine_tsx11_lock();
1330 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1331 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1332 x += virtual_screen_rect.left;
1333 y += virtual_screen_rect.top;
1334 wine_tsx11_unlock();
1336 if (!(data = X11DRV_get_win_data( hWnd ))) return;
1338 /* find out drop point and drop window */
1339 if( x < 0 || y < 0 ||
1340 x > (data->whole_rect.right - data->whole_rect.left) ||
1341 y > (data->whole_rect.bottom - data->whole_rect.top) )
1343 bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1344 x = 0;
1345 y = 0;
1347 else
1349 POINT pt = { x, y };
1350 HWND hwndDrop = find_drop_window( hWnd, &pt );
1351 if (hwndDrop)
1353 x = pt.x;
1354 y = pt.y;
1355 bAccept = TRUE;
1357 else
1359 bAccept = FALSE;
1363 if (!bAccept) return;
1365 wine_tsx11_lock();
1366 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1367 x11drv_atom(DndSelection), 0, 65535, FALSE,
1368 AnyPropertyType, &atom_aux, &dummy,
1369 &data_length, &aux_long, &p_data);
1370 wine_tsx11_unlock();
1372 if( !aux_long && p_data) /* don't bother if > 64K */
1374 char *p = (char *)p_data;
1375 char *p_drop;
1377 aux_long = 0;
1378 while( *p ) /* calculate buffer size */
1380 INT len = GetShortPathNameA( p, NULL, 0 );
1381 if (len) aux_long += len + 1;
1382 p += strlen(p) + 1;
1384 if( aux_long && aux_long < 65535 )
1386 HDROP hDrop;
1387 DROPFILES *lpDrop;
1389 aux_long += sizeof(DROPFILES) + 1;
1390 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1391 lpDrop = GlobalLock( hDrop );
1393 if( lpDrop )
1395 lpDrop->pFiles = sizeof(DROPFILES);
1396 lpDrop->pt.x = x;
1397 lpDrop->pt.y = y;
1398 lpDrop->fNC = FALSE;
1399 lpDrop->fWide = FALSE;
1400 p_drop = (char *)(lpDrop + 1);
1401 p = (char *)p_data;
1402 while(*p)
1404 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1405 p_drop += strlen( p_drop ) + 1;
1406 p += strlen(p) + 1;
1408 *p_drop = '\0';
1409 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1413 wine_tsx11_lock();
1414 if( p_data ) XFree(p_data);
1415 wine_tsx11_unlock();
1418 /**********************************************************************
1419 * EVENT_DropURLs
1421 * drop items are separated by \n
1422 * each item is prefixed by its mime type
1424 * event->data.l[3], event->data.l[4] contains drop x,y position
1426 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1428 struct x11drv_win_data *win_data;
1429 unsigned long data_length;
1430 unsigned long aux_long, drop_len = 0;
1431 unsigned char *p_data = NULL; /* property data */
1432 char *p_drop = NULL;
1433 char *p, *next;
1434 int x, y;
1435 DROPFILES *lpDrop;
1436 HDROP hDrop;
1437 union {
1438 Atom atom_aux;
1439 int i;
1440 Window w_aux;
1441 unsigned int u;
1442 } u; /* unused */
1444 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1446 wine_tsx11_lock();
1447 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1448 x11drv_atom(DndSelection), 0, 65535, FALSE,
1449 AnyPropertyType, &u.atom_aux, &u.i,
1450 &data_length, &aux_long, &p_data);
1451 wine_tsx11_unlock();
1452 if (aux_long)
1453 WARN("property too large, truncated!\n");
1454 TRACE("urls=%s\n", p_data);
1456 if( !aux_long && p_data) { /* don't bother if > 64K */
1457 /* calculate length */
1458 p = (char*) p_data;
1459 next = strchr(p, '\n');
1460 while (p) {
1461 if (next) *next=0;
1462 if (strncmp(p,"file:",5) == 0 ) {
1463 INT len = GetShortPathNameA( p+5, NULL, 0 );
1464 if (len) drop_len += len + 1;
1466 if (next) {
1467 *next = '\n';
1468 p = next + 1;
1469 next = strchr(p, '\n');
1470 } else {
1471 p = NULL;
1475 if( drop_len && drop_len < 65535 ) {
1476 wine_tsx11_lock();
1477 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1478 &x, &y, &u.i, &u.i, &u.u);
1479 x += virtual_screen_rect.left;
1480 y += virtual_screen_rect.top;
1481 wine_tsx11_unlock();
1483 drop_len += sizeof(DROPFILES) + 1;
1484 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1485 lpDrop = GlobalLock( hDrop );
1487 if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
1489 lpDrop->pFiles = sizeof(DROPFILES);
1490 lpDrop->pt.x = x;
1491 lpDrop->pt.y = y;
1492 lpDrop->fNC =
1493 ( x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1494 y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1495 x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1496 y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1497 lpDrop->fWide = FALSE;
1498 p_drop = (char*)(lpDrop + 1);
1501 /* create message content */
1502 if (p_drop) {
1503 p = (char*) p_data;
1504 next = strchr(p, '\n');
1505 while (p) {
1506 if (next) *next=0;
1507 if (strncmp(p,"file:",5) == 0 ) {
1508 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1509 if (len) {
1510 TRACE("drop file %s as %s\n", p+5, p_drop);
1511 p_drop += len+1;
1512 } else {
1513 WARN("can't convert file %s to dos name\n", p+5);
1515 } else {
1516 WARN("unknown mime type %s\n", p);
1518 if (next) {
1519 *next = '\n';
1520 p = next + 1;
1521 next = strchr(p, '\n');
1522 } else {
1523 p = NULL;
1525 *p_drop = '\0';
1528 GlobalUnlock(hDrop);
1529 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1532 wine_tsx11_lock();
1533 if( p_data ) XFree(p_data);
1534 wine_tsx11_unlock();
1539 /**********************************************************************
1540 * handle_xembed_protocol
1542 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1544 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1546 if (!data) return;
1548 switch (event->data.l[1])
1550 case XEMBED_EMBEDDED_NOTIFY:
1551 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1552 data->embedder = event->data.l[3];
1553 break;
1554 default:
1555 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1556 hwnd, event->window, event->data.l[1], event->data.l[2] );
1557 break;
1562 /**********************************************************************
1563 * handle_dnd_protocol
1565 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1567 Window root, child;
1568 int root_x, root_y, child_x, child_y;
1569 unsigned int u;
1571 /* query window (drag&drop event contains only drag window) */
1572 wine_tsx11_lock();
1573 XQueryPointer( event->display, root_window, &root, &child,
1574 &root_x, &root_y, &child_x, &child_y, &u);
1575 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1576 wine_tsx11_unlock();
1577 if (!hwnd) return;
1578 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1579 EVENT_DropFromOffiX(hwnd, event);
1580 else if (event->data.l[0] == DndURL)
1581 EVENT_DropURLs(hwnd, event);
1585 struct client_message_handler
1587 int atom; /* protocol atom */
1588 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1591 static const struct client_message_handler client_messages[] =
1593 { XATOM_MANAGER, handle_manager_message },
1594 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1595 { XATOM__XEMBED, handle_xembed_protocol },
1596 { XATOM_DndProtocol, handle_dnd_protocol },
1597 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1598 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1599 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1600 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1604 /**********************************************************************
1605 * X11DRV_ClientMessage
1607 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1609 XClientMessageEvent *event = &xev->xclient;
1610 unsigned int i;
1612 if (!hwnd) return;
1614 if (event->format != 32)
1616 WARN( "Don't know how to handle format %d\n", event->format );
1617 return;
1620 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1622 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1624 client_messages[i].handler( hwnd, event );
1625 return;
1628 TRACE( "no handler found for %ld\n", event->message_type );