windowscodecs: Implement TiffDecoder_GetResolution.
[wine/multimedia.git] / dlls / winex11.drv / event.c
blobba5cdff1e94b920f8b4d0d0e9237d775eb0b9ac9
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>
36 #include <assert.h>
37 #include <stdarg.h>
38 #include <string.h>
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winuser.h"
45 #include "wingdi.h"
47 #include "x11drv.h"
49 /* avoid conflict with field names in included win32 headers */
50 #undef Status
51 #include "shlobj.h" /* DROPFILES */
52 #include "shellapi.h"
54 #include "wine/server.h"
55 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(event);
59 extern BOOL ximInComposeMode;
61 #define DndNotDnd -1 /* OffiX drag&drop */
62 #define DndUnknown 0
63 #define DndRawData 1
64 #define DndFile 2
65 #define DndFiles 3
66 #define DndText 4
67 #define DndDir 5
68 #define DndLink 6
69 #define DndExe 7
71 #define DndEND 8
73 #define DndURL 128 /* KDE drag&drop */
75 #define XEMBED_EMBEDDED_NOTIFY 0
76 #define XEMBED_WINDOW_ACTIVATE 1
77 #define XEMBED_WINDOW_DEACTIVATE 2
78 #define XEMBED_REQUEST_FOCUS 3
79 #define XEMBED_FOCUS_IN 4
80 #define XEMBED_FOCUS_OUT 5
81 #define XEMBED_FOCUS_NEXT 6
82 #define XEMBED_FOCUS_PREV 7
83 #define XEMBED_MODALITY_ON 10
84 #define XEMBED_MODALITY_OFF 11
85 #define XEMBED_REGISTER_ACCELERATOR 12
86 #define XEMBED_UNREGISTER_ACCELERATOR 13
87 #define XEMBED_ACTIVATE_ACCELERATOR 14
89 /* Event handlers */
90 static void X11DRV_FocusIn( HWND hwnd, XEvent *event );
91 static void X11DRV_FocusOut( HWND hwnd, XEvent *event );
92 static void X11DRV_Expose( HWND hwnd, XEvent *event );
93 static void X11DRV_MapNotify( HWND hwnd, XEvent *event );
94 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
95 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
96 static void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
97 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
98 static void X11DRV_ClientMessage( HWND hwnd, XEvent *event );
99 static void X11DRV_GravityNotify( HWND hwnd, XEvent *event );
101 struct event_handler
103 int type; /* event type */
104 x11drv_event_handler handler; /* corresponding handler function */
107 #define MAX_EVENT_HANDLERS 64
109 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
111 /* list must be sorted by event type */
112 { KeyPress, X11DRV_KeyEvent },
113 { KeyRelease, X11DRV_KeyEvent },
114 { ButtonPress, X11DRV_ButtonPress },
115 { ButtonRelease, X11DRV_ButtonRelease },
116 { MotionNotify, X11DRV_MotionNotify },
117 { EnterNotify, X11DRV_EnterNotify },
118 /* LeaveNotify */
119 { FocusIn, X11DRV_FocusIn },
120 { FocusOut, X11DRV_FocusOut },
121 { KeymapNotify, X11DRV_KeymapNotify },
122 { Expose, X11DRV_Expose },
123 /* GraphicsExpose */
124 /* NoExpose */
125 /* VisibilityNotify */
126 /* CreateNotify */
127 { DestroyNotify, X11DRV_DestroyNotify },
128 { UnmapNotify, X11DRV_UnmapNotify },
129 { MapNotify, X11DRV_MapNotify },
130 /* MapRequest */
131 { ReparentNotify, X11DRV_ReparentNotify },
132 { ConfigureNotify, X11DRV_ConfigureNotify },
133 /* ConfigureRequest */
134 { GravityNotify, X11DRV_GravityNotify },
135 /* ResizeRequest */
136 /* CirculateNotify */
137 /* CirculateRequest */
138 { PropertyNotify, X11DRV_PropertyNotify },
139 { SelectionClear, X11DRV_SelectionClear },
140 { SelectionRequest, X11DRV_SelectionRequest },
141 /* SelectionNotify */
142 /* ColormapNotify */
143 { ClientMessage, X11DRV_ClientMessage },
144 { MappingNotify, X11DRV_MappingNotify },
147 static int nb_event_handlers = 20; /* change this if you add handlers above */
150 /* return the name of an X event */
151 static const char *dbgstr_event( int type )
153 static const char * const event_names[] =
155 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
156 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
157 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
158 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
159 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
160 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
161 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
162 "ClientMessage", "MappingNotify"
165 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
166 return wine_dbg_sprintf( "Extension event %d", type );
170 /***********************************************************************
171 * find_handler
173 * Find the handler for a given event type. Caller must hold the x11 lock.
175 static inline x11drv_event_handler find_handler( int type )
177 int min = 0, max = nb_event_handlers - 1;
179 while (min <= max)
181 int pos = (min + max) / 2;
182 if (handlers[pos].type == type) return handlers[pos].handler;
183 if (handlers[pos].type > type) max = pos - 1;
184 else min = pos + 1;
186 return NULL;
190 /***********************************************************************
191 * X11DRV_register_event_handler
193 * Register a handler for a given event type.
194 * If already registered, overwrite the previous handler.
196 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
198 int min, max;
200 wine_tsx11_lock();
201 min = 0;
202 max = nb_event_handlers - 1;
203 while (min <= max)
205 int pos = (min + max) / 2;
206 if (handlers[pos].type == type)
208 handlers[pos].handler = handler;
209 goto done;
211 if (handlers[pos].type > type) max = pos - 1;
212 else min = pos + 1;
214 /* insert it between max and min */
215 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
216 handlers[min].type = type;
217 handlers[min].handler = handler;
218 nb_event_handlers++;
219 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
220 done:
221 wine_tsx11_unlock();
222 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
226 /***********************************************************************
227 * filter_event
229 static Bool filter_event( Display *display, XEvent *event, char *arg )
231 ULONG_PTR mask = (ULONG_PTR)arg;
233 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
235 switch(event->type)
237 case KeyPress:
238 case KeyRelease:
239 case KeymapNotify:
240 case MappingNotify:
241 return (mask & QS_KEY) != 0;
242 case ButtonPress:
243 case ButtonRelease:
244 return (mask & QS_MOUSEBUTTON) != 0;
245 case MotionNotify:
246 case EnterNotify:
247 case LeaveNotify:
248 return (mask & QS_MOUSEMOVE) != 0;
249 case Expose:
250 return (mask & QS_PAINT) != 0;
251 case FocusIn:
252 case FocusOut:
253 case MapNotify:
254 case UnmapNotify:
255 case ConfigureNotify:
256 case PropertyNotify:
257 case ClientMessage:
258 return (mask & QS_POSTMESSAGE) != 0;
259 default:
260 return (mask & QS_SENDMESSAGE) != 0;
265 enum event_merge_action
267 MERGE_DISCARD, /* discard the old event */
268 MERGE_HANDLE, /* handle the old event */
269 MERGE_KEEP /* keep the old event for future merging */
272 /***********************************************************************
273 * merge_events
275 * Try to merge 2 consecutive events.
277 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
279 switch (prev->type)
281 case ConfigureNotify:
282 switch (next->type)
284 case ConfigureNotify:
285 if (prev->xany.window == next->xany.window)
287 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
288 return MERGE_DISCARD;
290 break;
291 case Expose:
292 case PropertyNotify:
293 return MERGE_KEEP;
295 break;
296 case MotionNotify:
297 if (prev->xany.window == next->xany.window && next->type == MotionNotify)
299 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
300 return MERGE_DISCARD;
302 break;
304 return MERGE_HANDLE;
308 /***********************************************************************
309 * call_event_handler
311 static inline void call_event_handler( Display *display, XEvent *event )
313 HWND hwnd;
314 x11drv_event_handler handler;
315 XEvent *prev;
316 struct x11drv_thread_data *thread_data;
318 if (!(handler = find_handler( event->type )))
320 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
321 return; /* no handler, ignore it */
324 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
325 hwnd = 0; /* not for a registered window */
326 if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
328 TRACE( "%lu %s for hwnd/window %p/%lx\n",
329 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
330 wine_tsx11_unlock();
331 thread_data = x11drv_thread_data();
332 prev = thread_data->current_event;
333 thread_data->current_event = event;
334 handler( hwnd, event );
335 thread_data->current_event = prev;
336 wine_tsx11_lock();
340 /***********************************************************************
341 * process_events
343 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
345 XEvent event, prev_event;
346 int count = 0;
347 enum event_merge_action action = MERGE_DISCARD;
349 prev_event.type = 0;
350 wine_tsx11_lock();
351 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
353 count++;
354 if (XFilterEvent( &event, None ))
357 * SCIM on linux filters key events strangely. It does not filter the
358 * KeyPress events for these keys however it does filter the
359 * KeyRelease events. This causes wine to become very confused as
360 * to the keyboard state.
362 * We need to let those KeyRelease events be processed so that the
363 * keyboard state is correct.
365 if (event.type == KeyRelease)
367 KeySym keysym = 0;
368 XKeyEvent *keyevent = &event.xkey;
370 XLookupString(keyevent, NULL, 0, &keysym, NULL);
371 if (!(keysym == XK_Shift_L ||
372 keysym == XK_Shift_R ||
373 keysym == XK_Control_L ||
374 keysym == XK_Control_R ||
375 keysym == XK_Alt_R ||
376 keysym == XK_Alt_L ||
377 keysym == XK_Meta_R ||
378 keysym == XK_Meta_L))
379 continue; /* not a key we care about, ignore it */
381 else
382 continue; /* filtered, ignore it */
384 if (prev_event.type) action = merge_events( &prev_event, &event );
385 switch( action )
387 case MERGE_DISCARD: /* discard prev, keep new */
388 prev_event = event;
389 break;
390 case MERGE_HANDLE: /* handle prev, keep new */
391 call_event_handler( display, &prev_event );
392 prev_event = event;
393 break;
394 case MERGE_KEEP: /* handle new, keep prev for future merging */
395 call_event_handler( display, &event );
396 break;
399 if (prev_event.type) call_event_handler( display, &prev_event );
400 XFlush( gdi_display );
401 wine_tsx11_unlock();
402 if (count) TRACE( "processed %d events\n", count );
403 return count;
407 /***********************************************************************
408 * MsgWaitForMultipleObjectsEx (X11DRV.@)
410 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
411 DWORD timeout, DWORD mask, DWORD flags )
413 DWORD ret;
414 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
416 if (!data)
418 if (!count && !timeout) return WAIT_TIMEOUT;
419 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
420 timeout, flags & MWMO_ALERTABLE );
423 if (data->current_event) mask = 0; /* don't process nested events */
425 if (process_events( data->display, filter_event, mask )) ret = count - 1;
426 else if (count || timeout)
428 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
429 timeout, flags & MWMO_ALERTABLE );
430 if (ret == count - 1) process_events( data->display, filter_event, mask );
432 else ret = WAIT_TIMEOUT;
434 return ret;
437 /***********************************************************************
438 * EVENT_x11_time_to_win32_time
440 * Make our timer and the X timer line up as best we can
441 * Pass 0 to retrieve the current adjustment value (times -1)
443 DWORD EVENT_x11_time_to_win32_time(Time time)
445 static DWORD adjust = 0;
446 DWORD now = GetTickCount();
447 DWORD ret;
449 if (! adjust && time != 0)
451 ret = now;
452 adjust = time - now;
454 else
456 /* If we got an event in the 'future', then our clock is clearly wrong.
457 If we got it more than 10000 ms in the future, then it's most likely
458 that the clock has wrapped. */
460 ret = time - adjust;
461 if (ret > now && ((ret - now) < 10000) && time != 0)
463 adjust += ret - now;
464 ret -= ret - now;
468 return ret;
472 /*******************************************************************
473 * can_activate_window
475 * Check if we can activate the specified window.
477 static inline BOOL can_activate_window( HWND hwnd )
479 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
480 if (!(style & WS_VISIBLE)) return FALSE;
481 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
482 if (style & WS_MINIMIZE) return FALSE;
483 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
484 if (hwnd == GetDesktopWindow()) return FALSE;
485 return !(style & WS_DISABLED);
489 /**********************************************************************
490 * set_focus
492 static void set_focus( Display *display, HWND hwnd, Time time )
494 HWND focus;
495 Window win;
496 GUITHREADINFO threadinfo;
498 TRACE( "setting foreground window to %p\n", hwnd );
499 SetForegroundWindow( hwnd );
501 threadinfo.cbSize = sizeof(threadinfo);
502 GetGUIThreadInfo(0, &threadinfo);
503 focus = threadinfo.hwndFocus;
504 if (!focus) focus = threadinfo.hwndActive;
505 if (focus) focus = GetAncestor( focus, GA_ROOT );
506 win = X11DRV_get_whole_window(focus);
508 if (win)
510 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
511 wine_tsx11_lock();
512 XSetInputFocus( display, win, RevertToParent, time );
513 wine_tsx11_unlock();
518 /**********************************************************************
519 * handle_manager_message
521 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
523 if (hwnd != GetDesktopWindow()) return;
524 if (systray_atom && event->data.l[1] == systray_atom)
525 change_systray_owner( event->display, event->data.l[2] );
529 /**********************************************************************
530 * handle_wm_protocols
532 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
534 Atom protocol = (Atom)event->data.l[0];
535 Time event_time = (Time)event->data.l[1];
537 if (!protocol) return;
539 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
541 update_user_time( event_time );
543 if (hwnd == GetDesktopWindow())
545 /* The desktop window does not have a close button that we can
546 * pretend to click. Therefore, we simply send it a close command. */
547 SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
548 return;
551 /* Ignore the delete window request if the window has been disabled
552 * and we are in managed mode. This is to disallow applications from
553 * being closed by the window manager while in a modal state.
555 if (IsWindowEnabled(hwnd))
557 HMENU hSysMenu;
559 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
560 hSysMenu = GetSystemMenu(hwnd, FALSE);
561 if (hSysMenu)
563 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
564 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
565 return;
567 if (GetActiveWindow() != hwnd)
569 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
570 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
571 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
572 switch(ma)
574 case MA_NOACTIVATEANDEAT:
575 case MA_ACTIVATEANDEAT:
576 return;
577 case MA_NOACTIVATE:
578 break;
579 case MA_ACTIVATE:
580 case 0:
581 SetActiveWindow(hwnd);
582 break;
583 default:
584 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
585 break;
589 PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
592 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
594 HWND last_focus = x11drv_thread_data()->last_focus;
596 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
597 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
598 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
600 if (can_activate_window(hwnd))
602 /* simulate a mouse click on the caption to find out
603 * whether the window wants to be activated */
604 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
605 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
606 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
607 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
609 set_focus( event->display, hwnd, event_time );
610 return;
613 else if (hwnd == GetDesktopWindow())
615 hwnd = GetForegroundWindow();
616 if (!hwnd) hwnd = last_focus;
617 if (!hwnd) hwnd = GetDesktopWindow();
618 set_focus( event->display, hwnd, event_time );
619 return;
621 /* try to find some other window to give the focus to */
622 hwnd = GetFocus();
623 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
624 if (!hwnd) hwnd = GetActiveWindow();
625 if (!hwnd) hwnd = last_focus;
626 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
628 else if (protocol == x11drv_atom(_NET_WM_PING))
630 XClientMessageEvent xev;
631 xev = *event;
633 TRACE("NET_WM Ping\n");
634 wine_tsx11_lock();
635 xev.window = DefaultRootWindow(xev.display);
636 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
637 wine_tsx11_unlock();
638 /* this line is semi-stolen from gtk2 */
639 TRACE("NET_WM Pong\n");
644 static const char * const focus_details[] =
646 "NotifyAncestor",
647 "NotifyVirtual",
648 "NotifyInferior",
649 "NotifyNonlinear",
650 "NotifyNonlinearVirtual",
651 "NotifyPointer",
652 "NotifyPointerRoot",
653 "NotifyDetailNone"
656 /**********************************************************************
657 * X11DRV_FocusIn
659 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
661 XFocusChangeEvent *event = &xev->xfocus;
662 XIC xic;
664 if (!hwnd) return;
666 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
668 if (event->detail == NotifyPointer) return;
670 if ((xic = X11DRV_get_ic( hwnd )))
672 wine_tsx11_lock();
673 XSetICFocus( xic );
674 wine_tsx11_unlock();
676 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
678 if (!can_activate_window(hwnd))
680 HWND hwnd = GetFocus();
681 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
682 if (!hwnd) hwnd = GetActiveWindow();
683 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
684 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
686 else SetForegroundWindow( hwnd );
690 /**********************************************************************
691 * X11DRV_FocusOut
693 * Note: only top-level windows get FocusOut events.
695 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
697 XFocusChangeEvent *event = &xev->xfocus;
698 HWND hwnd_tmp;
699 Window focus_win;
700 int revert;
701 XIC xic;
703 if (!hwnd) return;
705 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
707 if (event->detail == NotifyPointer) return;
708 if (ximInComposeMode) return;
710 x11drv_thread_data()->last_focus = hwnd;
711 if ((xic = X11DRV_get_ic( hwnd )))
713 wine_tsx11_lock();
714 XUnsetICFocus( xic );
715 wine_tsx11_unlock();
717 if (hwnd != GetForegroundWindow()) return;
718 if (root_window != DefaultRootWindow(event->display)) return;
719 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
721 /* don't reset the foreground window, if the window which is
722 getting the focus is a Wine window */
724 wine_tsx11_lock();
725 XGetInputFocus( event->display, &focus_win, &revert );
726 if (focus_win)
728 if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
729 focus_win = 0;
731 wine_tsx11_unlock();
733 if (!focus_win)
735 /* Abey : 6-Oct-99. Check again if the focus out window is the
736 Foreground window, because in most cases the messages sent
737 above must have already changed the foreground window, in which
738 case we don't have to change the foreground window to 0 */
739 if (hwnd == GetForegroundWindow())
741 TRACE( "lost focus, setting fg to desktop\n" );
742 SetForegroundWindow( GetDesktopWindow() );
748 /***********************************************************************
749 * X11DRV_Expose
751 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
753 XExposeEvent *event = &xev->xexpose;
754 RECT rect;
755 struct x11drv_win_data *data;
756 int flags = RDW_INVALIDATE | RDW_ERASE;
758 TRACE( "win %p (%lx) %d,%d %dx%d\n",
759 hwnd, event->window, event->x, event->y, event->width, event->height );
761 if (!(data = X11DRV_get_win_data( hwnd ))) return;
763 rect.left = event->x;
764 rect.top = event->y;
765 rect.right = event->x + event->width;
766 rect.bottom = event->y + event->height;
767 if (event->window == data->whole_window)
769 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
770 data->whole_rect.top - data->client_rect.top );
771 flags |= RDW_FRAME;
774 if (event->window != root_window)
776 if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
777 mirror_rect( &data->client_rect, &rect );
779 SERVER_START_REQ( update_window_zorder )
781 req->window = wine_server_user_handle( hwnd );
782 req->rect.left = rect.left;
783 req->rect.top = rect.top;
784 req->rect.right = rect.right;
785 req->rect.bottom = rect.bottom;
786 wine_server_call( req );
788 SERVER_END_REQ;
790 flags |= RDW_ALLCHILDREN;
792 else OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
794 RedrawWindow( hwnd, &rect, 0, flags );
798 /**********************************************************************
799 * X11DRV_MapNotify
801 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
803 struct x11drv_win_data *data;
805 if (event->xany.window == clip_window)
807 clipping_cursor = 1;
808 return;
810 if (!(data = X11DRV_get_win_data( hwnd ))) return;
811 if (!data->mapped || data->embedded) return;
813 if (!data->managed)
815 HWND hwndFocus = GetFocus();
816 if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus); /* FIXME */
821 /**********************************************************************
822 * X11DRV_UnmapNotify
824 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
826 if (event->xany.window == clip_window) clipping_cursor = 0;
830 /***********************************************************************
831 * is_net_wm_state_maximized
833 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
835 Atom type, *state;
836 int format, ret = 0;
837 unsigned long i, count, remaining;
839 if (!data->whole_window) return FALSE;
841 wine_tsx11_lock();
842 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
843 65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
844 &remaining, (unsigned char **)&state ))
846 if (type == XA_ATOM && format == 32)
848 for (i = 0; i < count; i++)
850 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
851 state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
852 ret++;
855 XFree( state );
857 wine_tsx11_unlock();
858 return (ret == 2);
862 /***********************************************************************
863 * X11DRV_ReparentNotify
865 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
867 XReparentEvent *event = &xev->xreparent;
868 struct x11drv_win_data *data;
869 HWND parent, old_parent;
870 DWORD style;
872 if (!(data = X11DRV_get_win_data( hwnd ))) return;
873 if (!data->embedded) return;
875 if (data->whole_window)
877 if (event->parent == root_window)
879 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
880 data->embedder = 0;
881 SendMessageW( hwnd, WM_CLOSE, 0, 0 );
882 return;
884 data->embedder = event->parent;
887 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
889 style = GetWindowLongW( hwnd, GWL_STYLE );
890 if (event->parent == root_window)
892 parent = GetDesktopWindow();
893 style = (style & ~WS_CHILD) | WS_POPUP;
895 else
897 if (!(parent = create_foreign_window( event->display, event->parent ))) return;
898 style = (style & ~WS_POPUP) | WS_CHILD;
901 ShowWindow( hwnd, SW_HIDE );
902 old_parent = SetParent( hwnd, parent );
903 SetWindowLongW( hwnd, GWL_STYLE, style );
904 SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
905 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
906 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
908 /* make old parent destroy itself if it no longer has children */
909 if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
913 /***********************************************************************
914 * X11DRV_ConfigureNotify
916 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
918 XConfigureEvent *event = &xev->xconfigure;
919 struct x11drv_win_data *data;
920 RECT rect;
921 UINT flags;
922 HWND parent;
923 BOOL root_coords;
924 int cx, cy, x = event->x, y = event->y;
926 if (!hwnd) return;
927 if (!(data = X11DRV_get_win_data( hwnd ))) return;
928 if (!data->mapped || data->iconic) return;
929 if (data->whole_window && !data->managed) return;
930 /* ignore synthetic events on foreign windows */
931 if (event->send_event && !data->whole_window) return;
932 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
934 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
935 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
936 event->serial, data->configure_serial );
937 return;
940 /* Get geometry */
942 parent = GetAncestor( hwnd, GA_PARENT );
943 root_coords = event->send_event; /* synthetic events are always in root coords */
945 if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
947 Window child;
948 wine_tsx11_lock();
949 XTranslateCoordinates( event->display, event->window, root_window,
950 0, 0, &x, &y, &child );
951 wine_tsx11_unlock();
952 root_coords = TRUE;
954 rect.left = x;
955 rect.top = y;
956 rect.right = x + event->width;
957 rect.bottom = y + event->height;
958 if (root_coords) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
959 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
960 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
961 event->x, event->y, event->width, event->height );
963 if (is_net_wm_state_maximized( event->display, data ))
965 if (!IsZoomed( data->hwnd ))
967 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
968 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
969 return;
972 else
974 if (IsZoomed( data->hwnd ))
976 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
977 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
978 return;
982 X11DRV_X_to_window_rect( data, &rect );
983 if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
985 /* Compare what has changed */
987 x = rect.left;
988 y = rect.top;
989 cx = rect.right - rect.left;
990 cy = rect.bottom - rect.top;
991 flags = SWP_NOACTIVATE | SWP_NOZORDER;
993 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
995 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
996 else
997 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
998 hwnd, data->window_rect.left, data->window_rect.top, x, y );
1000 if ((data->window_rect.right - data->window_rect.left == cx &&
1001 data->window_rect.bottom - data->window_rect.top == cy) ||
1002 (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
1004 if (flags & SWP_NOMOVE) return; /* if nothing changed, don't do anything */
1005 flags |= SWP_NOSIZE;
1007 else
1008 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1009 hwnd, data->window_rect.right - data->window_rect.left,
1010 data->window_rect.bottom - data->window_rect.top, cx, cy );
1012 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1016 /**********************************************************************
1017 * X11DRV_GravityNotify
1019 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1021 XGravityEvent *event = &xev->xgravity;
1022 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1023 RECT rect;
1025 if (!data || data->whole_window) return; /* only handle this for foreign windows */
1027 rect.left = event->x;
1028 rect.top = event->y;
1029 rect.right = rect.left + data->whole_rect.right - data->whole_rect.left;
1030 rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1032 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1033 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1034 event->x, event->y );
1036 X11DRV_X_to_window_rect( data, &rect );
1038 if (data->window_rect.left != rect.left || data ->window_rect.top != rect.top)
1039 SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1040 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1044 /***********************************************************************
1045 * get_window_wm_state
1047 static int get_window_wm_state( Display *display, struct x11drv_win_data *data )
1049 struct
1051 CARD32 state;
1052 XID icon;
1053 } *state;
1054 Atom type;
1055 int format, ret = -1;
1056 unsigned long count, remaining;
1058 wine_tsx11_lock();
1059 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
1060 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1061 &type, &format, &count, &remaining, (unsigned char **)&state ))
1063 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1064 ret = state->state;
1065 XFree( state );
1067 wine_tsx11_unlock();
1068 return ret;
1072 /***********************************************************************
1073 * handle_wm_state_notify
1075 * Handle a PropertyNotify for WM_STATE.
1077 static void handle_wm_state_notify( struct x11drv_win_data *data, XPropertyEvent *event,
1078 BOOL update_window )
1080 DWORD style;
1082 switch(event->state)
1084 case PropertyDelete:
1085 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1086 data->wm_state = WithdrawnState;
1087 break;
1088 case PropertyNewValue:
1090 int old_state = data->wm_state;
1091 int new_state = get_window_wm_state( event->display, data );
1092 if (new_state != -1 && new_state != data->wm_state)
1094 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1095 data->hwnd, data->whole_window, new_state, old_state );
1096 data->wm_state = new_state;
1097 /* ignore the initial state transition out of withdrawn state */
1098 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1099 if (!old_state) return;
1102 break;
1105 if (!update_window || !data->managed || !data->mapped) return;
1107 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1109 if (data->iconic && data->wm_state == NormalState) /* restore window */
1111 data->iconic = FALSE;
1112 if (is_net_wm_state_maximized( event->display, data ))
1114 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1116 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1117 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1119 else TRACE( "not restoring to max win %p/%lx style %08x\n",
1120 data->hwnd, data->whole_window, style );
1122 else if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1124 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1125 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1127 else TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1129 else if (!data->iconic && data->wm_state == IconicState)
1131 data->iconic = TRUE;
1132 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1134 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1135 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1137 else TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1142 /***********************************************************************
1143 * X11DRV_PropertyNotify
1145 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1147 XPropertyEvent *event = &xev->xproperty;
1148 struct x11drv_win_data *data;
1150 if (!hwnd) return;
1151 if (!(data = X11DRV_get_win_data( hwnd ))) return;
1153 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( data, event, TRUE );
1157 /* event filter to wait for a WM_STATE change notification on a window */
1158 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1160 if (event->xany.window != (Window)arg) return 0;
1161 return (event->type == DestroyNotify ||
1162 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1165 /***********************************************************************
1166 * wait_for_withdrawn_state
1168 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data, BOOL set )
1170 DWORD end = GetTickCount() + 2000;
1172 if (!data->managed) return;
1174 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
1175 data->hwnd, data->whole_window, set ? "" : "not " );
1177 while (data->whole_window && ((data->wm_state == WithdrawnState) == !set))
1179 XEvent event;
1180 int count = 0;
1182 wine_tsx11_lock();
1183 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)data->whole_window ))
1185 count++;
1186 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1187 if (event.type == DestroyNotify) call_event_handler( display, &event );
1188 else
1190 wine_tsx11_unlock();
1191 handle_wm_state_notify( data, &event.xproperty, FALSE );
1192 wine_tsx11_lock();
1195 wine_tsx11_unlock();
1197 if (!count)
1199 struct pollfd pfd;
1200 int timeout = end - GetTickCount();
1202 pfd.fd = ConnectionNumber(display);
1203 pfd.events = POLLIN;
1204 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1206 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
1207 break;
1211 TRACE( "window %p/%lx state now %d\n", data->hwnd, data->whole_window, data->wm_state );
1215 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1217 RECT tempRect;
1219 if (!IsWindowEnabled(hQueryWnd)) return 0;
1221 GetWindowRect(hQueryWnd, &tempRect);
1223 if(!PtInRect(&tempRect, *lpPt)) return 0;
1225 if (!IsIconic( hQueryWnd ))
1227 POINT pt = *lpPt;
1228 ScreenToClient( hQueryWnd, &pt );
1229 GetClientRect( hQueryWnd, &tempRect );
1231 if (PtInRect( &tempRect, pt))
1233 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1234 if (ret && ret != hQueryWnd)
1236 ret = find_drop_window( ret, lpPt );
1237 if (ret) return ret;
1242 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1244 ScreenToClient(hQueryWnd, lpPt);
1246 return hQueryWnd;
1249 /**********************************************************************
1250 * EVENT_DropFromOffix
1252 * don't know if it still works (last Changelog is from 96/11/04)
1254 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1256 struct x11drv_win_data *data;
1257 unsigned long data_length;
1258 unsigned long aux_long;
1259 unsigned char* p_data = NULL;
1260 Atom atom_aux;
1261 int x, y, dummy;
1262 BOOL bAccept;
1263 Window win, w_aux_root, w_aux_child;
1265 win = X11DRV_get_whole_window(hWnd);
1266 wine_tsx11_lock();
1267 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1268 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1269 x += virtual_screen_rect.left;
1270 y += virtual_screen_rect.top;
1271 wine_tsx11_unlock();
1273 if (!(data = X11DRV_get_win_data( hWnd ))) return;
1275 /* find out drop point and drop window */
1276 if( x < 0 || y < 0 ||
1277 x > (data->whole_rect.right - data->whole_rect.left) ||
1278 y > (data->whole_rect.bottom - data->whole_rect.top) )
1280 bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1281 x = 0;
1282 y = 0;
1284 else
1286 POINT pt = { x, y };
1287 HWND hwndDrop = find_drop_window( hWnd, &pt );
1288 if (hwndDrop)
1290 x = pt.x;
1291 y = pt.y;
1292 bAccept = TRUE;
1294 else
1296 bAccept = FALSE;
1300 if (!bAccept) return;
1302 wine_tsx11_lock();
1303 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1304 x11drv_atom(DndSelection), 0, 65535, FALSE,
1305 AnyPropertyType, &atom_aux, &dummy,
1306 &data_length, &aux_long, &p_data);
1307 wine_tsx11_unlock();
1309 if( !aux_long && p_data) /* don't bother if > 64K */
1311 char *p = (char *)p_data;
1312 char *p_drop;
1314 aux_long = 0;
1315 while( *p ) /* calculate buffer size */
1317 INT len = GetShortPathNameA( p, NULL, 0 );
1318 if (len) aux_long += len + 1;
1319 p += strlen(p) + 1;
1321 if( aux_long && aux_long < 65535 )
1323 HDROP hDrop;
1324 DROPFILES *lpDrop;
1326 aux_long += sizeof(DROPFILES) + 1;
1327 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1328 lpDrop = GlobalLock( hDrop );
1330 if( lpDrop )
1332 lpDrop->pFiles = sizeof(DROPFILES);
1333 lpDrop->pt.x = x;
1334 lpDrop->pt.y = y;
1335 lpDrop->fNC = FALSE;
1336 lpDrop->fWide = FALSE;
1337 p_drop = (char *)(lpDrop + 1);
1338 p = (char *)p_data;
1339 while(*p)
1341 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1342 p_drop += strlen( p_drop ) + 1;
1343 p += strlen(p) + 1;
1345 *p_drop = '\0';
1346 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1350 wine_tsx11_lock();
1351 if( p_data ) XFree(p_data);
1352 wine_tsx11_unlock();
1355 /**********************************************************************
1356 * EVENT_DropURLs
1358 * drop items are separated by \n
1359 * each item is prefixed by its mime type
1361 * event->data.l[3], event->data.l[4] contains drop x,y position
1363 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1365 struct x11drv_win_data *win_data;
1366 unsigned long data_length;
1367 unsigned long aux_long, drop_len = 0;
1368 unsigned char *p_data = NULL; /* property data */
1369 char *p_drop = NULL;
1370 char *p, *next;
1371 int x, y;
1372 DROPFILES *lpDrop;
1373 HDROP hDrop;
1374 union {
1375 Atom atom_aux;
1376 int i;
1377 Window w_aux;
1378 unsigned int u;
1379 } u; /* unused */
1381 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1383 wine_tsx11_lock();
1384 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1385 x11drv_atom(DndSelection), 0, 65535, FALSE,
1386 AnyPropertyType, &u.atom_aux, &u.i,
1387 &data_length, &aux_long, &p_data);
1388 wine_tsx11_unlock();
1389 if (aux_long)
1390 WARN("property too large, truncated!\n");
1391 TRACE("urls=%s\n", p_data);
1393 if( !aux_long && p_data) { /* don't bother if > 64K */
1394 /* calculate length */
1395 p = (char*) p_data;
1396 next = strchr(p, '\n');
1397 while (p) {
1398 if (next) *next=0;
1399 if (strncmp(p,"file:",5) == 0 ) {
1400 INT len = GetShortPathNameA( p+5, NULL, 0 );
1401 if (len) drop_len += len + 1;
1403 if (next) {
1404 *next = '\n';
1405 p = next + 1;
1406 next = strchr(p, '\n');
1407 } else {
1408 p = NULL;
1412 if( drop_len && drop_len < 65535 ) {
1413 wine_tsx11_lock();
1414 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1415 &x, &y, &u.i, &u.i, &u.u);
1416 x += virtual_screen_rect.left;
1417 y += virtual_screen_rect.top;
1418 wine_tsx11_unlock();
1420 drop_len += sizeof(DROPFILES) + 1;
1421 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1422 lpDrop = GlobalLock( hDrop );
1424 if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
1426 lpDrop->pFiles = sizeof(DROPFILES);
1427 lpDrop->pt.x = x;
1428 lpDrop->pt.y = y;
1429 lpDrop->fNC =
1430 ( x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1431 y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1432 x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1433 y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1434 lpDrop->fWide = FALSE;
1435 p_drop = (char*)(lpDrop + 1);
1438 /* create message content */
1439 if (p_drop) {
1440 p = (char*) p_data;
1441 next = strchr(p, '\n');
1442 while (p) {
1443 if (next) *next=0;
1444 if (strncmp(p,"file:",5) == 0 ) {
1445 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1446 if (len) {
1447 TRACE("drop file %s as %s\n", p+5, p_drop);
1448 p_drop += len+1;
1449 } else {
1450 WARN("can't convert file %s to dos name\n", p+5);
1452 } else {
1453 WARN("unknown mime type %s\n", p);
1455 if (next) {
1456 *next = '\n';
1457 p = next + 1;
1458 next = strchr(p, '\n');
1459 } else {
1460 p = NULL;
1462 *p_drop = '\0';
1465 GlobalUnlock(hDrop);
1466 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1469 wine_tsx11_lock();
1470 if( p_data ) XFree(p_data);
1471 wine_tsx11_unlock();
1476 /**********************************************************************
1477 * handle_xembed_protocol
1479 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1481 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1483 if (!data) return;
1485 switch (event->data.l[1])
1487 case XEMBED_EMBEDDED_NOTIFY:
1488 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1489 data->embedder = event->data.l[3];
1490 break;
1491 default:
1492 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1493 hwnd, event->window, event->data.l[1], event->data.l[2] );
1494 break;
1499 /**********************************************************************
1500 * handle_dnd_protocol
1502 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1504 Window root, child;
1505 int root_x, root_y, child_x, child_y;
1506 unsigned int u;
1508 /* query window (drag&drop event contains only drag window) */
1509 wine_tsx11_lock();
1510 XQueryPointer( event->display, root_window, &root, &child,
1511 &root_x, &root_y, &child_x, &child_y, &u);
1512 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1513 wine_tsx11_unlock();
1514 if (!hwnd) return;
1515 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1516 EVENT_DropFromOffiX(hwnd, event);
1517 else if (event->data.l[0] == DndURL)
1518 EVENT_DropURLs(hwnd, event);
1522 struct client_message_handler
1524 int atom; /* protocol atom */
1525 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1528 static const struct client_message_handler client_messages[] =
1530 { XATOM_MANAGER, handle_manager_message },
1531 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1532 { XATOM__XEMBED, handle_xembed_protocol },
1533 { XATOM_DndProtocol, handle_dnd_protocol },
1534 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1535 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1536 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1537 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1541 /**********************************************************************
1542 * X11DRV_ClientMessage
1544 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1546 XClientMessageEvent *event = &xev->xclient;
1547 unsigned int i;
1549 if (!hwnd) return;
1551 if (event->format != 32)
1553 WARN( "Don't know how to handle format %d\n", event->format );
1554 return;
1557 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1559 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1561 client_messages[i].handler( hwnd, event );
1562 return;
1565 TRACE( "no handler found for %ld\n", event->message_type );