Added full support for xbuttons (side mouse buttons).
[wine/multimedia.git] / dlls / x11drv / event.c
blob7ede4c7bab8f8bcf221bd142b9a70501ccfdee3f
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define COM_NO_WINDOWS_H
23 #include "config.h"
25 #include <X11/Xatom.h>
26 #include <X11/keysym.h>
27 #include <X11/Xlib.h>
28 #include <X11/Xresource.h>
29 #include <X11/Xutil.h>
30 #ifdef HAVE_LIBXXF86DGA2
31 #include <X11/extensions/xf86dga.h>
32 #endif
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <string.h>
38 #define NONAMELESSUNION
39 #define NONAMELESSSTRUCT
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winuser.h"
43 #include "wingdi.h"
44 #include "shlobj.h" /* DROPFILES */
46 #include "win.h"
47 #include "winreg.h"
48 #include "x11drv.h"
49 #include "shellapi.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(event);
54 extern BOOL ximInComposeMode;
56 #define DndNotDnd -1 /* OffiX drag&drop */
57 #define DndUnknown 0
58 #define DndRawData 1
59 #define DndFile 2
60 #define DndFiles 3
61 #define DndText 4
62 #define DndDir 5
63 #define DndLink 6
64 #define DndExe 7
66 #define DndEND 8
68 #define DndURL 128 /* KDE drag&drop */
70 /* Event handlers */
71 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
72 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
73 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
74 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
76 struct event_handler
78 int type; /* event type */
79 x11drv_event_handler handler; /* corresponding handler function */
82 #define MAX_EVENT_HANDLERS 64
84 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
86 /* list must be sorted by event type */
87 { KeyPress, X11DRV_KeyEvent },
88 { KeyRelease, X11DRV_KeyEvent },
89 { ButtonPress, X11DRV_ButtonPress },
90 { ButtonRelease, X11DRV_ButtonRelease },
91 { MotionNotify, X11DRV_MotionNotify },
92 { EnterNotify, X11DRV_EnterNotify },
93 /* LeaveNotify */
94 { FocusIn, EVENT_FocusIn },
95 { FocusOut, EVENT_FocusOut },
96 { KeymapNotify, X11DRV_KeymapNotify },
97 { Expose, X11DRV_Expose },
98 /* GraphicsExpose */
99 /* NoExpose */
100 /* VisibilityNotify */
101 /* CreateNotify */
102 /* DestroyNotify */
103 { UnmapNotify, X11DRV_UnmapNotify },
104 { MapNotify, X11DRV_MapNotify },
105 /* MapRequest */
106 /* ReparentNotify */
107 { ConfigureNotify, X11DRV_ConfigureNotify },
108 /* ConfigureRequest */
109 /* GravityNotify */
110 /* ResizeRequest */
111 /* CirculateNotify */
112 /* CirculateRequest */
113 { PropertyNotify, EVENT_PropertyNotify },
114 { SelectionClear, X11DRV_SelectionClear },
115 { SelectionRequest, X11DRV_SelectionRequest },
116 /* SelectionNotify */
117 /* ColormapNotify */
118 { ClientMessage, EVENT_ClientMessage },
119 { MappingNotify, X11DRV_MappingNotify },
122 static int nb_event_handlers = 18; /* change this if you add handlers above */
125 /* return the name of an X event */
126 static const char *dbgstr_event( int type )
128 static const char * const event_names[] =
130 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
131 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
132 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
133 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
134 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
135 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
136 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
137 "ClientMessage", "MappingNotify"
140 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
141 return wine_dbg_sprintf( "Extension event %d", type );
145 /***********************************************************************
146 * find_handler
148 * Find the handler for a given event type. Caller must hold the x11 lock.
150 static inline x11drv_event_handler find_handler( int type )
152 int min = 0, max = nb_event_handlers - 1;
154 while (min <= max)
156 int pos = (min + max) / 2;
157 if (handlers[pos].type == type) return handlers[pos].handler;
158 if (handlers[pos].type > type) max = pos - 1;
159 else min = pos + 1;
161 return NULL;
165 /***********************************************************************
166 * X11DRV_register_event_handler
168 * Register a handler for a given event type.
169 * If already registered, overwrite the previous handler.
171 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
173 int min, max;
175 wine_tsx11_lock();
176 min = 0;
177 max = nb_event_handlers - 1;
178 while (min <= max)
180 int pos = (min + max) / 2;
181 if (handlers[pos].type == type)
183 handlers[pos].handler = handler;
184 goto done;
186 if (handlers[pos].type > type) max = pos - 1;
187 else min = pos + 1;
189 /* insert it between max and min */
190 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
191 handlers[min].type = type;
192 handlers[min].handler = handler;
193 nb_event_handlers++;
194 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
195 done:
196 wine_tsx11_unlock();
197 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
201 /***********************************************************************
202 * filter_event
204 static Bool filter_event( Display *display, XEvent *event, char *arg )
206 DWORD mask = (ULONG_PTR)arg;
208 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
210 switch(event->type)
212 case KeyPress:
213 case KeyRelease:
214 case KeymapNotify:
215 return (mask & QS_KEY) != 0;
216 case ButtonPress:
217 case ButtonRelease:
218 return (mask & QS_MOUSEBUTTON) != 0;
219 case MotionNotify:
220 case EnterNotify:
221 case LeaveNotify:
222 return (mask & QS_MOUSEMOVE) != 0;
223 case Expose:
224 return (mask & QS_PAINT) != 0;
225 case ClientMessage:
226 return (mask & QS_POSTMESSAGE) != 0;
227 default:
228 return (mask & QS_SENDMESSAGE) != 0;
233 /***********************************************************************
234 * process_events
236 static int process_events( Display *display, DWORD mask )
238 XEvent event;
239 HWND hwnd;
240 int count = 0;
241 x11drv_event_handler handler;
243 wine_tsx11_lock();
244 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
246 count++;
247 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
249 if (!(handler = find_handler( event.type )))
251 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
252 continue; /* no handler, ignore it */
255 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
256 hwnd = 0; /* not for a registered window */
257 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
259 wine_tsx11_unlock();
260 TRACE( "%s for hwnd/window %p/%lx\n",
261 dbgstr_event( event.type ), hwnd, event.xany.window );
262 handler( hwnd, &event );
263 wine_tsx11_lock();
265 wine_tsx11_unlock();
266 if (count) TRACE( "processed %d events\n", count );
267 return count;
271 /***********************************************************************
272 * MsgWaitForMultipleObjectsEx (X11DRV.@)
274 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
275 DWORD timeout, DWORD mask, DWORD flags )
277 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
278 DWORD i, ret;
279 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
281 if (!data || data->process_event_count)
282 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
283 timeout, flags & MWMO_ALERTABLE );
285 /* check whether only server queue handle was passed in */
286 if (count < 2) flags &= ~MWMO_WAITALL;
288 for (i = 0; i < count; i++) new_handles[i] = handles[i];
289 new_handles[count] = data->display_fd;
291 wine_tsx11_lock();
292 XFlush( gdi_display );
293 XFlush( data->display );
294 wine_tsx11_unlock();
296 data->process_event_count++;
297 if (process_events( data->display, mask )) ret = count;
298 else
300 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
301 timeout, flags & MWMO_ALERTABLE );
302 if (ret == count) process_events( data->display, mask );
304 data->process_event_count--;
305 return ret;
308 /***********************************************************************
309 * EVENT_x11_time_to_win32_time
311 * Make our timer and the X timer line up as best we can
312 * Pass 0 to retrieve the current adjustment value (times -1)
314 DWORD EVENT_x11_time_to_win32_time(Time time)
316 static DWORD adjust = 0;
317 DWORD now = GetTickCount();
318 DWORD ret;
320 if (! adjust && time != 0)
322 ret = now;
323 adjust = time - now;
325 else
327 /* If we got an event in the 'future', then our clock is clearly wrong.
328 If we got it more than 10000 ms in the future, then it's most likely
329 that the clock has wrapped. */
331 ret = time - adjust;
332 if (ret > now && ((ret - now) < 10000) && time != 0)
334 adjust += ret - now;
335 ret -= ret - now;
339 return ret;
343 /*******************************************************************
344 * can_activate_window
346 * Check if we can activate the specified window.
348 inline static BOOL can_activate_window( HWND hwnd )
350 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
351 if (!(style & WS_VISIBLE)) return FALSE;
352 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
353 return !(style & WS_DISABLED);
357 /**********************************************************************
358 * set_focus
360 static void set_focus( HWND hwnd, Time time )
362 HWND focus;
363 Window win;
365 TRACE( "setting foreground window to %p\n", hwnd );
366 SetForegroundWindow( hwnd );
368 focus = GetFocus();
369 if (focus) focus = GetAncestor( focus, GA_ROOT );
370 win = X11DRV_get_whole_window(focus);
372 if (win)
374 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
375 wine_tsx11_lock();
376 XSetInputFocus( thread_display(), win, RevertToParent, time );
377 wine_tsx11_unlock();
382 /**********************************************************************
383 * handle_wm_protocols
385 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
387 Atom protocol = (Atom)event->data.l[0];
389 if (!protocol) return;
391 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
393 /* Ignore the delete window request if the window has been disabled
394 * and we are in managed mode. This is to disallow applications from
395 * being closed by the window manager while in a modal state.
397 if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
399 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
401 Time event_time = (Time)event->data.l[1];
402 HWND last_focus = x11drv_thread_data()->last_focus;
404 TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
405 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
406 GetForegroundWindow(), last_focus );
408 if (can_activate_window(hwnd))
410 /* simulate a mouse click on the caption to find out
411 * whether the window wants to be activated */
412 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
413 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
414 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
415 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
416 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
418 else
420 hwnd = GetFocus();
421 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
422 if (!hwnd) hwnd = GetActiveWindow();
423 if (!hwnd) hwnd = last_focus;
424 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
427 else if (protocol == x11drv_atom(_NET_WM_PING))
429 XClientMessageEvent xev;
430 xev = *event;
432 TRACE("NET_WM Ping\n");
433 xev.window = DefaultRootWindow(xev.display);
434 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
435 /* this line is semi-stolen from gtk2 */
436 TRACE("NET_WM Pong\n");
441 static const char * const focus_details[] =
443 "NotifyAncestor",
444 "NotifyVirtual",
445 "NotifyInferior",
446 "NotifyNonlinear",
447 "NotifyNonlinearVirtual",
448 "NotifyPointer",
449 "NotifyPointerRoot",
450 "NotifyDetailNone"
453 /**********************************************************************
454 * EVENT_FocusIn
456 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
458 XFocusChangeEvent *event = &xev->xfocus;
459 XIC xic;
461 if (!hwnd) return;
463 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
465 if (event->detail == NotifyPointer) return;
467 if ((xic = X11DRV_get_ic( hwnd )))
469 wine_tsx11_lock();
470 XSetICFocus( xic );
471 wine_tsx11_unlock();
473 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
475 if (!can_activate_window(hwnd))
477 HWND hwnd = GetFocus();
478 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
479 if (!hwnd) hwnd = GetActiveWindow();
480 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
481 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
483 else SetForegroundWindow( hwnd );
487 /**********************************************************************
488 * EVENT_FocusOut
490 * Note: only top-level windows get FocusOut events.
492 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
494 XFocusChangeEvent *event = &xev->xfocus;
495 HWND hwnd_tmp;
496 Window focus_win;
497 int revert;
498 XIC xic;
500 if (!hwnd) return;
502 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
504 if (event->detail == NotifyPointer) return;
505 if (ximInComposeMode) return;
507 x11drv_thread_data()->last_focus = hwnd;
508 if ((xic = X11DRV_get_ic( hwnd )))
510 wine_tsx11_lock();
511 XUnsetICFocus( xic );
512 wine_tsx11_unlock();
514 if (hwnd != GetForegroundWindow()) return;
515 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
517 /* don't reset the foreground window, if the window which is
518 getting the focus is a Wine window */
520 wine_tsx11_lock();
521 XGetInputFocus( thread_display(), &focus_win, &revert );
522 if (focus_win)
524 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
525 focus_win = 0;
527 wine_tsx11_unlock();
529 if (!focus_win)
531 /* Abey : 6-Oct-99. Check again if the focus out window is the
532 Foreground window, because in most cases the messages sent
533 above must have already changed the foreground window, in which
534 case we don't have to change the foreground window to 0 */
535 if (hwnd == GetForegroundWindow())
537 TRACE( "lost focus, setting fg to 0\n" );
538 SetForegroundWindow( 0 );
544 /***********************************************************************
545 * EVENT_PropertyNotify
546 * We use this to release resources like Pixmaps when a selection
547 * client no longer needs them.
549 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
551 XPropertyEvent *event = &xev->xproperty;
552 /* Check if we have any resources to free */
553 TRACE("Received PropertyNotify event: \n");
555 switch(event->state)
557 case PropertyDelete:
559 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
560 event->atom, (long)event->window);
561 break;
564 case PropertyNewValue:
566 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
567 event->atom, (long)event->window);
568 break;
571 default:
572 break;
576 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
578 RECT tempRect;
580 if (!IsWindowEnabled(hQueryWnd)) return 0;
582 GetWindowRect(hQueryWnd, &tempRect);
584 if(!PtInRect(&tempRect, *lpPt)) return 0;
586 if (!IsIconic( hQueryWnd ))
588 GetClientRect( hQueryWnd, &tempRect );
589 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
591 if (PtInRect( &tempRect, *lpPt))
593 HWND *list = WIN_ListChildren( hQueryWnd );
594 HWND bResult = 0;
596 if (list)
598 int i;
600 for (i = 0; list[i]; i++)
602 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
604 GetWindowRect( list[i], &tempRect );
605 if (PtInRect( &tempRect, *lpPt )) break;
608 if (list[i])
610 if (IsWindowEnabled( list[i] ))
611 bResult = find_drop_window( list[i], lpPt );
613 HeapFree( GetProcessHeap(), 0, list );
615 if(bResult) return bResult;
619 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
621 ScreenToClient(hQueryWnd, lpPt);
623 return hQueryWnd;
626 /**********************************************************************
627 * EVENT_DropFromOffix
629 * don't know if it still works (last Changlog is from 96/11/04)
631 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
633 unsigned long data_length;
634 unsigned long aux_long;
635 unsigned char* p_data = NULL;
636 union {
637 Atom atom_aux;
638 struct {
639 int x;
640 int y;
641 } pt_aux;
642 int i;
643 } u;
644 int x, y;
645 BOOL bAccept;
646 Window win, w_aux_root, w_aux_child;
647 WND* pWnd;
648 HWND hScope = hWnd;
650 win = X11DRV_get_whole_window(hWnd);
651 wine_tsx11_lock();
652 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
653 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
654 (unsigned int*)&aux_long);
655 wine_tsx11_unlock();
657 pWnd = WIN_GetPtr(hWnd);
659 /* find out drop point and drop window */
660 if( x < 0 || y < 0 ||
661 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
662 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
664 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
665 x = 0;
666 y = 0;
668 else
670 POINT pt = { x, y };
671 HWND hwndDrop = find_drop_window( hWnd, &pt );
672 if (hwndDrop)
674 x = pt.x;
675 y = pt.y;
676 hScope = hwndDrop;
677 bAccept = TRUE;
679 else
681 bAccept = FALSE;
684 WIN_ReleasePtr(pWnd);
686 if (!bAccept) return;
688 wine_tsx11_lock();
689 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
690 x11drv_atom(DndSelection), 0, 65535, FALSE,
691 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
692 &data_length, &aux_long, &p_data);
693 wine_tsx11_unlock();
695 if( !aux_long && p_data) /* don't bother if > 64K */
697 signed char *p = (signed char*) p_data;
698 char *p_drop;
700 aux_long = 0;
701 while( *p ) /* calculate buffer size */
703 p_drop = p;
704 if((u.i = *p) != -1 )
706 INT len = GetShortPathNameA( p, NULL, 0 );
707 if (len) aux_long += len + 1;
708 else *p = -1;
710 p += strlen(p) + 1;
712 if( aux_long && aux_long < 65535 )
714 HDROP hDrop;
715 DROPFILES *lpDrop;
717 aux_long += sizeof(DROPFILES) + 1;
718 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
719 lpDrop = (DROPFILES*)GlobalLock( hDrop );
721 if( lpDrop )
723 WND *pDropWnd = WIN_GetPtr( hScope );
724 lpDrop->pFiles = sizeof(DROPFILES);
725 lpDrop->pt.x = x;
726 lpDrop->pt.y = y;
727 lpDrop->fNC =
728 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
729 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
730 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
731 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
732 lpDrop->fWide = FALSE;
733 WIN_ReleasePtr(pDropWnd);
734 p_drop = (char *)(lpDrop + 1);
735 p = p_data;
736 while(*p)
738 if( *p != -1 ) /* use only "good" entries */
740 GetShortPathNameA( p, p_drop, 65535 );
741 p_drop += strlen( p_drop ) + 1;
743 p += strlen(p) + 1;
745 *p_drop = '\0';
746 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
750 wine_tsx11_lock();
751 if( p_data ) XFree(p_data);
752 wine_tsx11_unlock();
755 /**********************************************************************
756 * EVENT_DropURLs
758 * drop items are separated by \n
759 * each item is prefixed by its mime type
761 * event->data.l[3], event->data.l[4] contains drop x,y position
763 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
765 unsigned long data_length;
766 unsigned long aux_long, drop_len = 0;
767 unsigned char *p_data = NULL; /* property data */
768 char *p_drop = NULL;
769 char *p, *next;
770 int x, y;
771 DROPFILES *lpDrop;
772 HDROP hDrop;
773 union {
774 Atom atom_aux;
775 int i;
776 Window w_aux;
777 } u; /* unused */
779 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
781 wine_tsx11_lock();
782 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
783 x11drv_atom(DndSelection), 0, 65535, FALSE,
784 AnyPropertyType, &u.atom_aux, &u.i,
785 &data_length, &aux_long, &p_data);
786 wine_tsx11_unlock();
787 if (aux_long)
788 WARN("property too large, truncated!\n");
789 TRACE("urls=%s\n", p_data);
791 if( !aux_long && p_data) { /* don't bother if > 64K */
792 /* calculate length */
793 p = p_data;
794 next = strchr(p, '\n');
795 while (p) {
796 if (next) *next=0;
797 if (strncmp(p,"file:",5) == 0 ) {
798 INT len = GetShortPathNameA( p+5, NULL, 0 );
799 if (len) drop_len += len + 1;
801 if (next) {
802 *next = '\n';
803 p = next + 1;
804 next = strchr(p, '\n');
805 } else {
806 p = NULL;
810 if( drop_len && drop_len < 65535 ) {
811 wine_tsx11_lock();
812 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
813 &x, &y, &u.i, &u.i, &u.i);
814 wine_tsx11_unlock();
816 drop_len += sizeof(DROPFILES) + 1;
817 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
818 lpDrop = (DROPFILES *) GlobalLock( hDrop );
820 if( lpDrop ) {
821 WND *pDropWnd = WIN_GetPtr( hWnd );
822 lpDrop->pFiles = sizeof(DROPFILES);
823 lpDrop->pt.x = (INT)x;
824 lpDrop->pt.y = (INT)y;
825 lpDrop->fNC =
826 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
827 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
828 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
829 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
830 lpDrop->fWide = FALSE;
831 p_drop = (char*)(lpDrop + 1);
832 WIN_ReleasePtr(pDropWnd);
835 /* create message content */
836 if (p_drop) {
837 p = p_data;
838 next = strchr(p, '\n');
839 while (p) {
840 if (next) *next=0;
841 if (strncmp(p,"file:",5) == 0 ) {
842 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
843 if (len) {
844 TRACE("drop file %s as %s\n", p+5, p_drop);
845 p_drop += len+1;
846 } else {
847 WARN("can't convert file %s to dos name \n", p+5);
849 } else {
850 WARN("unknown mime type %s\n", p);
852 if (next) {
853 *next = '\n';
854 p = next + 1;
855 next = strchr(p, '\n');
856 } else {
857 p = NULL;
859 *p_drop = '\0';
862 GlobalUnlock(hDrop);
863 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
866 wine_tsx11_lock();
867 if( p_data ) XFree(p_data);
868 wine_tsx11_unlock();
872 /**********************************************************************
873 * handle_dnd_protocol
875 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
877 Window root, child;
878 int root_x, root_y, child_x, child_y;
879 unsigned int u;
881 /* query window (drag&drop event contains only drag window) */
882 wine_tsx11_lock();
883 XQueryPointer( event->display, root_window, &root, &child,
884 &root_x, &root_y, &child_x, &child_y, &u);
885 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
886 wine_tsx11_unlock();
887 if (!hwnd) return;
888 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
889 EVENT_DropFromOffiX(hwnd, event);
890 else if (event->data.l[0] == DndURL)
891 EVENT_DropURLs(hwnd, event);
895 struct client_message_handler
897 int atom; /* protocol atom */
898 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
901 static const struct client_message_handler client_messages[] =
903 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
904 { XATOM_DndProtocol, handle_dnd_protocol },
905 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
906 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
907 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
908 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
912 /**********************************************************************
913 * EVENT_ClientMessage
915 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
917 XClientMessageEvent *event = &xev->xclient;
918 unsigned int i;
920 if (!hwnd) return;
922 if (event->format != 32)
924 WARN( "Don't know how to handle format %d\n", event->format );
925 return;
928 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
930 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
932 client_messages[i].handler( hwnd, event );
933 return;
936 TRACE( "no handler found for %ld\n", event->message_type );
940 /**********************************************************************
941 * X11DRV_WindowMessage (X11DRV.@)
943 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
945 switch(msg)
947 case WM_X11DRV_ACQUIRE_SELECTION:
948 X11DRV_AcquireClipboard( hwnd );
949 return 0;
950 case WM_X11DRV_DELETE_WINDOW:
951 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
952 default:
953 FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
954 return 0;
959 /***********************************************************************
960 * X11DRV_SendInput (X11DRV.@)
962 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
964 UINT i;
966 for (i = 0; i < count; i++, inputs++)
968 switch(inputs->type)
970 case INPUT_MOUSE:
971 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
972 inputs->u.mi.mouseData, inputs->u.mi.time,
973 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
974 break;
975 case INPUT_KEYBOARD:
976 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
977 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
978 break;
979 case INPUT_HARDWARE:
980 FIXME( "INPUT_HARDWARE not supported\n" );
981 break;
984 return count;