ntdll: Extra check for ObjectAttributes (Coverity).
[wine/multimedia.git] / dlls / winex11.drv / event.c
blobfd84fb93c36c83f22e91ab079461c513bfd24028
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 "winreg.h"
44 #include "x11drv.h"
45 #include "shellapi.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(event);
50 extern BOOL ximInComposeMode;
52 #define DndNotDnd -1 /* OffiX drag&drop */
53 #define DndUnknown 0
54 #define DndRawData 1
55 #define DndFile 2
56 #define DndFiles 3
57 #define DndText 4
58 #define DndDir 5
59 #define DndLink 6
60 #define DndExe 7
62 #define DndEND 8
64 #define DndURL 128 /* KDE drag&drop */
66 /* Event handlers */
67 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
68 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
69 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
70 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
72 struct event_handler
74 int type; /* event type */
75 x11drv_event_handler handler; /* corresponding handler function */
78 #define MAX_EVENT_HANDLERS 64
80 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
82 /* list must be sorted by event type */
83 { KeyPress, X11DRV_KeyEvent },
84 { KeyRelease, X11DRV_KeyEvent },
85 { ButtonPress, X11DRV_ButtonPress },
86 { ButtonRelease, X11DRV_ButtonRelease },
87 { MotionNotify, X11DRV_MotionNotify },
88 { EnterNotify, X11DRV_EnterNotify },
89 /* LeaveNotify */
90 { FocusIn, EVENT_FocusIn },
91 { FocusOut, EVENT_FocusOut },
92 { KeymapNotify, X11DRV_KeymapNotify },
93 { Expose, X11DRV_Expose },
94 /* GraphicsExpose */
95 /* NoExpose */
96 /* VisibilityNotify */
97 /* CreateNotify */
98 /* DestroyNotify */
99 { UnmapNotify, X11DRV_UnmapNotify },
100 { MapNotify, X11DRV_MapNotify },
101 /* MapRequest */
102 /* ReparentNotify */
103 { ConfigureNotify, X11DRV_ConfigureNotify },
104 /* ConfigureRequest */
105 /* GravityNotify */
106 /* ResizeRequest */
107 /* CirculateNotify */
108 /* CirculateRequest */
109 { PropertyNotify, EVENT_PropertyNotify },
110 { SelectionClear, X11DRV_SelectionClear },
111 { SelectionRequest, X11DRV_SelectionRequest },
112 /* SelectionNotify */
113 /* ColormapNotify */
114 { ClientMessage, EVENT_ClientMessage },
115 { MappingNotify, X11DRV_MappingNotify },
118 static int nb_event_handlers = 18; /* change this if you add handlers above */
121 /* return the name of an X event */
122 static const char *dbgstr_event( int type )
124 static const char * const event_names[] =
126 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
127 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
128 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
129 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
130 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
131 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
132 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
133 "ClientMessage", "MappingNotify"
136 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
137 return wine_dbg_sprintf( "Extension event %d", type );
141 /***********************************************************************
142 * find_handler
144 * Find the handler for a given event type. Caller must hold the x11 lock.
146 static inline x11drv_event_handler find_handler( int type )
148 int min = 0, max = nb_event_handlers - 1;
150 while (min <= max)
152 int pos = (min + max) / 2;
153 if (handlers[pos].type == type) return handlers[pos].handler;
154 if (handlers[pos].type > type) max = pos - 1;
155 else min = pos + 1;
157 return NULL;
161 /***********************************************************************
162 * X11DRV_register_event_handler
164 * Register a handler for a given event type.
165 * If already registered, overwrite the previous handler.
167 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
169 int min, max;
171 wine_tsx11_lock();
172 min = 0;
173 max = nb_event_handlers - 1;
174 while (min <= max)
176 int pos = (min + max) / 2;
177 if (handlers[pos].type == type)
179 handlers[pos].handler = handler;
180 goto done;
182 if (handlers[pos].type > type) max = pos - 1;
183 else min = pos + 1;
185 /* insert it between max and min */
186 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
187 handlers[min].type = type;
188 handlers[min].handler = handler;
189 nb_event_handlers++;
190 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
191 done:
192 wine_tsx11_unlock();
193 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
197 /***********************************************************************
198 * filter_event
200 static Bool filter_event( Display *display, XEvent *event, char *arg )
202 ULONG_PTR mask = (ULONG_PTR)arg;
204 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
206 switch(event->type)
208 case KeyPress:
209 case KeyRelease:
210 case KeymapNotify:
211 case MappingNotify:
212 return (mask & QS_KEY) != 0;
213 case ButtonPress:
214 case ButtonRelease:
215 return (mask & QS_MOUSEBUTTON) != 0;
216 case MotionNotify:
217 case EnterNotify:
218 case LeaveNotify:
219 return (mask & QS_MOUSEMOVE) != 0;
220 case Expose:
221 return (mask & QS_PAINT) != 0;
222 case FocusIn:
223 case FocusOut:
224 case MapNotify:
225 case UnmapNotify:
226 case ConfigureNotify:
227 case PropertyNotify:
228 case ClientMessage:
229 return (mask & QS_POSTMESSAGE) != 0;
230 default:
231 return (mask & QS_SENDMESSAGE) != 0;
236 /***********************************************************************
237 * process_events
239 static int process_events( Display *display, ULONG_PTR mask )
241 XEvent event;
242 HWND hwnd;
243 int count = 0;
244 x11drv_event_handler handler;
246 wine_tsx11_lock();
247 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
249 count++;
250 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
252 if (!(handler = find_handler( event.type )))
254 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
255 continue; /* no handler, ignore it */
258 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
259 hwnd = 0; /* not for a registered window */
260 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
262 wine_tsx11_unlock();
263 TRACE( "%s for hwnd/window %p/%lx\n",
264 dbgstr_event( event.type ), hwnd, event.xany.window );
265 handler( hwnd, &event );
266 wine_tsx11_lock();
268 XFlush( gdi_display );
269 wine_tsx11_unlock();
270 if (count) TRACE( "processed %d events\n", count );
271 return count;
275 /***********************************************************************
276 * MsgWaitForMultipleObjectsEx (X11DRV.@)
278 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
279 DWORD timeout, DWORD mask, DWORD flags )
281 DWORD i, ret;
282 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
284 if (!data || data->process_event_count)
286 if (!count && !timeout) return WAIT_TIMEOUT;
287 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
288 timeout, flags & MWMO_ALERTABLE );
291 /* check whether only server queue handle was passed in */
292 if (count < 2) flags &= ~MWMO_WAITALL;
294 data->process_event_count++;
296 if (process_events( data->display, mask )) ret = count;
297 else if (count || timeout)
299 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
301 for (i = 0; i < count; i++) new_handles[i] = handles[i];
302 new_handles[count] = data->display_fd;
304 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
305 timeout, flags & MWMO_ALERTABLE );
306 if (ret == count) process_events( data->display, mask );
308 else ret = WAIT_TIMEOUT;
310 data->process_event_count--;
311 return ret;
314 /***********************************************************************
315 * EVENT_x11_time_to_win32_time
317 * Make our timer and the X timer line up as best we can
318 * Pass 0 to retrieve the current adjustment value (times -1)
320 DWORD EVENT_x11_time_to_win32_time(Time time)
322 static DWORD adjust = 0;
323 DWORD now = GetTickCount();
324 DWORD ret;
326 if (! adjust && time != 0)
328 ret = now;
329 adjust = time - now;
331 else
333 /* If we got an event in the 'future', then our clock is clearly wrong.
334 If we got it more than 10000 ms in the future, then it's most likely
335 that the clock has wrapped. */
337 ret = time - adjust;
338 if (ret > now && ((ret - now) < 10000) && time != 0)
340 adjust += ret - now;
341 ret -= ret - now;
345 return ret;
349 /*******************************************************************
350 * can_activate_window
352 * Check if we can activate the specified window.
354 inline static BOOL can_activate_window( HWND hwnd )
356 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
357 if (!(style & WS_VISIBLE)) return FALSE;
358 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
359 return !(style & WS_DISABLED);
363 /**********************************************************************
364 * set_focus
366 static void set_focus( HWND hwnd, Time time )
368 HWND focus;
369 Window win;
371 TRACE( "setting foreground window to %p\n", hwnd );
372 SetForegroundWindow( hwnd );
374 focus = GetFocus();
375 if (focus) focus = GetAncestor( focus, GA_ROOT );
376 win = X11DRV_get_whole_window(focus);
378 if (win)
380 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
381 wine_tsx11_lock();
382 XSetInputFocus( thread_display(), win, RevertToParent, time );
383 wine_tsx11_unlock();
388 /**********************************************************************
389 * handle_wm_protocols
391 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
393 Atom protocol = (Atom)event->data.l[0];
395 if (!protocol) return;
397 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
399 /* Ignore the delete window request if the window has been disabled
400 * and we are in managed mode. This is to disallow applications from
401 * being closed by the window manager while in a modal state.
403 if (IsWindowEnabled(hwnd))
405 HMENU hSysMenu;
407 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
408 hSysMenu = GetSystemMenu(hwnd, FALSE);
409 if (hSysMenu)
411 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
412 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
413 return;
415 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
418 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
420 Time event_time = (Time)event->data.l[1];
421 HWND last_focus = x11drv_thread_data()->last_focus;
423 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
424 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
425 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
427 if (can_activate_window(hwnd))
429 /* simulate a mouse click on the caption to find out
430 * whether the window wants to be activated */
431 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
432 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
433 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
434 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
435 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
437 else
439 hwnd = GetFocus();
440 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
441 if (!hwnd) hwnd = GetActiveWindow();
442 if (!hwnd) hwnd = last_focus;
443 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
446 else if (protocol == x11drv_atom(_NET_WM_PING))
448 XClientMessageEvent xev;
449 xev = *event;
451 TRACE("NET_WM Ping\n");
452 wine_tsx11_lock();
453 xev.window = DefaultRootWindow(xev.display);
454 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
455 wine_tsx11_unlock();
456 /* this line is semi-stolen from gtk2 */
457 TRACE("NET_WM Pong\n");
462 static const char * const focus_details[] =
464 "NotifyAncestor",
465 "NotifyVirtual",
466 "NotifyInferior",
467 "NotifyNonlinear",
468 "NotifyNonlinearVirtual",
469 "NotifyPointer",
470 "NotifyPointerRoot",
471 "NotifyDetailNone"
474 /**********************************************************************
475 * EVENT_FocusIn
477 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
479 XFocusChangeEvent *event = &xev->xfocus;
480 XIC xic;
482 if (!hwnd) return;
484 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
486 if (event->detail == NotifyPointer) return;
488 if ((xic = X11DRV_get_ic( hwnd )))
490 wine_tsx11_lock();
491 XSetICFocus( xic );
492 wine_tsx11_unlock();
494 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
496 if (!can_activate_window(hwnd))
498 HWND hwnd = GetFocus();
499 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
500 if (!hwnd) hwnd = GetActiveWindow();
501 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
502 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
504 else SetForegroundWindow( hwnd );
508 /**********************************************************************
509 * EVENT_FocusOut
511 * Note: only top-level windows get FocusOut events.
513 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
515 XFocusChangeEvent *event = &xev->xfocus;
516 HWND hwnd_tmp;
517 Window focus_win;
518 int revert;
519 XIC xic;
521 if (!hwnd) return;
523 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
525 if (event->detail == NotifyPointer) return;
526 if (ximInComposeMode) return;
528 x11drv_thread_data()->last_focus = hwnd;
529 if ((xic = X11DRV_get_ic( hwnd )))
531 wine_tsx11_lock();
532 XUnsetICFocus( xic );
533 wine_tsx11_unlock();
535 if (hwnd != GetForegroundWindow()) return;
536 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
538 /* don't reset the foreground window, if the window which is
539 getting the focus is a Wine window */
541 wine_tsx11_lock();
542 XGetInputFocus( thread_display(), &focus_win, &revert );
543 if (focus_win)
545 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
546 focus_win = 0;
548 wine_tsx11_unlock();
550 if (!focus_win)
552 /* Abey : 6-Oct-99. Check again if the focus out window is the
553 Foreground window, because in most cases the messages sent
554 above must have already changed the foreground window, in which
555 case we don't have to change the foreground window to 0 */
556 if (hwnd == GetForegroundWindow())
558 TRACE( "lost focus, setting fg to 0\n" );
559 SetForegroundWindow( 0 );
565 /***********************************************************************
566 * EVENT_PropertyNotify
567 * We use this to release resources like Pixmaps when a selection
568 * client no longer needs them.
570 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
572 XPropertyEvent *event = &xev->xproperty;
573 /* Check if we have any resources to free */
574 TRACE("Received PropertyNotify event:\n");
576 switch(event->state)
578 case PropertyDelete:
580 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
581 event->atom, (long)event->window);
582 break;
585 case PropertyNewValue:
587 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
588 event->atom, (long)event->window);
589 break;
592 default:
593 break;
597 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
599 RECT tempRect;
601 if (!IsWindowEnabled(hQueryWnd)) return 0;
603 GetWindowRect(hQueryWnd, &tempRect);
605 if(!PtInRect(&tempRect, *lpPt)) return 0;
607 if (!IsIconic( hQueryWnd ))
609 POINT pt = *lpPt;
610 ScreenToClient( hQueryWnd, &pt );
611 GetClientRect( hQueryWnd, &tempRect );
613 if (PtInRect( &tempRect, pt))
615 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
616 if (ret && ret != hQueryWnd)
618 ret = find_drop_window( ret, lpPt );
619 if (ret) return ret;
624 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
626 ScreenToClient(hQueryWnd, lpPt);
628 return hQueryWnd;
631 /**********************************************************************
632 * EVENT_DropFromOffix
634 * don't know if it still works (last Changlog is from 96/11/04)
636 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
638 unsigned long data_length;
639 unsigned long aux_long;
640 unsigned char* p_data = NULL;
641 Atom atom_aux;
642 int x, y, dummy;
643 BOOL bAccept;
644 Window win, w_aux_root, w_aux_child;
645 WND* pWnd;
646 HWND hScope = hWnd;
648 win = X11DRV_get_whole_window(hWnd);
649 wine_tsx11_lock();
650 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
651 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
652 x += virtual_screen_rect.left;
653 y += virtual_screen_rect.top;
654 wine_tsx11_unlock();
656 pWnd = WIN_GetPtr(hWnd);
658 /* find out drop point and drop window */
659 if( x < 0 || y < 0 ||
660 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
661 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
663 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
664 x = 0;
665 y = 0;
667 else
669 POINT pt = { x, y };
670 HWND hwndDrop = find_drop_window( hWnd, &pt );
671 if (hwndDrop)
673 x = pt.x;
674 y = pt.y;
675 hScope = hwndDrop;
676 bAccept = TRUE;
678 else
680 bAccept = FALSE;
683 WIN_ReleasePtr(pWnd);
685 if (!bAccept) return;
687 wine_tsx11_lock();
688 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
689 x11drv_atom(DndSelection), 0, 65535, FALSE,
690 AnyPropertyType, &atom_aux, &dummy,
691 &data_length, &aux_long, &p_data);
692 wine_tsx11_unlock();
694 if( !aux_long && p_data) /* don't bother if > 64K */
696 char *p = (char *)p_data;
697 char *p_drop;
699 aux_long = 0;
700 while( *p ) /* calculate buffer size */
702 INT len = GetShortPathNameA( p, NULL, 0 );
703 if (len) aux_long += len + 1;
704 p += strlen(p) + 1;
706 if( aux_long && aux_long < 65535 )
708 HDROP hDrop;
709 DROPFILES *lpDrop;
711 aux_long += sizeof(DROPFILES) + 1;
712 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
713 lpDrop = (DROPFILES*)GlobalLock( hDrop );
715 if( lpDrop )
717 WND *pDropWnd = WIN_GetPtr( hScope );
718 lpDrop->pFiles = sizeof(DROPFILES);
719 lpDrop->pt.x = x;
720 lpDrop->pt.y = y;
721 lpDrop->fNC =
722 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
723 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
724 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
725 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
726 lpDrop->fWide = FALSE;
727 WIN_ReleasePtr(pDropWnd);
728 p_drop = (char *)(lpDrop + 1);
729 p = (char *)p_data;
730 while(*p)
732 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
733 p_drop += strlen( p_drop ) + 1;
734 p += strlen(p) + 1;
736 *p_drop = '\0';
737 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
741 wine_tsx11_lock();
742 if( p_data ) XFree(p_data);
743 wine_tsx11_unlock();
746 /**********************************************************************
747 * EVENT_DropURLs
749 * drop items are separated by \n
750 * each item is prefixed by its mime type
752 * event->data.l[3], event->data.l[4] contains drop x,y position
754 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
756 unsigned long data_length;
757 unsigned long aux_long, drop_len = 0;
758 unsigned char *p_data = NULL; /* property data */
759 char *p_drop = NULL;
760 char *p, *next;
761 int x, y;
762 DROPFILES *lpDrop;
763 HDROP hDrop;
764 union {
765 Atom atom_aux;
766 int i;
767 Window w_aux;
768 unsigned int u;
769 } u; /* unused */
771 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
773 wine_tsx11_lock();
774 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
775 x11drv_atom(DndSelection), 0, 65535, FALSE,
776 AnyPropertyType, &u.atom_aux, &u.i,
777 &data_length, &aux_long, &p_data);
778 wine_tsx11_unlock();
779 if (aux_long)
780 WARN("property too large, truncated!\n");
781 TRACE("urls=%s\n", p_data);
783 if( !aux_long && p_data) { /* don't bother if > 64K */
784 /* calculate length */
785 p = (char*) p_data;
786 next = strchr(p, '\n');
787 while (p) {
788 if (next) *next=0;
789 if (strncmp(p,"file:",5) == 0 ) {
790 INT len = GetShortPathNameA( p+5, NULL, 0 );
791 if (len) drop_len += len + 1;
793 if (next) {
794 *next = '\n';
795 p = next + 1;
796 next = strchr(p, '\n');
797 } else {
798 p = NULL;
802 if( drop_len && drop_len < 65535 ) {
803 wine_tsx11_lock();
804 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
805 &x, &y, &u.i, &u.i, &u.u);
806 x += virtual_screen_rect.left;
807 y += virtual_screen_rect.top;
808 wine_tsx11_unlock();
810 drop_len += sizeof(DROPFILES) + 1;
811 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
812 lpDrop = (DROPFILES *) GlobalLock( hDrop );
814 if( lpDrop ) {
815 WND *pDropWnd = WIN_GetPtr( hWnd );
816 lpDrop->pFiles = sizeof(DROPFILES);
817 lpDrop->pt.x = (INT)x;
818 lpDrop->pt.y = (INT)y;
819 lpDrop->fNC =
820 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
821 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
822 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
823 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
824 lpDrop->fWide = FALSE;
825 p_drop = (char*)(lpDrop + 1);
826 WIN_ReleasePtr(pDropWnd);
829 /* create message content */
830 if (p_drop) {
831 p = (char*) p_data;
832 next = strchr(p, '\n');
833 while (p) {
834 if (next) *next=0;
835 if (strncmp(p,"file:",5) == 0 ) {
836 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
837 if (len) {
838 TRACE("drop file %s as %s\n", p+5, p_drop);
839 p_drop += len+1;
840 } else {
841 WARN("can't convert file %s to dos name\n", p+5);
843 } else {
844 WARN("unknown mime type %s\n", p);
846 if (next) {
847 *next = '\n';
848 p = next + 1;
849 next = strchr(p, '\n');
850 } else {
851 p = NULL;
853 *p_drop = '\0';
856 GlobalUnlock(hDrop);
857 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
860 wine_tsx11_lock();
861 if( p_data ) XFree(p_data);
862 wine_tsx11_unlock();
866 /**********************************************************************
867 * handle_dnd_protocol
869 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
871 Window root, child;
872 int root_x, root_y, child_x, child_y;
873 unsigned int u;
875 /* query window (drag&drop event contains only drag window) */
876 wine_tsx11_lock();
877 XQueryPointer( event->display, root_window, &root, &child,
878 &root_x, &root_y, &child_x, &child_y, &u);
879 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
880 wine_tsx11_unlock();
881 if (!hwnd) return;
882 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
883 EVENT_DropFromOffiX(hwnd, event);
884 else if (event->data.l[0] == DndURL)
885 EVENT_DropURLs(hwnd, event);
889 struct client_message_handler
891 int atom; /* protocol atom */
892 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
895 static const struct client_message_handler client_messages[] =
897 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
898 { XATOM_DndProtocol, handle_dnd_protocol },
899 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
900 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
901 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
902 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
906 /**********************************************************************
907 * EVENT_ClientMessage
909 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
911 XClientMessageEvent *event = &xev->xclient;
912 unsigned int i;
914 if (!hwnd) return;
916 if (event->format != 32)
918 WARN( "Don't know how to handle format %d\n", event->format );
919 return;
922 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
924 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
926 client_messages[i].handler( hwnd, event );
927 return;
930 TRACE( "no handler found for %ld\n", event->message_type );
934 /**********************************************************************
935 * X11DRV_WindowMessage (X11DRV.@)
937 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
939 switch(msg)
941 case WM_X11DRV_ACQUIRE_SELECTION:
942 return X11DRV_AcquireClipboard( hwnd );
943 case WM_X11DRV_DELETE_WINDOW:
944 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
945 default:
946 FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
947 return 0;
952 /***********************************************************************
953 * X11DRV_SendInput (X11DRV.@)
955 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
957 UINT i;
959 for (i = 0; i < count; i++, inputs++)
961 switch(inputs->type)
963 case INPUT_MOUSE:
964 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
965 inputs->u.mi.mouseData, inputs->u.mi.time,
966 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
967 break;
968 case INPUT_KEYBOARD:
969 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
970 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
971 break;
972 case INPUT_HARDWARE:
973 FIXME( "INPUT_HARDWARE not supported\n" );
974 break;
977 return count;