wininet: Support the Cache-Control max-age directive for setting url cache entry...
[wine/testsucceed.git] / dlls / winex11.drv / event.c
blob6e4225c7d3e189e33f3b365c866951cb63cd4c24
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_ReparentNotify( HWND hwnd, XEvent *event );
95 static void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
96 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
97 static void X11DRV_ClientMessage( HWND hwnd, XEvent *event );
98 static void X11DRV_GravityNotify( HWND hwnd, XEvent *event );
100 struct event_handler
102 int type; /* event type */
103 x11drv_event_handler handler; /* corresponding handler function */
106 #define MAX_EVENT_HANDLERS 64
108 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
110 /* list must be sorted by event type */
111 { KeyPress, X11DRV_KeyEvent },
112 { KeyRelease, X11DRV_KeyEvent },
113 { ButtonPress, X11DRV_ButtonPress },
114 { ButtonRelease, X11DRV_ButtonRelease },
115 { MotionNotify, X11DRV_MotionNotify },
116 { EnterNotify, X11DRV_EnterNotify },
117 /* LeaveNotify */
118 { FocusIn, X11DRV_FocusIn },
119 { FocusOut, X11DRV_FocusOut },
120 { KeymapNotify, X11DRV_KeymapNotify },
121 { Expose, X11DRV_Expose },
122 /* GraphicsExpose */
123 /* NoExpose */
124 /* VisibilityNotify */
125 /* CreateNotify */
126 { DestroyNotify, X11DRV_DestroyNotify },
127 /* UnmapNotify */
128 { MapNotify, X11DRV_MapNotify },
129 /* MapRequest */
130 { ReparentNotify, X11DRV_ReparentNotify },
131 { ConfigureNotify, X11DRV_ConfigureNotify },
132 /* ConfigureRequest */
133 { GravityNotify, X11DRV_GravityNotify },
134 /* ResizeRequest */
135 /* CirculateNotify */
136 /* CirculateRequest */
137 { PropertyNotify, X11DRV_PropertyNotify },
138 { SelectionClear, X11DRV_SelectionClear },
139 { SelectionRequest, X11DRV_SelectionRequest },
140 /* SelectionNotify */
141 /* ColormapNotify */
142 { ClientMessage, X11DRV_ClientMessage },
143 { MappingNotify, X11DRV_MappingNotify },
146 static int nb_event_handlers = 20; /* change this if you add handlers above */
149 /* return the name of an X event */
150 static const char *dbgstr_event( int type )
152 static const char * const event_names[] =
154 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
155 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
156 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
157 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
158 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
159 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
160 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
161 "ClientMessage", "MappingNotify"
164 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
165 return wine_dbg_sprintf( "Extension event %d", type );
169 /***********************************************************************
170 * find_handler
172 * Find the handler for a given event type. Caller must hold the x11 lock.
174 static inline x11drv_event_handler find_handler( int type )
176 int min = 0, max = nb_event_handlers - 1;
178 while (min <= max)
180 int pos = (min + max) / 2;
181 if (handlers[pos].type == type) return handlers[pos].handler;
182 if (handlers[pos].type > type) max = pos - 1;
183 else min = pos + 1;
185 return NULL;
189 /***********************************************************************
190 * X11DRV_register_event_handler
192 * Register a handler for a given event type.
193 * If already registered, overwrite the previous handler.
195 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
197 int min, max;
199 wine_tsx11_lock();
200 min = 0;
201 max = nb_event_handlers - 1;
202 while (min <= max)
204 int pos = (min + max) / 2;
205 if (handlers[pos].type == type)
207 handlers[pos].handler = handler;
208 goto done;
210 if (handlers[pos].type > type) max = pos - 1;
211 else min = pos + 1;
213 /* insert it between max and min */
214 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
215 handlers[min].type = type;
216 handlers[min].handler = handler;
217 nb_event_handlers++;
218 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
219 done:
220 wine_tsx11_unlock();
221 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
225 /***********************************************************************
226 * filter_event
228 static Bool filter_event( Display *display, XEvent *event, char *arg )
230 ULONG_PTR mask = (ULONG_PTR)arg;
232 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
234 switch(event->type)
236 case KeyPress:
237 case KeyRelease:
238 case KeymapNotify:
239 case MappingNotify:
240 return (mask & QS_KEY) != 0;
241 case ButtonPress:
242 case ButtonRelease:
243 return (mask & QS_MOUSEBUTTON) != 0;
244 case MotionNotify:
245 case EnterNotify:
246 case LeaveNotify:
247 return (mask & QS_MOUSEMOVE) != 0;
248 case Expose:
249 return (mask & QS_PAINT) != 0;
250 case FocusIn:
251 case FocusOut:
252 case MapNotify:
253 case UnmapNotify:
254 case ConfigureNotify:
255 case PropertyNotify:
256 case ClientMessage:
257 return (mask & QS_POSTMESSAGE) != 0;
258 default:
259 return (mask & QS_SENDMESSAGE) != 0;
264 enum event_merge_action
266 MERGE_DISCARD, /* discard the old event */
267 MERGE_HANDLE, /* handle the old event */
268 MERGE_KEEP /* keep the old event for future merging */
271 /***********************************************************************
272 * merge_events
274 * Try to merge 2 consecutive events.
276 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
278 switch (prev->type)
280 case ConfigureNotify:
281 switch (next->type)
283 case ConfigureNotify:
284 if (prev->xany.window == next->xany.window)
286 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
287 return MERGE_DISCARD;
289 break;
290 case Expose:
291 case PropertyNotify:
292 return MERGE_KEEP;
294 break;
295 case MotionNotify:
296 if (prev->xany.window == next->xany.window && next->type == MotionNotify)
298 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
299 return MERGE_DISCARD;
301 break;
303 return MERGE_HANDLE;
307 /***********************************************************************
308 * call_event_handler
310 static inline void call_event_handler( Display *display, XEvent *event )
312 HWND hwnd;
313 x11drv_event_handler handler;
314 XEvent *prev;
315 struct x11drv_thread_data *thread_data;
317 if (!(handler = find_handler( event->type )))
319 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
320 return; /* no handler, ignore it */
323 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
324 hwnd = 0; /* not for a registered window */
325 if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
327 TRACE( "%lu %s for hwnd/window %p/%lx\n",
328 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
329 wine_tsx11_unlock();
330 thread_data = x11drv_thread_data();
331 prev = thread_data->current_event;
332 thread_data->current_event = event;
333 handler( hwnd, event );
334 thread_data->current_event = prev;
335 wine_tsx11_lock();
339 /***********************************************************************
340 * process_events
342 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
344 XEvent event, prev_event;
345 int count = 0;
346 enum event_merge_action action = MERGE_DISCARD;
348 prev_event.type = 0;
349 wine_tsx11_lock();
350 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
352 count++;
353 if (XFilterEvent( &event, None ))
356 * SCIM on linux filters key events strangely. It does not filter the
357 * KeyPress events for these keys however it does filter the
358 * KeyRelease events. This causes wine to become very confused as
359 * to the keyboard state.
361 * We need to let those KeyRelease events be processed so that the
362 * keyboard state is correct.
364 if (event.type == KeyRelease)
366 KeySym keysym = 0;
367 XKeyEvent *keyevent = &event.xkey;
369 XLookupString(keyevent, NULL, 0, &keysym, NULL);
370 if (!(keysym == XK_Shift_L ||
371 keysym == XK_Shift_R ||
372 keysym == XK_Control_L ||
373 keysym == XK_Control_R ||
374 keysym == XK_Alt_R ||
375 keysym == XK_Alt_L ||
376 keysym == XK_Meta_R ||
377 keysym == XK_Meta_L))
378 continue; /* not a key we care about, ignore it */
380 else
381 continue; /* filtered, ignore it */
383 if (prev_event.type) action = merge_events( &prev_event, &event );
384 switch( action )
386 case MERGE_DISCARD: /* discard prev, keep new */
387 prev_event = event;
388 break;
389 case MERGE_HANDLE: /* handle prev, keep new */
390 call_event_handler( display, &prev_event );
391 prev_event = event;
392 break;
393 case MERGE_KEEP: /* handle new, keep prev for future merging */
394 call_event_handler( display, &event );
395 break;
398 if (prev_event.type) call_event_handler( display, &prev_event );
399 XFlush( gdi_display );
400 wine_tsx11_unlock();
401 if (count) TRACE( "processed %d events\n", count );
402 return count;
406 /***********************************************************************
407 * MsgWaitForMultipleObjectsEx (X11DRV.@)
409 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
410 DWORD timeout, DWORD mask, DWORD flags )
412 DWORD ret;
413 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
415 if (!data)
417 if (!count && !timeout) return WAIT_TIMEOUT;
418 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
419 timeout, flags & MWMO_ALERTABLE );
422 if (data->current_event) mask = 0; /* don't process nested events */
424 if (process_events( data->display, filter_event, mask )) ret = count - 1;
425 else if (count || timeout)
427 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
428 timeout, flags & MWMO_ALERTABLE );
429 if (ret == count - 1) process_events( data->display, filter_event, mask );
431 else ret = WAIT_TIMEOUT;
433 return ret;
436 /***********************************************************************
437 * EVENT_x11_time_to_win32_time
439 * Make our timer and the X timer line up as best we can
440 * Pass 0 to retrieve the current adjustment value (times -1)
442 DWORD EVENT_x11_time_to_win32_time(Time time)
444 static DWORD adjust = 0;
445 DWORD now = GetTickCount();
446 DWORD ret;
448 if (! adjust && time != 0)
450 ret = now;
451 adjust = time - now;
453 else
455 /* If we got an event in the 'future', then our clock is clearly wrong.
456 If we got it more than 10000 ms in the future, then it's most likely
457 that the clock has wrapped. */
459 ret = time - adjust;
460 if (ret > now && ((ret - now) < 10000) && time != 0)
462 adjust += ret - now;
463 ret -= ret - now;
467 return ret;
471 /*******************************************************************
472 * can_activate_window
474 * Check if we can activate the specified window.
476 static inline BOOL can_activate_window( HWND hwnd )
478 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
479 if (!(style & WS_VISIBLE)) return FALSE;
480 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
481 if (style & WS_MINIMIZE) return FALSE;
482 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
483 if (hwnd == GetDesktopWindow()) return FALSE;
484 return !(style & WS_DISABLED);
488 /**********************************************************************
489 * set_focus
491 static void set_focus( Display *display, HWND hwnd, Time time )
493 HWND focus;
494 Window win;
495 GUITHREADINFO threadinfo;
497 TRACE( "setting foreground window to %p\n", hwnd );
498 SetForegroundWindow( hwnd );
500 threadinfo.cbSize = sizeof(threadinfo);
501 GetGUIThreadInfo(0, &threadinfo);
502 focus = threadinfo.hwndFocus;
503 if (!focus) focus = threadinfo.hwndActive;
504 if (focus) focus = GetAncestor( focus, GA_ROOT );
505 win = X11DRV_get_whole_window(focus);
507 if (win)
509 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
510 wine_tsx11_lock();
511 XSetInputFocus( display, win, RevertToParent, time );
512 wine_tsx11_unlock();
517 /**********************************************************************
518 * handle_manager_message
520 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
522 if (hwnd != GetDesktopWindow()) return;
523 if (systray_atom && event->data.l[1] == systray_atom)
524 change_systray_owner( event->display, event->data.l[2] );
528 /**********************************************************************
529 * handle_wm_protocols
531 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
533 Atom protocol = (Atom)event->data.l[0];
534 Time event_time = (Time)event->data.l[1];
536 if (!protocol) return;
538 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
540 update_user_time( event_time );
542 if (hwnd == GetDesktopWindow())
544 /* The desktop window does not have a close button that we can
545 * pretend to click. Therefore, we simply send it a close command. */
546 SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
547 return;
550 /* Ignore the delete window request if the window has been disabled
551 * and we are in managed mode. This is to disallow applications from
552 * being closed by the window manager while in a modal state.
554 if (IsWindowEnabled(hwnd))
556 HMENU hSysMenu;
558 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
559 hSysMenu = GetSystemMenu(hwnd, FALSE);
560 if (hSysMenu)
562 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
563 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
564 return;
566 if (GetActiveWindow() != hwnd)
568 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
569 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
570 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
571 switch(ma)
573 case MA_NOACTIVATEANDEAT:
574 case MA_ACTIVATEANDEAT:
575 return;
576 case MA_NOACTIVATE:
577 break;
578 case MA_ACTIVATE:
579 case 0:
580 SetActiveWindow(hwnd);
581 break;
582 default:
583 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
584 break;
588 PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
591 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
593 HWND last_focus = x11drv_thread_data()->last_focus;
595 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
596 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
597 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
599 if (can_activate_window(hwnd))
601 /* simulate a mouse click on the caption to find out
602 * whether the window wants to be activated */
603 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
604 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
605 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
606 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
608 set_focus( event->display, hwnd, event_time );
609 return;
612 else if (hwnd == GetDesktopWindow())
614 hwnd = GetForegroundWindow();
615 if (!hwnd) hwnd = last_focus;
616 if (!hwnd) hwnd = GetDesktopWindow();
617 set_focus( event->display, hwnd, event_time );
618 return;
620 /* try to find some other window to give the focus to */
621 hwnd = GetFocus();
622 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
623 if (!hwnd) hwnd = GetActiveWindow();
624 if (!hwnd) hwnd = last_focus;
625 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
627 else if (protocol == x11drv_atom(_NET_WM_PING))
629 XClientMessageEvent xev;
630 xev = *event;
632 TRACE("NET_WM Ping\n");
633 wine_tsx11_lock();
634 xev.window = DefaultRootWindow(xev.display);
635 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
636 wine_tsx11_unlock();
637 /* this line is semi-stolen from gtk2 */
638 TRACE("NET_WM Pong\n");
643 static const char * const focus_details[] =
645 "NotifyAncestor",
646 "NotifyVirtual",
647 "NotifyInferior",
648 "NotifyNonlinear",
649 "NotifyNonlinearVirtual",
650 "NotifyPointer",
651 "NotifyPointerRoot",
652 "NotifyDetailNone"
655 /**********************************************************************
656 * X11DRV_FocusIn
658 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
660 XFocusChangeEvent *event = &xev->xfocus;
661 XIC xic;
663 if (!hwnd) return;
665 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
667 if (event->detail == NotifyPointer) return;
669 if ((xic = X11DRV_get_ic( hwnd )))
671 wine_tsx11_lock();
672 XSetICFocus( xic );
673 wine_tsx11_unlock();
675 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
677 if (!can_activate_window(hwnd))
679 HWND hwnd = GetFocus();
680 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
681 if (!hwnd) hwnd = GetActiveWindow();
682 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
683 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
685 else SetForegroundWindow( hwnd );
689 /**********************************************************************
690 * X11DRV_FocusOut
692 * Note: only top-level windows get FocusOut events.
694 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
696 XFocusChangeEvent *event = &xev->xfocus;
697 HWND hwnd_tmp;
698 Window focus_win;
699 int revert;
700 XIC xic;
702 if (!hwnd) return;
704 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
706 if (event->detail == NotifyPointer) return;
707 if (ximInComposeMode) return;
709 x11drv_thread_data()->last_focus = hwnd;
710 if ((xic = X11DRV_get_ic( hwnd )))
712 wine_tsx11_lock();
713 XUnsetICFocus( xic );
714 wine_tsx11_unlock();
716 if (hwnd != GetForegroundWindow()) return;
717 if (root_window != DefaultRootWindow(event->display)) return;
718 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
720 /* don't reset the foreground window, if the window which is
721 getting the focus is a Wine window */
723 wine_tsx11_lock();
724 XGetInputFocus( event->display, &focus_win, &revert );
725 if (focus_win)
727 if (XFindContext( event->display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
728 focus_win = 0;
730 wine_tsx11_unlock();
732 if (!focus_win)
734 /* Abey : 6-Oct-99. Check again if the focus out window is the
735 Foreground window, because in most cases the messages sent
736 above must have already changed the foreground window, in which
737 case we don't have to change the foreground window to 0 */
738 if (hwnd == GetForegroundWindow())
740 TRACE( "lost focus, setting fg to desktop\n" );
741 SetForegroundWindow( GetDesktopWindow() );
747 /***********************************************************************
748 * X11DRV_Expose
750 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
752 XExposeEvent *event = &xev->xexpose;
753 RECT rect;
754 struct x11drv_win_data *data;
755 int flags = RDW_INVALIDATE | RDW_ERASE;
757 TRACE( "win %p (%lx) %d,%d %dx%d\n",
758 hwnd, event->window, event->x, event->y, event->width, event->height );
760 if (!(data = X11DRV_get_win_data( hwnd ))) return;
762 rect.left = event->x;
763 rect.top = event->y;
764 rect.right = event->x + event->width;
765 rect.bottom = event->y + event->height;
766 if (event->window == data->whole_window)
768 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
769 data->whole_rect.top - data->client_rect.top );
770 flags |= RDW_FRAME;
773 if (event->window != root_window)
775 if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
776 mirror_rect( &data->client_rect, &rect );
778 SERVER_START_REQ( update_window_zorder )
780 req->window = wine_server_user_handle( hwnd );
781 req->rect.left = rect.left;
782 req->rect.top = rect.top;
783 req->rect.right = rect.right;
784 req->rect.bottom = rect.bottom;
785 wine_server_call( req );
787 SERVER_END_REQ;
789 flags |= RDW_ALLCHILDREN;
791 else OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
793 RedrawWindow( hwnd, &rect, 0, flags );
797 /**********************************************************************
798 * X11DRV_MapNotify
800 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
802 struct x11drv_win_data *data;
804 if (!(data = X11DRV_get_win_data( hwnd ))) return;
805 if (!data->mapped || data->embedded) return;
807 if (!data->managed)
809 HWND hwndFocus = GetFocus();
810 if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus); /* FIXME */
815 /***********************************************************************
816 * is_net_wm_state_maximized
818 static BOOL is_net_wm_state_maximized( Display *display, struct x11drv_win_data *data )
820 Atom type, *state;
821 int format, ret = 0;
822 unsigned long i, count, remaining;
824 if (!data->whole_window) return FALSE;
826 wine_tsx11_lock();
827 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), 0,
828 65536/sizeof(CARD32), False, XA_ATOM, &type, &format, &count,
829 &remaining, (unsigned char **)&state ))
831 if (type == XA_ATOM && format == 32)
833 for (i = 0; i < count; i++)
835 if (state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT) ||
836 state[i] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ))
837 ret++;
840 XFree( state );
842 wine_tsx11_unlock();
843 return (ret == 2);
847 /***********************************************************************
848 * X11DRV_ReparentNotify
850 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
852 XReparentEvent *event = &xev->xreparent;
853 struct x11drv_win_data *data;
854 HWND parent, old_parent;
855 DWORD style;
857 if (!(data = X11DRV_get_win_data( hwnd ))) return;
858 if (!data->embedded) return;
860 if (data->whole_window)
862 if (event->parent == root_window)
864 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
865 data->embedder = 0;
866 SendMessageW( hwnd, WM_CLOSE, 0, 0 );
867 return;
869 data->embedder = event->parent;
872 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
874 style = GetWindowLongW( hwnd, GWL_STYLE );
875 if (event->parent == root_window)
877 parent = GetDesktopWindow();
878 style = (style & ~WS_CHILD) | WS_POPUP;
880 else
882 if (!(parent = create_foreign_window( event->display, event->parent ))) return;
883 style = (style & ~WS_POPUP) | WS_CHILD;
886 ShowWindow( hwnd, SW_HIDE );
887 old_parent = SetParent( hwnd, parent );
888 SetWindowLongW( hwnd, GWL_STYLE, style );
889 SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
890 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
891 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
893 /* make old parent destroy itself if it no longer has children */
894 if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
898 /***********************************************************************
899 * X11DRV_ConfigureNotify
901 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
903 XConfigureEvent *event = &xev->xconfigure;
904 struct x11drv_win_data *data;
905 RECT rect;
906 UINT flags;
907 HWND parent;
908 BOOL root_coords;
909 int cx, cy, x = event->x, y = event->y;
911 if (!hwnd) return;
912 if (!(data = X11DRV_get_win_data( hwnd ))) return;
913 if (!data->mapped || data->iconic) return;
914 if (data->whole_window && !data->managed) return;
915 /* ignore synthetic events on foreign windows */
916 if (event->send_event && !data->whole_window) return;
917 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
919 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
920 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
921 event->serial, data->configure_serial );
922 return;
925 /* Get geometry */
927 parent = GetAncestor( hwnd, GA_PARENT );
928 root_coords = event->send_event; /* synthetic events are always in root coords */
930 if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
932 Window child;
933 wine_tsx11_lock();
934 XTranslateCoordinates( event->display, event->window, root_window,
935 0, 0, &x, &y, &child );
936 wine_tsx11_unlock();
937 root_coords = TRUE;
939 rect.left = x;
940 rect.top = y;
941 rect.right = x + event->width;
942 rect.bottom = y + event->height;
943 if (root_coords) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
944 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
945 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
946 event->x, event->y, event->width, event->height );
948 if (is_net_wm_state_maximized( event->display, data ))
950 if (!IsZoomed( data->hwnd ))
952 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
953 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
954 return;
957 else
959 if (IsZoomed( data->hwnd ))
961 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
962 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
963 return;
967 X11DRV_X_to_window_rect( data, &rect );
968 if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
970 /* Compare what has changed */
972 x = rect.left;
973 y = rect.top;
974 cx = rect.right - rect.left;
975 cy = rect.bottom - rect.top;
976 flags = SWP_NOACTIVATE | SWP_NOZORDER;
978 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
980 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
981 else
982 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
983 hwnd, data->window_rect.left, data->window_rect.top, x, y );
985 if ((data->window_rect.right - data->window_rect.left == cx &&
986 data->window_rect.bottom - data->window_rect.top == cy) ||
987 (IsRectEmpty( &data->window_rect ) && event->width == 1 && event->height == 1))
989 if (flags & SWP_NOMOVE) return; /* if nothing changed, don't do anything */
990 flags |= SWP_NOSIZE;
992 else
993 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
994 hwnd, data->window_rect.right - data->window_rect.left,
995 data->window_rect.bottom - data->window_rect.top, cx, cy );
997 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1001 /**********************************************************************
1002 * X11DRV_GravityNotify
1004 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1006 XGravityEvent *event = &xev->xgravity;
1007 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1008 RECT rect;
1010 if (!data || data->whole_window) return; /* only handle this for foreign windows */
1012 rect.left = event->x;
1013 rect.top = event->y;
1014 rect.right = rect.left + data->whole_rect.right - data->whole_rect.left;
1015 rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1017 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1018 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1019 event->x, event->y );
1021 X11DRV_X_to_window_rect( data, &rect );
1023 if (data->window_rect.left != rect.left || data ->window_rect.top != rect.top)
1024 SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1025 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1029 /***********************************************************************
1030 * get_window_wm_state
1032 static int get_window_wm_state( Display *display, struct x11drv_win_data *data )
1034 struct
1036 CARD32 state;
1037 XID icon;
1038 } *state;
1039 Atom type;
1040 int format, ret = -1;
1041 unsigned long count, remaining;
1043 wine_tsx11_lock();
1044 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
1045 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1046 &type, &format, &count, &remaining, (unsigned char **)&state ))
1048 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1049 ret = state->state;
1050 XFree( state );
1052 wine_tsx11_unlock();
1053 return ret;
1057 /***********************************************************************
1058 * handle_wm_state_notify
1060 * Handle a PropertyNotify for WM_STATE.
1062 static void handle_wm_state_notify( struct x11drv_win_data *data, XPropertyEvent *event,
1063 BOOL update_window )
1065 DWORD style;
1067 switch(event->state)
1069 case PropertyDelete:
1070 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1071 data->wm_state = WithdrawnState;
1072 break;
1073 case PropertyNewValue:
1075 int old_state = data->wm_state;
1076 int new_state = get_window_wm_state( event->display, data );
1077 if (new_state != -1 && new_state != data->wm_state)
1079 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1080 data->hwnd, data->whole_window, new_state, old_state );
1081 data->wm_state = new_state;
1082 /* ignore the initial state transition out of withdrawn state */
1083 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1084 if (!old_state) return;
1087 break;
1090 if (!update_window || !data->managed || !data->mapped) return;
1092 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1094 if (data->iconic && data->wm_state == NormalState) /* restore window */
1096 data->iconic = FALSE;
1097 if (is_net_wm_state_maximized( event->display, data ))
1099 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1101 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1102 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1104 else TRACE( "not restoring to max win %p/%lx style %08x\n",
1105 data->hwnd, data->whole_window, style );
1107 else if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1109 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1110 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1112 else TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1114 else if (!data->iconic && data->wm_state == IconicState)
1116 data->iconic = TRUE;
1117 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1119 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1120 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1122 else TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1127 /***********************************************************************
1128 * X11DRV_PropertyNotify
1130 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1132 XPropertyEvent *event = &xev->xproperty;
1133 struct x11drv_win_data *data;
1135 if (!hwnd) return;
1136 if (!(data = X11DRV_get_win_data( hwnd ))) return;
1138 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( data, event, TRUE );
1142 /* event filter to wait for a WM_STATE change notification on a window */
1143 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1145 if (event->xany.window != (Window)arg) return 0;
1146 return (event->type == DestroyNotify ||
1147 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1150 /***********************************************************************
1151 * wait_for_withdrawn_state
1153 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data, BOOL set )
1155 DWORD end = GetTickCount() + 2000;
1157 if (!data->managed) return;
1159 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
1160 data->hwnd, data->whole_window, set ? "" : "not " );
1162 while (data->whole_window && ((data->wm_state == WithdrawnState) == !set))
1164 XEvent event;
1165 int count = 0;
1167 wine_tsx11_lock();
1168 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)data->whole_window ))
1170 count++;
1171 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1172 if (event.type == DestroyNotify) call_event_handler( display, &event );
1173 else
1175 wine_tsx11_unlock();
1176 handle_wm_state_notify( data, &event.xproperty, FALSE );
1177 wine_tsx11_lock();
1180 wine_tsx11_unlock();
1182 if (!count)
1184 struct pollfd pfd;
1185 int timeout = end - GetTickCount();
1187 pfd.fd = ConnectionNumber(display);
1188 pfd.events = POLLIN;
1189 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1191 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
1192 break;
1196 TRACE( "window %p/%lx state now %d\n", data->hwnd, data->whole_window, data->wm_state );
1200 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1202 RECT tempRect;
1204 if (!IsWindowEnabled(hQueryWnd)) return 0;
1206 GetWindowRect(hQueryWnd, &tempRect);
1208 if(!PtInRect(&tempRect, *lpPt)) return 0;
1210 if (!IsIconic( hQueryWnd ))
1212 POINT pt = *lpPt;
1213 ScreenToClient( hQueryWnd, &pt );
1214 GetClientRect( hQueryWnd, &tempRect );
1216 if (PtInRect( &tempRect, pt))
1218 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1219 if (ret && ret != hQueryWnd)
1221 ret = find_drop_window( ret, lpPt );
1222 if (ret) return ret;
1227 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1229 ScreenToClient(hQueryWnd, lpPt);
1231 return hQueryWnd;
1234 /**********************************************************************
1235 * EVENT_DropFromOffix
1237 * don't know if it still works (last Changelog is from 96/11/04)
1239 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1241 struct x11drv_win_data *data;
1242 unsigned long data_length;
1243 unsigned long aux_long;
1244 unsigned char* p_data = NULL;
1245 Atom atom_aux;
1246 int x, y, dummy;
1247 BOOL bAccept;
1248 Window win, w_aux_root, w_aux_child;
1250 win = X11DRV_get_whole_window(hWnd);
1251 wine_tsx11_lock();
1252 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1253 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1254 x += virtual_screen_rect.left;
1255 y += virtual_screen_rect.top;
1256 wine_tsx11_unlock();
1258 if (!(data = X11DRV_get_win_data( hWnd ))) return;
1260 /* find out drop point and drop window */
1261 if( x < 0 || y < 0 ||
1262 x > (data->whole_rect.right - data->whole_rect.left) ||
1263 y > (data->whole_rect.bottom - data->whole_rect.top) )
1265 bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
1266 x = 0;
1267 y = 0;
1269 else
1271 POINT pt = { x, y };
1272 HWND hwndDrop = find_drop_window( hWnd, &pt );
1273 if (hwndDrop)
1275 x = pt.x;
1276 y = pt.y;
1277 bAccept = TRUE;
1279 else
1281 bAccept = FALSE;
1285 if (!bAccept) return;
1287 wine_tsx11_lock();
1288 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1289 x11drv_atom(DndSelection), 0, 65535, FALSE,
1290 AnyPropertyType, &atom_aux, &dummy,
1291 &data_length, &aux_long, &p_data);
1292 wine_tsx11_unlock();
1294 if( !aux_long && p_data) /* don't bother if > 64K */
1296 char *p = (char *)p_data;
1297 char *p_drop;
1299 aux_long = 0;
1300 while( *p ) /* calculate buffer size */
1302 INT len = GetShortPathNameA( p, NULL, 0 );
1303 if (len) aux_long += len + 1;
1304 p += strlen(p) + 1;
1306 if( aux_long && aux_long < 65535 )
1308 HDROP hDrop;
1309 DROPFILES *lpDrop;
1311 aux_long += sizeof(DROPFILES) + 1;
1312 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1313 lpDrop = GlobalLock( hDrop );
1315 if( lpDrop )
1317 lpDrop->pFiles = sizeof(DROPFILES);
1318 lpDrop->pt.x = x;
1319 lpDrop->pt.y = y;
1320 lpDrop->fNC = FALSE;
1321 lpDrop->fWide = FALSE;
1322 p_drop = (char *)(lpDrop + 1);
1323 p = (char *)p_data;
1324 while(*p)
1326 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1327 p_drop += strlen( p_drop ) + 1;
1328 p += strlen(p) + 1;
1330 *p_drop = '\0';
1331 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1335 wine_tsx11_lock();
1336 if( p_data ) XFree(p_data);
1337 wine_tsx11_unlock();
1340 /**********************************************************************
1341 * EVENT_DropURLs
1343 * drop items are separated by \n
1344 * each item is prefixed by its mime type
1346 * event->data.l[3], event->data.l[4] contains drop x,y position
1348 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1350 struct x11drv_win_data *win_data;
1351 unsigned long data_length;
1352 unsigned long aux_long, drop_len = 0;
1353 unsigned char *p_data = NULL; /* property data */
1354 char *p_drop = NULL;
1355 char *p, *next;
1356 int x, y;
1357 DROPFILES *lpDrop;
1358 HDROP hDrop;
1359 union {
1360 Atom atom_aux;
1361 int i;
1362 Window w_aux;
1363 unsigned int u;
1364 } u; /* unused */
1366 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1368 wine_tsx11_lock();
1369 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1370 x11drv_atom(DndSelection), 0, 65535, FALSE,
1371 AnyPropertyType, &u.atom_aux, &u.i,
1372 &data_length, &aux_long, &p_data);
1373 wine_tsx11_unlock();
1374 if (aux_long)
1375 WARN("property too large, truncated!\n");
1376 TRACE("urls=%s\n", p_data);
1378 if( !aux_long && p_data) { /* don't bother if > 64K */
1379 /* calculate length */
1380 p = (char*) p_data;
1381 next = strchr(p, '\n');
1382 while (p) {
1383 if (next) *next=0;
1384 if (strncmp(p,"file:",5) == 0 ) {
1385 INT len = GetShortPathNameA( p+5, NULL, 0 );
1386 if (len) drop_len += len + 1;
1388 if (next) {
1389 *next = '\n';
1390 p = next + 1;
1391 next = strchr(p, '\n');
1392 } else {
1393 p = NULL;
1397 if( drop_len && drop_len < 65535 ) {
1398 wine_tsx11_lock();
1399 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1400 &x, &y, &u.i, &u.i, &u.u);
1401 x += virtual_screen_rect.left;
1402 y += virtual_screen_rect.top;
1403 wine_tsx11_unlock();
1405 drop_len += sizeof(DROPFILES) + 1;
1406 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1407 lpDrop = GlobalLock( hDrop );
1409 if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
1411 lpDrop->pFiles = sizeof(DROPFILES);
1412 lpDrop->pt.x = x;
1413 lpDrop->pt.y = y;
1414 lpDrop->fNC =
1415 ( x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1416 y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1417 x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1418 y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1419 lpDrop->fWide = FALSE;
1420 p_drop = (char*)(lpDrop + 1);
1423 /* create message content */
1424 if (p_drop) {
1425 p = (char*) p_data;
1426 next = strchr(p, '\n');
1427 while (p) {
1428 if (next) *next=0;
1429 if (strncmp(p,"file:",5) == 0 ) {
1430 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1431 if (len) {
1432 TRACE("drop file %s as %s\n", p+5, p_drop);
1433 p_drop += len+1;
1434 } else {
1435 WARN("can't convert file %s to dos name\n", p+5);
1437 } else {
1438 WARN("unknown mime type %s\n", p);
1440 if (next) {
1441 *next = '\n';
1442 p = next + 1;
1443 next = strchr(p, '\n');
1444 } else {
1445 p = NULL;
1447 *p_drop = '\0';
1450 GlobalUnlock(hDrop);
1451 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1454 wine_tsx11_lock();
1455 if( p_data ) XFree(p_data);
1456 wine_tsx11_unlock();
1461 /**********************************************************************
1462 * handle_xembed_protocol
1464 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1466 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1468 if (!data) return;
1470 switch (event->data.l[1])
1472 case XEMBED_EMBEDDED_NOTIFY:
1473 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1474 data->embedder = event->data.l[3];
1475 break;
1476 default:
1477 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1478 hwnd, event->window, event->data.l[1], event->data.l[2] );
1479 break;
1484 /**********************************************************************
1485 * handle_dnd_protocol
1487 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1489 Window root, child;
1490 int root_x, root_y, child_x, child_y;
1491 unsigned int u;
1493 /* query window (drag&drop event contains only drag window) */
1494 wine_tsx11_lock();
1495 XQueryPointer( event->display, root_window, &root, &child,
1496 &root_x, &root_y, &child_x, &child_y, &u);
1497 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1498 wine_tsx11_unlock();
1499 if (!hwnd) return;
1500 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1501 EVENT_DropFromOffiX(hwnd, event);
1502 else if (event->data.l[0] == DndURL)
1503 EVENT_DropURLs(hwnd, event);
1507 struct client_message_handler
1509 int atom; /* protocol atom */
1510 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1513 static const struct client_message_handler client_messages[] =
1515 { XATOM_MANAGER, handle_manager_message },
1516 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1517 { XATOM__XEMBED, handle_xembed_protocol },
1518 { XATOM_DndProtocol, handle_dnd_protocol },
1519 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1520 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1521 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1522 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1526 /**********************************************************************
1527 * X11DRV_ClientMessage
1529 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1531 XClientMessageEvent *event = &xev->xclient;
1532 unsigned int i;
1534 if (!hwnd) return;
1536 if (event->format != 32)
1538 WARN( "Don't know how to handle format %d\n", event->format );
1539 return;
1542 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1544 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1546 client_messages[i].handler( hwnd, event );
1547 return;
1550 TRACE( "no handler found for %ld\n", event->message_type );