Made test loadable on win95 again (EnumDisplayDevicesA not present).
[wine/testsucceed.git] / dlls / x11drv / event.c
blobe47523d1142917c34282be55986bc1c1c34f749e
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 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 ClientMessage:
226 return (mask & QS_POSTMESSAGE) != 0;
227 default:
228 return (mask & QS_SENDMESSAGE) != 0;
233 /***********************************************************************
234 * process_events
236 static int process_events( Display *display, ULONG_PTR mask )
238 XEvent event;
239 HWND hwnd;
240 int count = 0;
241 x11drv_event_handler handler;
243 wine_tsx11_lock();
244 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
246 count++;
247 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
249 if (!(handler = find_handler( event.type )))
251 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
252 continue; /* no handler, ignore it */
255 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
256 hwnd = 0; /* not for a registered window */
257 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
259 wine_tsx11_unlock();
260 TRACE( "%s for hwnd/window %p/%lx\n",
261 dbgstr_event( event.type ), hwnd, event.xany.window );
262 handler( hwnd, &event );
263 wine_tsx11_lock();
265 wine_tsx11_unlock();
266 if (count) TRACE( "processed %d events\n", count );
267 return count;
271 /***********************************************************************
272 * MsgWaitForMultipleObjectsEx (X11DRV.@)
274 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
275 DWORD timeout, DWORD mask, DWORD flags )
277 DWORD i, ret;
278 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
280 if (!data || data->process_event_count)
282 if (!count && !timeout) return WAIT_TIMEOUT;
283 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
284 timeout, flags & MWMO_ALERTABLE );
287 /* check whether only server queue handle was passed in */
288 if (count < 2) flags &= ~MWMO_WAITALL;
290 wine_tsx11_lock();
291 XFlush( gdi_display );
292 XFlush( data->display );
293 wine_tsx11_unlock();
295 data->process_event_count++;
297 if (process_events( data->display, mask )) ret = count;
298 else if (count || timeout)
300 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
302 for (i = 0; i < count; i++) new_handles[i] = handles[i];
303 new_handles[count] = data->display_fd;
305 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
306 timeout, flags & MWMO_ALERTABLE );
307 if (ret == count) process_events( data->display, mask );
309 else ret = WAIT_TIMEOUT;
311 data->process_event_count--;
312 return ret;
315 /***********************************************************************
316 * EVENT_x11_time_to_win32_time
318 * Make our timer and the X timer line up as best we can
319 * Pass 0 to retrieve the current adjustment value (times -1)
321 DWORD EVENT_x11_time_to_win32_time(Time time)
323 static DWORD adjust = 0;
324 DWORD now = GetTickCount();
325 DWORD ret;
327 if (! adjust && time != 0)
329 ret = now;
330 adjust = time - now;
332 else
334 /* If we got an event in the 'future', then our clock is clearly wrong.
335 If we got it more than 10000 ms in the future, then it's most likely
336 that the clock has wrapped. */
338 ret = time - adjust;
339 if (ret > now && ((ret - now) < 10000) && time != 0)
341 adjust += ret - now;
342 ret -= ret - now;
346 return ret;
350 /*******************************************************************
351 * can_activate_window
353 * Check if we can activate the specified window.
355 inline static BOOL can_activate_window( HWND hwnd )
357 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
358 if (!(style & WS_VISIBLE)) return FALSE;
359 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
360 return !(style & WS_DISABLED);
364 /**********************************************************************
365 * set_focus
367 static void set_focus( HWND hwnd, Time time )
369 HWND focus;
370 Window win;
372 TRACE( "setting foreground window to %p\n", hwnd );
373 SetForegroundWindow( hwnd );
375 focus = GetFocus();
376 if (focus) focus = GetAncestor( focus, GA_ROOT );
377 win = X11DRV_get_whole_window(focus);
379 if (win)
381 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
382 wine_tsx11_lock();
383 XSetInputFocus( thread_display(), win, RevertToParent, time );
384 wine_tsx11_unlock();
389 /**********************************************************************
390 * handle_wm_protocols
392 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
394 Atom protocol = (Atom)event->data.l[0];
396 if (!protocol) return;
398 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
400 /* Ignore the delete window request if the window has been disabled
401 * and we are in managed mode. This is to disallow applications from
402 * being closed by the window manager while in a modal state.
404 if (IsWindowEnabled(hwnd))
406 HMENU hSysMenu;
408 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
409 hSysMenu = GetSystemMenu(hwnd, FALSE);
410 if (hSysMenu)
412 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
413 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
414 return;
416 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
419 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
421 Time event_time = (Time)event->data.l[1];
422 HWND last_focus = x11drv_thread_data()->last_focus;
424 TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
425 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
426 GetForegroundWindow(), last_focus );
428 if (can_activate_window(hwnd))
430 /* simulate a mouse click on the caption to find out
431 * whether the window wants to be activated */
432 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
433 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
434 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
435 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
436 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
438 else
440 hwnd = GetFocus();
441 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
442 if (!hwnd) hwnd = GetActiveWindow();
443 if (!hwnd) hwnd = last_focus;
444 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
447 else if (protocol == x11drv_atom(_NET_WM_PING))
449 XClientMessageEvent xev;
450 xev = *event;
452 TRACE("NET_WM Ping\n");
453 xev.window = DefaultRootWindow(xev.display);
454 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
455 /* this line is semi-stolen from gtk2 */
456 TRACE("NET_WM Pong\n");
461 static const char * const focus_details[] =
463 "NotifyAncestor",
464 "NotifyVirtual",
465 "NotifyInferior",
466 "NotifyNonlinear",
467 "NotifyNonlinearVirtual",
468 "NotifyPointer",
469 "NotifyPointerRoot",
470 "NotifyDetailNone"
473 /**********************************************************************
474 * EVENT_FocusIn
476 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
478 XFocusChangeEvent *event = &xev->xfocus;
479 XIC xic;
481 if (!hwnd) return;
483 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
485 if (event->detail == NotifyPointer) return;
487 if ((xic = X11DRV_get_ic( hwnd )))
489 wine_tsx11_lock();
490 XSetICFocus( xic );
491 wine_tsx11_unlock();
493 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
495 if (!can_activate_window(hwnd))
497 HWND hwnd = GetFocus();
498 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
499 if (!hwnd) hwnd = GetActiveWindow();
500 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
501 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
503 else SetForegroundWindow( hwnd );
507 /**********************************************************************
508 * EVENT_FocusOut
510 * Note: only top-level windows get FocusOut events.
512 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
514 XFocusChangeEvent *event = &xev->xfocus;
515 HWND hwnd_tmp;
516 Window focus_win;
517 int revert;
518 XIC xic;
520 if (!hwnd) return;
522 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
524 if (event->detail == NotifyPointer) return;
525 if (ximInComposeMode) return;
527 x11drv_thread_data()->last_focus = hwnd;
528 if ((xic = X11DRV_get_ic( hwnd )))
530 wine_tsx11_lock();
531 XUnsetICFocus( xic );
532 wine_tsx11_unlock();
534 if (hwnd != GetForegroundWindow()) return;
535 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
537 /* don't reset the foreground window, if the window which is
538 getting the focus is a Wine window */
540 wine_tsx11_lock();
541 XGetInputFocus( thread_display(), &focus_win, &revert );
542 if (focus_win)
544 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
545 focus_win = 0;
547 wine_tsx11_unlock();
549 if (!focus_win)
551 /* Abey : 6-Oct-99. Check again if the focus out window is the
552 Foreground window, because in most cases the messages sent
553 above must have already changed the foreground window, in which
554 case we don't have to change the foreground window to 0 */
555 if (hwnd == GetForegroundWindow())
557 TRACE( "lost focus, setting fg to 0\n" );
558 SetForegroundWindow( 0 );
564 /***********************************************************************
565 * EVENT_PropertyNotify
566 * We use this to release resources like Pixmaps when a selection
567 * client no longer needs them.
569 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
571 XPropertyEvent *event = &xev->xproperty;
572 /* Check if we have any resources to free */
573 TRACE("Received PropertyNotify event:\n");
575 switch(event->state)
577 case PropertyDelete:
579 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
580 event->atom, (long)event->window);
581 break;
584 case PropertyNewValue:
586 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
587 event->atom, (long)event->window);
588 break;
591 default:
592 break;
596 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
598 RECT tempRect;
600 if (!IsWindowEnabled(hQueryWnd)) return 0;
602 GetWindowRect(hQueryWnd, &tempRect);
604 if(!PtInRect(&tempRect, *lpPt)) return 0;
606 if (!IsIconic( hQueryWnd ))
608 POINT pt = *lpPt;
609 ScreenToClient( hQueryWnd, &pt );
610 GetClientRect( hQueryWnd, &tempRect );
612 if (PtInRect( &tempRect, pt))
614 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
615 if (ret && ret != hQueryWnd)
617 ret = find_drop_window( ret, lpPt );
618 if (ret) return ret;
623 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
625 ScreenToClient(hQueryWnd, lpPt);
627 return hQueryWnd;
630 /**********************************************************************
631 * EVENT_DropFromOffix
633 * don't know if it still works (last Changlog is from 96/11/04)
635 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
637 unsigned long data_length;
638 unsigned long aux_long;
639 unsigned char* p_data = NULL;
640 union {
641 Atom atom_aux;
642 struct {
643 int x;
644 int y;
645 } pt_aux;
646 int i;
647 } u;
648 int x, y;
649 BOOL bAccept;
650 Window win, w_aux_root, w_aux_child;
651 WND* pWnd;
652 HWND hScope = hWnd;
654 win = X11DRV_get_whole_window(hWnd);
655 wine_tsx11_lock();
656 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
657 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
658 (unsigned int*)&aux_long);
659 wine_tsx11_unlock();
661 pWnd = WIN_GetPtr(hWnd);
663 /* find out drop point and drop window */
664 if( x < 0 || y < 0 ||
665 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
666 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
668 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
669 x = 0;
670 y = 0;
672 else
674 POINT pt = { x, y };
675 HWND hwndDrop = find_drop_window( hWnd, &pt );
676 if (hwndDrop)
678 x = pt.x;
679 y = pt.y;
680 hScope = hwndDrop;
681 bAccept = TRUE;
683 else
685 bAccept = FALSE;
688 WIN_ReleasePtr(pWnd);
690 if (!bAccept) return;
692 wine_tsx11_lock();
693 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
694 x11drv_atom(DndSelection), 0, 65535, FALSE,
695 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
696 &data_length, &aux_long, &p_data);
697 wine_tsx11_unlock();
699 if( !aux_long && p_data) /* don't bother if > 64K */
701 signed char *p = (signed char*) p_data;
702 char *p_drop;
704 aux_long = 0;
705 while( *p ) /* calculate buffer size */
707 p_drop = p;
708 if((u.i = *p) != -1 )
710 INT len = GetShortPathNameA( p, NULL, 0 );
711 if (len) aux_long += len + 1;
712 else *p = -1;
714 p += strlen(p) + 1;
716 if( aux_long && aux_long < 65535 )
718 HDROP hDrop;
719 DROPFILES *lpDrop;
721 aux_long += sizeof(DROPFILES) + 1;
722 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
723 lpDrop = (DROPFILES*)GlobalLock( hDrop );
725 if( lpDrop )
727 WND *pDropWnd = WIN_GetPtr( hScope );
728 lpDrop->pFiles = sizeof(DROPFILES);
729 lpDrop->pt.x = x;
730 lpDrop->pt.y = y;
731 lpDrop->fNC =
732 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
733 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
734 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
735 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
736 lpDrop->fWide = FALSE;
737 WIN_ReleasePtr(pDropWnd);
738 p_drop = (char *)(lpDrop + 1);
739 p = p_data;
740 while(*p)
742 if( *p != -1 ) /* use only "good" entries */
744 GetShortPathNameA( p, p_drop, 65535 );
745 p_drop += strlen( p_drop ) + 1;
747 p += strlen(p) + 1;
749 *p_drop = '\0';
750 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
754 wine_tsx11_lock();
755 if( p_data ) XFree(p_data);
756 wine_tsx11_unlock();
759 /**********************************************************************
760 * EVENT_DropURLs
762 * drop items are separated by \n
763 * each item is prefixed by its mime type
765 * event->data.l[3], event->data.l[4] contains drop x,y position
767 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
769 unsigned long data_length;
770 unsigned long aux_long, drop_len = 0;
771 unsigned char *p_data = NULL; /* property data */
772 char *p_drop = NULL;
773 char *p, *next;
774 int x, y;
775 DROPFILES *lpDrop;
776 HDROP hDrop;
777 union {
778 Atom atom_aux;
779 int i;
780 Window w_aux;
781 unsigned int u;
782 } u; /* unused */
784 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
786 wine_tsx11_lock();
787 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
788 x11drv_atom(DndSelection), 0, 65535, FALSE,
789 AnyPropertyType, &u.atom_aux, &u.i,
790 &data_length, &aux_long, &p_data);
791 wine_tsx11_unlock();
792 if (aux_long)
793 WARN("property too large, truncated!\n");
794 TRACE("urls=%s\n", p_data);
796 if( !aux_long && p_data) { /* don't bother if > 64K */
797 /* calculate length */
798 p = (char*) p_data;
799 next = strchr(p, '\n');
800 while (p) {
801 if (next) *next=0;
802 if (strncmp(p,"file:",5) == 0 ) {
803 INT len = GetShortPathNameA( p+5, NULL, 0 );
804 if (len) drop_len += len + 1;
806 if (next) {
807 *next = '\n';
808 p = next + 1;
809 next = strchr(p, '\n');
810 } else {
811 p = NULL;
815 if( drop_len && drop_len < 65535 ) {
816 wine_tsx11_lock();
817 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
818 &x, &y, &u.i, &u.i, &u.u);
819 wine_tsx11_unlock();
821 drop_len += sizeof(DROPFILES) + 1;
822 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
823 lpDrop = (DROPFILES *) GlobalLock( hDrop );
825 if( lpDrop ) {
826 WND *pDropWnd = WIN_GetPtr( hWnd );
827 lpDrop->pFiles = sizeof(DROPFILES);
828 lpDrop->pt.x = (INT)x;
829 lpDrop->pt.y = (INT)y;
830 lpDrop->fNC =
831 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
832 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
833 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
834 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
835 lpDrop->fWide = FALSE;
836 p_drop = (char*)(lpDrop + 1);
837 WIN_ReleasePtr(pDropWnd);
840 /* create message content */
841 if (p_drop) {
842 p = (char*) p_data;
843 next = strchr(p, '\n');
844 while (p) {
845 if (next) *next=0;
846 if (strncmp(p,"file:",5) == 0 ) {
847 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
848 if (len) {
849 TRACE("drop file %s as %s\n", p+5, p_drop);
850 p_drop += len+1;
851 } else {
852 WARN("can't convert file %s to dos name\n", p+5);
854 } else {
855 WARN("unknown mime type %s\n", p);
857 if (next) {
858 *next = '\n';
859 p = next + 1;
860 next = strchr(p, '\n');
861 } else {
862 p = NULL;
864 *p_drop = '\0';
867 GlobalUnlock(hDrop);
868 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
871 wine_tsx11_lock();
872 if( p_data ) XFree(p_data);
873 wine_tsx11_unlock();
877 /**********************************************************************
878 * handle_dnd_protocol
880 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
882 Window root, child;
883 int root_x, root_y, child_x, child_y;
884 unsigned int u;
886 /* query window (drag&drop event contains only drag window) */
887 wine_tsx11_lock();
888 XQueryPointer( event->display, root_window, &root, &child,
889 &root_x, &root_y, &child_x, &child_y, &u);
890 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
891 wine_tsx11_unlock();
892 if (!hwnd) return;
893 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
894 EVENT_DropFromOffiX(hwnd, event);
895 else if (event->data.l[0] == DndURL)
896 EVENT_DropURLs(hwnd, event);
900 struct client_message_handler
902 int atom; /* protocol atom */
903 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
906 static const struct client_message_handler client_messages[] =
908 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
909 { XATOM_DndProtocol, handle_dnd_protocol },
910 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
911 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
912 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
913 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
917 /**********************************************************************
918 * EVENT_ClientMessage
920 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
922 XClientMessageEvent *event = &xev->xclient;
923 unsigned int i;
925 if (!hwnd) return;
927 if (event->format != 32)
929 WARN( "Don't know how to handle format %d\n", event->format );
930 return;
933 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
935 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
937 client_messages[i].handler( hwnd, event );
938 return;
941 TRACE( "no handler found for %ld\n", event->message_type );
945 /**********************************************************************
946 * X11DRV_WindowMessage (X11DRV.@)
948 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
950 switch(msg)
952 case WM_X11DRV_ACQUIRE_SELECTION:
953 X11DRV_AcquireClipboard( hwnd );
954 return 0;
955 case WM_X11DRV_DELETE_WINDOW:
956 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
957 default:
958 FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
959 return 0;
964 /***********************************************************************
965 * X11DRV_SendInput (X11DRV.@)
967 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
969 UINT i;
971 for (i = 0; i < count; i++, inputs++)
973 switch(inputs->type)
975 case INPUT_MOUSE:
976 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
977 inputs->u.mi.mouseData, inputs->u.mi.time,
978 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
979 break;
980 case INPUT_KEYBOARD:
981 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
982 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
983 break;
984 case INPUT_HARDWARE:
985 FIXME( "INPUT_HARDWARE not supported\n" );
986 break;
989 return count;