dmime: Use the generic IPersistStream for DMParamControlTrack.
[wine.git] / dlls / winex11.drv / event.c
blobee302592acf1162cdbd5e8fc28472c07b5f0c46a
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #ifdef HAVE_POLL_H
25 #include <poll.h>
26 #endif
27 #ifdef HAVE_SYS_POLL_H
28 #include <sys/poll.h>
29 #endif
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
35 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
36 #include <X11/extensions/XInput2.h>
37 #endif
39 #include <assert.h>
40 #include <stdarg.h>
41 #include <string.h>
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winuser.h"
46 #include "wingdi.h"
48 #include "x11drv.h"
50 /* avoid conflict with field names in included win32 headers */
51 #undef Status
52 #include "shlobj.h" /* DROPFILES */
53 #include "shellapi.h"
55 #include "wine/server.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(event);
60 extern BOOL ximInComposeMode;
62 #define DndNotDnd -1 /* OffiX drag&drop */
63 #define DndUnknown 0
64 #define DndRawData 1
65 #define DndFile 2
66 #define DndFiles 3
67 #define DndText 4
68 #define DndDir 5
69 #define DndLink 6
70 #define DndExe 7
72 #define DndEND 8
74 #define DndURL 128 /* KDE drag&drop */
76 #define XEMBED_EMBEDDED_NOTIFY 0
77 #define XEMBED_WINDOW_ACTIVATE 1
78 #define XEMBED_WINDOW_DEACTIVATE 2
79 #define XEMBED_REQUEST_FOCUS 3
80 #define XEMBED_FOCUS_IN 4
81 #define XEMBED_FOCUS_OUT 5
82 #define XEMBED_FOCUS_NEXT 6
83 #define XEMBED_FOCUS_PREV 7
84 #define XEMBED_MODALITY_ON 10
85 #define XEMBED_MODALITY_OFF 11
86 #define XEMBED_REGISTER_ACCELERATOR 12
87 #define XEMBED_UNREGISTER_ACCELERATOR 13
88 #define XEMBED_ACTIVATE_ACCELERATOR 14
90 Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
91 void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL;
93 /* Event handlers */
94 static void X11DRV_FocusIn( HWND hwnd, XEvent *event );
95 static void X11DRV_FocusOut( HWND hwnd, XEvent *event );
96 static void X11DRV_Expose( HWND hwnd, XEvent *event );
97 static void X11DRV_MapNotify( HWND hwnd, XEvent *event );
98 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
99 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
100 static void X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
101 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
102 static void X11DRV_ClientMessage( HWND hwnd, XEvent *event );
103 static void X11DRV_GravityNotify( HWND hwnd, XEvent *event );
105 #define MAX_EVENT_HANDLERS 128
107 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
109 NULL, /* 0 reserved */
110 NULL, /* 1 reserved */
111 X11DRV_KeyEvent, /* 2 KeyPress */
112 X11DRV_KeyEvent, /* 3 KeyRelease */
113 X11DRV_ButtonPress, /* 4 ButtonPress */
114 X11DRV_ButtonRelease, /* 5 ButtonRelease */
115 X11DRV_MotionNotify, /* 6 MotionNotify */
116 X11DRV_EnterNotify, /* 7 EnterNotify */
117 NULL, /* 8 LeaveNotify */
118 X11DRV_FocusIn, /* 9 FocusIn */
119 X11DRV_FocusOut, /* 10 FocusOut */
120 X11DRV_KeymapNotify, /* 11 KeymapNotify */
121 X11DRV_Expose, /* 12 Expose */
122 NULL, /* 13 GraphicsExpose */
123 NULL, /* 14 NoExpose */
124 NULL, /* 15 VisibilityNotify */
125 NULL, /* 16 CreateNotify */
126 X11DRV_DestroyNotify, /* 17 DestroyNotify */
127 X11DRV_UnmapNotify, /* 18 UnmapNotify */
128 X11DRV_MapNotify, /* 19 MapNotify */
129 NULL, /* 20 MapRequest */
130 X11DRV_ReparentNotify, /* 21 ReparentNotify */
131 X11DRV_ConfigureNotify, /* 22 ConfigureNotify */
132 NULL, /* 23 ConfigureRequest */
133 X11DRV_GravityNotify, /* 24 GravityNotify */
134 NULL, /* 25 ResizeRequest */
135 NULL, /* 26 CirculateNotify */
136 NULL, /* 27 CirculateRequest */
137 X11DRV_PropertyNotify, /* 28 PropertyNotify */
138 X11DRV_SelectionClear, /* 29 SelectionClear */
139 X11DRV_SelectionRequest, /* 30 SelectionRequest */
140 NULL, /* 31 SelectionNotify */
141 NULL, /* 32 ColormapNotify */
142 X11DRV_ClientMessage, /* 33 ClientMessage */
143 X11DRV_MappingNotify, /* 34 MappingNotify */
144 X11DRV_GenericEvent /* 35 GenericEvent */
147 static const char * event_names[MAX_EVENT_HANDLERS] =
149 NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
150 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
151 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
152 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
153 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
154 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
155 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
158 int xinput2_opcode = 0;
160 /* return the name of an X event */
161 static const char *dbgstr_event( int type )
163 if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
164 return wine_dbg_sprintf( "Unknown event %d", type );
167 static inline void get_event_data( XEvent *event )
169 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
170 if (event->xany.type != GenericEvent) return;
171 if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
172 #endif
175 static inline void free_event_data( XEvent *event )
177 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
178 if (event->xany.type != GenericEvent) return;
179 if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
180 #endif
183 /***********************************************************************
184 * xembed_request_focus
186 static void xembed_request_focus( Display *display, Window window, DWORD timestamp )
188 XEvent xev;
190 xev.xclient.type = ClientMessage;
191 xev.xclient.window = window;
192 xev.xclient.message_type = x11drv_atom(_XEMBED);
193 xev.xclient.serial = 0;
194 xev.xclient.display = display;
195 xev.xclient.send_event = True;
196 xev.xclient.format = 32;
198 xev.xclient.data.l[0] = timestamp;
199 xev.xclient.data.l[1] = XEMBED_REQUEST_FOCUS;
200 xev.xclient.data.l[2] = 0;
201 xev.xclient.data.l[3] = 0;
202 xev.xclient.data.l[4] = 0;
204 XSendEvent(display, window, False, NoEventMask, &xev);
205 XFlush( display );
208 /***********************************************************************
209 * X11DRV_register_event_handler
211 * Register a handler for a given event type.
212 * If already registered, overwrite the previous handler.
214 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
216 assert( type < MAX_EVENT_HANDLERS );
217 assert( !handlers[type] || handlers[type] == handler );
218 handlers[type] = handler;
219 event_names[type] = name;
220 TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
224 /***********************************************************************
225 * filter_event
227 static Bool filter_event( Display *display, XEvent *event, char *arg )
229 ULONG_PTR mask = (ULONG_PTR)arg;
231 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
233 switch(event->type)
235 case KeyPress:
236 case KeyRelease:
237 case KeymapNotify:
238 case MappingNotify:
239 return (mask & (QS_KEY|QS_HOTKEY)) != 0;
240 case ButtonPress:
241 case ButtonRelease:
242 return (mask & QS_MOUSEBUTTON) != 0;
243 case MotionNotify:
244 case EnterNotify:
245 case LeaveNotify:
246 return (mask & QS_MOUSEMOVE) != 0;
247 case Expose:
248 return (mask & QS_PAINT) != 0;
249 case FocusIn:
250 case FocusOut:
251 case MapNotify:
252 case UnmapNotify:
253 case ConfigureNotify:
254 case PropertyNotify:
255 case ClientMessage:
256 return (mask & QS_POSTMESSAGE) != 0;
257 default:
258 return (mask & QS_SENDMESSAGE) != 0;
263 enum event_merge_action
265 MERGE_DISCARD, /* discard the old event */
266 MERGE_HANDLE, /* handle the old event */
267 MERGE_KEEP, /* keep the old event for future merging */
268 MERGE_IGNORE /* ignore the new event, keep the old one */
271 /***********************************************************************
272 * merge_raw_motion_events
274 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
275 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
277 int i, j, k;
278 unsigned char mask;
280 if (!prev->valuators.mask_len) return MERGE_HANDLE;
281 if (!next->valuators.mask_len) return MERGE_HANDLE;
283 mask = prev->valuators.mask[0] | next->valuators.mask[0];
284 if (mask == next->valuators.mask[0]) /* keep next */
286 for (i = j = k = 0; i < 8; i++)
288 if (XIMaskIsSet( prev->valuators.mask, i ))
289 next->valuators.values[j] += prev->valuators.values[k++];
290 if (XIMaskIsSet( next->valuators.mask, i )) j++;
292 TRACE( "merging duplicate GenericEvent\n" );
293 return MERGE_DISCARD;
295 if (mask == prev->valuators.mask[0]) /* keep prev */
297 for (i = j = k = 0; i < 8; i++)
299 if (XIMaskIsSet( next->valuators.mask, i ))
300 prev->valuators.values[j] += next->valuators.values[k++];
301 if (XIMaskIsSet( prev->valuators.mask, i )) j++;
303 TRACE( "merging duplicate GenericEvent\n" );
304 return MERGE_IGNORE;
306 /* can't merge events with disjoint masks */
307 return MERGE_HANDLE;
309 #endif
311 /***********************************************************************
312 * merge_events
314 * Try to merge 2 consecutive events.
316 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
318 switch (prev->type)
320 case ConfigureNotify:
321 switch (next->type)
323 case ConfigureNotify:
324 if (prev->xany.window == next->xany.window)
326 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
327 return MERGE_DISCARD;
329 break;
330 case Expose:
331 case PropertyNotify:
332 return MERGE_KEEP;
334 break;
335 case MotionNotify:
336 switch (next->type)
338 case MotionNotify:
339 if (prev->xany.window == next->xany.window)
341 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
342 return MERGE_DISCARD;
344 break;
345 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
346 case GenericEvent:
347 if (next->xcookie.extension != xinput2_opcode) break;
348 if (next->xcookie.evtype != XI_RawMotion) break;
349 if (x11drv_thread_data()->warp_serial) break;
350 return MERGE_KEEP;
352 break;
353 case GenericEvent:
354 if (prev->xcookie.extension != xinput2_opcode) break;
355 if (prev->xcookie.evtype != XI_RawMotion) break;
356 switch (next->type)
358 case GenericEvent:
359 if (next->xcookie.extension != xinput2_opcode) break;
360 if (next->xcookie.evtype != XI_RawMotion) break;
361 if (x11drv_thread_data()->warp_serial) break;
362 return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
363 #endif
365 break;
367 return MERGE_HANDLE;
371 /***********************************************************************
372 * call_event_handler
374 static inline void call_event_handler( Display *display, XEvent *event )
376 HWND hwnd;
377 XEvent *prev;
378 struct x11drv_thread_data *thread_data;
380 if (!handlers[event->type])
382 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
383 return; /* no handler, ignore it */
386 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
387 hwnd = 0; /* not for a registered window */
388 if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
390 TRACE( "%lu %s for hwnd/window %p/%lx\n",
391 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
392 thread_data = x11drv_thread_data();
393 prev = thread_data->current_event;
394 thread_data->current_event = event;
395 handlers[event->type]( hwnd, event );
396 thread_data->current_event = prev;
400 /***********************************************************************
401 * process_events
403 static int process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
405 XEvent event, prev_event;
406 int count = 0;
407 enum event_merge_action action = MERGE_DISCARD;
409 prev_event.type = 0;
410 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
412 count++;
413 if (XFilterEvent( &event, None ))
416 * SCIM on linux filters key events strangely. It does not filter the
417 * KeyPress events for these keys however it does filter the
418 * KeyRelease events. This causes wine to become very confused as
419 * to the keyboard state.
421 * We need to let those KeyRelease events be processed so that the
422 * keyboard state is correct.
424 if (event.type == KeyRelease)
426 KeySym keysym = 0;
427 XKeyEvent *keyevent = &event.xkey;
429 XLookupString(keyevent, NULL, 0, &keysym, NULL);
430 if (!(keysym == XK_Shift_L ||
431 keysym == XK_Shift_R ||
432 keysym == XK_Control_L ||
433 keysym == XK_Control_R ||
434 keysym == XK_Alt_R ||
435 keysym == XK_Alt_L ||
436 keysym == XK_Meta_R ||
437 keysym == XK_Meta_L))
438 continue; /* not a key we care about, ignore it */
440 else
441 continue; /* filtered, ignore it */
443 get_event_data( &event );
444 if (prev_event.type) action = merge_events( &prev_event, &event );
445 switch( action )
447 case MERGE_HANDLE: /* handle prev, keep new */
448 call_event_handler( display, &prev_event );
449 /* fall through */
450 case MERGE_DISCARD: /* discard prev, keep new */
451 free_event_data( &prev_event );
452 prev_event = event;
453 break;
454 case MERGE_KEEP: /* handle new, keep prev for future merging */
455 call_event_handler( display, &event );
456 /* fall through */
457 case MERGE_IGNORE: /* ignore new, keep prev for future merging */
458 free_event_data( &event );
459 break;
462 if (prev_event.type) call_event_handler( display, &prev_event );
463 free_event_data( &prev_event );
464 XFlush( gdi_display );
465 if (count) TRACE( "processed %d events\n", count );
466 return count;
470 /***********************************************************************
471 * MsgWaitForMultipleObjectsEx (X11DRV.@)
473 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
474 DWORD timeout, DWORD mask, DWORD flags )
476 DWORD ret;
477 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
479 if (!data)
481 if (!count && !timeout) return WAIT_TIMEOUT;
482 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
483 timeout, flags & MWMO_ALERTABLE );
486 if (data->current_event) mask = 0; /* don't process nested events */
488 if (process_events( data->display, filter_event, mask )) ret = count - 1;
489 else if (count || timeout)
491 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
492 timeout, flags & MWMO_ALERTABLE );
493 if (ret == count - 1) process_events( data->display, filter_event, mask );
495 else ret = WAIT_TIMEOUT;
497 return ret;
500 /***********************************************************************
501 * EVENT_x11_time_to_win32_time
503 * Make our timer and the X timer line up as best we can
504 * Pass 0 to retrieve the current adjustment value (times -1)
506 DWORD EVENT_x11_time_to_win32_time(Time time)
508 static DWORD adjust = 0;
509 DWORD now = GetTickCount();
510 DWORD ret;
512 if (! adjust && time != 0)
514 ret = now;
515 adjust = time - now;
517 else
519 /* If we got an event in the 'future', then our clock is clearly wrong.
520 If we got it more than 10000 ms in the future, then it's most likely
521 that the clock has wrapped. */
523 ret = time - adjust;
524 if (ret > now && ((ret - now) < 10000) && time != 0)
526 adjust += ret - now;
527 ret -= ret - now;
531 return ret;
535 /*******************************************************************
536 * can_activate_window
538 * Check if we can activate the specified window.
540 static inline BOOL can_activate_window( HWND hwnd )
542 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
543 RECT rect;
545 if (!(style & WS_VISIBLE)) return FALSE;
546 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
547 if (style & WS_MINIMIZE) return FALSE;
548 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
549 if (hwnd == GetDesktopWindow()) return FALSE;
550 if (GetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE;
551 return !(style & WS_DISABLED);
555 /**********************************************************************
556 * set_input_focus
558 * Try to force focus for embedded or non-managed windows.
560 static void set_input_focus( struct x11drv_win_data *data )
562 XWindowChanges changes;
563 DWORD timestamp;
565 if (!data->whole_window) return;
567 if (EVENT_x11_time_to_win32_time(0))
568 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
569 /* FIXME: this is not entirely correct */
570 timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
571 else
572 timestamp = CurrentTime;
574 /* Set X focus and install colormap */
575 changes.stack_mode = Above;
576 XConfigureWindow( data->display, data->whole_window, CWStackMode, &changes );
578 if (data->embedder)
579 xembed_request_focus( data->display, data->embedder, timestamp );
580 else
581 XSetInputFocus( data->display, data->whole_window, RevertToParent, timestamp );
585 /**********************************************************************
586 * set_focus
588 static void set_focus( Display *display, HWND hwnd, Time time )
590 HWND focus;
591 Window win;
592 GUITHREADINFO threadinfo;
594 TRACE( "setting foreground window to %p\n", hwnd );
595 SetForegroundWindow( hwnd );
597 threadinfo.cbSize = sizeof(threadinfo);
598 GetGUIThreadInfo(0, &threadinfo);
599 focus = threadinfo.hwndFocus;
600 if (!focus) focus = threadinfo.hwndActive;
601 if (focus) focus = GetAncestor( focus, GA_ROOT );
602 win = X11DRV_get_whole_window(focus);
604 if (win)
606 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
607 XSetInputFocus( display, win, RevertToParent, time );
612 /**********************************************************************
613 * handle_manager_message
615 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
617 if (hwnd != GetDesktopWindow()) return;
618 if (systray_atom && event->data.l[1] == systray_atom)
619 change_systray_owner( event->display, event->data.l[2] );
623 /**********************************************************************
624 * handle_wm_protocols
626 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
628 Atom protocol = (Atom)event->data.l[0];
629 Time event_time = (Time)event->data.l[1];
631 if (!protocol) return;
633 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
635 update_user_time( event_time );
637 if (hwnd == GetDesktopWindow())
639 /* The desktop window does not have a close button that we can
640 * pretend to click. Therefore, we simply send it a close command. */
641 SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
642 return;
645 /* Ignore the delete window request if the window has been disabled
646 * and we are in managed mode. This is to disallow applications from
647 * being closed by the window manager while in a modal state.
649 if (IsWindowEnabled(hwnd))
651 HMENU hSysMenu;
653 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
654 hSysMenu = GetSystemMenu(hwnd, FALSE);
655 if (hSysMenu)
657 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
658 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
659 return;
661 if (GetActiveWindow() != hwnd)
663 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
664 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
665 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
666 switch(ma)
668 case MA_NOACTIVATEANDEAT:
669 case MA_ACTIVATEANDEAT:
670 return;
671 case MA_NOACTIVATE:
672 break;
673 case MA_ACTIVATE:
674 case 0:
675 SetActiveWindow(hwnd);
676 break;
677 default:
678 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
679 break;
683 PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
686 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
688 HWND last_focus = x11drv_thread_data()->last_focus;
690 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
691 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
692 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
694 if (can_activate_window(hwnd))
696 /* simulate a mouse click on the caption to find out
697 * whether the window wants to be activated */
698 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
699 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
700 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
701 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
703 set_focus( event->display, hwnd, event_time );
704 return;
707 else if (hwnd == GetDesktopWindow())
709 hwnd = GetForegroundWindow();
710 if (!hwnd) hwnd = last_focus;
711 if (!hwnd) hwnd = GetDesktopWindow();
712 set_focus( event->display, hwnd, event_time );
713 return;
715 /* try to find some other window to give the focus to */
716 hwnd = GetFocus();
717 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
718 if (!hwnd) hwnd = GetActiveWindow();
719 if (!hwnd) hwnd = last_focus;
720 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
722 else if (protocol == x11drv_atom(_NET_WM_PING))
724 XClientMessageEvent xev;
725 xev = *event;
727 TRACE("NET_WM Ping\n");
728 xev.window = DefaultRootWindow(xev.display);
729 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
734 static const char * const focus_details[] =
736 "NotifyAncestor",
737 "NotifyVirtual",
738 "NotifyInferior",
739 "NotifyNonlinear",
740 "NotifyNonlinearVirtual",
741 "NotifyPointer",
742 "NotifyPointerRoot",
743 "NotifyDetailNone"
746 /**********************************************************************
747 * X11DRV_FocusIn
749 static void X11DRV_FocusIn( HWND hwnd, XEvent *xev )
751 XFocusChangeEvent *event = &xev->xfocus;
752 XIC xic;
754 if (!hwnd) return;
756 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
758 if (event->detail == NotifyPointer) return;
759 if (hwnd == GetDesktopWindow()) return;
761 if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic );
762 if (use_take_focus)
764 if (hwnd == GetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE );
765 return;
768 if (!can_activate_window(hwnd))
770 HWND hwnd = GetFocus();
771 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
772 if (!hwnd) hwnd = GetActiveWindow();
773 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
774 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
776 else SetForegroundWindow( hwnd );
779 /**********************************************************************
780 * focus_out
782 static void focus_out( Display *display , HWND hwnd )
784 HWND hwnd_tmp;
785 Window focus_win;
786 int revert;
787 XIC xic;
789 if (ximInComposeMode) return;
791 x11drv_thread_data()->last_focus = hwnd;
792 if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
794 if (root_window != DefaultRootWindow(display))
796 if (hwnd == GetDesktopWindow()) reset_clipping_window();
797 return;
799 if (hwnd != GetForegroundWindow()) return;
800 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
802 /* don't reset the foreground window, if the window which is
803 getting the focus is a Wine window */
805 XGetInputFocus( display, &focus_win, &revert );
806 if (focus_win)
808 if (XFindContext( display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
809 focus_win = 0;
812 if (!focus_win)
814 /* Abey : 6-Oct-99. Check again if the focus out window is the
815 Foreground window, because in most cases the messages sent
816 above must have already changed the foreground window, in which
817 case we don't have to change the foreground window to 0 */
818 if (hwnd == GetForegroundWindow())
820 TRACE( "lost focus, setting fg to desktop\n" );
821 SetForegroundWindow( GetDesktopWindow() );
826 /**********************************************************************
827 * X11DRV_FocusOut
829 * Note: only top-level windows get FocusOut events.
831 static void X11DRV_FocusOut( HWND hwnd, XEvent *xev )
833 XFocusChangeEvent *event = &xev->xfocus;
835 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
837 if (event->detail == NotifyPointer)
839 if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
840 return;
842 if (!hwnd) return;
843 focus_out( event->display, hwnd );
847 /***********************************************************************
848 * X11DRV_Expose
850 static void X11DRV_Expose( HWND hwnd, XEvent *xev )
852 XExposeEvent *event = &xev->xexpose;
853 RECT rect;
854 POINT pos;
855 struct x11drv_win_data *data;
856 HRGN surface_region = 0;
857 UINT flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN;
859 TRACE( "win %p (%lx) %d,%d %dx%d\n",
860 hwnd, event->window, event->x, event->y, event->width, event->height );
862 if (event->window != root_window)
864 pos.x = event->x;
865 pos.y = event->y;
867 else pos = root_to_virtual_screen( event->x, event->y );
869 if (!(data = get_win_data( hwnd ))) return;
871 rect.left = pos.x;
872 rect.top = pos.y;
873 rect.right = pos.x + event->width;
874 rect.bottom = pos.y + event->height;
876 if (event->window != data->client_window)
878 if (data->surface)
880 surface_region = expose_surface( data->surface, &rect );
881 if (!surface_region) flags = 0;
882 else OffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
883 data->whole_rect.top - data->client_rect.top );
885 if (data->vis.visualid != default_visual.visualid)
886 data->surface->funcs->flush( data->surface );
888 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
889 data->whole_rect.top - data->client_rect.top );
892 if (event->window != root_window)
894 if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
895 mirror_rect( &data->client_rect, &rect );
897 SERVER_START_REQ( update_window_zorder )
899 req->window = wine_server_user_handle( hwnd );
900 req->rect.left = rect.left;
901 req->rect.top = rect.top;
902 req->rect.right = rect.right;
903 req->rect.bottom = rect.bottom;
904 wine_server_call( req );
906 SERVER_END_REQ;
908 else flags &= ~RDW_ALLCHILDREN;
910 release_win_data( data );
912 if (flags) RedrawWindow( hwnd, &rect, surface_region, flags );
913 if (surface_region) DeleteObject( surface_region );
917 /**********************************************************************
918 * X11DRV_MapNotify
920 static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
922 struct x11drv_win_data *data;
924 if (event->xany.window == x11drv_thread_data()->clip_window)
926 clipping_cursor = TRUE;
927 return;
929 if (!(data = get_win_data( hwnd ))) return;
931 if (!data->managed && !data->embedded && data->mapped)
933 HWND hwndFocus = GetFocus();
934 if (hwndFocus && IsChild( hwnd, hwndFocus ))
935 set_input_focus( data );
937 release_win_data( data );
941 /**********************************************************************
942 * X11DRV_UnmapNotify
944 static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
946 if (event->xany.window == x11drv_thread_data()->clip_window)
947 clipping_cursor = FALSE;
951 /***********************************************************************
952 * reparent_notify
954 static void reparent_notify( Display *display, HWND hwnd, Window xparent, int x, int y )
956 HWND parent, old_parent;
957 DWORD style;
959 style = GetWindowLongW( hwnd, GWL_STYLE );
960 if (xparent == root_window)
962 parent = GetDesktopWindow();
963 style = (style & ~WS_CHILD) | WS_POPUP;
965 else
967 if (!(parent = create_foreign_window( display, xparent ))) return;
968 style = (style & ~WS_POPUP) | WS_CHILD;
971 ShowWindow( hwnd, SW_HIDE );
972 old_parent = SetParent( hwnd, parent );
973 SetWindowLongW( hwnd, GWL_STYLE, style );
974 SetWindowPos( hwnd, HWND_TOP, x, y, 0, 0,
975 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
976 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
978 /* make old parent destroy itself if it no longer has children */
979 if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
983 /***********************************************************************
984 * X11DRV_ReparentNotify
986 static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
988 XReparentEvent *event = &xev->xreparent;
989 struct x11drv_win_data *data;
991 if (!(data = get_win_data( hwnd ))) return;
993 if (!data->embedded)
995 release_win_data( data );
996 return;
999 if (data->whole_window)
1001 if (event->parent == root_window)
1003 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
1004 data->embedder = 0;
1005 release_win_data( data );
1006 SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1007 return;
1009 data->embedder = event->parent;
1012 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
1013 release_win_data( data );
1015 reparent_notify( event->display, hwnd, event->parent, event->x, event->y );
1019 /***********************************************************************
1020 * X11DRV_ConfigureNotify
1022 void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
1024 XConfigureEvent *event = &xev->xconfigure;
1025 struct x11drv_win_data *data;
1026 RECT rect;
1027 POINT pos;
1028 UINT flags;
1029 HWND parent;
1030 BOOL root_coords;
1031 int cx, cy, x = event->x, y = event->y;
1032 DWORD style;
1034 if (!hwnd) return;
1035 if (!(data = get_win_data( hwnd ))) return;
1036 if (!data->mapped || data->iconic) goto done;
1037 if (data->whole_window && !data->managed) goto done;
1038 /* ignore synthetic events on foreign windows */
1039 if (event->send_event && !data->whole_window) goto done;
1040 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
1042 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1043 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
1044 event->serial, data->configure_serial );
1045 goto done;
1048 /* Get geometry */
1050 parent = GetAncestor( hwnd, GA_PARENT );
1051 root_coords = event->send_event; /* synthetic events are always in root coords */
1053 if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
1055 Window child;
1056 XTranslateCoordinates( event->display, event->window, root_window,
1057 0, 0, &x, &y, &child );
1058 root_coords = TRUE;
1061 if (!root_coords)
1063 pos.x = x;
1064 pos.y = y;
1066 else pos = root_to_virtual_screen( x, y );
1068 rect.left = pos.x;
1069 rect.top = pos.y;
1070 rect.right = pos.x + event->width;
1071 rect.bottom = pos.y + event->height;
1072 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1073 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1074 event->x, event->y, event->width, event->height );
1076 X11DRV_X_to_window_rect( data, &rect );
1077 if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1079 /* Compare what has changed */
1081 x = rect.left;
1082 y = rect.top;
1083 cx = rect.right - rect.left;
1084 cy = rect.bottom - rect.top;
1085 flags = SWP_NOACTIVATE | SWP_NOZORDER;
1087 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
1089 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1090 else
1091 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1092 hwnd, data->window_rect.left, data->window_rect.top, x, y );
1094 if ((data->window_rect.right - data->window_rect.left == cx &&
1095 data->window_rect.bottom - data->window_rect.top == cy) ||
1096 IsRectEmpty( &data->window_rect ))
1097 flags |= SWP_NOSIZE;
1098 else
1099 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1100 hwnd, data->window_rect.right - data->window_rect.left,
1101 data->window_rect.bottom - data->window_rect.top, cx, cy );
1103 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1104 if ((style & WS_CAPTION) == WS_CAPTION)
1106 read_net_wm_states( event->display, data );
1107 if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1109 if (!(style & WS_MAXIMIZE))
1111 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1112 release_win_data( data );
1113 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1114 return;
1117 else if (style & WS_MAXIMIZE)
1119 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1120 release_win_data( data );
1121 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1122 return;
1126 if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
1128 release_win_data( data );
1129 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1130 return;
1133 done:
1134 release_win_data( data );
1138 /**********************************************************************
1139 * X11DRV_GravityNotify
1141 static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1143 XGravityEvent *event = &xev->xgravity;
1144 struct x11drv_win_data *data = get_win_data( hwnd );
1145 RECT rect, window_rect;
1147 if (!data) return;
1149 if (data->whole_window) /* only handle this for foreign windows */
1151 release_win_data( data );
1152 return;
1155 rect.left = event->x;
1156 rect.top = event->y;
1157 rect.right = rect.left + data->whole_rect.right - data->whole_rect.left;
1158 rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1160 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1161 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1162 event->x, event->y );
1164 X11DRV_X_to_window_rect( data, &rect );
1165 window_rect = data->window_rect;
1166 release_win_data( data );
1168 if (window_rect.left != rect.left || window_rect.top != rect.top)
1169 SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1170 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1174 /***********************************************************************
1175 * get_window_wm_state
1177 static int get_window_wm_state( Display *display, Window window )
1179 struct
1181 CARD32 state;
1182 XID icon;
1183 } *state;
1184 Atom type;
1185 int format, ret = -1;
1186 unsigned long count, remaining;
1188 if (!XGetWindowProperty( display, window, x11drv_atom(WM_STATE), 0,
1189 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1190 &type, &format, &count, &remaining, (unsigned char **)&state ))
1192 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1193 ret = state->state;
1194 XFree( state );
1196 return ret;
1200 /***********************************************************************
1201 * handle_wm_state_notify
1203 * Handle a PropertyNotify for WM_STATE.
1205 static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
1207 struct x11drv_win_data *data = get_win_data( hwnd );
1208 DWORD style;
1210 if (!data) return;
1212 switch(event->state)
1214 case PropertyDelete:
1215 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1216 data->wm_state = WithdrawnState;
1217 break;
1218 case PropertyNewValue:
1220 int old_state = data->wm_state;
1221 int new_state = get_window_wm_state( event->display, data->whole_window );
1222 if (new_state != -1 && new_state != data->wm_state)
1224 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1225 data->hwnd, data->whole_window, new_state, old_state );
1226 data->wm_state = new_state;
1227 /* ignore the initial state transition out of withdrawn state */
1228 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1229 if (!old_state) goto done;
1232 break;
1235 if (!update_window || !data->managed || !data->mapped) goto done;
1237 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1239 if (data->iconic && data->wm_state == NormalState) /* restore window */
1241 data->iconic = FALSE;
1242 read_net_wm_states( event->display, data );
1243 if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1245 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1247 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1248 release_win_data( data );
1249 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1250 return;
1252 TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1254 else
1256 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1258 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1259 release_win_data( data );
1260 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1261 return;
1263 TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1266 else if (!data->iconic && data->wm_state == IconicState)
1268 data->iconic = TRUE;
1269 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1271 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1272 release_win_data( data );
1273 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1274 return;
1276 TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1278 done:
1279 release_win_data( data );
1283 /***********************************************************************
1284 * X11DRV_PropertyNotify
1286 static void X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1288 XPropertyEvent *event = &xev->xproperty;
1290 if (!hwnd) return;
1291 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
1295 /* event filter to wait for a WM_STATE change notification on a window */
1296 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1298 if (event->xany.window != (Window)arg) return 0;
1299 return (event->type == DestroyNotify ||
1300 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1303 /***********************************************************************
1304 * wait_for_withdrawn_state
1306 void wait_for_withdrawn_state( HWND hwnd, BOOL set )
1308 Display *display = thread_display();
1309 struct x11drv_win_data *data;
1310 DWORD end = GetTickCount() + 2000;
1312 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
1314 for (;;)
1316 XEvent event;
1317 Window window;
1318 int count = 0;
1320 if (!(data = get_win_data( hwnd ))) break;
1321 if (!data->managed || data->embedded || data->display != display) break;
1322 if (!(window = data->whole_window)) break;
1323 if (!data->mapped == !set)
1325 TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
1326 break;
1328 if ((data->wm_state == WithdrawnState) != !set)
1330 TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
1331 break;
1333 release_win_data( data );
1335 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
1337 count++;
1338 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1339 if (event.type == DestroyNotify) call_event_handler( display, &event );
1340 else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
1343 if (!count)
1345 struct pollfd pfd;
1346 int timeout = end - GetTickCount();
1348 pfd.fd = ConnectionNumber(display);
1349 pfd.events = POLLIN;
1350 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1352 FIXME( "window %p/%lx wait timed out\n", hwnd, window );
1353 return;
1357 release_win_data( data );
1361 /*****************************************************************
1362 * SetFocus (X11DRV.@)
1364 * Set the X focus.
1366 void CDECL X11DRV_SetFocus( HWND hwnd )
1368 struct x11drv_win_data *data;
1370 HWND parent;
1372 for (;;)
1374 if (!(data = get_win_data( hwnd ))) return;
1375 if (data->embedded) break;
1376 parent = GetAncestor( hwnd, GA_PARENT );
1377 if (!parent || parent == GetDesktopWindow()) break;
1378 release_win_data( data );
1379 hwnd = parent;
1381 if (!data->managed || data->embedder) set_input_focus( data );
1382 release_win_data( data );
1386 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1388 RECT tempRect;
1390 if (!IsWindowEnabled(hQueryWnd)) return 0;
1392 GetWindowRect(hQueryWnd, &tempRect);
1394 if(!PtInRect(&tempRect, *lpPt)) return 0;
1396 if (!IsIconic( hQueryWnd ))
1398 POINT pt = *lpPt;
1399 ScreenToClient( hQueryWnd, &pt );
1400 GetClientRect( hQueryWnd, &tempRect );
1402 if (PtInRect( &tempRect, pt))
1404 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1405 if (ret && ret != hQueryWnd)
1407 ret = find_drop_window( ret, lpPt );
1408 if (ret) return ret;
1413 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1415 ScreenToClient(hQueryWnd, lpPt);
1417 return hQueryWnd;
1420 /**********************************************************************
1421 * EVENT_DropFromOffix
1423 * don't know if it still works (last Changelog is from 96/11/04)
1425 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1427 struct x11drv_win_data *data;
1428 POINT pt;
1429 unsigned long data_length;
1430 unsigned long aux_long;
1431 unsigned char* p_data = NULL;
1432 Atom atom_aux;
1433 int x, y, cx, cy, dummy;
1434 Window win, w_aux_root, w_aux_child;
1436 if (!(data = get_win_data( hWnd ))) return;
1437 cx = data->whole_rect.right - data->whole_rect.left;
1438 cy = data->whole_rect.bottom - data->whole_rect.top;
1439 win = data->whole_window;
1440 release_win_data( data );
1442 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1443 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1444 pt = root_to_virtual_screen( x, y );
1446 /* find out drop point and drop window */
1447 if (pt.x < 0 || pt.y < 0 || pt.x > cx || pt.y > cy)
1449 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1450 pt.x = pt.y = 0;
1452 else
1454 if (!find_drop_window( hWnd, &pt )) return;
1457 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1458 x11drv_atom(DndSelection), 0, 65535, FALSE,
1459 AnyPropertyType, &atom_aux, &dummy,
1460 &data_length, &aux_long, &p_data);
1462 if( !aux_long && p_data) /* don't bother if > 64K */
1464 char *p = (char *)p_data;
1465 char *p_drop;
1467 aux_long = 0;
1468 while( *p ) /* calculate buffer size */
1470 INT len = GetShortPathNameA( p, NULL, 0 );
1471 if (len) aux_long += len + 1;
1472 p += strlen(p) + 1;
1474 if( aux_long && aux_long < 65535 )
1476 HDROP hDrop;
1477 DROPFILES *lpDrop;
1479 aux_long += sizeof(DROPFILES) + 1;
1480 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1481 lpDrop = GlobalLock( hDrop );
1483 if( lpDrop )
1485 lpDrop->pFiles = sizeof(DROPFILES);
1486 lpDrop->pt = pt;
1487 lpDrop->fNC = FALSE;
1488 lpDrop->fWide = FALSE;
1489 p_drop = (char *)(lpDrop + 1);
1490 p = (char *)p_data;
1491 while(*p)
1493 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1494 p_drop += strlen( p_drop ) + 1;
1495 p += strlen(p) + 1;
1497 *p_drop = '\0';
1498 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1502 if( p_data ) XFree(p_data);
1505 /**********************************************************************
1506 * EVENT_DropURLs
1508 * drop items are separated by \n
1509 * each item is prefixed by its mime type
1511 * event->data.l[3], event->data.l[4] contains drop x,y position
1513 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1515 struct x11drv_win_data *win_data;
1516 unsigned long data_length;
1517 unsigned long aux_long, drop_len = 0;
1518 unsigned char *p_data = NULL; /* property data */
1519 char *p_drop = NULL;
1520 char *p, *next;
1521 int x, y;
1522 POINT pos;
1523 DROPFILES *lpDrop;
1524 HDROP hDrop;
1525 union {
1526 Atom atom_aux;
1527 int i;
1528 Window w_aux;
1529 unsigned int u;
1530 } u; /* unused */
1532 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1534 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1535 x11drv_atom(DndSelection), 0, 65535, FALSE,
1536 AnyPropertyType, &u.atom_aux, &u.i,
1537 &data_length, &aux_long, &p_data);
1538 if (aux_long)
1539 WARN("property too large, truncated!\n");
1540 TRACE("urls=%s\n", p_data);
1542 if( !aux_long && p_data) { /* don't bother if > 64K */
1543 /* calculate length */
1544 p = (char*) p_data;
1545 next = strchr(p, '\n');
1546 while (p) {
1547 if (next) *next=0;
1548 if (strncmp(p,"file:",5) == 0 ) {
1549 INT len = GetShortPathNameA( p+5, NULL, 0 );
1550 if (len) drop_len += len + 1;
1552 if (next) {
1553 *next = '\n';
1554 p = next + 1;
1555 next = strchr(p, '\n');
1556 } else {
1557 p = NULL;
1561 if( drop_len && drop_len < 65535 ) {
1562 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1563 &x, &y, &u.i, &u.i, &u.u);
1564 pos = root_to_virtual_screen( x, y );
1566 drop_len += sizeof(DROPFILES) + 1;
1567 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1568 lpDrop = GlobalLock( hDrop );
1570 if( lpDrop && (win_data = get_win_data( hWnd )))
1572 lpDrop->pFiles = sizeof(DROPFILES);
1573 lpDrop->pt = pos;
1574 lpDrop->fNC =
1575 (pos.x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1576 pos.y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1577 pos.x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1578 pos.y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1579 lpDrop->fWide = FALSE;
1580 p_drop = (char*)(lpDrop + 1);
1581 release_win_data( win_data );
1584 /* create message content */
1585 if (p_drop) {
1586 p = (char*) p_data;
1587 next = strchr(p, '\n');
1588 while (p) {
1589 if (next) *next=0;
1590 if (strncmp(p,"file:",5) == 0 ) {
1591 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1592 if (len) {
1593 TRACE("drop file %s as %s\n", p+5, p_drop);
1594 p_drop += len+1;
1595 } else {
1596 WARN("can't convert file %s to dos name\n", p+5);
1598 } else {
1599 WARN("unknown mime type %s\n", p);
1601 if (next) {
1602 *next = '\n';
1603 p = next + 1;
1604 next = strchr(p, '\n');
1605 } else {
1606 p = NULL;
1608 *p_drop = '\0';
1611 GlobalUnlock(hDrop);
1612 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1615 if( p_data ) XFree(p_data);
1620 /**********************************************************************
1621 * handle_xembed_protocol
1623 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1625 switch (event->data.l[1])
1627 case XEMBED_EMBEDDED_NOTIFY:
1629 struct x11drv_win_data *data = get_win_data( hwnd );
1630 if (!data) break;
1632 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1633 data->embedder = event->data.l[3];
1635 /* window has been marked as embedded before (e.g. systray) */
1636 if (data->embedded || !data->embedder /* broken QX11EmbedContainer implementation */)
1638 release_win_data( data );
1639 break;
1642 make_window_embedded( data );
1643 release_win_data( data );
1644 reparent_notify( event->display, hwnd, event->data.l[3], 0, 0 );
1646 break;
1648 case XEMBED_WINDOW_DEACTIVATE:
1649 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd, event->window );
1650 focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
1651 break;
1653 case XEMBED_FOCUS_OUT:
1654 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd, event->window );
1655 focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
1656 break;
1658 case XEMBED_MODALITY_ON:
1659 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd, event->window );
1660 EnableWindow( hwnd, FALSE );
1661 break;
1663 case XEMBED_MODALITY_OFF:
1664 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd, event->window );
1665 EnableWindow( hwnd, TRUE );
1666 break;
1668 default:
1669 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1670 hwnd, event->window, event->data.l[1], event->data.l[2] );
1671 break;
1676 /**********************************************************************
1677 * handle_dnd_protocol
1679 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1681 Window root, child;
1682 int root_x, root_y, child_x, child_y;
1683 unsigned int u;
1685 /* query window (drag&drop event contains only drag window) */
1686 XQueryPointer( event->display, root_window, &root, &child,
1687 &root_x, &root_y, &child_x, &child_y, &u);
1688 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1689 if (!hwnd) return;
1690 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1691 EVENT_DropFromOffiX(hwnd, event);
1692 else if (event->data.l[0] == DndURL)
1693 EVENT_DropURLs(hwnd, event);
1697 struct client_message_handler
1699 int atom; /* protocol atom */
1700 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1703 static const struct client_message_handler client_messages[] =
1705 { XATOM_MANAGER, handle_manager_message },
1706 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1707 { XATOM__XEMBED, handle_xembed_protocol },
1708 { XATOM_DndProtocol, handle_dnd_protocol },
1709 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1710 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1711 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1712 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1716 /**********************************************************************
1717 * X11DRV_ClientMessage
1719 static void X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1721 XClientMessageEvent *event = &xev->xclient;
1722 unsigned int i;
1724 if (!hwnd) return;
1726 if (event->format != 32)
1728 WARN( "Don't know how to handle format %d\n", event->format );
1729 return;
1732 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1734 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1736 client_messages[i].handler( hwnd, event );
1737 return;
1740 TRACE( "no handler found for %ld\n", event->message_type );