Removes all unnecessary WINE_DEFAULT_DEBUG_CHANNEL and respective wine/debug.h includes.
[wine/multimedia.git] / dlls / winex11.drv / event.c
blob210d816706a9fa7814dd930fc70d500874c6d3e2
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 #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>
31 #include <assert.h>
32 #include <stdarg.h>
33 #include <string.h>
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winuser.h"
40 #include "wingdi.h"
41 #include "shlobj.h" /* DROPFILES */
43 #include "win.h"
44 #include "winreg.h"
45 #include "x11drv.h"
46 #include "shellapi.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(event);
51 extern BOOL ximInComposeMode;
53 #define DndNotDnd -1 /* OffiX drag&drop */
54 #define DndUnknown 0
55 #define DndRawData 1
56 #define DndFile 2
57 #define DndFiles 3
58 #define DndText 4
59 #define DndDir 5
60 #define DndLink 6
61 #define DndExe 7
63 #define DndEND 8
65 #define DndURL 128 /* KDE drag&drop */
67 /* Event handlers */
68 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
69 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
70 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
71 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
73 struct event_handler
75 int type; /* event type */
76 x11drv_event_handler handler; /* corresponding handler function */
79 #define MAX_EVENT_HANDLERS 64
81 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
83 /* list must be sorted by event type */
84 { KeyPress, X11DRV_KeyEvent },
85 { KeyRelease, X11DRV_KeyEvent },
86 { ButtonPress, X11DRV_ButtonPress },
87 { ButtonRelease, X11DRV_ButtonRelease },
88 { MotionNotify, X11DRV_MotionNotify },
89 { EnterNotify, X11DRV_EnterNotify },
90 /* LeaveNotify */
91 { FocusIn, EVENT_FocusIn },
92 { FocusOut, EVENT_FocusOut },
93 { KeymapNotify, X11DRV_KeymapNotify },
94 { Expose, X11DRV_Expose },
95 /* GraphicsExpose */
96 /* NoExpose */
97 /* VisibilityNotify */
98 /* CreateNotify */
99 /* DestroyNotify */
100 { UnmapNotify, X11DRV_UnmapNotify },
101 { MapNotify, X11DRV_MapNotify },
102 /* MapRequest */
103 /* ReparentNotify */
104 { ConfigureNotify, X11DRV_ConfigureNotify },
105 /* ConfigureRequest */
106 /* GravityNotify */
107 /* ResizeRequest */
108 /* CirculateNotify */
109 /* CirculateRequest */
110 { PropertyNotify, EVENT_PropertyNotify },
111 { SelectionClear, X11DRV_SelectionClear },
112 { SelectionRequest, X11DRV_SelectionRequest },
113 /* SelectionNotify */
114 /* ColormapNotify */
115 { ClientMessage, EVENT_ClientMessage },
116 { MappingNotify, X11DRV_MappingNotify },
119 static int nb_event_handlers = 18; /* change this if you add handlers above */
122 /* return the name of an X event */
123 static const char *dbgstr_event( int type )
125 static const char * const event_names[] =
127 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
128 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
129 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
130 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
131 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
132 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
133 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
134 "ClientMessage", "MappingNotify"
137 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
138 return wine_dbg_sprintf( "Extension event %d", type );
142 /***********************************************************************
143 * find_handler
145 * Find the handler for a given event type. Caller must hold the x11 lock.
147 static inline x11drv_event_handler find_handler( int type )
149 int min = 0, max = nb_event_handlers - 1;
151 while (min <= max)
153 int pos = (min + max) / 2;
154 if (handlers[pos].type == type) return handlers[pos].handler;
155 if (handlers[pos].type > type) max = pos - 1;
156 else min = pos + 1;
158 return NULL;
162 /***********************************************************************
163 * X11DRV_register_event_handler
165 * Register a handler for a given event type.
166 * If already registered, overwrite the previous handler.
168 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
170 int min, max;
172 wine_tsx11_lock();
173 min = 0;
174 max = nb_event_handlers - 1;
175 while (min <= max)
177 int pos = (min + max) / 2;
178 if (handlers[pos].type == type)
180 handlers[pos].handler = handler;
181 goto done;
183 if (handlers[pos].type > type) max = pos - 1;
184 else min = pos + 1;
186 /* insert it between max and min */
187 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
188 handlers[min].type = type;
189 handlers[min].handler = handler;
190 nb_event_handlers++;
191 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
192 done:
193 wine_tsx11_unlock();
194 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
198 /***********************************************************************
199 * filter_event
201 static Bool filter_event( Display *display, XEvent *event, char *arg )
203 ULONG_PTR mask = (ULONG_PTR)arg;
205 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
207 switch(event->type)
209 case KeyPress:
210 case KeyRelease:
211 case KeymapNotify:
212 case MappingNotify:
213 return (mask & QS_KEY) != 0;
214 case ButtonPress:
215 case ButtonRelease:
216 return (mask & QS_MOUSEBUTTON) != 0;
217 case MotionNotify:
218 case EnterNotify:
219 case LeaveNotify:
220 return (mask & QS_MOUSEMOVE) != 0;
221 case Expose:
222 return (mask & QS_PAINT) != 0;
223 case FocusIn:
224 case FocusOut:
225 case MapNotify:
226 case UnmapNotify:
227 case ConfigureNotify:
228 case PropertyNotify:
229 case ClientMessage:
230 return (mask & QS_POSTMESSAGE) != 0;
231 default:
232 return (mask & QS_SENDMESSAGE) != 0;
237 /***********************************************************************
238 * process_events
240 static int process_events( Display *display, ULONG_PTR mask )
242 XEvent event;
243 HWND hwnd;
244 int count = 0;
245 x11drv_event_handler handler;
247 wine_tsx11_lock();
248 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
250 count++;
251 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
253 if (!(handler = find_handler( event.type )))
255 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
256 continue; /* no handler, ignore it */
259 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
260 hwnd = 0; /* not for a registered window */
261 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
263 wine_tsx11_unlock();
264 TRACE( "%s for hwnd/window %p/%lx\n",
265 dbgstr_event( event.type ), hwnd, event.xany.window );
266 handler( hwnd, &event );
267 wine_tsx11_lock();
269 XFlush( gdi_display );
270 wine_tsx11_unlock();
271 if (count) TRACE( "processed %d events\n", count );
272 return count;
276 /***********************************************************************
277 * MsgWaitForMultipleObjectsEx (X11DRV.@)
279 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
280 DWORD timeout, DWORD mask, DWORD flags )
282 DWORD i, ret;
283 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
285 if (!data || data->process_event_count)
287 if (!count && !timeout) return WAIT_TIMEOUT;
288 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
289 timeout, flags & MWMO_ALERTABLE );
292 /* check whether only server queue handle was passed in */
293 if (count < 2) flags &= ~MWMO_WAITALL;
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, visible=%d (style %08lx), focus=%p, active=%p, fg=%p, last=%p\n",
425 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
426 GetFocus(), GetActiveWindow(), 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 wine_tsx11_lock();
454 xev.window = DefaultRootWindow(xev.display);
455 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
456 wine_tsx11_unlock();
457 /* this line is semi-stolen from gtk2 */
458 TRACE("NET_WM Pong\n");
463 static const char * const focus_details[] =
465 "NotifyAncestor",
466 "NotifyVirtual",
467 "NotifyInferior",
468 "NotifyNonlinear",
469 "NotifyNonlinearVirtual",
470 "NotifyPointer",
471 "NotifyPointerRoot",
472 "NotifyDetailNone"
475 /**********************************************************************
476 * EVENT_FocusIn
478 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
480 XFocusChangeEvent *event = &xev->xfocus;
481 XIC xic;
483 if (!hwnd) return;
485 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
487 if (event->detail == NotifyPointer) return;
489 if ((xic = X11DRV_get_ic( hwnd )))
491 wine_tsx11_lock();
492 XSetICFocus( xic );
493 wine_tsx11_unlock();
495 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
497 if (!can_activate_window(hwnd))
499 HWND hwnd = GetFocus();
500 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
501 if (!hwnd) hwnd = GetActiveWindow();
502 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
503 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
505 else SetForegroundWindow( hwnd );
509 /**********************************************************************
510 * EVENT_FocusOut
512 * Note: only top-level windows get FocusOut events.
514 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
516 XFocusChangeEvent *event = &xev->xfocus;
517 HWND hwnd_tmp;
518 Window focus_win;
519 int revert;
520 XIC xic;
522 if (!hwnd) return;
524 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
526 if (event->detail == NotifyPointer) return;
527 if (ximInComposeMode) return;
529 x11drv_thread_data()->last_focus = hwnd;
530 if ((xic = X11DRV_get_ic( hwnd )))
532 wine_tsx11_lock();
533 XUnsetICFocus( xic );
534 wine_tsx11_unlock();
536 if (hwnd != GetForegroundWindow()) return;
537 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
539 /* don't reset the foreground window, if the window which is
540 getting the focus is a Wine window */
542 wine_tsx11_lock();
543 XGetInputFocus( thread_display(), &focus_win, &revert );
544 if (focus_win)
546 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
547 focus_win = 0;
549 wine_tsx11_unlock();
551 if (!focus_win)
553 /* Abey : 6-Oct-99. Check again if the focus out window is the
554 Foreground window, because in most cases the messages sent
555 above must have already changed the foreground window, in which
556 case we don't have to change the foreground window to 0 */
557 if (hwnd == GetForegroundWindow())
559 TRACE( "lost focus, setting fg to 0\n" );
560 SetForegroundWindow( 0 );
566 /***********************************************************************
567 * EVENT_PropertyNotify
568 * We use this to release resources like Pixmaps when a selection
569 * client no longer needs them.
571 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
573 XPropertyEvent *event = &xev->xproperty;
574 /* Check if we have any resources to free */
575 TRACE("Received PropertyNotify event:\n");
577 switch(event->state)
579 case PropertyDelete:
581 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
582 event->atom, (long)event->window);
583 break;
586 case PropertyNewValue:
588 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
589 event->atom, (long)event->window);
590 break;
593 default:
594 break;
598 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
600 RECT tempRect;
602 if (!IsWindowEnabled(hQueryWnd)) return 0;
604 GetWindowRect(hQueryWnd, &tempRect);
606 if(!PtInRect(&tempRect, *lpPt)) return 0;
608 if (!IsIconic( hQueryWnd ))
610 POINT pt = *lpPt;
611 ScreenToClient( hQueryWnd, &pt );
612 GetClientRect( hQueryWnd, &tempRect );
614 if (PtInRect( &tempRect, pt))
616 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
617 if (ret && ret != hQueryWnd)
619 ret = find_drop_window( ret, lpPt );
620 if (ret) return ret;
625 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
627 ScreenToClient(hQueryWnd, lpPt);
629 return hQueryWnd;
632 /**********************************************************************
633 * EVENT_DropFromOffix
635 * don't know if it still works (last Changlog is from 96/11/04)
637 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
639 unsigned long data_length;
640 unsigned long aux_long;
641 unsigned char* p_data = NULL;
642 Atom atom_aux;
643 int x, y, dummy;
644 BOOL bAccept;
645 Window win, w_aux_root, w_aux_child;
646 WND* pWnd;
647 HWND hScope = hWnd;
649 win = X11DRV_get_whole_window(hWnd);
650 wine_tsx11_lock();
651 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
652 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
653 wine_tsx11_unlock();
655 pWnd = WIN_GetPtr(hWnd);
657 /* find out drop point and drop window */
658 if( x < 0 || y < 0 ||
659 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
660 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
662 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
663 x = 0;
664 y = 0;
666 else
668 POINT pt = { x, y };
669 HWND hwndDrop = find_drop_window( hWnd, &pt );
670 if (hwndDrop)
672 x = pt.x;
673 y = pt.y;
674 hScope = hwndDrop;
675 bAccept = TRUE;
677 else
679 bAccept = FALSE;
682 WIN_ReleasePtr(pWnd);
684 if (!bAccept) return;
686 wine_tsx11_lock();
687 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
688 x11drv_atom(DndSelection), 0, 65535, FALSE,
689 AnyPropertyType, &atom_aux, &dummy,
690 &data_length, &aux_long, &p_data);
691 wine_tsx11_unlock();
693 if( !aux_long && p_data) /* don't bother if > 64K */
695 char *p = (char *)p_data;
696 char *p_drop;
698 aux_long = 0;
699 while( *p ) /* calculate buffer size */
701 INT len = GetShortPathNameA( p, NULL, 0 );
702 if (len) aux_long += len + 1;
703 p += strlen(p) + 1;
705 if( aux_long && aux_long < 65535 )
707 HDROP hDrop;
708 DROPFILES *lpDrop;
710 aux_long += sizeof(DROPFILES) + 1;
711 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
712 lpDrop = (DROPFILES*)GlobalLock( hDrop );
714 if( lpDrop )
716 WND *pDropWnd = WIN_GetPtr( hScope );
717 lpDrop->pFiles = sizeof(DROPFILES);
718 lpDrop->pt.x = x;
719 lpDrop->pt.y = y;
720 lpDrop->fNC =
721 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
722 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
723 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
724 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
725 lpDrop->fWide = FALSE;
726 WIN_ReleasePtr(pDropWnd);
727 p_drop = (char *)(lpDrop + 1);
728 p = (char *)p_data;
729 while(*p)
731 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
732 p_drop += strlen( p_drop ) + 1;
733 p += strlen(p) + 1;
735 *p_drop = '\0';
736 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
740 wine_tsx11_lock();
741 if( p_data ) XFree(p_data);
742 wine_tsx11_unlock();
745 /**********************************************************************
746 * EVENT_DropURLs
748 * drop items are separated by \n
749 * each item is prefixed by its mime type
751 * event->data.l[3], event->data.l[4] contains drop x,y position
753 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
755 unsigned long data_length;
756 unsigned long aux_long, drop_len = 0;
757 unsigned char *p_data = NULL; /* property data */
758 char *p_drop = NULL;
759 char *p, *next;
760 int x, y;
761 DROPFILES *lpDrop;
762 HDROP hDrop;
763 union {
764 Atom atom_aux;
765 int i;
766 Window w_aux;
767 unsigned int u;
768 } u; /* unused */
770 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
772 wine_tsx11_lock();
773 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
774 x11drv_atom(DndSelection), 0, 65535, FALSE,
775 AnyPropertyType, &u.atom_aux, &u.i,
776 &data_length, &aux_long, &p_data);
777 wine_tsx11_unlock();
778 if (aux_long)
779 WARN("property too large, truncated!\n");
780 TRACE("urls=%s\n", p_data);
782 if( !aux_long && p_data) { /* don't bother if > 64K */
783 /* calculate length */
784 p = (char*) p_data;
785 next = strchr(p, '\n');
786 while (p) {
787 if (next) *next=0;
788 if (strncmp(p,"file:",5) == 0 ) {
789 INT len = GetShortPathNameA( p+5, NULL, 0 );
790 if (len) drop_len += len + 1;
792 if (next) {
793 *next = '\n';
794 p = next + 1;
795 next = strchr(p, '\n');
796 } else {
797 p = NULL;
801 if( drop_len && drop_len < 65535 ) {
802 wine_tsx11_lock();
803 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
804 &x, &y, &u.i, &u.i, &u.u);
805 wine_tsx11_unlock();
807 drop_len += sizeof(DROPFILES) + 1;
808 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
809 lpDrop = (DROPFILES *) GlobalLock( hDrop );
811 if( lpDrop ) {
812 WND *pDropWnd = WIN_GetPtr( hWnd );
813 lpDrop->pFiles = sizeof(DROPFILES);
814 lpDrop->pt.x = (INT)x;
815 lpDrop->pt.y = (INT)y;
816 lpDrop->fNC =
817 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
818 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
819 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
820 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
821 lpDrop->fWide = FALSE;
822 p_drop = (char*)(lpDrop + 1);
823 WIN_ReleasePtr(pDropWnd);
826 /* create message content */
827 if (p_drop) {
828 p = (char*) p_data;
829 next = strchr(p, '\n');
830 while (p) {
831 if (next) *next=0;
832 if (strncmp(p,"file:",5) == 0 ) {
833 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
834 if (len) {
835 TRACE("drop file %s as %s\n", p+5, p_drop);
836 p_drop += len+1;
837 } else {
838 WARN("can't convert file %s to dos name\n", p+5);
840 } else {
841 WARN("unknown mime type %s\n", p);
843 if (next) {
844 *next = '\n';
845 p = next + 1;
846 next = strchr(p, '\n');
847 } else {
848 p = NULL;
850 *p_drop = '\0';
853 GlobalUnlock(hDrop);
854 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
857 wine_tsx11_lock();
858 if( p_data ) XFree(p_data);
859 wine_tsx11_unlock();
863 /**********************************************************************
864 * handle_dnd_protocol
866 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
868 Window root, child;
869 int root_x, root_y, child_x, child_y;
870 unsigned int u;
872 /* query window (drag&drop event contains only drag window) */
873 wine_tsx11_lock();
874 XQueryPointer( event->display, root_window, &root, &child,
875 &root_x, &root_y, &child_x, &child_y, &u);
876 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
877 wine_tsx11_unlock();
878 if (!hwnd) return;
879 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
880 EVENT_DropFromOffiX(hwnd, event);
881 else if (event->data.l[0] == DndURL)
882 EVENT_DropURLs(hwnd, event);
886 struct client_message_handler
888 int atom; /* protocol atom */
889 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
892 static const struct client_message_handler client_messages[] =
894 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
895 { XATOM_DndProtocol, handle_dnd_protocol },
896 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
897 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
898 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
899 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
903 /**********************************************************************
904 * EVENT_ClientMessage
906 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
908 XClientMessageEvent *event = &xev->xclient;
909 unsigned int i;
911 if (!hwnd) return;
913 if (event->format != 32)
915 WARN( "Don't know how to handle format %d\n", event->format );
916 return;
919 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
921 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
923 client_messages[i].handler( hwnd, event );
924 return;
927 TRACE( "no handler found for %ld\n", event->message_type );
931 /**********************************************************************
932 * X11DRV_WindowMessage (X11DRV.@)
934 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
936 switch(msg)
938 case WM_X11DRV_ACQUIRE_SELECTION:
939 return X11DRV_AcquireClipboard( hwnd );
940 case WM_X11DRV_DELETE_WINDOW:
941 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
942 default:
943 FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
944 return 0;
949 /***********************************************************************
950 * X11DRV_SendInput (X11DRV.@)
952 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
954 UINT i;
956 for (i = 0; i < count; i++, inputs++)
958 switch(inputs->type)
960 case INPUT_MOUSE:
961 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
962 inputs->u.mi.mouseData, inputs->u.mi.time,
963 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
964 break;
965 case INPUT_KEYBOARD:
966 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
967 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
968 break;
969 case INPUT_HARDWARE:
970 FIXME( "INPUT_HARDWARE not supported\n" );
971 break;
974 return count;