Spelling fixes.
[wine/multimedia.git] / dlls / winex11.drv / event.c
blob726ff3ec84ac59d6fe09de29aef2bdfe850af79d
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"
41 #include "win.h"
42 #include "x11drv.h"
44 /* avoid conflict with field names in included win32 headers */
45 #undef Status
46 #include "shlobj.h" /* DROPFILES */
47 #include "shellapi.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(event);
53 extern BOOL ximInComposeMode;
55 #define DndNotDnd -1 /* OffiX drag&drop */
56 #define DndUnknown 0
57 #define DndRawData 1
58 #define DndFile 2
59 #define DndFiles 3
60 #define DndText 4
61 #define DndDir 5
62 #define DndLink 6
63 #define DndExe 7
65 #define DndEND 8
67 #define DndURL 128 /* KDE drag&drop */
69 /* Event handlers */
70 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
71 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
72 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
73 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
75 struct event_handler
77 int type; /* event type */
78 x11drv_event_handler handler; /* corresponding handler function */
81 #define MAX_EVENT_HANDLERS 64
83 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
85 /* list must be sorted by event type */
86 { KeyPress, X11DRV_KeyEvent },
87 { KeyRelease, X11DRV_KeyEvent },
88 { ButtonPress, X11DRV_ButtonPress },
89 { ButtonRelease, X11DRV_ButtonRelease },
90 { MotionNotify, X11DRV_MotionNotify },
91 { EnterNotify, X11DRV_EnterNotify },
92 /* LeaveNotify */
93 { FocusIn, EVENT_FocusIn },
94 { FocusOut, EVENT_FocusOut },
95 { KeymapNotify, X11DRV_KeymapNotify },
96 { Expose, X11DRV_Expose },
97 /* GraphicsExpose */
98 /* NoExpose */
99 /* VisibilityNotify */
100 /* CreateNotify */
101 /* DestroyNotify */
102 { UnmapNotify, X11DRV_UnmapNotify },
103 { MapNotify, X11DRV_MapNotify },
104 /* MapRequest */
105 /* ReparentNotify */
106 { ConfigureNotify, X11DRV_ConfigureNotify },
107 /* ConfigureRequest */
108 /* GravityNotify */
109 /* ResizeRequest */
110 /* CirculateNotify */
111 /* CirculateRequest */
112 { PropertyNotify, EVENT_PropertyNotify },
113 { SelectionClear, X11DRV_SelectionClear },
114 { SelectionRequest, X11DRV_SelectionRequest },
115 /* SelectionNotify */
116 /* ColormapNotify */
117 { ClientMessage, EVENT_ClientMessage },
118 { MappingNotify, X11DRV_MappingNotify },
121 static int nb_event_handlers = 18; /* change this if you add handlers above */
124 /* return the name of an X event */
125 static const char *dbgstr_event( int type )
127 static const char * const event_names[] =
129 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
130 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
131 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
132 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
133 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
134 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
135 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
136 "ClientMessage", "MappingNotify"
139 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
140 return wine_dbg_sprintf( "Extension event %d", type );
144 /***********************************************************************
145 * find_handler
147 * Find the handler for a given event type. Caller must hold the x11 lock.
149 static inline x11drv_event_handler find_handler( int type )
151 int min = 0, max = nb_event_handlers - 1;
153 while (min <= max)
155 int pos = (min + max) / 2;
156 if (handlers[pos].type == type) return handlers[pos].handler;
157 if (handlers[pos].type > type) max = pos - 1;
158 else min = pos + 1;
160 return NULL;
164 /***********************************************************************
165 * X11DRV_register_event_handler
167 * Register a handler for a given event type.
168 * If already registered, overwrite the previous handler.
170 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
172 int min, max;
174 wine_tsx11_lock();
175 min = 0;
176 max = nb_event_handlers - 1;
177 while (min <= max)
179 int pos = (min + max) / 2;
180 if (handlers[pos].type == type)
182 handlers[pos].handler = handler;
183 goto done;
185 if (handlers[pos].type > type) max = pos - 1;
186 else min = pos + 1;
188 /* insert it between max and min */
189 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
190 handlers[min].type = type;
191 handlers[min].handler = handler;
192 nb_event_handlers++;
193 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
194 done:
195 wine_tsx11_unlock();
196 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
200 /***********************************************************************
201 * filter_event
203 static Bool filter_event( Display *display, XEvent *event, char *arg )
205 ULONG_PTR mask = (ULONG_PTR)arg;
207 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
209 switch(event->type)
211 case KeyPress:
212 case KeyRelease:
213 case KeymapNotify:
214 case MappingNotify:
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 FocusIn:
226 case FocusOut:
227 case MapNotify:
228 case UnmapNotify:
229 case ConfigureNotify:
230 case PropertyNotify:
231 case ClientMessage:
232 return (mask & QS_POSTMESSAGE) != 0;
233 default:
234 return (mask & QS_SENDMESSAGE) != 0;
239 /***********************************************************************
240 * process_events
242 static int process_events( Display *display, ULONG_PTR mask )
244 XEvent event;
245 HWND hwnd;
246 int count = 0;
247 x11drv_event_handler handler;
249 wine_tsx11_lock();
250 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
252 count++;
253 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
255 if (!(handler = find_handler( event.type )))
257 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
258 continue; /* no handler, ignore it */
261 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
262 hwnd = 0; /* not for a registered window */
263 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
265 wine_tsx11_unlock();
266 TRACE( "%s for hwnd/window %p/%lx\n",
267 dbgstr_event( event.type ), hwnd, event.xany.window );
268 handler( hwnd, &event );
269 wine_tsx11_lock();
271 XFlush( gdi_display );
272 wine_tsx11_unlock();
273 if (count) TRACE( "processed %d events\n", count );
274 return count;
278 /***********************************************************************
279 * MsgWaitForMultipleObjectsEx (X11DRV.@)
281 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
282 DWORD timeout, DWORD mask, DWORD flags )
284 DWORD ret;
285 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
287 if (!data)
289 if (!count && !timeout) return WAIT_TIMEOUT;
290 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
291 timeout, flags & MWMO_ALERTABLE );
294 if (data->process_event_count) mask = 0; /* don't process nested events */
296 data->process_event_count++;
298 if (process_events( data->display, mask )) ret = count - 1;
299 else if (count || timeout)
301 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
302 timeout, flags & MWMO_ALERTABLE );
303 if (ret == count - 1) process_events( data->display, mask );
305 else ret = WAIT_TIMEOUT;
307 data->process_event_count--;
308 return ret;
311 /***********************************************************************
312 * EVENT_x11_time_to_win32_time
314 * Make our timer and the X timer line up as best we can
315 * Pass 0 to retrieve the current adjustment value (times -1)
317 DWORD EVENT_x11_time_to_win32_time(Time time)
319 static DWORD adjust = 0;
320 DWORD now = GetTickCount();
321 DWORD ret;
323 if (! adjust && time != 0)
325 ret = now;
326 adjust = time - now;
328 else
330 /* If we got an event in the 'future', then our clock is clearly wrong.
331 If we got it more than 10000 ms in the future, then it's most likely
332 that the clock has wrapped. */
334 ret = time - adjust;
335 if (ret > now && ((ret - now) < 10000) && time != 0)
337 adjust += ret - now;
338 ret -= ret - now;
342 return ret;
346 /*******************************************************************
347 * can_activate_window
349 * Check if we can activate the specified window.
351 static inline BOOL can_activate_window( HWND hwnd )
353 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
354 if (!(style & WS_VISIBLE)) return FALSE;
355 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
356 if (hwnd == GetDesktopWindow()) return FALSE;
357 return !(style & WS_DISABLED);
361 /**********************************************************************
362 * set_focus
364 static void set_focus( HWND hwnd, Time time )
366 HWND focus;
367 Window win;
369 TRACE( "setting foreground window to %p\n", hwnd );
370 SetForegroundWindow( hwnd );
372 focus = GetFocus();
373 if (focus) focus = GetAncestor( focus, GA_ROOT );
374 win = X11DRV_get_whole_window(focus);
376 if (win)
378 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
379 wine_tsx11_lock();
380 XSetInputFocus( thread_display(), win, RevertToParent, time );
381 wine_tsx11_unlock();
386 /**********************************************************************
387 * handle_wm_protocols
389 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
391 Atom protocol = (Atom)event->data.l[0];
393 if (!protocol) return;
395 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
397 /* Ignore the delete window request if the window has been disabled
398 * and we are in managed mode. This is to disallow applications from
399 * being closed by the window manager while in a modal state.
401 if (IsWindowEnabled(hwnd))
403 HMENU hSysMenu;
405 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
406 hSysMenu = GetSystemMenu(hwnd, FALSE);
407 if (hSysMenu)
409 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
410 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
411 return;
413 if (GetActiveWindow() != hwnd)
415 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
416 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
417 MAKELONG(HTCLOSE,WM_LBUTTONDOWN) );
418 switch(ma)
420 case MA_NOACTIVATEANDEAT:
421 case MA_ACTIVATEANDEAT:
422 return;
423 case MA_NOACTIVATE:
424 break;
425 case MA_ACTIVATE:
426 case 0:
427 SetActiveWindow(hwnd);
428 break;
429 default:
430 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
431 break;
434 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
437 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
439 Time event_time = (Time)event->data.l[1];
440 HWND last_focus = x11drv_thread_data()->last_focus;
442 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
443 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
444 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
446 if (can_activate_window(hwnd))
448 /* simulate a mouse click on the caption to find out
449 * whether the window wants to be activated */
450 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
451 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
452 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
453 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
455 set_focus( hwnd, event_time );
456 return;
459 /* try to find some other window to give the focus to */
460 hwnd = GetFocus();
461 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
462 if (!hwnd) hwnd = GetActiveWindow();
463 if (!hwnd) hwnd = last_focus;
464 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
466 else if (protocol == x11drv_atom(_NET_WM_PING))
468 XClientMessageEvent xev;
469 xev = *event;
471 TRACE("NET_WM Ping\n");
472 wine_tsx11_lock();
473 xev.window = DefaultRootWindow(xev.display);
474 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
475 wine_tsx11_unlock();
476 /* this line is semi-stolen from gtk2 */
477 TRACE("NET_WM Pong\n");
482 static const char * const focus_details[] =
484 "NotifyAncestor",
485 "NotifyVirtual",
486 "NotifyInferior",
487 "NotifyNonlinear",
488 "NotifyNonlinearVirtual",
489 "NotifyPointer",
490 "NotifyPointerRoot",
491 "NotifyDetailNone"
494 /**********************************************************************
495 * EVENT_FocusIn
497 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
499 XFocusChangeEvent *event = &xev->xfocus;
500 XIC xic;
502 if (!hwnd) return;
504 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
506 if (event->detail == NotifyPointer) return;
508 if ((xic = X11DRV_get_ic( hwnd )))
510 wine_tsx11_lock();
511 XSetICFocus( xic );
512 wine_tsx11_unlock();
514 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
516 if (!can_activate_window(hwnd))
518 HWND hwnd = GetFocus();
519 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
520 if (!hwnd) hwnd = GetActiveWindow();
521 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
522 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
524 else SetForegroundWindow( hwnd );
528 /**********************************************************************
529 * EVENT_FocusOut
531 * Note: only top-level windows get FocusOut events.
533 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
535 XFocusChangeEvent *event = &xev->xfocus;
536 HWND hwnd_tmp;
537 Window focus_win;
538 int revert;
539 XIC xic;
541 if (!hwnd) return;
543 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
545 if (event->detail == NotifyPointer) return;
546 if (ximInComposeMode) return;
548 x11drv_thread_data()->last_focus = hwnd;
549 if ((xic = X11DRV_get_ic( hwnd )))
551 wine_tsx11_lock();
552 XUnsetICFocus( xic );
553 wine_tsx11_unlock();
555 if (hwnd != GetForegroundWindow()) return;
556 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
558 /* don't reset the foreground window, if the window which is
559 getting the focus is a Wine window */
561 wine_tsx11_lock();
562 XGetInputFocus( thread_display(), &focus_win, &revert );
563 if (focus_win)
565 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
566 focus_win = 0;
568 wine_tsx11_unlock();
570 if (!focus_win)
572 /* Abey : 6-Oct-99. Check again if the focus out window is the
573 Foreground window, because in most cases the messages sent
574 above must have already changed the foreground window, in which
575 case we don't have to change the foreground window to 0 */
576 if (hwnd == GetForegroundWindow())
578 TRACE( "lost focus, setting fg to desktop\n" );
579 SetForegroundWindow( GetDesktopWindow() );
585 /***********************************************************************
586 * EVENT_PropertyNotify
587 * We use this to release resources like Pixmaps when a selection
588 * client no longer needs them.
590 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
592 XPropertyEvent *event = &xev->xproperty;
593 /* Check if we have any resources to free */
594 TRACE("Received PropertyNotify event:\n");
596 switch(event->state)
598 case PropertyDelete:
600 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
601 event->atom, (long)event->window);
602 break;
605 case PropertyNewValue:
607 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
608 event->atom, (long)event->window);
609 break;
612 default:
613 break;
617 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
619 RECT tempRect;
621 if (!IsWindowEnabled(hQueryWnd)) return 0;
623 GetWindowRect(hQueryWnd, &tempRect);
625 if(!PtInRect(&tempRect, *lpPt)) return 0;
627 if (!IsIconic( hQueryWnd ))
629 POINT pt = *lpPt;
630 ScreenToClient( hQueryWnd, &pt );
631 GetClientRect( hQueryWnd, &tempRect );
633 if (PtInRect( &tempRect, pt))
635 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
636 if (ret && ret != hQueryWnd)
638 ret = find_drop_window( ret, lpPt );
639 if (ret) return ret;
644 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
646 ScreenToClient(hQueryWnd, lpPt);
648 return hQueryWnd;
651 /**********************************************************************
652 * EVENT_DropFromOffix
654 * don't know if it still works (last Changelog is from 96/11/04)
656 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
658 unsigned long data_length;
659 unsigned long aux_long;
660 unsigned char* p_data = NULL;
661 Atom atom_aux;
662 int x, y, dummy;
663 BOOL bAccept;
664 Window win, w_aux_root, w_aux_child;
665 WND* pWnd;
666 HWND hScope = hWnd;
668 win = X11DRV_get_whole_window(hWnd);
669 wine_tsx11_lock();
670 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
671 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
672 x += virtual_screen_rect.left;
673 y += virtual_screen_rect.top;
674 wine_tsx11_unlock();
676 pWnd = WIN_GetPtr(hWnd);
678 /* find out drop point and drop window */
679 if( x < 0 || y < 0 ||
680 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
681 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
683 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
684 x = 0;
685 y = 0;
687 else
689 POINT pt = { x, y };
690 HWND hwndDrop = find_drop_window( hWnd, &pt );
691 if (hwndDrop)
693 x = pt.x;
694 y = pt.y;
695 hScope = hwndDrop;
696 bAccept = TRUE;
698 else
700 bAccept = FALSE;
703 WIN_ReleasePtr(pWnd);
705 if (!bAccept) return;
707 wine_tsx11_lock();
708 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
709 x11drv_atom(DndSelection), 0, 65535, FALSE,
710 AnyPropertyType, &atom_aux, &dummy,
711 &data_length, &aux_long, &p_data);
712 wine_tsx11_unlock();
714 if( !aux_long && p_data) /* don't bother if > 64K */
716 char *p = (char *)p_data;
717 char *p_drop;
719 aux_long = 0;
720 while( *p ) /* calculate buffer size */
722 INT len = GetShortPathNameA( p, NULL, 0 );
723 if (len) aux_long += len + 1;
724 p += strlen(p) + 1;
726 if( aux_long && aux_long < 65535 )
728 HDROP hDrop;
729 DROPFILES *lpDrop;
731 aux_long += sizeof(DROPFILES) + 1;
732 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
733 lpDrop = (DROPFILES*)GlobalLock( hDrop );
735 if( lpDrop )
737 WND *pDropWnd = WIN_GetPtr( hScope );
738 lpDrop->pFiles = sizeof(DROPFILES);
739 lpDrop->pt.x = x;
740 lpDrop->pt.y = y;
741 lpDrop->fNC =
742 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
743 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
744 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
745 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
746 lpDrop->fWide = FALSE;
747 WIN_ReleasePtr(pDropWnd);
748 p_drop = (char *)(lpDrop + 1);
749 p = (char *)p_data;
750 while(*p)
752 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
753 p_drop += strlen( p_drop ) + 1;
754 p += strlen(p) + 1;
756 *p_drop = '\0';
757 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
761 wine_tsx11_lock();
762 if( p_data ) XFree(p_data);
763 wine_tsx11_unlock();
766 /**********************************************************************
767 * EVENT_DropURLs
769 * drop items are separated by \n
770 * each item is prefixed by its mime type
772 * event->data.l[3], event->data.l[4] contains drop x,y position
774 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
776 unsigned long data_length;
777 unsigned long aux_long, drop_len = 0;
778 unsigned char *p_data = NULL; /* property data */
779 char *p_drop = NULL;
780 char *p, *next;
781 int x, y;
782 DROPFILES *lpDrop;
783 HDROP hDrop;
784 union {
785 Atom atom_aux;
786 int i;
787 Window w_aux;
788 unsigned int u;
789 } u; /* unused */
791 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
793 wine_tsx11_lock();
794 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
795 x11drv_atom(DndSelection), 0, 65535, FALSE,
796 AnyPropertyType, &u.atom_aux, &u.i,
797 &data_length, &aux_long, &p_data);
798 wine_tsx11_unlock();
799 if (aux_long)
800 WARN("property too large, truncated!\n");
801 TRACE("urls=%s\n", p_data);
803 if( !aux_long && p_data) { /* don't bother if > 64K */
804 /* calculate length */
805 p = (char*) p_data;
806 next = strchr(p, '\n');
807 while (p) {
808 if (next) *next=0;
809 if (strncmp(p,"file:",5) == 0 ) {
810 INT len = GetShortPathNameA( p+5, NULL, 0 );
811 if (len) drop_len += len + 1;
813 if (next) {
814 *next = '\n';
815 p = next + 1;
816 next = strchr(p, '\n');
817 } else {
818 p = NULL;
822 if( drop_len && drop_len < 65535 ) {
823 wine_tsx11_lock();
824 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
825 &x, &y, &u.i, &u.i, &u.u);
826 x += virtual_screen_rect.left;
827 y += virtual_screen_rect.top;
828 wine_tsx11_unlock();
830 drop_len += sizeof(DROPFILES) + 1;
831 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
832 lpDrop = (DROPFILES *) GlobalLock( hDrop );
834 if( lpDrop ) {
835 WND *pDropWnd = WIN_GetPtr( hWnd );
836 lpDrop->pFiles = sizeof(DROPFILES);
837 lpDrop->pt.x = (INT)x;
838 lpDrop->pt.y = (INT)y;
839 lpDrop->fNC =
840 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
841 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
842 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
843 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
844 lpDrop->fWide = FALSE;
845 p_drop = (char*)(lpDrop + 1);
846 WIN_ReleasePtr(pDropWnd);
849 /* create message content */
850 if (p_drop) {
851 p = (char*) p_data;
852 next = strchr(p, '\n');
853 while (p) {
854 if (next) *next=0;
855 if (strncmp(p,"file:",5) == 0 ) {
856 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
857 if (len) {
858 TRACE("drop file %s as %s\n", p+5, p_drop);
859 p_drop += len+1;
860 } else {
861 WARN("can't convert file %s to dos name\n", p+5);
863 } else {
864 WARN("unknown mime type %s\n", p);
866 if (next) {
867 *next = '\n';
868 p = next + 1;
869 next = strchr(p, '\n');
870 } else {
871 p = NULL;
873 *p_drop = '\0';
876 GlobalUnlock(hDrop);
877 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
880 wine_tsx11_lock();
881 if( p_data ) XFree(p_data);
882 wine_tsx11_unlock();
886 /**********************************************************************
887 * handle_dnd_protocol
889 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
891 Window root, child;
892 int root_x, root_y, child_x, child_y;
893 unsigned int u;
895 /* query window (drag&drop event contains only drag window) */
896 wine_tsx11_lock();
897 XQueryPointer( event->display, root_window, &root, &child,
898 &root_x, &root_y, &child_x, &child_y, &u);
899 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
900 wine_tsx11_unlock();
901 if (!hwnd) return;
902 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
903 EVENT_DropFromOffiX(hwnd, event);
904 else if (event->data.l[0] == DndURL)
905 EVENT_DropURLs(hwnd, event);
909 struct client_message_handler
911 int atom; /* protocol atom */
912 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
915 static const struct client_message_handler client_messages[] =
917 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
918 { XATOM_DndProtocol, handle_dnd_protocol },
919 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
920 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
921 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
922 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
926 /**********************************************************************
927 * EVENT_ClientMessage
929 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
931 XClientMessageEvent *event = &xev->xclient;
932 unsigned int i;
934 if (!hwnd) return;
936 if (event->format != 32)
938 WARN( "Don't know how to handle format %d\n", event->format );
939 return;
942 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
944 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
946 client_messages[i].handler( hwnd, event );
947 return;
950 TRACE( "no handler found for %ld\n", event->message_type );
954 /**********************************************************************
955 * X11DRV_WindowMessage (X11DRV.@)
957 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
959 switch(msg)
961 case WM_X11DRV_ACQUIRE_SELECTION:
962 return X11DRV_AcquireClipboard( hwnd );
963 case WM_X11DRV_DELETE_WINDOW:
964 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
965 case WM_X11DRV_SET_WIN_FORMAT:
966 return X11DRV_set_win_format( hwnd, (XID)wp );
967 default:
968 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
969 return 0;
974 /***********************************************************************
975 * X11DRV_SendInput (X11DRV.@)
977 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
979 UINT i;
981 for (i = 0; i < count; i++, inputs++)
983 switch(inputs->type)
985 case INPUT_MOUSE:
986 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
987 inputs->u.mi.mouseData, inputs->u.mi.time,
988 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
989 break;
990 case INPUT_KEYBOARD:
991 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
992 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
993 break;
994 case INPUT_HARDWARE:
995 FIXME( "INPUT_HARDWARE not supported\n" );
996 break;
999 return count;