push 0a6b4a6c9e6bf38a9b3d5ed71f415701d1ca15d1
[wine/hacks.git] / dlls / winex11.drv / event.c
blobd06ade8cda7fb62d0acad1ec27f2d1121fb7991a
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 if (hwnd == GetDesktopWindow()) 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))
399 HMENU hSysMenu;
401 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
402 hSysMenu = GetSystemMenu(hwnd, FALSE);
403 if (hSysMenu)
405 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
406 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
407 return;
409 if (GetActiveWindow() != hwnd)
411 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
412 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
413 MAKELONG(HTCLOSE,WM_LBUTTONDOWN) );
414 switch(ma)
416 case MA_NOACTIVATEANDEAT:
417 case MA_ACTIVATEANDEAT:
418 return;
419 case MA_NOACTIVATE:
420 break;
421 case MA_ACTIVATE:
422 case 0:
423 SetActiveWindow(hwnd);
424 break;
425 default:
426 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
427 break;
430 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
433 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
435 Time event_time = (Time)event->data.l[1];
436 HWND last_focus = x11drv_thread_data()->last_focus;
438 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
439 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
440 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
442 if (can_activate_window(hwnd))
444 /* simulate a mouse click on the caption to find out
445 * whether the window wants to be activated */
446 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
447 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
448 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
449 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
451 set_focus( hwnd, event_time );
452 return;
455 /* try to find some other window to give the focus to */
456 hwnd = GetFocus();
457 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
458 if (!hwnd) hwnd = GetActiveWindow();
459 if (!hwnd) hwnd = last_focus;
460 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
462 else if (protocol == x11drv_atom(_NET_WM_PING))
464 XClientMessageEvent xev;
465 xev = *event;
467 TRACE("NET_WM Ping\n");
468 wine_tsx11_lock();
469 xev.window = DefaultRootWindow(xev.display);
470 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
471 wine_tsx11_unlock();
472 /* this line is semi-stolen from gtk2 */
473 TRACE("NET_WM Pong\n");
478 static const char * const focus_details[] =
480 "NotifyAncestor",
481 "NotifyVirtual",
482 "NotifyInferior",
483 "NotifyNonlinear",
484 "NotifyNonlinearVirtual",
485 "NotifyPointer",
486 "NotifyPointerRoot",
487 "NotifyDetailNone"
490 /**********************************************************************
491 * EVENT_FocusIn
493 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
495 XFocusChangeEvent *event = &xev->xfocus;
496 XIC xic;
498 if (!hwnd) return;
500 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
502 if (event->detail == NotifyPointer) return;
504 if ((xic = X11DRV_get_ic( hwnd )))
506 wine_tsx11_lock();
507 XSetICFocus( xic );
508 wine_tsx11_unlock();
510 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
512 if (!can_activate_window(hwnd))
514 HWND hwnd = GetFocus();
515 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
516 if (!hwnd) hwnd = GetActiveWindow();
517 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
518 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
520 else SetForegroundWindow( hwnd );
524 /**********************************************************************
525 * EVENT_FocusOut
527 * Note: only top-level windows get FocusOut events.
529 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
531 XFocusChangeEvent *event = &xev->xfocus;
532 HWND hwnd_tmp;
533 Window focus_win;
534 int revert;
535 XIC xic;
537 if (!hwnd) return;
539 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
541 if (event->detail == NotifyPointer) return;
542 if (ximInComposeMode) return;
544 x11drv_thread_data()->last_focus = hwnd;
545 if ((xic = X11DRV_get_ic( hwnd )))
547 wine_tsx11_lock();
548 XUnsetICFocus( xic );
549 wine_tsx11_unlock();
551 if (hwnd != GetForegroundWindow()) return;
552 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
554 /* don't reset the foreground window, if the window which is
555 getting the focus is a Wine window */
557 wine_tsx11_lock();
558 XGetInputFocus( thread_display(), &focus_win, &revert );
559 if (focus_win)
561 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
562 focus_win = 0;
564 wine_tsx11_unlock();
566 if (!focus_win)
568 /* Abey : 6-Oct-99. Check again if the focus out window is the
569 Foreground window, because in most cases the messages sent
570 above must have already changed the foreground window, in which
571 case we don't have to change the foreground window to 0 */
572 if (hwnd == GetForegroundWindow())
574 TRACE( "lost focus, setting fg to desktop\n" );
575 SetForegroundWindow( GetDesktopWindow() );
581 /***********************************************************************
582 * EVENT_PropertyNotify
583 * We use this to release resources like Pixmaps when a selection
584 * client no longer needs them.
586 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
588 XPropertyEvent *event = &xev->xproperty;
589 /* Check if we have any resources to free */
590 TRACE("Received PropertyNotify event:\n");
592 switch(event->state)
594 case PropertyDelete:
596 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
597 event->atom, (long)event->window);
598 break;
601 case PropertyNewValue:
603 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
604 event->atom, (long)event->window);
605 break;
608 default:
609 break;
613 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
615 RECT tempRect;
617 if (!IsWindowEnabled(hQueryWnd)) return 0;
619 GetWindowRect(hQueryWnd, &tempRect);
621 if(!PtInRect(&tempRect, *lpPt)) return 0;
623 if (!IsIconic( hQueryWnd ))
625 POINT pt = *lpPt;
626 ScreenToClient( hQueryWnd, &pt );
627 GetClientRect( hQueryWnd, &tempRect );
629 if (PtInRect( &tempRect, pt))
631 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
632 if (ret && ret != hQueryWnd)
634 ret = find_drop_window( ret, lpPt );
635 if (ret) return ret;
640 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
642 ScreenToClient(hQueryWnd, lpPt);
644 return hQueryWnd;
647 /**********************************************************************
648 * EVENT_DropFromOffix
650 * don't know if it still works (last Changlog is from 96/11/04)
652 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
654 unsigned long data_length;
655 unsigned long aux_long;
656 unsigned char* p_data = NULL;
657 Atom atom_aux;
658 int x, y, dummy;
659 BOOL bAccept;
660 Window win, w_aux_root, w_aux_child;
661 WND* pWnd;
662 HWND hScope = hWnd;
664 win = X11DRV_get_whole_window(hWnd);
665 wine_tsx11_lock();
666 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
667 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
668 x += virtual_screen_rect.left;
669 y += virtual_screen_rect.top;
670 wine_tsx11_unlock();
672 pWnd = WIN_GetPtr(hWnd);
674 /* find out drop point and drop window */
675 if( x < 0 || y < 0 ||
676 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
677 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
679 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
680 x = 0;
681 y = 0;
683 else
685 POINT pt = { x, y };
686 HWND hwndDrop = find_drop_window( hWnd, &pt );
687 if (hwndDrop)
689 x = pt.x;
690 y = pt.y;
691 hScope = hwndDrop;
692 bAccept = TRUE;
694 else
696 bAccept = FALSE;
699 WIN_ReleasePtr(pWnd);
701 if (!bAccept) return;
703 wine_tsx11_lock();
704 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
705 x11drv_atom(DndSelection), 0, 65535, FALSE,
706 AnyPropertyType, &atom_aux, &dummy,
707 &data_length, &aux_long, &p_data);
708 wine_tsx11_unlock();
710 if( !aux_long && p_data) /* don't bother if > 64K */
712 char *p = (char *)p_data;
713 char *p_drop;
715 aux_long = 0;
716 while( *p ) /* calculate buffer size */
718 INT len = GetShortPathNameA( p, NULL, 0 );
719 if (len) aux_long += len + 1;
720 p += strlen(p) + 1;
722 if( aux_long && aux_long < 65535 )
724 HDROP hDrop;
725 DROPFILES *lpDrop;
727 aux_long += sizeof(DROPFILES) + 1;
728 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
729 lpDrop = (DROPFILES*)GlobalLock( hDrop );
731 if( lpDrop )
733 WND *pDropWnd = WIN_GetPtr( hScope );
734 lpDrop->pFiles = sizeof(DROPFILES);
735 lpDrop->pt.x = x;
736 lpDrop->pt.y = y;
737 lpDrop->fNC =
738 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
739 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
740 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
741 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
742 lpDrop->fWide = FALSE;
743 WIN_ReleasePtr(pDropWnd);
744 p_drop = (char *)(lpDrop + 1);
745 p = (char *)p_data;
746 while(*p)
748 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
749 p_drop += strlen( p_drop ) + 1;
750 p += strlen(p) + 1;
752 *p_drop = '\0';
753 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
757 wine_tsx11_lock();
758 if( p_data ) XFree(p_data);
759 wine_tsx11_unlock();
762 /**********************************************************************
763 * EVENT_DropURLs
765 * drop items are separated by \n
766 * each item is prefixed by its mime type
768 * event->data.l[3], event->data.l[4] contains drop x,y position
770 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
772 unsigned long data_length;
773 unsigned long aux_long, drop_len = 0;
774 unsigned char *p_data = NULL; /* property data */
775 char *p_drop = NULL;
776 char *p, *next;
777 int x, y;
778 DROPFILES *lpDrop;
779 HDROP hDrop;
780 union {
781 Atom atom_aux;
782 int i;
783 Window w_aux;
784 unsigned int u;
785 } u; /* unused */
787 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
789 wine_tsx11_lock();
790 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
791 x11drv_atom(DndSelection), 0, 65535, FALSE,
792 AnyPropertyType, &u.atom_aux, &u.i,
793 &data_length, &aux_long, &p_data);
794 wine_tsx11_unlock();
795 if (aux_long)
796 WARN("property too large, truncated!\n");
797 TRACE("urls=%s\n", p_data);
799 if( !aux_long && p_data) { /* don't bother if > 64K */
800 /* calculate length */
801 p = (char*) p_data;
802 next = strchr(p, '\n');
803 while (p) {
804 if (next) *next=0;
805 if (strncmp(p,"file:",5) == 0 ) {
806 INT len = GetShortPathNameA( p+5, NULL, 0 );
807 if (len) drop_len += len + 1;
809 if (next) {
810 *next = '\n';
811 p = next + 1;
812 next = strchr(p, '\n');
813 } else {
814 p = NULL;
818 if( drop_len && drop_len < 65535 ) {
819 wine_tsx11_lock();
820 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
821 &x, &y, &u.i, &u.i, &u.u);
822 x += virtual_screen_rect.left;
823 y += virtual_screen_rect.top;
824 wine_tsx11_unlock();
826 drop_len += sizeof(DROPFILES) + 1;
827 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
828 lpDrop = (DROPFILES *) GlobalLock( hDrop );
830 if( lpDrop ) {
831 WND *pDropWnd = WIN_GetPtr( hWnd );
832 lpDrop->pFiles = sizeof(DROPFILES);
833 lpDrop->pt.x = (INT)x;
834 lpDrop->pt.y = (INT)y;
835 lpDrop->fNC =
836 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
837 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
838 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
839 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
840 lpDrop->fWide = FALSE;
841 p_drop = (char*)(lpDrop + 1);
842 WIN_ReleasePtr(pDropWnd);
845 /* create message content */
846 if (p_drop) {
847 p = (char*) p_data;
848 next = strchr(p, '\n');
849 while (p) {
850 if (next) *next=0;
851 if (strncmp(p,"file:",5) == 0 ) {
852 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
853 if (len) {
854 TRACE("drop file %s as %s\n", p+5, p_drop);
855 p_drop += len+1;
856 } else {
857 WARN("can't convert file %s to dos name\n", p+5);
859 } else {
860 WARN("unknown mime type %s\n", p);
862 if (next) {
863 *next = '\n';
864 p = next + 1;
865 next = strchr(p, '\n');
866 } else {
867 p = NULL;
869 *p_drop = '\0';
872 GlobalUnlock(hDrop);
873 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
876 wine_tsx11_lock();
877 if( p_data ) XFree(p_data);
878 wine_tsx11_unlock();
882 /**********************************************************************
883 * handle_dnd_protocol
885 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
887 Window root, child;
888 int root_x, root_y, child_x, child_y;
889 unsigned int u;
891 /* query window (drag&drop event contains only drag window) */
892 wine_tsx11_lock();
893 XQueryPointer( event->display, root_window, &root, &child,
894 &root_x, &root_y, &child_x, &child_y, &u);
895 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
896 wine_tsx11_unlock();
897 if (!hwnd) return;
898 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
899 EVENT_DropFromOffiX(hwnd, event);
900 else if (event->data.l[0] == DndURL)
901 EVENT_DropURLs(hwnd, event);
905 struct client_message_handler
907 int atom; /* protocol atom */
908 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
911 static const struct client_message_handler client_messages[] =
913 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
914 { XATOM_DndProtocol, handle_dnd_protocol },
915 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
916 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
917 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
918 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
922 /**********************************************************************
923 * EVENT_ClientMessage
925 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
927 XClientMessageEvent *event = &xev->xclient;
928 unsigned int i;
930 if (!hwnd) return;
932 if (event->format != 32)
934 WARN( "Don't know how to handle format %d\n", event->format );
935 return;
938 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
940 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
942 client_messages[i].handler( hwnd, event );
943 return;
946 TRACE( "no handler found for %ld\n", event->message_type );
950 /**********************************************************************
951 * X11DRV_WindowMessage (X11DRV.@)
953 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
955 switch(msg)
957 case WM_X11DRV_ACQUIRE_SELECTION:
958 return X11DRV_AcquireClipboard( hwnd );
959 case WM_X11DRV_DELETE_WINDOW:
960 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
961 case WM_X11DRV_SET_WIN_FORMAT:
962 return X11DRV_set_win_format( hwnd, (XID)wp );
963 default:
964 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
965 return 0;
970 /***********************************************************************
971 * X11DRV_SendInput (X11DRV.@)
973 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
975 UINT i;
977 for (i = 0; i < count; i++, inputs++)
979 switch(inputs->type)
981 case INPUT_MOUSE:
982 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
983 inputs->u.mi.mouseData, inputs->u.mi.time,
984 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
985 break;
986 case INPUT_KEYBOARD:
987 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
988 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
989 break;
990 case INPUT_HARDWARE:
991 FIXME( "INPUT_HARDWARE not supported\n" );
992 break;
995 return count;