winex11: Use XWithdrawWindow to unmap managed windows, and wait until they are withdr...
[wine/wine-gecko.git] / dlls / winex11.drv / event.c
blob01dfc6d30aaef58b5695f37d4272691f42c468de
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #ifdef HAVE_POLL_H
25 #include <poll.h>
26 #endif
27 #ifdef HAVE_SYS_POLL_H
28 #include <sys/poll.h>
29 #endif
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
36 #include <assert.h>
37 #include <stdarg.h>
38 #include <string.h>
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winuser.h"
45 #include "wingdi.h"
47 #include "win.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/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(event);
59 extern BOOL ximInComposeMode;
61 #define DndNotDnd -1 /* OffiX drag&drop */
62 #define DndUnknown 0
63 #define DndRawData 1
64 #define DndFile 2
65 #define DndFiles 3
66 #define DndText 4
67 #define DndDir 5
68 #define DndLink 6
69 #define DndExe 7
71 #define DndEND 8
73 #define DndURL 128 /* KDE drag&drop */
75 /* Event handlers */
76 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
77 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
78 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
79 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
81 struct event_handler
83 int type; /* event type */
84 x11drv_event_handler handler; /* corresponding handler function */
87 #define MAX_EVENT_HANDLERS 64
89 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
91 /* list must be sorted by event type */
92 { KeyPress, X11DRV_KeyEvent },
93 { KeyRelease, X11DRV_KeyEvent },
94 { ButtonPress, X11DRV_ButtonPress },
95 { ButtonRelease, X11DRV_ButtonRelease },
96 { MotionNotify, X11DRV_MotionNotify },
97 { EnterNotify, X11DRV_EnterNotify },
98 /* LeaveNotify */
99 { FocusIn, EVENT_FocusIn },
100 { FocusOut, EVENT_FocusOut },
101 { KeymapNotify, X11DRV_KeymapNotify },
102 { Expose, X11DRV_Expose },
103 /* GraphicsExpose */
104 /* NoExpose */
105 /* VisibilityNotify */
106 /* CreateNotify */
107 /* DestroyNotify */
108 { UnmapNotify, X11DRV_UnmapNotify },
109 { MapNotify, X11DRV_MapNotify },
110 /* MapRequest */
111 /* ReparentNotify */
112 { ConfigureNotify, X11DRV_ConfigureNotify },
113 /* ConfigureRequest */
114 /* GravityNotify */
115 /* ResizeRequest */
116 /* CirculateNotify */
117 /* CirculateRequest */
118 { PropertyNotify, EVENT_PropertyNotify },
119 { SelectionClear, X11DRV_SelectionClear },
120 { SelectionRequest, X11DRV_SelectionRequest },
121 /* SelectionNotify */
122 /* ColormapNotify */
123 { ClientMessage, EVENT_ClientMessage },
124 { MappingNotify, X11DRV_MappingNotify },
127 static int nb_event_handlers = 18; /* change this if you add handlers above */
130 /* return the name of an X event */
131 static const char *dbgstr_event( int type )
133 static const char * const event_names[] =
135 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
136 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
137 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
138 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
139 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
140 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
141 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
142 "ClientMessage", "MappingNotify"
145 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
146 return wine_dbg_sprintf( "Extension event %d", type );
150 /***********************************************************************
151 * find_handler
153 * Find the handler for a given event type. Caller must hold the x11 lock.
155 static inline x11drv_event_handler find_handler( int type )
157 int min = 0, max = nb_event_handlers - 1;
159 while (min <= max)
161 int pos = (min + max) / 2;
162 if (handlers[pos].type == type) return handlers[pos].handler;
163 if (handlers[pos].type > type) max = pos - 1;
164 else min = pos + 1;
166 return NULL;
170 /***********************************************************************
171 * X11DRV_register_event_handler
173 * Register a handler for a given event type.
174 * If already registered, overwrite the previous handler.
176 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
178 int min, max;
180 wine_tsx11_lock();
181 min = 0;
182 max = nb_event_handlers - 1;
183 while (min <= max)
185 int pos = (min + max) / 2;
186 if (handlers[pos].type == type)
188 handlers[pos].handler = handler;
189 goto done;
191 if (handlers[pos].type > type) max = pos - 1;
192 else min = pos + 1;
194 /* insert it between max and min */
195 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
196 handlers[min].type = type;
197 handlers[min].handler = handler;
198 nb_event_handlers++;
199 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
200 done:
201 wine_tsx11_unlock();
202 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
206 /***********************************************************************
207 * filter_event
209 static Bool filter_event( Display *display, XEvent *event, char *arg )
211 ULONG_PTR mask = (ULONG_PTR)arg;
213 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
215 switch(event->type)
217 case KeyPress:
218 case KeyRelease:
219 case KeymapNotify:
220 case MappingNotify:
221 return (mask & QS_KEY) != 0;
222 case ButtonPress:
223 case ButtonRelease:
224 return (mask & QS_MOUSEBUTTON) != 0;
225 case MotionNotify:
226 case EnterNotify:
227 case LeaveNotify:
228 return (mask & QS_MOUSEMOVE) != 0;
229 case Expose:
230 return (mask & QS_PAINT) != 0;
231 case FocusIn:
232 case FocusOut:
233 case MapNotify:
234 case UnmapNotify:
235 case ConfigureNotify:
236 case PropertyNotify:
237 case ClientMessage:
238 return (mask & QS_POSTMESSAGE) != 0;
239 default:
240 return (mask & QS_SENDMESSAGE) != 0;
245 /***********************************************************************
246 * process_events
248 static int process_events( Display *display, Bool (*filter)(), ULONG_PTR arg )
250 XEvent event;
251 HWND hwnd;
252 int count = 0;
253 x11drv_event_handler handler;
255 wine_tsx11_lock();
256 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
258 count++;
259 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
261 if (!(handler = find_handler( event.type )))
263 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event.type ), event.xany.window );
264 continue; /* no handler, ignore it */
267 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
268 hwnd = 0; /* not for a registered window */
269 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
271 wine_tsx11_unlock();
272 TRACE( "%s for hwnd/window %p/%lx\n",
273 dbgstr_event( event.type ), hwnd, event.xany.window );
274 handler( hwnd, &event );
275 wine_tsx11_lock();
277 XFlush( gdi_display );
278 wine_tsx11_unlock();
279 if (count) TRACE( "processed %d events\n", count );
280 return count;
284 /***********************************************************************
285 * MsgWaitForMultipleObjectsEx (X11DRV.@)
287 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
288 DWORD timeout, DWORD mask, DWORD flags )
290 DWORD ret;
291 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
293 if (!data)
295 if (!count && !timeout) return WAIT_TIMEOUT;
296 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
297 timeout, flags & MWMO_ALERTABLE );
300 if (data->process_event_count) mask = 0; /* don't process nested events */
302 data->process_event_count++;
304 if (process_events( data->display, filter_event, mask )) ret = count - 1;
305 else if (count || timeout)
307 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
308 timeout, flags & MWMO_ALERTABLE );
309 if (ret == count - 1) process_events( data->display, filter_event, mask );
311 else ret = WAIT_TIMEOUT;
313 data->process_event_count--;
314 return ret;
317 /***********************************************************************
318 * EVENT_x11_time_to_win32_time
320 * Make our timer and the X timer line up as best we can
321 * Pass 0 to retrieve the current adjustment value (times -1)
323 DWORD EVENT_x11_time_to_win32_time(Time time)
325 static DWORD adjust = 0;
326 DWORD now = GetTickCount();
327 DWORD ret;
329 if (! adjust && time != 0)
331 ret = now;
332 adjust = time - now;
334 else
336 /* If we got an event in the 'future', then our clock is clearly wrong.
337 If we got it more than 10000 ms in the future, then it's most likely
338 that the clock has wrapped. */
340 ret = time - adjust;
341 if (ret > now && ((ret - now) < 10000) && time != 0)
343 adjust += ret - now;
344 ret -= ret - now;
348 return ret;
352 /*******************************************************************
353 * can_activate_window
355 * Check if we can activate the specified window.
357 static inline BOOL can_activate_window( HWND hwnd )
359 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
360 if (!(style & WS_VISIBLE)) return FALSE;
361 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
362 if (hwnd == GetDesktopWindow()) return FALSE;
363 return !(style & WS_DISABLED);
367 /**********************************************************************
368 * set_focus
370 static void set_focus( HWND hwnd, Time time )
372 HWND focus;
373 Window win;
375 TRACE( "setting foreground window to %p\n", hwnd );
376 SetForegroundWindow( hwnd );
378 focus = GetFocus();
379 if (focus) focus = GetAncestor( focus, GA_ROOT );
380 win = X11DRV_get_whole_window(focus);
382 if (win)
384 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
385 wine_tsx11_lock();
386 XSetInputFocus( thread_display(), win, RevertToParent, time );
387 wine_tsx11_unlock();
392 /**********************************************************************
393 * handle_wm_protocols
395 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
397 Atom protocol = (Atom)event->data.l[0];
399 if (!protocol) return;
401 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
403 /* Ignore the delete window request if the window has been disabled
404 * and we are in managed mode. This is to disallow applications from
405 * being closed by the window manager while in a modal state.
407 if (IsWindowEnabled(hwnd))
409 HMENU hSysMenu;
411 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
412 hSysMenu = GetSystemMenu(hwnd, FALSE);
413 if (hSysMenu)
415 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
416 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
417 return;
419 if (GetActiveWindow() != hwnd)
421 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
422 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
423 MAKELONG(HTCLOSE,WM_LBUTTONDOWN) );
424 switch(ma)
426 case MA_NOACTIVATEANDEAT:
427 case MA_ACTIVATEANDEAT:
428 return;
429 case MA_NOACTIVATE:
430 break;
431 case MA_ACTIVATE:
432 case 0:
433 SetActiveWindow(hwnd);
434 break;
435 default:
436 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
437 break;
440 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
443 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
445 Time event_time = (Time)event->data.l[1];
446 HWND last_focus = x11drv_thread_data()->last_focus;
448 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
449 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
450 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
452 if (can_activate_window(hwnd))
454 /* simulate a mouse click on the caption to find out
455 * whether the window wants to be activated */
456 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
457 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
458 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
459 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
461 set_focus( hwnd, event_time );
462 return;
465 /* try to find some other window to give the focus to */
466 hwnd = GetFocus();
467 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
468 if (!hwnd) hwnd = GetActiveWindow();
469 if (!hwnd) hwnd = last_focus;
470 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
472 else if (protocol == x11drv_atom(_NET_WM_PING))
474 XClientMessageEvent xev;
475 xev = *event;
477 TRACE("NET_WM Ping\n");
478 wine_tsx11_lock();
479 xev.window = DefaultRootWindow(xev.display);
480 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
481 wine_tsx11_unlock();
482 /* this line is semi-stolen from gtk2 */
483 TRACE("NET_WM Pong\n");
488 static const char * const focus_details[] =
490 "NotifyAncestor",
491 "NotifyVirtual",
492 "NotifyInferior",
493 "NotifyNonlinear",
494 "NotifyNonlinearVirtual",
495 "NotifyPointer",
496 "NotifyPointerRoot",
497 "NotifyDetailNone"
500 /**********************************************************************
501 * EVENT_FocusIn
503 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
505 XFocusChangeEvent *event = &xev->xfocus;
506 XIC xic;
508 if (!hwnd) return;
510 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
512 if (event->detail == NotifyPointer) return;
514 if ((xic = X11DRV_get_ic( hwnd )))
516 wine_tsx11_lock();
517 XSetICFocus( xic );
518 wine_tsx11_unlock();
520 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
522 if (!can_activate_window(hwnd))
524 HWND hwnd = GetFocus();
525 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
526 if (!hwnd) hwnd = GetActiveWindow();
527 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
528 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
530 else SetForegroundWindow( hwnd );
534 /**********************************************************************
535 * EVENT_FocusOut
537 * Note: only top-level windows get FocusOut events.
539 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
541 XFocusChangeEvent *event = &xev->xfocus;
542 HWND hwnd_tmp;
543 Window focus_win;
544 int revert;
545 XIC xic;
547 if (!hwnd) return;
549 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
551 if (event->detail == NotifyPointer) return;
552 if (ximInComposeMode) return;
554 x11drv_thread_data()->last_focus = hwnd;
555 if ((xic = X11DRV_get_ic( hwnd )))
557 wine_tsx11_lock();
558 XUnsetICFocus( xic );
559 wine_tsx11_unlock();
561 if (hwnd != GetForegroundWindow()) return;
562 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
564 /* don't reset the foreground window, if the window which is
565 getting the focus is a Wine window */
567 wine_tsx11_lock();
568 XGetInputFocus( thread_display(), &focus_win, &revert );
569 if (focus_win)
571 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
572 focus_win = 0;
574 wine_tsx11_unlock();
576 if (!focus_win)
578 /* Abey : 6-Oct-99. Check again if the focus out window is the
579 Foreground window, because in most cases the messages sent
580 above must have already changed the foreground window, in which
581 case we don't have to change the foreground window to 0 */
582 if (hwnd == GetForegroundWindow())
584 TRACE( "lost focus, setting fg to desktop\n" );
585 SetForegroundWindow( GetDesktopWindow() );
591 /***********************************************************************
592 * get_window_wm_state
594 int get_window_wm_state( Display *display, struct x11drv_win_data *data )
596 struct
598 CARD32 state;
599 XID icon;
600 } *state;
601 Atom type;
602 int format, ret = -1;
603 unsigned long count, remaining;
605 wine_tsx11_lock();
606 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
607 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
608 &type, &format, &count, &remaining, (unsigned char **)&state ))
610 if (type == x11drv_atom(WM_STATE) && format && count >= sizeof(*state)/(format/8))
611 ret = state->state;
612 XFree( state );
614 wine_tsx11_unlock();
615 return ret;
619 /***********************************************************************
620 * EVENT_PropertyNotify
622 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
624 XPropertyEvent *event = &xev->xproperty;
625 struct x11drv_win_data *data;
627 if (!hwnd) return;
628 if (!(data = X11DRV_get_win_data( hwnd ))) return;
630 switch(event->state)
632 case PropertyDelete:
633 if (event->atom == x11drv_atom(WM_STATE))
635 data->wm_state = WithdrawnState;
636 TRACE( "%p/%lx: WM_STATE deleted\n", data->hwnd, data->whole_window );
638 break;
640 case PropertyNewValue:
641 if (event->atom == x11drv_atom(WM_STATE))
643 int new_state = get_window_wm_state( event->display, data );
644 if (new_state != -1 && new_state != data->wm_state)
646 TRACE( "%p/%lx: new WM_STATE %d\n", data->hwnd, data->whole_window, new_state );
647 data->wm_state = new_state;
650 break;
655 /* event filter to wait for a WM_STATE change notification on a window */
656 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
658 return (event->type == PropertyNotify &&
659 event->xproperty.window == (Window)arg &&
660 event->xproperty.atom == x11drv_atom(WM_STATE));
663 /***********************************************************************
664 * wait_for_withdrawn_state
666 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data )
668 DWORD end = GetTickCount() + 2000;
670 if (!data->whole_window || !data->managed) return;
672 while (data->wm_state != WithdrawnState &&
673 !process_events( display, is_wm_state_notify, data->whole_window ))
675 struct pollfd pfd;
676 int timeout = end - GetTickCount();
678 TRACE( "waiting for window %p/%lx to become withdrawn\n", data->hwnd, data->whole_window );
679 pfd.fd = ConnectionNumber(display);
680 pfd.events = POLLIN;
681 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
683 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
684 return;
690 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
692 RECT tempRect;
694 if (!IsWindowEnabled(hQueryWnd)) return 0;
696 GetWindowRect(hQueryWnd, &tempRect);
698 if(!PtInRect(&tempRect, *lpPt)) return 0;
700 if (!IsIconic( hQueryWnd ))
702 POINT pt = *lpPt;
703 ScreenToClient( hQueryWnd, &pt );
704 GetClientRect( hQueryWnd, &tempRect );
706 if (PtInRect( &tempRect, pt))
708 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
709 if (ret && ret != hQueryWnd)
711 ret = find_drop_window( ret, lpPt );
712 if (ret) return ret;
717 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
719 ScreenToClient(hQueryWnd, lpPt);
721 return hQueryWnd;
724 /**********************************************************************
725 * EVENT_DropFromOffix
727 * don't know if it still works (last Changelog is from 96/11/04)
729 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
731 unsigned long data_length;
732 unsigned long aux_long;
733 unsigned char* p_data = NULL;
734 Atom atom_aux;
735 int x, y, dummy;
736 BOOL bAccept;
737 Window win, w_aux_root, w_aux_child;
738 WND* pWnd;
739 HWND hScope = hWnd;
741 win = X11DRV_get_whole_window(hWnd);
742 wine_tsx11_lock();
743 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
744 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
745 x += virtual_screen_rect.left;
746 y += virtual_screen_rect.top;
747 wine_tsx11_unlock();
749 pWnd = WIN_GetPtr(hWnd);
751 /* find out drop point and drop window */
752 if( x < 0 || y < 0 ||
753 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
754 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
756 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
757 x = 0;
758 y = 0;
760 else
762 POINT pt = { x, y };
763 HWND hwndDrop = find_drop_window( hWnd, &pt );
764 if (hwndDrop)
766 x = pt.x;
767 y = pt.y;
768 hScope = hwndDrop;
769 bAccept = TRUE;
771 else
773 bAccept = FALSE;
776 WIN_ReleasePtr(pWnd);
778 if (!bAccept) return;
780 wine_tsx11_lock();
781 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
782 x11drv_atom(DndSelection), 0, 65535, FALSE,
783 AnyPropertyType, &atom_aux, &dummy,
784 &data_length, &aux_long, &p_data);
785 wine_tsx11_unlock();
787 if( !aux_long && p_data) /* don't bother if > 64K */
789 char *p = (char *)p_data;
790 char *p_drop;
792 aux_long = 0;
793 while( *p ) /* calculate buffer size */
795 INT len = GetShortPathNameA( p, NULL, 0 );
796 if (len) aux_long += len + 1;
797 p += strlen(p) + 1;
799 if( aux_long && aux_long < 65535 )
801 HDROP hDrop;
802 DROPFILES *lpDrop;
804 aux_long += sizeof(DROPFILES) + 1;
805 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
806 lpDrop = (DROPFILES*)GlobalLock( hDrop );
808 if( lpDrop )
810 WND *pDropWnd = WIN_GetPtr( hScope );
811 lpDrop->pFiles = sizeof(DROPFILES);
812 lpDrop->pt.x = x;
813 lpDrop->pt.y = y;
814 lpDrop->fNC =
815 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
816 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
817 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
818 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
819 lpDrop->fWide = FALSE;
820 WIN_ReleasePtr(pDropWnd);
821 p_drop = (char *)(lpDrop + 1);
822 p = (char *)p_data;
823 while(*p)
825 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
826 p_drop += strlen( p_drop ) + 1;
827 p += strlen(p) + 1;
829 *p_drop = '\0';
830 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
834 wine_tsx11_lock();
835 if( p_data ) XFree(p_data);
836 wine_tsx11_unlock();
839 /**********************************************************************
840 * EVENT_DropURLs
842 * drop items are separated by \n
843 * each item is prefixed by its mime type
845 * event->data.l[3], event->data.l[4] contains drop x,y position
847 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
849 unsigned long data_length;
850 unsigned long aux_long, drop_len = 0;
851 unsigned char *p_data = NULL; /* property data */
852 char *p_drop = NULL;
853 char *p, *next;
854 int x, y;
855 DROPFILES *lpDrop;
856 HDROP hDrop;
857 union {
858 Atom atom_aux;
859 int i;
860 Window w_aux;
861 unsigned int u;
862 } u; /* unused */
864 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
866 wine_tsx11_lock();
867 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
868 x11drv_atom(DndSelection), 0, 65535, FALSE,
869 AnyPropertyType, &u.atom_aux, &u.i,
870 &data_length, &aux_long, &p_data);
871 wine_tsx11_unlock();
872 if (aux_long)
873 WARN("property too large, truncated!\n");
874 TRACE("urls=%s\n", p_data);
876 if( !aux_long && p_data) { /* don't bother if > 64K */
877 /* calculate length */
878 p = (char*) p_data;
879 next = strchr(p, '\n');
880 while (p) {
881 if (next) *next=0;
882 if (strncmp(p,"file:",5) == 0 ) {
883 INT len = GetShortPathNameA( p+5, NULL, 0 );
884 if (len) drop_len += len + 1;
886 if (next) {
887 *next = '\n';
888 p = next + 1;
889 next = strchr(p, '\n');
890 } else {
891 p = NULL;
895 if( drop_len && drop_len < 65535 ) {
896 wine_tsx11_lock();
897 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
898 &x, &y, &u.i, &u.i, &u.u);
899 x += virtual_screen_rect.left;
900 y += virtual_screen_rect.top;
901 wine_tsx11_unlock();
903 drop_len += sizeof(DROPFILES) + 1;
904 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
905 lpDrop = (DROPFILES *) GlobalLock( hDrop );
907 if( lpDrop ) {
908 WND *pDropWnd = WIN_GetPtr( hWnd );
909 lpDrop->pFiles = sizeof(DROPFILES);
910 lpDrop->pt.x = x;
911 lpDrop->pt.y = y;
912 lpDrop->fNC =
913 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
914 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
915 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
916 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
917 lpDrop->fWide = FALSE;
918 p_drop = (char*)(lpDrop + 1);
919 WIN_ReleasePtr(pDropWnd);
922 /* create message content */
923 if (p_drop) {
924 p = (char*) p_data;
925 next = strchr(p, '\n');
926 while (p) {
927 if (next) *next=0;
928 if (strncmp(p,"file:",5) == 0 ) {
929 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
930 if (len) {
931 TRACE("drop file %s as %s\n", p+5, p_drop);
932 p_drop += len+1;
933 } else {
934 WARN("can't convert file %s to dos name\n", p+5);
936 } else {
937 WARN("unknown mime type %s\n", p);
939 if (next) {
940 *next = '\n';
941 p = next + 1;
942 next = strchr(p, '\n');
943 } else {
944 p = NULL;
946 *p_drop = '\0';
949 GlobalUnlock(hDrop);
950 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
953 wine_tsx11_lock();
954 if( p_data ) XFree(p_data);
955 wine_tsx11_unlock();
959 /**********************************************************************
960 * handle_dnd_protocol
962 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
964 Window root, child;
965 int root_x, root_y, child_x, child_y;
966 unsigned int u;
968 /* query window (drag&drop event contains only drag window) */
969 wine_tsx11_lock();
970 XQueryPointer( event->display, root_window, &root, &child,
971 &root_x, &root_y, &child_x, &child_y, &u);
972 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
973 wine_tsx11_unlock();
974 if (!hwnd) return;
975 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
976 EVENT_DropFromOffiX(hwnd, event);
977 else if (event->data.l[0] == DndURL)
978 EVENT_DropURLs(hwnd, event);
982 struct client_message_handler
984 int atom; /* protocol atom */
985 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
988 static const struct client_message_handler client_messages[] =
990 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
991 { XATOM_DndProtocol, handle_dnd_protocol },
992 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
993 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
994 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
995 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
999 /**********************************************************************
1000 * EVENT_ClientMessage
1002 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
1004 XClientMessageEvent *event = &xev->xclient;
1005 unsigned int i;
1007 if (!hwnd) return;
1009 if (event->format != 32)
1011 WARN( "Don't know how to handle format %d\n", event->format );
1012 return;
1015 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1017 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1019 client_messages[i].handler( hwnd, event );
1020 return;
1023 TRACE( "no handler found for %ld\n", event->message_type );
1027 /**********************************************************************
1028 * X11DRV_WindowMessage (X11DRV.@)
1030 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1032 switch(msg)
1034 case WM_X11DRV_ACQUIRE_SELECTION:
1035 return X11DRV_AcquireClipboard( hwnd );
1036 case WM_X11DRV_DELETE_WINDOW:
1037 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1038 case WM_X11DRV_SET_WIN_FORMAT:
1039 return X11DRV_set_win_format( hwnd, (XID)wp );
1040 case WM_X11DRV_RESIZE_DESKTOP:
1041 X11DRV_resize_desktop( LOWORD(lp), HIWORD(lp) );
1042 return 0;
1043 default:
1044 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
1045 return 0;
1050 /***********************************************************************
1051 * X11DRV_SendInput (X11DRV.@)
1053 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
1055 UINT i;
1057 for (i = 0; i < count; i++, inputs++)
1059 switch(inputs->type)
1061 case INPUT_MOUSE:
1062 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
1063 inputs->u.mi.mouseData, inputs->u.mi.time,
1064 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
1065 break;
1066 case INPUT_KEYBOARD:
1067 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
1068 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
1069 break;
1070 case INPUT_HARDWARE:
1071 FIXME( "INPUT_HARDWARE not supported\n" );
1072 break;
1075 return count;