dsound: Don't write more than three periods to IAudioClient.
[wine.git] / dlls / winex11.drv / event.c
bloba0bfe052df3ab72404b5bcc26e63c95f8c876534
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 BOOL X11DRV_FocusIn( HWND hwnd, XEvent *event );
95 static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *event );
96 static BOOL X11DRV_Expose( HWND hwnd, XEvent *event );
97 static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event );
98 static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event );
99 static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *event );
100 static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *event );
101 static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *event );
102 static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *event );
103 static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *event );
105 #define MAX_EVENT_HANDLERS 128
107 static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
109 NULL, /* 0 reserved */
110 NULL, /* 1 reserved */
111 X11DRV_KeyEvent, /* 2 KeyPress */
112 X11DRV_KeyEvent, /* 3 KeyRelease */
113 X11DRV_ButtonPress, /* 4 ButtonPress */
114 X11DRV_ButtonRelease, /* 5 ButtonRelease */
115 X11DRV_MotionNotify, /* 6 MotionNotify */
116 X11DRV_EnterNotify, /* 7 EnterNotify */
117 NULL, /* 8 LeaveNotify */
118 X11DRV_FocusIn, /* 9 FocusIn */
119 X11DRV_FocusOut, /* 10 FocusOut */
120 X11DRV_KeymapNotify, /* 11 KeymapNotify */
121 X11DRV_Expose, /* 12 Expose */
122 NULL, /* 13 GraphicsExpose */
123 NULL, /* 14 NoExpose */
124 NULL, /* 15 VisibilityNotify */
125 NULL, /* 16 CreateNotify */
126 X11DRV_DestroyNotify, /* 17 DestroyNotify */
127 X11DRV_UnmapNotify, /* 18 UnmapNotify */
128 X11DRV_MapNotify, /* 19 MapNotify */
129 NULL, /* 20 MapRequest */
130 X11DRV_ReparentNotify, /* 21 ReparentNotify */
131 X11DRV_ConfigureNotify, /* 22 ConfigureNotify */
132 NULL, /* 23 ConfigureRequest */
133 X11DRV_GravityNotify, /* 24 GravityNotify */
134 NULL, /* 25 ResizeRequest */
135 NULL, /* 26 CirculateNotify */
136 NULL, /* 27 CirculateRequest */
137 X11DRV_PropertyNotify, /* 28 PropertyNotify */
138 X11DRV_SelectionClear, /* 29 SelectionClear */
139 X11DRV_SelectionRequest, /* 30 SelectionRequest */
140 NULL, /* 31 SelectionNotify */
141 NULL, /* 32 ColormapNotify */
142 X11DRV_ClientMessage, /* 33 ClientMessage */
143 X11DRV_MappingNotify, /* 34 MappingNotify */
144 X11DRV_GenericEvent /* 35 GenericEvent */
147 static const char * event_names[MAX_EVENT_HANDLERS] =
149 NULL, NULL, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
150 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
151 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
152 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
153 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
154 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
155 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
158 int xinput2_opcode = 0;
160 /* return the name of an X event */
161 static const char *dbgstr_event( int type )
163 if (type < MAX_EVENT_HANDLERS && event_names[type]) return event_names[type];
164 return wine_dbg_sprintf( "Unknown event %d", type );
167 static inline void get_event_data( XEvent *event )
169 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
170 if (event->xany.type != GenericEvent) return;
171 if (!pXGetEventData || !pXGetEventData( event->xany.display, event )) event->xcookie.data = NULL;
172 #endif
175 static inline void free_event_data( XEvent *event )
177 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
178 if (event->xany.type != GenericEvent) return;
179 if (event->xcookie.data) pXFreeEventData( event->xany.display, event );
180 #endif
183 /***********************************************************************
184 * xembed_request_focus
186 static void xembed_request_focus( Display *display, Window window, DWORD timestamp )
188 XEvent xev;
190 xev.xclient.type = ClientMessage;
191 xev.xclient.window = window;
192 xev.xclient.message_type = x11drv_atom(_XEMBED);
193 xev.xclient.serial = 0;
194 xev.xclient.display = display;
195 xev.xclient.send_event = True;
196 xev.xclient.format = 32;
198 xev.xclient.data.l[0] = timestamp;
199 xev.xclient.data.l[1] = XEMBED_REQUEST_FOCUS;
200 xev.xclient.data.l[2] = 0;
201 xev.xclient.data.l[3] = 0;
202 xev.xclient.data.l[4] = 0;
204 XSendEvent(display, window, False, NoEventMask, &xev);
205 XFlush( display );
208 /***********************************************************************
209 * X11DRV_register_event_handler
211 * Register a handler for a given event type.
212 * If already registered, overwrite the previous handler.
214 void X11DRV_register_event_handler( int type, x11drv_event_handler handler, const char *name )
216 assert( type < MAX_EVENT_HANDLERS );
217 assert( !handlers[type] || handlers[type] == handler );
218 handlers[type] = handler;
219 event_names[type] = name;
220 TRACE("registered handler %p for event %d %s\n", handler, type, debugstr_a(name) );
224 /***********************************************************************
225 * filter_event
227 static Bool filter_event( Display *display, XEvent *event, char *arg )
229 ULONG_PTR mask = (ULONG_PTR)arg;
231 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
233 switch(event->type)
235 case KeyPress:
236 case KeyRelease:
237 case KeymapNotify:
238 case MappingNotify:
239 return (mask & (QS_KEY|QS_HOTKEY)) != 0;
240 case ButtonPress:
241 case ButtonRelease:
242 return (mask & QS_MOUSEBUTTON) != 0;
243 #ifdef GenericEvent
244 case GenericEvent:
245 #endif
246 case MotionNotify:
247 case EnterNotify:
248 case LeaveNotify:
249 return (mask & QS_MOUSEMOVE) != 0;
250 case Expose:
251 return (mask & QS_PAINT) != 0;
252 case FocusIn:
253 case FocusOut:
254 case MapNotify:
255 case UnmapNotify:
256 case ConfigureNotify:
257 case PropertyNotify:
258 case ClientMessage:
259 return (mask & QS_POSTMESSAGE) != 0;
260 default:
261 return (mask & QS_SENDMESSAGE) != 0;
266 enum event_merge_action
268 MERGE_DISCARD, /* discard the old event */
269 MERGE_HANDLE, /* handle the old event */
270 MERGE_KEEP, /* keep the old event for future merging */
271 MERGE_IGNORE /* ignore the new event, keep the old one */
274 /***********************************************************************
275 * merge_raw_motion_events
277 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
278 static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawEvent *next )
280 int i, j, k;
281 unsigned char mask;
283 if (!prev->valuators.mask_len) return MERGE_HANDLE;
284 if (!next->valuators.mask_len) return MERGE_HANDLE;
286 mask = prev->valuators.mask[0] | next->valuators.mask[0];
287 if (mask == next->valuators.mask[0]) /* keep next */
289 for (i = j = k = 0; i < 8; i++)
291 if (XIMaskIsSet( prev->valuators.mask, i ))
292 next->valuators.values[j] += prev->valuators.values[k++];
293 if (XIMaskIsSet( next->valuators.mask, i )) j++;
295 TRACE( "merging duplicate GenericEvent\n" );
296 return MERGE_DISCARD;
298 if (mask == prev->valuators.mask[0]) /* keep prev */
300 for (i = j = k = 0; i < 8; i++)
302 if (XIMaskIsSet( next->valuators.mask, i ))
303 prev->valuators.values[j] += next->valuators.values[k++];
304 if (XIMaskIsSet( prev->valuators.mask, i )) j++;
306 TRACE( "merging duplicate GenericEvent\n" );
307 return MERGE_IGNORE;
309 /* can't merge events with disjoint masks */
310 return MERGE_HANDLE;
312 #endif
314 /***********************************************************************
315 * merge_events
317 * Try to merge 2 consecutive events.
319 static enum event_merge_action merge_events( XEvent *prev, XEvent *next )
321 switch (prev->type)
323 case ConfigureNotify:
324 switch (next->type)
326 case ConfigureNotify:
327 if (prev->xany.window == next->xany.window)
329 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev->xany.window );
330 return MERGE_DISCARD;
332 break;
333 case Expose:
334 case PropertyNotify:
335 return MERGE_KEEP;
337 break;
338 case MotionNotify:
339 switch (next->type)
341 case MotionNotify:
342 if (prev->xany.window == next->xany.window)
344 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev->xany.window );
345 return MERGE_DISCARD;
347 break;
348 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
349 case GenericEvent:
350 if (next->xcookie.extension != xinput2_opcode) break;
351 if (next->xcookie.evtype != XI_RawMotion) break;
352 if (x11drv_thread_data()->warp_serial) break;
353 return MERGE_KEEP;
355 break;
356 case GenericEvent:
357 if (prev->xcookie.extension != xinput2_opcode) break;
358 if (prev->xcookie.evtype != XI_RawMotion) break;
359 switch (next->type)
361 case GenericEvent:
362 if (next->xcookie.extension != xinput2_opcode) break;
363 if (next->xcookie.evtype != XI_RawMotion) break;
364 if (x11drv_thread_data()->warp_serial) break;
365 return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data );
366 #endif
368 break;
370 return MERGE_HANDLE;
374 /***********************************************************************
375 * call_event_handler
377 static inline BOOL call_event_handler( Display *display, XEvent *event )
379 HWND hwnd;
380 XEvent *prev;
381 struct x11drv_thread_data *thread_data;
382 BOOL ret;
384 if (!handlers[event->type])
386 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event->type ), event->xany.window );
387 return FALSE; /* no handler, ignore it */
390 if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0)
391 hwnd = 0; /* not for a registered window */
392 if (!hwnd && event->xany.window == root_window) hwnd = GetDesktopWindow();
394 TRACE( "%lu %s for hwnd/window %p/%lx\n",
395 event->xany.serial, dbgstr_event( event->type ), hwnd, event->xany.window );
396 thread_data = x11drv_thread_data();
397 prev = thread_data->current_event;
398 thread_data->current_event = event;
399 ret = handlers[event->type]( hwnd, event );
400 thread_data->current_event = prev;
401 return ret;
405 /***********************************************************************
406 * process_events
408 static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg )
410 XEvent event, prev_event;
411 int count = 0;
412 BOOL queued = FALSE;
413 enum event_merge_action action = MERGE_DISCARD;
415 prev_event.type = 0;
416 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
418 count++;
419 if (XFilterEvent( &event, None ))
422 * SCIM on linux filters key events strangely. It does not filter the
423 * KeyPress events for these keys however it does filter the
424 * KeyRelease events. This causes wine to become very confused as
425 * to the keyboard state.
427 * We need to let those KeyRelease events be processed so that the
428 * keyboard state is correct.
430 if (event.type == KeyRelease)
432 KeySym keysym = 0;
433 XKeyEvent *keyevent = &event.xkey;
435 XLookupString(keyevent, NULL, 0, &keysym, NULL);
436 if (!(keysym == XK_Shift_L ||
437 keysym == XK_Shift_R ||
438 keysym == XK_Control_L ||
439 keysym == XK_Control_R ||
440 keysym == XK_Alt_R ||
441 keysym == XK_Alt_L ||
442 keysym == XK_Meta_R ||
443 keysym == XK_Meta_L))
444 continue; /* not a key we care about, ignore it */
446 else
447 continue; /* filtered, ignore it */
449 get_event_data( &event );
450 if (prev_event.type) action = merge_events( &prev_event, &event );
451 switch( action )
453 case MERGE_HANDLE: /* handle prev, keep new */
454 queued |= call_event_handler( display, &prev_event );
455 /* fall through */
456 case MERGE_DISCARD: /* discard prev, keep new */
457 free_event_data( &prev_event );
458 prev_event = event;
459 break;
460 case MERGE_KEEP: /* handle new, keep prev for future merging */
461 queued |= call_event_handler( display, &event );
462 /* fall through */
463 case MERGE_IGNORE: /* ignore new, keep prev for future merging */
464 free_event_data( &event );
465 break;
468 if (prev_event.type) queued |= call_event_handler( display, &prev_event );
469 free_event_data( &prev_event );
470 XFlush( gdi_display );
471 if (count) TRACE( "processed %d events, returning %d\n", count, queued );
472 return queued;
476 /***********************************************************************
477 * MsgWaitForMultipleObjectsEx (X11DRV.@)
479 DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
480 DWORD timeout, DWORD mask, DWORD flags )
482 DWORD ret;
483 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
485 if (!data)
487 if (!count && !timeout) return WAIT_TIMEOUT;
488 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
489 timeout, flags & MWMO_ALERTABLE );
492 if (data->current_event) mask = 0; /* don't process nested events */
494 if (process_events( data->display, filter_event, mask )) ret = count - 1;
495 else if (count || timeout)
497 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
498 timeout, flags & MWMO_ALERTABLE );
499 if (ret == count - 1) process_events( data->display, filter_event, mask );
501 else ret = WAIT_TIMEOUT;
503 return ret;
506 /***********************************************************************
507 * EVENT_x11_time_to_win32_time
509 * Make our timer and the X timer line up as best we can
510 * Pass 0 to retrieve the current adjustment value (times -1)
512 DWORD EVENT_x11_time_to_win32_time(Time time)
514 static DWORD adjust = 0;
515 DWORD now = GetTickCount();
516 DWORD ret;
518 if (! adjust && time != 0)
520 ret = now;
521 adjust = time - now;
523 else
525 /* If we got an event in the 'future', then our clock is clearly wrong.
526 If we got it more than 10000 ms in the future, then it's most likely
527 that the clock has wrapped. */
529 ret = time - adjust;
530 if (ret > now && ((ret - now) < 10000) && time != 0)
532 adjust += ret - now;
533 ret -= ret - now;
537 return ret;
541 /*******************************************************************
542 * can_activate_window
544 * Check if we can activate the specified window.
546 static inline BOOL can_activate_window( HWND hwnd )
548 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
549 RECT rect;
551 if (!(style & WS_VISIBLE)) return FALSE;
552 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
553 if (style & WS_MINIMIZE) return FALSE;
554 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE;
555 if (hwnd == GetDesktopWindow()) return FALSE;
556 if (GetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE;
557 return !(style & WS_DISABLED);
561 /**********************************************************************
562 * set_input_focus
564 * Try to force focus for embedded or non-managed windows.
566 static void set_input_focus( struct x11drv_win_data *data )
568 XWindowChanges changes;
569 DWORD timestamp;
571 if (!data->whole_window) return;
573 if (EVENT_x11_time_to_win32_time(0))
574 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
575 /* FIXME: this is not entirely correct */
576 timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
577 else
578 timestamp = CurrentTime;
580 /* Set X focus and install colormap */
581 changes.stack_mode = Above;
582 XConfigureWindow( data->display, data->whole_window, CWStackMode, &changes );
584 if (data->embedder)
585 xembed_request_focus( data->display, data->embedder, timestamp );
586 else
587 XSetInputFocus( data->display, data->whole_window, RevertToParent, timestamp );
591 /**********************************************************************
592 * set_focus
594 static void set_focus( Display *display, HWND hwnd, Time time )
596 HWND focus;
597 Window win;
598 GUITHREADINFO threadinfo;
600 TRACE( "setting foreground window to %p\n", hwnd );
601 SetForegroundWindow( hwnd );
603 threadinfo.cbSize = sizeof(threadinfo);
604 GetGUIThreadInfo(0, &threadinfo);
605 focus = threadinfo.hwndFocus;
606 if (!focus) focus = threadinfo.hwndActive;
607 if (focus) focus = GetAncestor( focus, GA_ROOT );
608 win = X11DRV_get_whole_window(focus);
610 if (win)
612 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
613 XSetInputFocus( display, win, RevertToParent, time );
618 /**********************************************************************
619 * handle_manager_message
621 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
623 if (hwnd != GetDesktopWindow()) return;
624 if (systray_atom && event->data.l[1] == systray_atom)
625 change_systray_owner( event->display, event->data.l[2] );
629 /**********************************************************************
630 * handle_wm_protocols
632 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
634 Atom protocol = (Atom)event->data.l[0];
635 Time event_time = (Time)event->data.l[1];
637 if (!protocol) return;
639 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
641 update_user_time( event_time );
643 if (hwnd == GetDesktopWindow())
645 /* The desktop window does not have a close button that we can
646 * pretend to click. Therefore, we simply send it a close command. */
647 SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
648 return;
651 /* Ignore the delete window request if the window has been disabled
652 * and we are in managed mode. This is to disallow applications from
653 * being closed by the window manager while in a modal state.
655 if (IsWindowEnabled(hwnd))
657 HMENU hSysMenu;
659 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
660 hSysMenu = GetSystemMenu(hwnd, FALSE);
661 if (hSysMenu)
663 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
664 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
665 return;
667 if (GetActiveWindow() != hwnd)
669 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
670 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
671 MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
672 switch(ma)
674 case MA_NOACTIVATEANDEAT:
675 case MA_ACTIVATEANDEAT:
676 return;
677 case MA_NOACTIVATE:
678 break;
679 case MA_ACTIVATE:
680 case 0:
681 SetActiveWindow(hwnd);
682 break;
683 default:
684 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
685 break;
689 PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
692 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
694 HWND last_focus = x11drv_thread_data()->last_focus;
696 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
697 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
698 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
700 if (can_activate_window(hwnd))
702 /* simulate a mouse click on the caption to find out
703 * whether the window wants to be activated */
704 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
705 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
706 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
707 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
709 set_focus( event->display, hwnd, event_time );
710 return;
713 else if (hwnd == GetDesktopWindow())
715 hwnd = GetForegroundWindow();
716 if (!hwnd) hwnd = last_focus;
717 if (!hwnd) hwnd = GetDesktopWindow();
718 set_focus( event->display, hwnd, event_time );
719 return;
721 /* try to find some other window to give the focus to */
722 hwnd = GetFocus();
723 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
724 if (!hwnd) hwnd = GetActiveWindow();
725 if (!hwnd) hwnd = last_focus;
726 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
728 else if (protocol == x11drv_atom(_NET_WM_PING))
730 XClientMessageEvent xev;
731 xev = *event;
733 TRACE("NET_WM Ping\n");
734 xev.window = DefaultRootWindow(xev.display);
735 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
740 static const char * const focus_details[] =
742 "NotifyAncestor",
743 "NotifyVirtual",
744 "NotifyInferior",
745 "NotifyNonlinear",
746 "NotifyNonlinearVirtual",
747 "NotifyPointer",
748 "NotifyPointerRoot",
749 "NotifyDetailNone"
752 /**********************************************************************
753 * X11DRV_FocusIn
755 static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
757 XFocusChangeEvent *event = &xev->xfocus;
758 XIC xic;
760 if (!hwnd) return FALSE;
762 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
764 if (event->detail == NotifyPointer) return FALSE;
765 if (hwnd == GetDesktopWindow()) return FALSE;
767 if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic );
768 if (use_take_focus)
770 if (hwnd == GetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE );
771 return TRUE;
774 if (!can_activate_window(hwnd))
776 HWND hwnd = GetFocus();
777 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
778 if (!hwnd) hwnd = GetActiveWindow();
779 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
780 if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime );
782 else SetForegroundWindow( hwnd );
783 return TRUE;
786 /**********************************************************************
787 * focus_out
789 static void focus_out( Display *display , HWND hwnd )
791 HWND hwnd_tmp;
792 Window focus_win;
793 int revert;
794 XIC xic;
796 if (ximInComposeMode) return;
798 x11drv_thread_data()->last_focus = hwnd;
799 if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic );
801 if (root_window != DefaultRootWindow(display))
803 if (hwnd == GetDesktopWindow()) reset_clipping_window();
804 return;
806 if (hwnd != GetForegroundWindow()) return;
807 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
809 /* don't reset the foreground window, if the window which is
810 getting the focus is a Wine window */
812 XGetInputFocus( display, &focus_win, &revert );
813 if (focus_win)
815 if (XFindContext( display, focus_win, winContext, (char **)&hwnd_tmp ) != 0)
816 focus_win = 0;
819 if (!focus_win)
821 /* Abey : 6-Oct-99. Check again if the focus out window is the
822 Foreground window, because in most cases the messages sent
823 above must have already changed the foreground window, in which
824 case we don't have to change the foreground window to 0 */
825 if (hwnd == GetForegroundWindow())
827 TRACE( "lost focus, setting fg to desktop\n" );
828 SetForegroundWindow( GetDesktopWindow() );
833 /**********************************************************************
834 * X11DRV_FocusOut
836 * Note: only top-level windows get FocusOut events.
838 static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev )
840 XFocusChangeEvent *event = &xev->xfocus;
842 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
844 if (event->detail == NotifyPointer)
846 if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window();
847 return TRUE;
849 if (!hwnd) return FALSE;
850 focus_out( event->display, hwnd );
851 return TRUE;
855 /***********************************************************************
856 * X11DRV_Expose
858 static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev )
860 XExposeEvent *event = &xev->xexpose;
861 RECT rect;
862 POINT pos;
863 struct x11drv_win_data *data;
864 HRGN surface_region = 0;
865 UINT flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN;
867 TRACE( "win %p (%lx) %d,%d %dx%d\n",
868 hwnd, event->window, event->x, event->y, event->width, event->height );
870 if (event->window != root_window)
872 pos.x = event->x;
873 pos.y = event->y;
875 else pos = root_to_virtual_screen( event->x, event->y );
877 if (!(data = get_win_data( hwnd ))) return FALSE;
879 rect.left = pos.x;
880 rect.top = pos.y;
881 rect.right = pos.x + event->width;
882 rect.bottom = pos.y + event->height;
884 if (event->window != data->client_window)
886 if (data->surface)
888 surface_region = expose_surface( data->surface, &rect );
889 if (!surface_region) flags = 0;
890 else OffsetRgn( surface_region, data->whole_rect.left - data->client_rect.left,
891 data->whole_rect.top - data->client_rect.top );
893 if (data->vis.visualid != default_visual.visualid)
894 data->surface->funcs->flush( data->surface );
896 OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
897 data->whole_rect.top - data->client_rect.top );
900 if (event->window != root_window)
902 if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
903 mirror_rect( &data->client_rect, &rect );
905 SERVER_START_REQ( update_window_zorder )
907 req->window = wine_server_user_handle( hwnd );
908 req->rect.left = rect.left;
909 req->rect.top = rect.top;
910 req->rect.right = rect.right;
911 req->rect.bottom = rect.bottom;
912 wine_server_call( req );
914 SERVER_END_REQ;
916 else flags &= ~RDW_ALLCHILDREN;
918 release_win_data( data );
920 if (flags) RedrawWindow( hwnd, &rect, surface_region, flags );
921 if (surface_region) DeleteObject( surface_region );
922 return TRUE;
926 /**********************************************************************
927 * X11DRV_MapNotify
929 static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event )
931 struct x11drv_win_data *data;
933 if (event->xany.window == x11drv_thread_data()->clip_window)
935 clipping_cursor = TRUE;
936 return TRUE;
938 if (!(data = get_win_data( hwnd ))) return FALSE;
940 if (!data->managed && !data->embedded && data->mapped)
942 HWND hwndFocus = GetFocus();
943 if (hwndFocus && IsChild( hwnd, hwndFocus ))
944 set_input_focus( data );
946 release_win_data( data );
947 return TRUE;
951 /**********************************************************************
952 * X11DRV_UnmapNotify
954 static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
956 if (event->xany.window == x11drv_thread_data()->clip_window)
957 clipping_cursor = FALSE;
958 return TRUE;
962 /***********************************************************************
963 * reparent_notify
965 static void reparent_notify( Display *display, HWND hwnd, Window xparent, int x, int y )
967 HWND parent, old_parent;
968 DWORD style;
970 style = GetWindowLongW( hwnd, GWL_STYLE );
971 if (xparent == root_window)
973 parent = GetDesktopWindow();
974 style = (style & ~WS_CHILD) | WS_POPUP;
976 else
978 if (!(parent = create_foreign_window( display, xparent ))) return;
979 style = (style & ~WS_POPUP) | WS_CHILD;
982 ShowWindow( hwnd, SW_HIDE );
983 old_parent = SetParent( hwnd, parent );
984 SetWindowLongW( hwnd, GWL_STYLE, style );
985 SetWindowPos( hwnd, HWND_TOP, x, y, 0, 0,
986 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
987 ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
989 /* make old parent destroy itself if it no longer has children */
990 if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
994 /***********************************************************************
995 * X11DRV_ReparentNotify
997 static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
999 XReparentEvent *event = &xev->xreparent;
1000 struct x11drv_win_data *data;
1002 if (!(data = get_win_data( hwnd ))) return FALSE;
1004 if (!data->embedded)
1006 release_win_data( data );
1007 return FALSE;
1010 if (data->whole_window)
1012 if (event->parent == root_window)
1014 TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
1015 data->embedder = 0;
1016 release_win_data( data );
1017 SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1018 return TRUE;
1020 data->embedder = event->parent;
1023 TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
1024 release_win_data( data );
1026 reparent_notify( event->display, hwnd, event->parent, event->x, event->y );
1027 return TRUE;
1031 /***********************************************************************
1032 * X11DRV_ConfigureNotify
1034 static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
1036 XConfigureEvent *event = &xev->xconfigure;
1037 struct x11drv_win_data *data;
1038 RECT rect;
1039 POINT pos;
1040 UINT flags;
1041 HWND parent;
1042 BOOL root_coords;
1043 int cx, cy, x = event->x, y = event->y;
1044 DWORD style;
1046 if (!hwnd) return FALSE;
1047 if (!(data = get_win_data( hwnd ))) return FALSE;
1048 if (!data->mapped || data->iconic) goto done;
1049 if (data->whole_window && !data->managed) goto done;
1050 /* ignore synthetic events on foreign windows */
1051 if (event->send_event && !data->whole_window) goto done;
1052 if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
1054 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1055 hwnd, data->whole_window, event->x, event->y, event->width, event->height,
1056 event->serial, data->configure_serial );
1057 goto done;
1060 /* Get geometry */
1062 parent = GetAncestor( hwnd, GA_PARENT );
1063 root_coords = event->send_event; /* synthetic events are always in root coords */
1065 if (!root_coords && parent == GetDesktopWindow()) /* normal event, map coordinates to the root */
1067 Window child;
1068 XTranslateCoordinates( event->display, event->window, root_window,
1069 0, 0, &x, &y, &child );
1070 root_coords = TRUE;
1073 if (!root_coords)
1075 pos.x = x;
1076 pos.y = y;
1078 else pos = root_to_virtual_screen( x, y );
1080 rect.left = pos.x;
1081 rect.top = pos.y;
1082 rect.right = pos.x + event->width;
1083 rect.bottom = pos.y + event->height;
1084 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1085 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1086 event->x, event->y, event->width, event->height );
1088 X11DRV_X_to_window_rect( data, &rect );
1089 if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
1091 /* Compare what has changed */
1093 x = rect.left;
1094 y = rect.top;
1095 cx = rect.right - rect.left;
1096 cy = rect.bottom - rect.top;
1097 flags = SWP_NOACTIVATE | SWP_NOZORDER;
1099 if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
1101 if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
1102 else
1103 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1104 hwnd, data->window_rect.left, data->window_rect.top, x, y );
1106 if ((data->window_rect.right - data->window_rect.left == cx &&
1107 data->window_rect.bottom - data->window_rect.top == cy) ||
1108 IsRectEmpty( &data->window_rect ))
1109 flags |= SWP_NOSIZE;
1110 else
1111 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1112 hwnd, data->window_rect.right - data->window_rect.left,
1113 data->window_rect.bottom - data->window_rect.top, cx, cy );
1115 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1116 if ((style & WS_CAPTION) == WS_CAPTION)
1118 read_net_wm_states( event->display, data );
1119 if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1121 if (!(style & WS_MAXIMIZE))
1123 TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window );
1124 release_win_data( data );
1125 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1126 return TRUE;
1129 else if (style & WS_MAXIMIZE)
1131 TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
1132 release_win_data( data );
1133 SendMessageW( data->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1134 return TRUE;
1138 if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
1140 release_win_data( data );
1141 SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1142 return TRUE;
1145 done:
1146 release_win_data( data );
1147 return FALSE;
1151 /**********************************************************************
1152 * X11DRV_GravityNotify
1154 static BOOL X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
1156 XGravityEvent *event = &xev->xgravity;
1157 struct x11drv_win_data *data = get_win_data( hwnd );
1158 RECT rect, window_rect;
1160 if (!data) return FALSE;
1162 if (data->whole_window) /* only handle this for foreign windows */
1164 release_win_data( data );
1165 return FALSE;
1168 rect.left = event->x;
1169 rect.top = event->y;
1170 rect.right = rect.left + data->whole_rect.right - data->whole_rect.left;
1171 rect.bottom = rect.top + data->whole_rect.bottom - data->whole_rect.top;
1173 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1174 hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1175 event->x, event->y );
1177 X11DRV_X_to_window_rect( data, &rect );
1178 window_rect = data->window_rect;
1179 release_win_data( data );
1181 if (window_rect.left != rect.left || window_rect.top != rect.top)
1182 SetWindowPos( hwnd, 0, rect.left, rect.top, 0, 0,
1183 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS );
1184 return TRUE;
1188 /***********************************************************************
1189 * get_window_wm_state
1191 static int get_window_wm_state( Display *display, Window window )
1193 struct
1195 CARD32 state;
1196 XID icon;
1197 } *state;
1198 Atom type;
1199 int format, ret = -1;
1200 unsigned long count, remaining;
1202 if (!XGetWindowProperty( display, window, x11drv_atom(WM_STATE), 0,
1203 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
1204 &type, &format, &count, &remaining, (unsigned char **)&state ))
1206 if (type == x11drv_atom(WM_STATE) && get_property_size( format, count ) >= sizeof(*state))
1207 ret = state->state;
1208 XFree( state );
1210 return ret;
1214 /***********************************************************************
1215 * handle_wm_state_notify
1217 * Handle a PropertyNotify for WM_STATE.
1219 static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window )
1221 struct x11drv_win_data *data = get_win_data( hwnd );
1222 DWORD style;
1224 if (!data) return;
1226 switch(event->state)
1228 case PropertyDelete:
1229 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
1230 data->wm_state = WithdrawnState;
1231 break;
1232 case PropertyNewValue:
1234 int old_state = data->wm_state;
1235 int new_state = get_window_wm_state( event->display, data->whole_window );
1236 if (new_state != -1 && new_state != data->wm_state)
1238 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1239 data->hwnd, data->whole_window, new_state, old_state );
1240 data->wm_state = new_state;
1241 /* ignore the initial state transition out of withdrawn state */
1242 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1243 if (!old_state) goto done;
1246 break;
1249 if (!update_window || !data->managed || !data->mapped) goto done;
1251 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1253 if (data->iconic && data->wm_state == NormalState) /* restore window */
1255 data->iconic = FALSE;
1256 read_net_wm_states( event->display, data );
1257 if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
1259 if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
1261 TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
1262 release_win_data( data );
1263 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 );
1264 return;
1266 TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1268 else
1270 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1272 TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
1273 release_win_data( data );
1274 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 );
1275 return;
1277 TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1280 else if (!data->iconic && data->wm_state == IconicState)
1282 data->iconic = TRUE;
1283 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1285 TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
1286 release_win_data( data );
1287 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 );
1288 return;
1290 TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style );
1292 done:
1293 release_win_data( data );
1297 /***********************************************************************
1298 * X11DRV_PropertyNotify
1300 static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
1302 XPropertyEvent *event = &xev->xproperty;
1304 if (!hwnd) return FALSE;
1305 if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE );
1306 return TRUE;
1310 /* event filter to wait for a WM_STATE change notification on a window */
1311 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
1313 if (event->xany.window != (Window)arg) return 0;
1314 return (event->type == DestroyNotify ||
1315 (event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
1318 /***********************************************************************
1319 * wait_for_withdrawn_state
1321 void wait_for_withdrawn_state( HWND hwnd, BOOL set )
1323 Display *display = thread_display();
1324 struct x11drv_win_data *data;
1325 DWORD end = GetTickCount() + 2000;
1327 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
1329 for (;;)
1331 XEvent event;
1332 Window window;
1333 int count = 0;
1335 if (!(data = get_win_data( hwnd ))) break;
1336 if (!data->managed || data->embedded || data->display != display) break;
1337 if (!(window = data->whole_window)) break;
1338 if (!data->mapped == !set)
1340 TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
1341 break;
1343 if ((data->wm_state == WithdrawnState) != !set)
1345 TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
1346 break;
1348 release_win_data( data );
1350 while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
1352 count++;
1353 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
1354 if (event.type == DestroyNotify) call_event_handler( display, &event );
1355 else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
1358 if (!count)
1360 struct pollfd pfd;
1361 int timeout = end - GetTickCount();
1363 pfd.fd = ConnectionNumber(display);
1364 pfd.events = POLLIN;
1365 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
1367 FIXME( "window %p/%lx wait timed out\n", hwnd, window );
1368 return;
1372 release_win_data( data );
1376 /*****************************************************************
1377 * SetFocus (X11DRV.@)
1379 * Set the X focus.
1381 void CDECL X11DRV_SetFocus( HWND hwnd )
1383 struct x11drv_win_data *data;
1385 HWND parent;
1387 for (;;)
1389 if (!(data = get_win_data( hwnd ))) return;
1390 if (data->embedded) break;
1391 parent = GetAncestor( hwnd, GA_PARENT );
1392 if (!parent || parent == GetDesktopWindow()) break;
1393 release_win_data( data );
1394 hwnd = parent;
1396 if (!data->managed || data->embedder) set_input_focus( data );
1397 release_win_data( data );
1401 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1403 RECT tempRect;
1405 if (!IsWindowEnabled(hQueryWnd)) return 0;
1407 GetWindowRect(hQueryWnd, &tempRect);
1409 if(!PtInRect(&tempRect, *lpPt)) return 0;
1411 if (!IsIconic( hQueryWnd ))
1413 POINT pt = *lpPt;
1414 ScreenToClient( hQueryWnd, &pt );
1415 GetClientRect( hQueryWnd, &tempRect );
1417 if (PtInRect( &tempRect, pt))
1419 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
1420 if (ret && ret != hQueryWnd)
1422 ret = find_drop_window( ret, lpPt );
1423 if (ret) return ret;
1428 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1430 ScreenToClient(hQueryWnd, lpPt);
1432 return hQueryWnd;
1435 /**********************************************************************
1436 * EVENT_DropFromOffix
1438 * don't know if it still works (last Changelog is from 96/11/04)
1440 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1442 struct x11drv_win_data *data;
1443 POINT pt;
1444 unsigned long data_length;
1445 unsigned long aux_long;
1446 unsigned char* p_data = NULL;
1447 Atom atom_aux;
1448 int x, y, cx, cy, dummy;
1449 Window win, w_aux_root, w_aux_child;
1451 if (!(data = get_win_data( hWnd ))) return;
1452 cx = data->whole_rect.right - data->whole_rect.left;
1453 cy = data->whole_rect.bottom - data->whole_rect.top;
1454 win = data->whole_window;
1455 release_win_data( data );
1457 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
1458 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
1459 pt = root_to_virtual_screen( x, y );
1461 /* find out drop point and drop window */
1462 if (pt.x < 0 || pt.y < 0 || pt.x > cx || pt.y > cy)
1464 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1465 pt.x = pt.y = 0;
1467 else
1469 if (!find_drop_window( hWnd, &pt )) return;
1472 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1473 x11drv_atom(DndSelection), 0, 65535, FALSE,
1474 AnyPropertyType, &atom_aux, &dummy,
1475 &data_length, &aux_long, &p_data);
1477 if( !aux_long && p_data) /* don't bother if > 64K */
1479 char *p = (char *)p_data;
1480 char *p_drop;
1482 aux_long = 0;
1483 while( *p ) /* calculate buffer size */
1485 INT len = GetShortPathNameA( p, NULL, 0 );
1486 if (len) aux_long += len + 1;
1487 p += strlen(p) + 1;
1489 if( aux_long && aux_long < 65535 )
1491 HDROP hDrop;
1492 DROPFILES *lpDrop;
1494 aux_long += sizeof(DROPFILES) + 1;
1495 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1496 lpDrop = GlobalLock( hDrop );
1498 if( lpDrop )
1500 lpDrop->pFiles = sizeof(DROPFILES);
1501 lpDrop->pt = pt;
1502 lpDrop->fNC = FALSE;
1503 lpDrop->fWide = FALSE;
1504 p_drop = (char *)(lpDrop + 1);
1505 p = (char *)p_data;
1506 while(*p)
1508 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
1509 p_drop += strlen( p_drop ) + 1;
1510 p += strlen(p) + 1;
1512 *p_drop = '\0';
1513 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1517 if( p_data ) XFree(p_data);
1520 /**********************************************************************
1521 * EVENT_DropURLs
1523 * drop items are separated by \n
1524 * each item is prefixed by its mime type
1526 * event->data.l[3], event->data.l[4] contains drop x,y position
1528 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1530 struct x11drv_win_data *win_data;
1531 unsigned long data_length;
1532 unsigned long aux_long, drop_len = 0;
1533 unsigned char *p_data = NULL; /* property data */
1534 char *p_drop = NULL;
1535 char *p, *next;
1536 int x, y;
1537 POINT pos;
1538 DROPFILES *lpDrop;
1539 HDROP hDrop;
1540 union {
1541 Atom atom_aux;
1542 int i;
1543 Window w_aux;
1544 unsigned int u;
1545 } u; /* unused */
1547 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1549 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1550 x11drv_atom(DndSelection), 0, 65535, FALSE,
1551 AnyPropertyType, &u.atom_aux, &u.i,
1552 &data_length, &aux_long, &p_data);
1553 if (aux_long)
1554 WARN("property too large, truncated!\n");
1555 TRACE("urls=%s\n", p_data);
1557 if( !aux_long && p_data) { /* don't bother if > 64K */
1558 /* calculate length */
1559 p = (char*) p_data;
1560 next = strchr(p, '\n');
1561 while (p) {
1562 if (next) *next=0;
1563 if (strncmp(p,"file:",5) == 0 ) {
1564 INT len = GetShortPathNameA( p+5, NULL, 0 );
1565 if (len) drop_len += len + 1;
1567 if (next) {
1568 *next = '\n';
1569 p = next + 1;
1570 next = strchr(p, '\n');
1571 } else {
1572 p = NULL;
1576 if( drop_len && drop_len < 65535 ) {
1577 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1578 &x, &y, &u.i, &u.i, &u.u);
1579 pos = root_to_virtual_screen( x, y );
1581 drop_len += sizeof(DROPFILES) + 1;
1582 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1583 lpDrop = GlobalLock( hDrop );
1585 if( lpDrop && (win_data = get_win_data( hWnd )))
1587 lpDrop->pFiles = sizeof(DROPFILES);
1588 lpDrop->pt = pos;
1589 lpDrop->fNC =
1590 (pos.x < (win_data->client_rect.left - win_data->whole_rect.left) ||
1591 pos.y < (win_data->client_rect.top - win_data->whole_rect.top) ||
1592 pos.x > (win_data->client_rect.right - win_data->whole_rect.left) ||
1593 pos.y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
1594 lpDrop->fWide = FALSE;
1595 p_drop = (char*)(lpDrop + 1);
1596 release_win_data( win_data );
1599 /* create message content */
1600 if (p_drop) {
1601 p = (char*) p_data;
1602 next = strchr(p, '\n');
1603 while (p) {
1604 if (next) *next=0;
1605 if (strncmp(p,"file:",5) == 0 ) {
1606 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1607 if (len) {
1608 TRACE("drop file %s as %s\n", p+5, p_drop);
1609 p_drop += len+1;
1610 } else {
1611 WARN("can't convert file %s to dos name\n", p+5);
1613 } else {
1614 WARN("unknown mime type %s\n", p);
1616 if (next) {
1617 *next = '\n';
1618 p = next + 1;
1619 next = strchr(p, '\n');
1620 } else {
1621 p = NULL;
1623 *p_drop = '\0';
1626 GlobalUnlock(hDrop);
1627 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1630 if( p_data ) XFree(p_data);
1635 /**********************************************************************
1636 * handle_xembed_protocol
1638 static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event )
1640 switch (event->data.l[1])
1642 case XEMBED_EMBEDDED_NOTIFY:
1644 struct x11drv_win_data *data = get_win_data( hwnd );
1645 if (!data) break;
1647 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd, event->window, event->data.l[3] );
1648 data->embedder = event->data.l[3];
1650 /* window has been marked as embedded before (e.g. systray) */
1651 if (data->embedded || !data->embedder /* broken QX11EmbedContainer implementation */)
1653 release_win_data( data );
1654 break;
1657 make_window_embedded( data );
1658 release_win_data( data );
1659 reparent_notify( event->display, hwnd, event->data.l[3], 0, 0 );
1661 break;
1663 case XEMBED_WINDOW_DEACTIVATE:
1664 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd, event->window );
1665 focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
1666 break;
1668 case XEMBED_FOCUS_OUT:
1669 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd, event->window );
1670 focus_out( event->display, GetAncestor( hwnd, GA_ROOT ) );
1671 break;
1673 case XEMBED_MODALITY_ON:
1674 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd, event->window );
1675 EnableWindow( hwnd, FALSE );
1676 break;
1678 case XEMBED_MODALITY_OFF:
1679 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd, event->window );
1680 EnableWindow( hwnd, TRUE );
1681 break;
1683 default:
1684 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1685 hwnd, event->window, event->data.l[1], event->data.l[2] );
1686 break;
1691 /**********************************************************************
1692 * handle_dnd_protocol
1694 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
1696 Window root, child;
1697 int root_x, root_y, child_x, child_y;
1698 unsigned int u;
1700 /* query window (drag&drop event contains only drag window) */
1701 XQueryPointer( event->display, root_window, &root, &child,
1702 &root_x, &root_y, &child_x, &child_y, &u);
1703 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
1704 if (!hwnd) return;
1705 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1706 EVENT_DropFromOffiX(hwnd, event);
1707 else if (event->data.l[0] == DndURL)
1708 EVENT_DropURLs(hwnd, event);
1712 struct client_message_handler
1714 int atom; /* protocol atom */
1715 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
1718 static const struct client_message_handler client_messages[] =
1720 { XATOM_MANAGER, handle_manager_message },
1721 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
1722 { XATOM__XEMBED, handle_xembed_protocol },
1723 { XATOM_DndProtocol, handle_dnd_protocol },
1724 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
1725 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
1726 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
1727 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
1731 /**********************************************************************
1732 * X11DRV_ClientMessage
1734 static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev )
1736 XClientMessageEvent *event = &xev->xclient;
1737 unsigned int i;
1739 if (!hwnd) return FALSE;
1741 if (event->format != 32)
1743 WARN( "Don't know how to handle format %d\n", event->format );
1744 return FALSE;
1747 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1749 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1751 client_messages[i].handler( hwnd, event );
1752 return TRUE;
1755 TRACE( "no handler found for %ld\n", event->message_type );
1756 return FALSE;