ntdll: Add wrappers for the string functions.
[wine.git] / dlls / x11drv / event.c
blob2271cae11ed5e0bed43d0aea96a6cd86b3b6971c
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define COM_NO_WINDOWS_H
23 #include "config.h"
25 #include <X11/Xatom.h>
26 #include <X11/keysym.h>
27 #include <X11/Xlib.h>
28 #include <X11/Xresource.h>
29 #include <X11/Xutil.h>
30 #ifdef HAVE_LIBXXF86DGA2
31 #include <X11/extensions/xf86dga.h>
32 #endif
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <string.h>
38 #define NONAMELESSUNION
39 #define NONAMELESSSTRUCT
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winuser.h"
43 #include "wingdi.h"
44 #include "shlobj.h" /* DROPFILES */
46 #include "win.h"
47 #include "winreg.h"
48 #include "x11drv.h"
49 #include "shellapi.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(event);
54 extern BOOL ximInComposeMode;
56 #define DndNotDnd -1 /* OffiX drag&drop */
57 #define DndUnknown 0
58 #define DndRawData 1
59 #define DndFile 2
60 #define DndFiles 3
61 #define DndText 4
62 #define DndDir 5
63 #define DndLink 6
64 #define DndExe 7
66 #define DndEND 8
68 #define DndURL 128 /* KDE drag&drop */
70 /* Event handlers */
71 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
72 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
73 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
74 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
76 struct event_handler
78 int type; /* event type */
79 x11drv_event_handler handler; /* corresponding handler function */
82 #define MAX_EVENT_HANDLERS 64
84 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
86 /* list must be sorted by event type */
87 { KeyPress, X11DRV_KeyEvent },
88 { KeyRelease, X11DRV_KeyEvent },
89 { ButtonPress, X11DRV_ButtonPress },
90 { ButtonRelease, X11DRV_ButtonRelease },
91 { MotionNotify, X11DRV_MotionNotify },
92 { EnterNotify, X11DRV_EnterNotify },
93 /* LeaveNotify */
94 { FocusIn, EVENT_FocusIn },
95 { FocusOut, EVENT_FocusOut },
96 { KeymapNotify, X11DRV_KeymapNotify },
97 { Expose, X11DRV_Expose },
98 /* GraphicsExpose */
99 /* NoExpose */
100 /* VisibilityNotify */
101 /* CreateNotify */
102 /* DestroyNotify */
103 { UnmapNotify, X11DRV_UnmapNotify },
104 { MapNotify, X11DRV_MapNotify },
105 /* MapRequest */
106 /* ReparentNotify */
107 { ConfigureNotify, X11DRV_ConfigureNotify },
108 /* ConfigureRequest */
109 /* GravityNotify */
110 /* ResizeRequest */
111 /* CirculateNotify */
112 /* CirculateRequest */
113 { PropertyNotify, EVENT_PropertyNotify },
114 { SelectionClear, X11DRV_SelectionClear },
115 { SelectionRequest, X11DRV_SelectionRequest },
116 /* SelectionNotify */
117 /* ColormapNotify */
118 { ClientMessage, EVENT_ClientMessage },
119 { MappingNotify, X11DRV_MappingNotify },
122 static int nb_event_handlers = 18; /* change this if you add handlers above */
125 /* return the name of an X event */
126 static const char *dbgstr_event( int type )
128 static const char * const event_names[] =
130 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
131 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
132 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
133 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
134 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
135 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
136 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
137 "ClientMessage", "MappingNotify"
140 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
141 return wine_dbg_sprintf( "Extension event %d", type );
145 /***********************************************************************
146 * find_handler
148 * Find the handler for a given event type. Caller must hold the x11 lock.
150 static inline x11drv_event_handler find_handler( int type )
152 int min = 0, max = nb_event_handlers - 1;
154 while (min <= max)
156 int pos = (min + max) / 2;
157 if (handlers[pos].type == type) return handlers[pos].handler;
158 if (handlers[pos].type > type) max = pos - 1;
159 else min = pos + 1;
161 return NULL;
165 /***********************************************************************
166 * X11DRV_register_event_handler
168 * Register a handler for a given event type.
169 * If already registered, overwrite the previous handler.
171 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
173 int min, max;
175 wine_tsx11_lock();
176 min = 0;
177 max = nb_event_handlers - 1;
178 while (min <= max)
180 int pos = (min + max) / 2;
181 if (handlers[pos].type == type)
183 handlers[pos].handler = handler;
184 goto done;
186 if (handlers[pos].type > type) max = pos - 1;
187 else min = pos + 1;
189 /* insert it between max and min */
190 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
191 handlers[min].type = type;
192 handlers[min].handler = handler;
193 nb_event_handlers++;
194 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
195 done:
196 wine_tsx11_unlock();
197 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
201 /***********************************************************************
202 * filter_event
204 static Bool filter_event( Display *display, XEvent *event, char *arg )
206 ULONG_PTR mask = (ULONG_PTR)arg;
208 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
210 switch(event->type)
212 case KeyPress:
213 case KeyRelease:
214 case KeymapNotify:
215 case MappingNotify:
216 return (mask & QS_KEY) != 0;
217 case ButtonPress:
218 case ButtonRelease:
219 return (mask & QS_MOUSEBUTTON) != 0;
220 case MotionNotify:
221 case EnterNotify:
222 case LeaveNotify:
223 return (mask & QS_MOUSEMOVE) != 0;
224 case Expose:
225 return (mask & QS_PAINT) != 0;
226 case FocusIn:
227 case FocusOut:
228 case MapNotify:
229 case UnmapNotify:
230 case ConfigureNotify:
231 case PropertyNotify:
232 case ClientMessage:
233 return (mask & QS_POSTMESSAGE) != 0;
234 default:
235 return (mask & QS_SENDMESSAGE) != 0;
240 /***********************************************************************
241 * process_events
243 static int process_events( Display *display, ULONG_PTR mask )
245 XEvent event;
246 HWND hwnd;
247 int count = 0;
248 x11drv_event_handler handler;
250 wine_tsx11_lock();
251 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
253 count++;
254 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
256 if (!(handler = find_handler( event.type )))
258 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
259 continue; /* no handler, ignore it */
262 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
263 hwnd = 0; /* not for a registered window */
264 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
266 wine_tsx11_unlock();
267 TRACE( "%s for hwnd/window %p/%lx\n",
268 dbgstr_event( event.type ), hwnd, event.xany.window );
269 handler( hwnd, &event );
270 wine_tsx11_lock();
272 XFlush( gdi_display );
273 wine_tsx11_unlock();
274 if (count) TRACE( "processed %d events\n", count );
275 return count;
279 /***********************************************************************
280 * MsgWaitForMultipleObjectsEx (X11DRV.@)
282 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
283 DWORD timeout, DWORD mask, DWORD flags )
285 DWORD i, ret;
286 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
288 if (!data || data->process_event_count)
290 if (!count && !timeout) return WAIT_TIMEOUT;
291 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
292 timeout, flags & MWMO_ALERTABLE );
295 /* check whether only server queue handle was passed in */
296 if (count < 2) flags &= ~MWMO_WAITALL;
298 data->process_event_count++;
300 if (process_events( data->display, mask )) ret = count;
301 else if (count || timeout)
303 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
305 for (i = 0; i < count; i++) new_handles[i] = handles[i];
306 new_handles[count] = data->display_fd;
308 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
309 timeout, flags & MWMO_ALERTABLE );
310 if (ret == count) process_events( data->display, mask );
312 else ret = WAIT_TIMEOUT;
314 data->process_event_count--;
315 return ret;
318 /***********************************************************************
319 * EVENT_x11_time_to_win32_time
321 * Make our timer and the X timer line up as best we can
322 * Pass 0 to retrieve the current adjustment value (times -1)
324 DWORD EVENT_x11_time_to_win32_time(Time time)
326 static DWORD adjust = 0;
327 DWORD now = GetTickCount();
328 DWORD ret;
330 if (! adjust && time != 0)
332 ret = now;
333 adjust = time - now;
335 else
337 /* If we got an event in the 'future', then our clock is clearly wrong.
338 If we got it more than 10000 ms in the future, then it's most likely
339 that the clock has wrapped. */
341 ret = time - adjust;
342 if (ret > now && ((ret - now) < 10000) && time != 0)
344 adjust += ret - now;
345 ret -= ret - now;
349 return ret;
353 /*******************************************************************
354 * can_activate_window
356 * Check if we can activate the specified window.
358 inline static BOOL can_activate_window( HWND hwnd )
360 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
361 if (!(style & WS_VISIBLE)) return FALSE;
362 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
363 return !(style & WS_DISABLED);
367 /**********************************************************************
368 * set_focus
370 static void set_focus( HWND hwnd, Time time )
372 HWND focus;
373 Window win;
375 TRACE( "setting foreground window to %p\n", hwnd );
376 SetForegroundWindow( hwnd );
378 focus = GetFocus();
379 if (focus) focus = GetAncestor( focus, GA_ROOT );
380 win = X11DRV_get_whole_window(focus);
382 if (win)
384 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
385 wine_tsx11_lock();
386 XSetInputFocus( thread_display(), win, RevertToParent, time );
387 wine_tsx11_unlock();
392 /**********************************************************************
393 * handle_wm_protocols
395 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
397 Atom protocol = (Atom)event->data.l[0];
399 if (!protocol) return;
401 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
403 /* Ignore the delete window request if the window has been disabled
404 * and we are in managed mode. This is to disallow applications from
405 * being closed by the window manager while in a modal state.
407 if (IsWindowEnabled(hwnd))
409 HMENU hSysMenu;
411 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
412 hSysMenu = GetSystemMenu(hwnd, FALSE);
413 if (hSysMenu)
415 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
416 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
417 return;
419 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
422 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
424 Time event_time = (Time)event->data.l[1];
425 HWND last_focus = x11drv_thread_data()->last_focus;
427 TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
428 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
429 GetForegroundWindow(), last_focus );
431 if (can_activate_window(hwnd))
433 /* simulate a mouse click on the caption to find out
434 * whether the window wants to be activated */
435 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
436 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
437 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
438 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
439 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
441 else
443 hwnd = GetFocus();
444 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
445 if (!hwnd) hwnd = GetActiveWindow();
446 if (!hwnd) hwnd = last_focus;
447 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
450 else if (protocol == x11drv_atom(_NET_WM_PING))
452 XClientMessageEvent xev;
453 xev = *event;
455 TRACE("NET_WM Ping\n");
456 xev.window = DefaultRootWindow(xev.display);
457 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
458 /* this line is semi-stolen from gtk2 */
459 TRACE("NET_WM Pong\n");
464 static const char * const focus_details[] =
466 "NotifyAncestor",
467 "NotifyVirtual",
468 "NotifyInferior",
469 "NotifyNonlinear",
470 "NotifyNonlinearVirtual",
471 "NotifyPointer",
472 "NotifyPointerRoot",
473 "NotifyDetailNone"
476 /**********************************************************************
477 * EVENT_FocusIn
479 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
481 XFocusChangeEvent *event = &xev->xfocus;
482 XIC xic;
484 if (!hwnd) return;
486 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
488 if (event->detail == NotifyPointer) return;
490 if ((xic = X11DRV_get_ic( hwnd )))
492 wine_tsx11_lock();
493 XSetICFocus( xic );
494 wine_tsx11_unlock();
496 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
498 if (!can_activate_window(hwnd))
500 HWND hwnd = GetFocus();
501 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
502 if (!hwnd) hwnd = GetActiveWindow();
503 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
504 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
506 else SetForegroundWindow( hwnd );
510 /**********************************************************************
511 * EVENT_FocusOut
513 * Note: only top-level windows get FocusOut events.
515 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
517 XFocusChangeEvent *event = &xev->xfocus;
518 HWND hwnd_tmp;
519 Window focus_win;
520 int revert;
521 XIC xic;
523 if (!hwnd) return;
525 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
527 if (event->detail == NotifyPointer) return;
528 if (ximInComposeMode) return;
530 x11drv_thread_data()->last_focus = hwnd;
531 if ((xic = X11DRV_get_ic( hwnd )))
533 wine_tsx11_lock();
534 XUnsetICFocus( xic );
535 wine_tsx11_unlock();
537 if (hwnd != GetForegroundWindow()) return;
538 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
540 /* don't reset the foreground window, if the window which is
541 getting the focus is a Wine window */
543 wine_tsx11_lock();
544 XGetInputFocus( thread_display(), &focus_win, &revert );
545 if (focus_win)
547 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
548 focus_win = 0;
550 wine_tsx11_unlock();
552 if (!focus_win)
554 /* Abey : 6-Oct-99. Check again if the focus out window is the
555 Foreground window, because in most cases the messages sent
556 above must have already changed the foreground window, in which
557 case we don't have to change the foreground window to 0 */
558 if (hwnd == GetForegroundWindow())
560 TRACE( "lost focus, setting fg to 0\n" );
561 SetForegroundWindow( 0 );
567 /***********************************************************************
568 * EVENT_PropertyNotify
569 * We use this to release resources like Pixmaps when a selection
570 * client no longer needs them.
572 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
574 XPropertyEvent *event = &xev->xproperty;
575 /* Check if we have any resources to free */
576 TRACE("Received PropertyNotify event:\n");
578 switch(event->state)
580 case PropertyDelete:
582 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
583 event->atom, (long)event->window);
584 break;
587 case PropertyNewValue:
589 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
590 event->atom, (long)event->window);
591 break;
594 default:
595 break;
599 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
601 RECT tempRect;
603 if (!IsWindowEnabled(hQueryWnd)) return 0;
605 GetWindowRect(hQueryWnd, &tempRect);
607 if(!PtInRect(&tempRect, *lpPt)) return 0;
609 if (!IsIconic( hQueryWnd ))
611 POINT pt = *lpPt;
612 ScreenToClient( hQueryWnd, &pt );
613 GetClientRect( hQueryWnd, &tempRect );
615 if (PtInRect( &tempRect, pt))
617 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
618 if (ret && ret != hQueryWnd)
620 ret = find_drop_window( ret, lpPt );
621 if (ret) return ret;
626 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
628 ScreenToClient(hQueryWnd, lpPt);
630 return hQueryWnd;
633 /**********************************************************************
634 * EVENT_DropFromOffix
636 * don't know if it still works (last Changlog is from 96/11/04)
638 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
640 unsigned long data_length;
641 unsigned long aux_long;
642 unsigned char* p_data = NULL;
643 Atom atom_aux;
644 int x, y, dummy;
645 BOOL bAccept;
646 Window win, w_aux_root, w_aux_child;
647 WND* pWnd;
648 HWND hScope = hWnd;
650 win = X11DRV_get_whole_window(hWnd);
651 wine_tsx11_lock();
652 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
653 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
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 wine_tsx11_unlock();
808 drop_len += sizeof(DROPFILES) + 1;
809 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
810 lpDrop = (DROPFILES *) GlobalLock( hDrop );
812 if( lpDrop ) {
813 WND *pDropWnd = WIN_GetPtr( hWnd );
814 lpDrop->pFiles = sizeof(DROPFILES);
815 lpDrop->pt.x = (INT)x;
816 lpDrop->pt.y = (INT)y;
817 lpDrop->fNC =
818 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
819 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
820 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
821 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
822 lpDrop->fWide = FALSE;
823 p_drop = (char*)(lpDrop + 1);
824 WIN_ReleasePtr(pDropWnd);
827 /* create message content */
828 if (p_drop) {
829 p = (char*) p_data;
830 next = strchr(p, '\n');
831 while (p) {
832 if (next) *next=0;
833 if (strncmp(p,"file:",5) == 0 ) {
834 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
835 if (len) {
836 TRACE("drop file %s as %s\n", p+5, p_drop);
837 p_drop += len+1;
838 } else {
839 WARN("can't convert file %s to dos name\n", p+5);
841 } else {
842 WARN("unknown mime type %s\n", p);
844 if (next) {
845 *next = '\n';
846 p = next + 1;
847 next = strchr(p, '\n');
848 } else {
849 p = NULL;
851 *p_drop = '\0';
854 GlobalUnlock(hDrop);
855 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
858 wine_tsx11_lock();
859 if( p_data ) XFree(p_data);
860 wine_tsx11_unlock();
864 /**********************************************************************
865 * handle_dnd_protocol
867 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
869 Window root, child;
870 int root_x, root_y, child_x, child_y;
871 unsigned int u;
873 /* query window (drag&drop event contains only drag window) */
874 wine_tsx11_lock();
875 XQueryPointer( event->display, root_window, &root, &child,
876 &root_x, &root_y, &child_x, &child_y, &u);
877 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
878 wine_tsx11_unlock();
879 if (!hwnd) return;
880 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
881 EVENT_DropFromOffiX(hwnd, event);
882 else if (event->data.l[0] == DndURL)
883 EVENT_DropURLs(hwnd, event);
887 struct client_message_handler
889 int atom; /* protocol atom */
890 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
893 static const struct client_message_handler client_messages[] =
895 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
896 { XATOM_DndProtocol, handle_dnd_protocol },
897 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
898 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
899 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
900 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
904 /**********************************************************************
905 * EVENT_ClientMessage
907 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
909 XClientMessageEvent *event = &xev->xclient;
910 unsigned int i;
912 if (!hwnd) return;
914 if (event->format != 32)
916 WARN( "Don't know how to handle format %d\n", event->format );
917 return;
920 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
922 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
924 client_messages[i].handler( hwnd, event );
925 return;
928 TRACE( "no handler found for %ld\n", event->message_type );
932 /**********************************************************************
933 * X11DRV_WindowMessage (X11DRV.@)
935 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
937 switch(msg)
939 case WM_X11DRV_ACQUIRE_SELECTION:
940 X11DRV_AcquireClipboard( hwnd );
941 return 0;
942 case WM_X11DRV_DELETE_WINDOW:
943 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
944 default:
945 FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
946 return 0;
951 /***********************************************************************
952 * X11DRV_SendInput (X11DRV.@)
954 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
956 UINT i;
958 for (i = 0; i < count; i++, inputs++)
960 switch(inputs->type)
962 case INPUT_MOUSE:
963 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
964 inputs->u.mi.mouseData, inputs->u.mi.time,
965 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
966 break;
967 case INPUT_KEYBOARD:
968 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
969 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
970 break;
971 case INPUT_HARDWARE:
972 FIXME( "INPUT_HARDWARE not supported\n" );
973 break;
976 return count;