Release 0.9.39.
[wine/gsoc-2012-control.git] / dlls / winex11.drv / event.c
blobe3047fd895db23688b74f065277e9ffd4c6ba0ad
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 #include <X11/Xatom.h>
25 #include <X11/keysym.h>
26 #include <X11/Xlib.h>
27 #include <X11/Xresource.h>
28 #include <X11/Xutil.h>
30 #include <assert.h>
31 #include <stdarg.h>
32 #include <string.h>
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winuser.h"
39 #include "wingdi.h"
40 #include "shlobj.h" /* DROPFILES */
42 #include "win.h"
43 #include "x11drv.h"
44 #include "shellapi.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(event);
49 extern BOOL ximInComposeMode;
51 #define DndNotDnd -1 /* OffiX drag&drop */
52 #define DndUnknown 0
53 #define DndRawData 1
54 #define DndFile 2
55 #define DndFiles 3
56 #define DndText 4
57 #define DndDir 5
58 #define DndLink 6
59 #define DndExe 7
61 #define DndEND 8
63 #define DndURL 128 /* KDE drag&drop */
65 /* Event handlers */
66 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
67 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
68 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
69 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
71 struct event_handler
73 int type; /* event type */
74 x11drv_event_handler handler; /* corresponding handler function */
77 #define MAX_EVENT_HANDLERS 64
79 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
81 /* list must be sorted by event type */
82 { KeyPress, X11DRV_KeyEvent },
83 { KeyRelease, X11DRV_KeyEvent },
84 { ButtonPress, X11DRV_ButtonPress },
85 { ButtonRelease, X11DRV_ButtonRelease },
86 { MotionNotify, X11DRV_MotionNotify },
87 { EnterNotify, X11DRV_EnterNotify },
88 /* LeaveNotify */
89 { FocusIn, EVENT_FocusIn },
90 { FocusOut, EVENT_FocusOut },
91 { KeymapNotify, X11DRV_KeymapNotify },
92 { Expose, X11DRV_Expose },
93 /* GraphicsExpose */
94 /* NoExpose */
95 /* VisibilityNotify */
96 /* CreateNotify */
97 /* DestroyNotify */
98 { UnmapNotify, X11DRV_UnmapNotify },
99 { MapNotify, X11DRV_MapNotify },
100 /* MapRequest */
101 /* ReparentNotify */
102 { ConfigureNotify, X11DRV_ConfigureNotify },
103 /* ConfigureRequest */
104 /* GravityNotify */
105 /* ResizeRequest */
106 /* CirculateNotify */
107 /* CirculateRequest */
108 { PropertyNotify, EVENT_PropertyNotify },
109 { SelectionClear, X11DRV_SelectionClear },
110 { SelectionRequest, X11DRV_SelectionRequest },
111 /* SelectionNotify */
112 /* ColormapNotify */
113 { ClientMessage, EVENT_ClientMessage },
114 { MappingNotify, X11DRV_MappingNotify },
117 static int nb_event_handlers = 18; /* change this if you add handlers above */
120 /* return the name of an X event */
121 static const char *dbgstr_event( int type )
123 static const char * const event_names[] =
125 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
126 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
127 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
128 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
129 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
130 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
131 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
132 "ClientMessage", "MappingNotify"
135 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
136 return wine_dbg_sprintf( "Extension event %d", type );
140 /***********************************************************************
141 * find_handler
143 * Find the handler for a given event type. Caller must hold the x11 lock.
145 static inline x11drv_event_handler find_handler( int type )
147 int min = 0, max = nb_event_handlers - 1;
149 while (min <= max)
151 int pos = (min + max) / 2;
152 if (handlers[pos].type == type) return handlers[pos].handler;
153 if (handlers[pos].type > type) max = pos - 1;
154 else min = pos + 1;
156 return NULL;
160 /***********************************************************************
161 * X11DRV_register_event_handler
163 * Register a handler for a given event type.
164 * If already registered, overwrite the previous handler.
166 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
168 int min, max;
170 wine_tsx11_lock();
171 min = 0;
172 max = nb_event_handlers - 1;
173 while (min <= max)
175 int pos = (min + max) / 2;
176 if (handlers[pos].type == type)
178 handlers[pos].handler = handler;
179 goto done;
181 if (handlers[pos].type > type) max = pos - 1;
182 else min = pos + 1;
184 /* insert it between max and min */
185 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
186 handlers[min].type = type;
187 handlers[min].handler = handler;
188 nb_event_handlers++;
189 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
190 done:
191 wine_tsx11_unlock();
192 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
196 /***********************************************************************
197 * filter_event
199 static Bool filter_event( Display *display, XEvent *event, char *arg )
201 ULONG_PTR mask = (ULONG_PTR)arg;
203 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
205 switch(event->type)
207 case KeyPress:
208 case KeyRelease:
209 case KeymapNotify:
210 case MappingNotify:
211 return (mask & QS_KEY) != 0;
212 case ButtonPress:
213 case ButtonRelease:
214 return (mask & QS_MOUSEBUTTON) != 0;
215 case MotionNotify:
216 case EnterNotify:
217 case LeaveNotify:
218 return (mask & QS_MOUSEMOVE) != 0;
219 case Expose:
220 return (mask & QS_PAINT) != 0;
221 case FocusIn:
222 case FocusOut:
223 case MapNotify:
224 case UnmapNotify:
225 case ConfigureNotify:
226 case PropertyNotify:
227 case ClientMessage:
228 return (mask & QS_POSTMESSAGE) != 0;
229 default:
230 return (mask & QS_SENDMESSAGE) != 0;
235 /***********************************************************************
236 * process_events
238 static int process_events( Display *display, ULONG_PTR mask )
240 XEvent event;
241 HWND hwnd;
242 int count = 0;
243 x11drv_event_handler handler;
245 wine_tsx11_lock();
246 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
248 count++;
249 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
251 if (!(handler = find_handler( event.type )))
253 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
254 continue; /* no handler, ignore it */
257 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
258 hwnd = 0; /* not for a registered window */
259 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
261 wine_tsx11_unlock();
262 TRACE( "%s for hwnd/window %p/%lx\n",
263 dbgstr_event( event.type ), hwnd, event.xany.window );
264 handler( hwnd, &event );
265 wine_tsx11_lock();
267 XFlush( gdi_display );
268 wine_tsx11_unlock();
269 if (count) TRACE( "processed %d events\n", count );
270 return count;
274 /***********************************************************************
275 * MsgWaitForMultipleObjectsEx (X11DRV.@)
277 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
278 DWORD timeout, DWORD mask, DWORD flags )
280 DWORD ret;
281 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
283 if (!data)
285 if (!count && !timeout) return WAIT_TIMEOUT;
286 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
287 timeout, flags & MWMO_ALERTABLE );
290 if (data->process_event_count) mask = 0; /* don't process nested events */
292 data->process_event_count++;
294 if (process_events( data->display, mask )) ret = count - 1;
295 else if (count || timeout)
297 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
298 timeout, flags & MWMO_ALERTABLE );
299 if (ret == count - 1) process_events( data->display, mask );
301 else ret = WAIT_TIMEOUT;
303 data->process_event_count--;
304 return ret;
307 /***********************************************************************
308 * EVENT_x11_time_to_win32_time
310 * Make our timer and the X timer line up as best we can
311 * Pass 0 to retrieve the current adjustment value (times -1)
313 DWORD EVENT_x11_time_to_win32_time(Time time)
315 static DWORD adjust = 0;
316 DWORD now = GetTickCount();
317 DWORD ret;
319 if (! adjust && time != 0)
321 ret = now;
322 adjust = time - now;
324 else
326 /* If we got an event in the 'future', then our clock is clearly wrong.
327 If we got it more than 10000 ms in the future, then it's most likely
328 that the clock has wrapped. */
330 ret = time - adjust;
331 if (ret > now && ((ret - now) < 10000) && time != 0)
333 adjust += ret - now;
334 ret -= ret - now;
338 return ret;
342 /*******************************************************************
343 * can_activate_window
345 * Check if we can activate the specified window.
347 static inline BOOL can_activate_window( HWND hwnd )
349 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
350 if (!(style & WS_VISIBLE)) return FALSE;
351 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
352 return !(style & WS_DISABLED);
356 /**********************************************************************
357 * set_focus
359 static void set_focus( HWND hwnd, Time time )
361 HWND focus;
362 Window win;
364 TRACE( "setting foreground window to %p\n", hwnd );
365 SetForegroundWindow( hwnd );
367 focus = GetFocus();
368 if (focus) focus = GetAncestor( focus, GA_ROOT );
369 win = X11DRV_get_whole_window(focus);
371 if (win)
373 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
374 wine_tsx11_lock();
375 XSetInputFocus( thread_display(), win, RevertToParent, time );
376 wine_tsx11_unlock();
381 /**********************************************************************
382 * handle_wm_protocols
384 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
386 Atom protocol = (Atom)event->data.l[0];
388 if (!protocol) return;
390 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
392 /* Ignore the delete window request if the window has been disabled
393 * and we are in managed mode. This is to disallow applications from
394 * being closed by the window manager while in a modal state.
396 if (IsWindowEnabled(hwnd))
398 HMENU hSysMenu;
400 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
401 hSysMenu = GetSystemMenu(hwnd, FALSE);
402 if (hSysMenu)
404 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
405 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
406 return;
408 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
411 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
413 Time event_time = (Time)event->data.l[1];
414 HWND last_focus = x11drv_thread_data()->last_focus;
416 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
417 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
418 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
420 if (can_activate_window(hwnd))
422 /* simulate a mouse click on the caption to find out
423 * whether the window wants to be activated */
424 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
425 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
426 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
427 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
428 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
430 else
432 hwnd = GetFocus();
433 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
434 if (!hwnd) hwnd = GetActiveWindow();
435 if (!hwnd) hwnd = last_focus;
436 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
439 else if (protocol == x11drv_atom(_NET_WM_PING))
441 XClientMessageEvent xev;
442 xev = *event;
444 TRACE("NET_WM Ping\n");
445 wine_tsx11_lock();
446 xev.window = DefaultRootWindow(xev.display);
447 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
448 wine_tsx11_unlock();
449 /* this line is semi-stolen from gtk2 */
450 TRACE("NET_WM Pong\n");
455 static const char * const focus_details[] =
457 "NotifyAncestor",
458 "NotifyVirtual",
459 "NotifyInferior",
460 "NotifyNonlinear",
461 "NotifyNonlinearVirtual",
462 "NotifyPointer",
463 "NotifyPointerRoot",
464 "NotifyDetailNone"
467 /**********************************************************************
468 * EVENT_FocusIn
470 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
472 XFocusChangeEvent *event = &xev->xfocus;
473 XIC xic;
475 if (!hwnd) return;
477 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
479 if (event->detail == NotifyPointer) return;
481 if ((xic = X11DRV_get_ic( hwnd )))
483 wine_tsx11_lock();
484 XSetICFocus( xic );
485 wine_tsx11_unlock();
487 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
489 if (!can_activate_window(hwnd))
491 HWND hwnd = GetFocus();
492 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
493 if (!hwnd) hwnd = GetActiveWindow();
494 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
495 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
497 else SetForegroundWindow( hwnd );
501 /**********************************************************************
502 * EVENT_FocusOut
504 * Note: only top-level windows get FocusOut events.
506 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
508 XFocusChangeEvent *event = &xev->xfocus;
509 HWND hwnd_tmp;
510 Window focus_win;
511 int revert;
512 XIC xic;
514 if (!hwnd) return;
516 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
518 if (event->detail == NotifyPointer) return;
519 if (ximInComposeMode) return;
521 x11drv_thread_data()->last_focus = hwnd;
522 if ((xic = X11DRV_get_ic( hwnd )))
524 wine_tsx11_lock();
525 XUnsetICFocus( xic );
526 wine_tsx11_unlock();
528 if (hwnd != GetForegroundWindow()) return;
529 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
531 /* don't reset the foreground window, if the window which is
532 getting the focus is a Wine window */
534 wine_tsx11_lock();
535 XGetInputFocus( thread_display(), &focus_win, &revert );
536 if (focus_win)
538 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
539 focus_win = 0;
541 wine_tsx11_unlock();
543 if (!focus_win)
545 /* Abey : 6-Oct-99. Check again if the focus out window is the
546 Foreground window, because in most cases the messages sent
547 above must have already changed the foreground window, in which
548 case we don't have to change the foreground window to 0 */
549 if (hwnd == GetForegroundWindow())
551 TRACE( "lost focus, setting fg to 0\n" );
552 SetForegroundWindow( 0 );
558 /***********************************************************************
559 * EVENT_PropertyNotify
560 * We use this to release resources like Pixmaps when a selection
561 * client no longer needs them.
563 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
565 XPropertyEvent *event = &xev->xproperty;
566 /* Check if we have any resources to free */
567 TRACE("Received PropertyNotify event:\n");
569 switch(event->state)
571 case PropertyDelete:
573 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
574 event->atom, (long)event->window);
575 break;
578 case PropertyNewValue:
580 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
581 event->atom, (long)event->window);
582 break;
585 default:
586 break;
590 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
592 RECT tempRect;
594 if (!IsWindowEnabled(hQueryWnd)) return 0;
596 GetWindowRect(hQueryWnd, &tempRect);
598 if(!PtInRect(&tempRect, *lpPt)) return 0;
600 if (!IsIconic( hQueryWnd ))
602 POINT pt = *lpPt;
603 ScreenToClient( hQueryWnd, &pt );
604 GetClientRect( hQueryWnd, &tempRect );
606 if (PtInRect( &tempRect, pt))
608 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
609 if (ret && ret != hQueryWnd)
611 ret = find_drop_window( ret, lpPt );
612 if (ret) return ret;
617 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
619 ScreenToClient(hQueryWnd, lpPt);
621 return hQueryWnd;
624 /**********************************************************************
625 * EVENT_DropFromOffix
627 * don't know if it still works (last Changlog is from 96/11/04)
629 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
631 unsigned long data_length;
632 unsigned long aux_long;
633 unsigned char* p_data = NULL;
634 Atom atom_aux;
635 int x, y, dummy;
636 BOOL bAccept;
637 Window win, w_aux_root, w_aux_child;
638 WND* pWnd;
639 HWND hScope = hWnd;
641 win = X11DRV_get_whole_window(hWnd);
642 wine_tsx11_lock();
643 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
644 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
645 x += virtual_screen_rect.left;
646 y += virtual_screen_rect.top;
647 wine_tsx11_unlock();
649 pWnd = WIN_GetPtr(hWnd);
651 /* find out drop point and drop window */
652 if( x < 0 || y < 0 ||
653 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
654 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
656 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
657 x = 0;
658 y = 0;
660 else
662 POINT pt = { x, y };
663 HWND hwndDrop = find_drop_window( hWnd, &pt );
664 if (hwndDrop)
666 x = pt.x;
667 y = pt.y;
668 hScope = hwndDrop;
669 bAccept = TRUE;
671 else
673 bAccept = FALSE;
676 WIN_ReleasePtr(pWnd);
678 if (!bAccept) return;
680 wine_tsx11_lock();
681 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
682 x11drv_atom(DndSelection), 0, 65535, FALSE,
683 AnyPropertyType, &atom_aux, &dummy,
684 &data_length, &aux_long, &p_data);
685 wine_tsx11_unlock();
687 if( !aux_long && p_data) /* don't bother if > 64K */
689 char *p = (char *)p_data;
690 char *p_drop;
692 aux_long = 0;
693 while( *p ) /* calculate buffer size */
695 INT len = GetShortPathNameA( p, NULL, 0 );
696 if (len) aux_long += len + 1;
697 p += strlen(p) + 1;
699 if( aux_long && aux_long < 65535 )
701 HDROP hDrop;
702 DROPFILES *lpDrop;
704 aux_long += sizeof(DROPFILES) + 1;
705 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
706 lpDrop = (DROPFILES*)GlobalLock( hDrop );
708 if( lpDrop )
710 WND *pDropWnd = WIN_GetPtr( hScope );
711 lpDrop->pFiles = sizeof(DROPFILES);
712 lpDrop->pt.x = x;
713 lpDrop->pt.y = y;
714 lpDrop->fNC =
715 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
716 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
717 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
718 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
719 lpDrop->fWide = FALSE;
720 WIN_ReleasePtr(pDropWnd);
721 p_drop = (char *)(lpDrop + 1);
722 p = (char *)p_data;
723 while(*p)
725 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
726 p_drop += strlen( p_drop ) + 1;
727 p += strlen(p) + 1;
729 *p_drop = '\0';
730 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
734 wine_tsx11_lock();
735 if( p_data ) XFree(p_data);
736 wine_tsx11_unlock();
739 /**********************************************************************
740 * EVENT_DropURLs
742 * drop items are separated by \n
743 * each item is prefixed by its mime type
745 * event->data.l[3], event->data.l[4] contains drop x,y position
747 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
749 unsigned long data_length;
750 unsigned long aux_long, drop_len = 0;
751 unsigned char *p_data = NULL; /* property data */
752 char *p_drop = NULL;
753 char *p, *next;
754 int x, y;
755 DROPFILES *lpDrop;
756 HDROP hDrop;
757 union {
758 Atom atom_aux;
759 int i;
760 Window w_aux;
761 unsigned int u;
762 } u; /* unused */
764 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
766 wine_tsx11_lock();
767 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
768 x11drv_atom(DndSelection), 0, 65535, FALSE,
769 AnyPropertyType, &u.atom_aux, &u.i,
770 &data_length, &aux_long, &p_data);
771 wine_tsx11_unlock();
772 if (aux_long)
773 WARN("property too large, truncated!\n");
774 TRACE("urls=%s\n", p_data);
776 if( !aux_long && p_data) { /* don't bother if > 64K */
777 /* calculate length */
778 p = (char*) p_data;
779 next = strchr(p, '\n');
780 while (p) {
781 if (next) *next=0;
782 if (strncmp(p,"file:",5) == 0 ) {
783 INT len = GetShortPathNameA( p+5, NULL, 0 );
784 if (len) drop_len += len + 1;
786 if (next) {
787 *next = '\n';
788 p = next + 1;
789 next = strchr(p, '\n');
790 } else {
791 p = NULL;
795 if( drop_len && drop_len < 65535 ) {
796 wine_tsx11_lock();
797 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
798 &x, &y, &u.i, &u.i, &u.u);
799 x += virtual_screen_rect.left;
800 y += virtual_screen_rect.top;
801 wine_tsx11_unlock();
803 drop_len += sizeof(DROPFILES) + 1;
804 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
805 lpDrop = (DROPFILES *) GlobalLock( hDrop );
807 if( lpDrop ) {
808 WND *pDropWnd = WIN_GetPtr( hWnd );
809 lpDrop->pFiles = sizeof(DROPFILES);
810 lpDrop->pt.x = (INT)x;
811 lpDrop->pt.y = (INT)y;
812 lpDrop->fNC =
813 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
814 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
815 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
816 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
817 lpDrop->fWide = FALSE;
818 p_drop = (char*)(lpDrop + 1);
819 WIN_ReleasePtr(pDropWnd);
822 /* create message content */
823 if (p_drop) {
824 p = (char*) p_data;
825 next = strchr(p, '\n');
826 while (p) {
827 if (next) *next=0;
828 if (strncmp(p,"file:",5) == 0 ) {
829 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
830 if (len) {
831 TRACE("drop file %s as %s\n", p+5, p_drop);
832 p_drop += len+1;
833 } else {
834 WARN("can't convert file %s to dos name\n", p+5);
836 } else {
837 WARN("unknown mime type %s\n", p);
839 if (next) {
840 *next = '\n';
841 p = next + 1;
842 next = strchr(p, '\n');
843 } else {
844 p = NULL;
846 *p_drop = '\0';
849 GlobalUnlock(hDrop);
850 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
853 wine_tsx11_lock();
854 if( p_data ) XFree(p_data);
855 wine_tsx11_unlock();
859 /**********************************************************************
860 * handle_dnd_protocol
862 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
864 Window root, child;
865 int root_x, root_y, child_x, child_y;
866 unsigned int u;
868 /* query window (drag&drop event contains only drag window) */
869 wine_tsx11_lock();
870 XQueryPointer( event->display, root_window, &root, &child,
871 &root_x, &root_y, &child_x, &child_y, &u);
872 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
873 wine_tsx11_unlock();
874 if (!hwnd) return;
875 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
876 EVENT_DropFromOffiX(hwnd, event);
877 else if (event->data.l[0] == DndURL)
878 EVENT_DropURLs(hwnd, event);
882 struct client_message_handler
884 int atom; /* protocol atom */
885 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
888 static const struct client_message_handler client_messages[] =
890 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
891 { XATOM_DndProtocol, handle_dnd_protocol },
892 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
893 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
894 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
895 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
899 /**********************************************************************
900 * EVENT_ClientMessage
902 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
904 XClientMessageEvent *event = &xev->xclient;
905 unsigned int i;
907 if (!hwnd) return;
909 if (event->format != 32)
911 WARN( "Don't know how to handle format %d\n", event->format );
912 return;
915 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
917 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
919 client_messages[i].handler( hwnd, event );
920 return;
923 TRACE( "no handler found for %ld\n", event->message_type );
927 /**********************************************************************
928 * X11DRV_WindowMessage (X11DRV.@)
930 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
932 switch(msg)
934 case WM_X11DRV_ACQUIRE_SELECTION:
935 return X11DRV_AcquireClipboard( hwnd );
936 case WM_X11DRV_DELETE_WINDOW:
937 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
938 default:
939 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
940 return 0;
945 /***********************************************************************
946 * X11DRV_SendInput (X11DRV.@)
948 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
950 UINT i;
952 for (i = 0; i < count; i++, inputs++)
954 switch(inputs->type)
956 case INPUT_MOUSE:
957 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
958 inputs->u.mi.mouseData, inputs->u.mi.time,
959 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
960 break;
961 case INPUT_KEYBOARD:
962 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
963 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
964 break;
965 case INPUT_HARDWARE:
966 FIXME( "INPUT_HARDWARE not supported\n" );
967 break;
970 return count;