push 014043c4937c940c54cd1214c96e33a3b3c8cf7d
[wine/hacks.git] / dlls / winex11.drv / event.c
blob30f0c573a8adda7ff542576e512a3f544e99fed7
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #ifdef HAVE_POLL_H
25 #include <poll.h>
26 #endif
27 #ifdef HAVE_SYS_POLL_H
28 #include <sys/poll.h>
29 #endif
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
36 #include <assert.h>
37 #include <stdarg.h>
38 #include <string.h>
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winuser.h"
45 #include "wingdi.h"
47 #include "x11drv.h"
49 /* avoid conflict with field names in included win32 headers */
50 #undef Status
51 #include "shlobj.h" /* DROPFILES */
52 #include "shellapi.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(event);
58 extern BOOL ximInComposeMode;
60 #define DndNotDnd -1 /* OffiX drag&drop */
61 #define DndUnknown 0
62 #define DndRawData 1
63 #define DndFile 2
64 #define DndFiles 3
65 #define DndText 4
66 #define DndDir 5
67 #define DndLink 6
68 #define DndExe 7
70 #define DndEND 8
72 #define DndURL 128 /* KDE drag&drop */
74 /* Event handlers */
75 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
76 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
77 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
78 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
80 struct event_handler
82 int type; /* event type */
83 x11drv_event_handler handler; /* corresponding handler function */
86 #define MAX_EVENT_HANDLERS 64
88 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
90 /* list must be sorted by event type */
91 { KeyPress, X11DRV_KeyEvent },
92 { KeyRelease, X11DRV_KeyEvent },
93 { ButtonPress, X11DRV_ButtonPress },
94 { ButtonRelease, X11DRV_ButtonRelease },
95 { MotionNotify, X11DRV_MotionNotify },
96 { EnterNotify, X11DRV_EnterNotify },
97 /* LeaveNotify */
98 { FocusIn, EVENT_FocusIn },
99 { FocusOut, EVENT_FocusOut },
100 { KeymapNotify, X11DRV_KeymapNotify },
101 { Expose, X11DRV_Expose },
102 /* GraphicsExpose */
103 /* NoExpose */
104 /* VisibilityNotify */
105 /* CreateNotify */
106 /* DestroyNotify */
107 { UnmapNotify, X11DRV_UnmapNotify },
108 { MapNotify, X11DRV_MapNotify },
109 /* MapRequest */
110 /* ReparentNotify */
111 { ConfigureNotify, X11DRV_ConfigureNotify },
112 /* ConfigureRequest */
113 /* GravityNotify */
114 /* ResizeRequest */
115 /* CirculateNotify */
116 /* CirculateRequest */
117 { PropertyNotify, EVENT_PropertyNotify },
118 { SelectionClear, X11DRV_SelectionClear },
119 { SelectionRequest, X11DRV_SelectionRequest },
120 /* SelectionNotify */
121 /* ColormapNotify */
122 { ClientMessage, EVENT_ClientMessage },
123 { MappingNotify, X11DRV_MappingNotify },
126 static int nb_event_handlers = 18; /* change this if you add handlers above */
129 /* return the name of an X event */
130 static const char *dbgstr_event( int type )
132 static const char * const event_names[] =
134 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
135 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
136 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
137 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
138 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
139 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
140 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
141 "ClientMessage", "MappingNotify"
144 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
145 return wine_dbg_sprintf( "Extension event %d", type );
149 /***********************************************************************
150 * find_handler
152 * Find the handler for a given event type. Caller must hold the x11 lock.
154 static inline x11drv_event_handler find_handler( int type )
156 int min = 0, max = nb_event_handlers - 1;
158 while (min <= max)
160 int pos = (min + max) / 2;
161 if (handlers[pos].type == type) return handlers[pos].handler;
162 if (handlers[pos].type > type) max = pos - 1;
163 else min = pos + 1;
165 return NULL;
169 /***********************************************************************
170 * X11DRV_register_event_handler
172 * Register a handler for a given event type.
173 * If already registered, overwrite the previous handler.
175 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
177 int min, max;
179 wine_tsx11_lock();
180 min = 0;
181 max = nb_event_handlers - 1;
182 while (min <= max)
184 int pos = (min + max) / 2;
185 if (handlers[pos].type == type)
187 handlers[pos].handler = handler;
188 goto done;
190 if (handlers[pos].type > type) max = pos - 1;
191 else min = pos + 1;
193 /* insert it between max and min */
194 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
195 handlers[min].type = type;
196 handlers[min].handler = handler;
197 nb_event_handlers++;
198 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
199 done:
200 wine_tsx11_unlock();
201 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
205 /***********************************************************************
206 * filter_event
208 static Bool filter_event( Display *display, XEvent *event, char *arg )
210 ULONG_PTR mask = (ULONG_PTR)arg;
212 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
214 switch(event->type)
216 case KeyPress:
217 case KeyRelease:
218 case KeymapNotify:
219 case MappingNotify:
220 return (mask & QS_KEY) != 0;
221 case ButtonPress:
222 case ButtonRelease:
223 return (mask & QS_MOUSEBUTTON) != 0;
224 case MotionNotify:
225 case EnterNotify:
226 case LeaveNotify:
227 return (mask & QS_MOUSEMOVE) != 0;
228 case Expose:
229 return (mask & QS_PAINT) != 0;
230 case FocusIn:
231 case FocusOut:
232 case MapNotify:
233 case UnmapNotify:
234 case ConfigureNotify:
235 case PropertyNotify:
236 case ClientMessage:
237 return (mask & QS_POSTMESSAGE) != 0;
238 default:
239 return (mask & QS_SENDMESSAGE) != 0;
244 /***********************************************************************
245 * process_events
247 static int process_events( Display *display, Bool (*filter)(), ULONG_PTR arg )
249 XEvent event;
250 HWND hwnd;
251 int count = 0;
252 x11drv_event_handler handler;
254 wine_tsx11_lock();
255 while (XCheckIfEvent( display, &event, filter, (char *)arg ))
257 count++;
258 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
260 if (!(handler = find_handler( event.type )))
262 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event.type ), event.xany.window );
263 continue; /* no handler, ignore it */
266 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
267 hwnd = 0; /* not for a registered window */
268 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
270 wine_tsx11_unlock();
271 TRACE( "%s for hwnd/window %p/%lx\n",
272 dbgstr_event( event.type ), hwnd, event.xany.window );
273 handler( hwnd, &event );
274 wine_tsx11_lock();
276 XFlush( gdi_display );
277 wine_tsx11_unlock();
278 if (count) TRACE( "processed %d events\n", count );
279 return count;
283 /***********************************************************************
284 * MsgWaitForMultipleObjectsEx (X11DRV.@)
286 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
287 DWORD timeout, DWORD mask, DWORD flags )
289 DWORD ret;
290 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
292 if (!data)
294 if (!count && !timeout) return WAIT_TIMEOUT;
295 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
296 timeout, flags & MWMO_ALERTABLE );
299 if (data->process_event_count) mask = 0; /* don't process nested events */
301 data->process_event_count++;
303 if (process_events( data->display, filter_event, mask )) ret = count - 1;
304 else if (count || timeout)
306 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
307 timeout, flags & MWMO_ALERTABLE );
308 if (ret == count - 1) process_events( data->display, filter_event, mask );
310 else ret = WAIT_TIMEOUT;
312 data->process_event_count--;
313 return ret;
316 /***********************************************************************
317 * EVENT_x11_time_to_win32_time
319 * Make our timer and the X timer line up as best we can
320 * Pass 0 to retrieve the current adjustment value (times -1)
322 DWORD EVENT_x11_time_to_win32_time(Time time)
324 static DWORD adjust = 0;
325 DWORD now = GetTickCount();
326 DWORD ret;
328 if (! adjust && time != 0)
330 ret = now;
331 adjust = time - now;
333 else
335 /* If we got an event in the 'future', then our clock is clearly wrong.
336 If we got it more than 10000 ms in the future, then it's most likely
337 that the clock has wrapped. */
339 ret = time - adjust;
340 if (ret > now && ((ret - now) < 10000) && time != 0)
342 adjust += ret - now;
343 ret -= ret - now;
347 return ret;
351 /*******************************************************************
352 * can_activate_window
354 * Check if we can activate the specified window.
356 static inline BOOL can_activate_window( HWND hwnd )
358 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
359 if (!(style & WS_VISIBLE)) return FALSE;
360 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
361 if (hwnd == GetDesktopWindow()) return FALSE;
362 return !(style & WS_DISABLED);
366 /**********************************************************************
367 * set_focus
369 static void set_focus( HWND hwnd, Time time )
371 HWND focus;
372 Window win;
374 TRACE( "setting foreground window to %p\n", hwnd );
375 SetForegroundWindow( hwnd );
377 focus = GetFocus();
378 if (focus) focus = GetAncestor( focus, GA_ROOT );
379 win = X11DRV_get_whole_window(focus);
381 if (win)
383 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
384 wine_tsx11_lock();
385 XSetInputFocus( thread_display(), win, RevertToParent, time );
386 wine_tsx11_unlock();
391 /**********************************************************************
392 * handle_wm_protocols
394 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
396 Atom protocol = (Atom)event->data.l[0];
398 if (!protocol) return;
400 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
402 /* Ignore the delete window request if the window has been disabled
403 * and we are in managed mode. This is to disallow applications from
404 * being closed by the window manager while in a modal state.
406 if (IsWindowEnabled(hwnd))
408 HMENU hSysMenu;
410 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
411 hSysMenu = GetSystemMenu(hwnd, FALSE);
412 if (hSysMenu)
414 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
415 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
416 return;
418 if (GetActiveWindow() != hwnd)
420 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
421 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
422 MAKELONG(HTCLOSE,WM_LBUTTONDOWN) );
423 switch(ma)
425 case MA_NOACTIVATEANDEAT:
426 case MA_ACTIVATEANDEAT:
427 return;
428 case MA_NOACTIVATE:
429 break;
430 case MA_ACTIVATE:
431 case 0:
432 SetActiveWindow(hwnd);
433 break;
434 default:
435 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
436 break;
439 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
442 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
444 Time event_time = (Time)event->data.l[1];
445 HWND last_focus = x11drv_thread_data()->last_focus;
447 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
448 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
449 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
451 if (can_activate_window(hwnd))
453 /* simulate a mouse click on the caption to find out
454 * whether the window wants to be activated */
455 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
456 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
457 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
458 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
460 set_focus( hwnd, event_time );
461 return;
464 /* try to find some other window to give the focus to */
465 hwnd = GetFocus();
466 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
467 if (!hwnd) hwnd = GetActiveWindow();
468 if (!hwnd) hwnd = last_focus;
469 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
471 else if (protocol == x11drv_atom(_NET_WM_PING))
473 XClientMessageEvent xev;
474 xev = *event;
476 TRACE("NET_WM Ping\n");
477 wine_tsx11_lock();
478 xev.window = DefaultRootWindow(xev.display);
479 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
480 wine_tsx11_unlock();
481 /* this line is semi-stolen from gtk2 */
482 TRACE("NET_WM Pong\n");
487 static const char * const focus_details[] =
489 "NotifyAncestor",
490 "NotifyVirtual",
491 "NotifyInferior",
492 "NotifyNonlinear",
493 "NotifyNonlinearVirtual",
494 "NotifyPointer",
495 "NotifyPointerRoot",
496 "NotifyDetailNone"
499 /**********************************************************************
500 * EVENT_FocusIn
502 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
504 XFocusChangeEvent *event = &xev->xfocus;
505 XIC xic;
507 if (!hwnd) return;
509 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
511 if (event->detail == NotifyPointer) return;
513 if ((xic = X11DRV_get_ic( hwnd )))
515 wine_tsx11_lock();
516 XSetICFocus( xic );
517 wine_tsx11_unlock();
519 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
521 if (!can_activate_window(hwnd))
523 HWND hwnd = GetFocus();
524 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
525 if (!hwnd) hwnd = GetActiveWindow();
526 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
527 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
529 else SetForegroundWindow( hwnd );
533 /**********************************************************************
534 * EVENT_FocusOut
536 * Note: only top-level windows get FocusOut events.
538 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
540 XFocusChangeEvent *event = &xev->xfocus;
541 HWND hwnd_tmp;
542 Window focus_win;
543 int revert;
544 XIC xic;
546 if (!hwnd) return;
548 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
550 if (event->detail == NotifyPointer) return;
551 if (ximInComposeMode) return;
553 x11drv_thread_data()->last_focus = hwnd;
554 if ((xic = X11DRV_get_ic( hwnd )))
556 wine_tsx11_lock();
557 XUnsetICFocus( xic );
558 wine_tsx11_unlock();
560 if (hwnd != GetForegroundWindow()) return;
561 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
563 /* don't reset the foreground window, if the window which is
564 getting the focus is a Wine window */
566 wine_tsx11_lock();
567 XGetInputFocus( thread_display(), &focus_win, &revert );
568 if (focus_win)
570 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
571 focus_win = 0;
573 wine_tsx11_unlock();
575 if (!focus_win)
577 /* Abey : 6-Oct-99. Check again if the focus out window is the
578 Foreground window, because in most cases the messages sent
579 above must have already changed the foreground window, in which
580 case we don't have to change the foreground window to 0 */
581 if (hwnd == GetForegroundWindow())
583 TRACE( "lost focus, setting fg to desktop\n" );
584 SetForegroundWindow( GetDesktopWindow() );
590 /***********************************************************************
591 * get_window_wm_state
593 int get_window_wm_state( Display *display, struct x11drv_win_data *data )
595 struct
597 CARD32 state;
598 XID icon;
599 } *state;
600 Atom type;
601 int format, ret = -1;
602 unsigned long count, remaining;
604 wine_tsx11_lock();
605 if (!XGetWindowProperty( display, data->whole_window, x11drv_atom(WM_STATE), 0,
606 sizeof(*state)/sizeof(CARD32), False, x11drv_atom(WM_STATE),
607 &type, &format, &count, &remaining, (unsigned char **)&state ))
609 if (type == x11drv_atom(WM_STATE) && format && count >= sizeof(*state)/(format/8))
610 ret = state->state;
611 XFree( state );
613 wine_tsx11_unlock();
614 return ret;
618 /***********************************************************************
619 * EVENT_PropertyNotify
621 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
623 XPropertyEvent *event = &xev->xproperty;
624 struct x11drv_win_data *data;
626 if (!hwnd) return;
627 if (!(data = X11DRV_get_win_data( hwnd ))) return;
629 switch(event->state)
631 case PropertyDelete:
632 if (event->atom == x11drv_atom(WM_STATE))
634 data->wm_state = WithdrawnState;
635 TRACE( "%p/%lx: WM_STATE deleted\n", data->hwnd, data->whole_window );
637 break;
639 case PropertyNewValue:
640 if (event->atom == x11drv_atom(WM_STATE))
642 int new_state = get_window_wm_state( event->display, data );
643 if (new_state != -1 && new_state != data->wm_state)
645 TRACE( "%p/%lx: new WM_STATE %d\n", data->hwnd, data->whole_window, new_state );
646 data->wm_state = new_state;
649 break;
654 /* event filter to wait for a WM_STATE change notification on a window */
655 static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
657 return (event->type == PropertyNotify &&
658 event->xproperty.window == (Window)arg &&
659 event->xproperty.atom == x11drv_atom(WM_STATE));
662 /***********************************************************************
663 * wait_for_withdrawn_state
665 void wait_for_withdrawn_state( Display *display, struct x11drv_win_data *data )
667 DWORD end = GetTickCount() + 2000;
669 if (!data->whole_window || !data->managed) return;
671 while (data->wm_state != WithdrawnState &&
672 !process_events( display, is_wm_state_notify, data->whole_window ))
674 struct pollfd pfd;
675 int timeout = end - GetTickCount();
677 TRACE( "waiting for window %p/%lx to become withdrawn\n", data->hwnd, data->whole_window );
678 pfd.fd = ConnectionNumber(display);
679 pfd.events = POLLIN;
680 if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
682 FIXME( "window %p/%lx wait timed out\n", data->hwnd, data->whole_window );
683 return;
689 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
691 RECT tempRect;
693 if (!IsWindowEnabled(hQueryWnd)) return 0;
695 GetWindowRect(hQueryWnd, &tempRect);
697 if(!PtInRect(&tempRect, *lpPt)) return 0;
699 if (!IsIconic( hQueryWnd ))
701 POINT pt = *lpPt;
702 ScreenToClient( hQueryWnd, &pt );
703 GetClientRect( hQueryWnd, &tempRect );
705 if (PtInRect( &tempRect, pt))
707 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
708 if (ret && ret != hQueryWnd)
710 ret = find_drop_window( ret, lpPt );
711 if (ret) return ret;
716 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
718 ScreenToClient(hQueryWnd, lpPt);
720 return hQueryWnd;
723 /**********************************************************************
724 * EVENT_DropFromOffix
726 * don't know if it still works (last Changelog is from 96/11/04)
728 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
730 struct x11drv_win_data *data;
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 HWND hScope = hWnd;
740 win = X11DRV_get_whole_window(hWnd);
741 wine_tsx11_lock();
742 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
743 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
744 x += virtual_screen_rect.left;
745 y += virtual_screen_rect.top;
746 wine_tsx11_unlock();
748 if (!(data = X11DRV_get_win_data( hWnd ))) return;
750 /* find out drop point and drop window */
751 if( x < 0 || y < 0 ||
752 x > (data->whole_rect.right - data->whole_rect.left) ||
753 y > (data->whole_rect.bottom - data->whole_rect.top) )
755 bAccept = GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES;
756 x = 0;
757 y = 0;
759 else
761 POINT pt = { x, y };
762 HWND hwndDrop = find_drop_window( hWnd, &pt );
763 if (hwndDrop)
765 x = pt.x;
766 y = pt.y;
767 hScope = hwndDrop;
768 bAccept = TRUE;
770 else
772 bAccept = FALSE;
776 if (!bAccept) return;
778 wine_tsx11_lock();
779 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
780 x11drv_atom(DndSelection), 0, 65535, FALSE,
781 AnyPropertyType, &atom_aux, &dummy,
782 &data_length, &aux_long, &p_data);
783 wine_tsx11_unlock();
785 if( !aux_long && p_data) /* don't bother if > 64K */
787 char *p = (char *)p_data;
788 char *p_drop;
790 aux_long = 0;
791 while( *p ) /* calculate buffer size */
793 INT len = GetShortPathNameA( p, NULL, 0 );
794 if (len) aux_long += len + 1;
795 p += strlen(p) + 1;
797 if( aux_long && aux_long < 65535 )
799 HDROP hDrop;
800 DROPFILES *lpDrop;
802 aux_long += sizeof(DROPFILES) + 1;
803 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
804 lpDrop = (DROPFILES*)GlobalLock( hDrop );
806 if( lpDrop )
808 lpDrop->pFiles = sizeof(DROPFILES);
809 lpDrop->pt.x = x;
810 lpDrop->pt.y = y;
811 lpDrop->fNC = FALSE;
812 lpDrop->fWide = FALSE;
813 p_drop = (char *)(lpDrop + 1);
814 p = (char *)p_data;
815 while(*p)
817 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
818 p_drop += strlen( p_drop ) + 1;
819 p += strlen(p) + 1;
821 *p_drop = '\0';
822 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
826 wine_tsx11_lock();
827 if( p_data ) XFree(p_data);
828 wine_tsx11_unlock();
831 /**********************************************************************
832 * EVENT_DropURLs
834 * drop items are separated by \n
835 * each item is prefixed by its mime type
837 * event->data.l[3], event->data.l[4] contains drop x,y position
839 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
841 struct x11drv_win_data *win_data;
842 unsigned long data_length;
843 unsigned long aux_long, drop_len = 0;
844 unsigned char *p_data = NULL; /* property data */
845 char *p_drop = NULL;
846 char *p, *next;
847 int x, y;
848 DROPFILES *lpDrop;
849 HDROP hDrop;
850 union {
851 Atom atom_aux;
852 int i;
853 Window w_aux;
854 unsigned int u;
855 } u; /* unused */
857 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
859 wine_tsx11_lock();
860 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
861 x11drv_atom(DndSelection), 0, 65535, FALSE,
862 AnyPropertyType, &u.atom_aux, &u.i,
863 &data_length, &aux_long, &p_data);
864 wine_tsx11_unlock();
865 if (aux_long)
866 WARN("property too large, truncated!\n");
867 TRACE("urls=%s\n", p_data);
869 if( !aux_long && p_data) { /* don't bother if > 64K */
870 /* calculate length */
871 p = (char*) p_data;
872 next = strchr(p, '\n');
873 while (p) {
874 if (next) *next=0;
875 if (strncmp(p,"file:",5) == 0 ) {
876 INT len = GetShortPathNameA( p+5, NULL, 0 );
877 if (len) drop_len += len + 1;
879 if (next) {
880 *next = '\n';
881 p = next + 1;
882 next = strchr(p, '\n');
883 } else {
884 p = NULL;
888 if( drop_len && drop_len < 65535 ) {
889 wine_tsx11_lock();
890 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
891 &x, &y, &u.i, &u.i, &u.u);
892 x += virtual_screen_rect.left;
893 y += virtual_screen_rect.top;
894 wine_tsx11_unlock();
896 drop_len += sizeof(DROPFILES) + 1;
897 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
898 lpDrop = (DROPFILES *) GlobalLock( hDrop );
900 if( lpDrop && (win_data = X11DRV_get_win_data( hWnd )))
902 lpDrop->pFiles = sizeof(DROPFILES);
903 lpDrop->pt.x = x;
904 lpDrop->pt.y = y;
905 lpDrop->fNC =
906 ( x < (win_data->client_rect.left - win_data->whole_rect.left) ||
907 y < (win_data->client_rect.top - win_data->whole_rect.top) ||
908 x > (win_data->client_rect.right - win_data->whole_rect.left) ||
909 y > (win_data->client_rect.bottom - win_data->whole_rect.top) );
910 lpDrop->fWide = FALSE;
911 p_drop = (char*)(lpDrop + 1);
914 /* create message content */
915 if (p_drop) {
916 p = (char*) p_data;
917 next = strchr(p, '\n');
918 while (p) {
919 if (next) *next=0;
920 if (strncmp(p,"file:",5) == 0 ) {
921 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
922 if (len) {
923 TRACE("drop file %s as %s\n", p+5, p_drop);
924 p_drop += len+1;
925 } else {
926 WARN("can't convert file %s to dos name\n", p+5);
928 } else {
929 WARN("unknown mime type %s\n", p);
931 if (next) {
932 *next = '\n';
933 p = next + 1;
934 next = strchr(p, '\n');
935 } else {
936 p = NULL;
938 *p_drop = '\0';
941 GlobalUnlock(hDrop);
942 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
945 wine_tsx11_lock();
946 if( p_data ) XFree(p_data);
947 wine_tsx11_unlock();
951 /**********************************************************************
952 * handle_dnd_protocol
954 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
956 Window root, child;
957 int root_x, root_y, child_x, child_y;
958 unsigned int u;
960 /* query window (drag&drop event contains only drag window) */
961 wine_tsx11_lock();
962 XQueryPointer( event->display, root_window, &root, &child,
963 &root_x, &root_y, &child_x, &child_y, &u);
964 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
965 wine_tsx11_unlock();
966 if (!hwnd) return;
967 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
968 EVENT_DropFromOffiX(hwnd, event);
969 else if (event->data.l[0] == DndURL)
970 EVENT_DropURLs(hwnd, event);
974 struct client_message_handler
976 int atom; /* protocol atom */
977 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
980 static const struct client_message_handler client_messages[] =
982 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
983 { XATOM_DndProtocol, handle_dnd_protocol },
984 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
985 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
986 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
987 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
991 /**********************************************************************
992 * EVENT_ClientMessage
994 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
996 XClientMessageEvent *event = &xev->xclient;
997 unsigned int i;
999 if (!hwnd) return;
1001 if (event->format != 32)
1003 WARN( "Don't know how to handle format %d\n", event->format );
1004 return;
1007 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
1009 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
1011 client_messages[i].handler( hwnd, event );
1012 return;
1015 TRACE( "no handler found for %ld\n", event->message_type );
1019 /**********************************************************************
1020 * X11DRV_WindowMessage (X11DRV.@)
1022 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1024 switch(msg)
1026 case WM_X11DRV_ACQUIRE_SELECTION:
1027 return X11DRV_AcquireClipboard( hwnd );
1028 case WM_X11DRV_DELETE_WINDOW:
1029 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1030 case WM_X11DRV_SET_WIN_FORMAT:
1031 return X11DRV_set_win_format( hwnd, (XID)wp );
1032 case WM_X11DRV_RESIZE_DESKTOP:
1033 X11DRV_resize_desktop( LOWORD(lp), HIWORD(lp) );
1034 return 0;
1035 default:
1036 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
1037 return 0;
1042 /***********************************************************************
1043 * X11DRV_SendInput (X11DRV.@)
1045 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
1047 UINT i;
1049 for (i = 0; i < count; i++, inputs++)
1051 switch(inputs->type)
1053 case INPUT_MOUSE:
1054 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
1055 inputs->u.mi.mouseData, inputs->u.mi.time,
1056 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
1057 break;
1058 case INPUT_KEYBOARD:
1059 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
1060 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
1061 break;
1062 case INPUT_HARDWARE:
1063 FIXME( "INPUT_HARDWARE not supported\n" );
1064 break;
1067 return count;