crypt32: Accept OSS errors as well.
[wine/wine-gecko.git] / dlls / winex11.drv / event.c
blobaad09c677182627b95ec973fde7a45ef6a246c53
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 "x11drv.h"
44 #include "shellapi.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(event);
49 extern BOOL ximInComposeMode;
51 #define DndNotDnd -1 /* OffiX drag&drop */
52 #define DndUnknown 0
53 #define DndRawData 1
54 #define DndFile 2
55 #define DndFiles 3
56 #define DndText 4
57 #define DndDir 5
58 #define DndLink 6
59 #define DndExe 7
61 #define DndEND 8
63 #define DndURL 128 /* KDE drag&drop */
65 /* Event handlers */
66 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
67 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
68 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
69 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
71 struct event_handler
73 int type; /* event type */
74 x11drv_event_handler handler; /* corresponding handler function */
77 #define MAX_EVENT_HANDLERS 64
79 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
81 /* list must be sorted by event type */
82 { KeyPress, X11DRV_KeyEvent },
83 { KeyRelease, X11DRV_KeyEvent },
84 { ButtonPress, X11DRV_ButtonPress },
85 { ButtonRelease, X11DRV_ButtonRelease },
86 { MotionNotify, X11DRV_MotionNotify },
87 { EnterNotify, X11DRV_EnterNotify },
88 /* LeaveNotify */
89 { FocusIn, EVENT_FocusIn },
90 { FocusOut, EVENT_FocusOut },
91 { KeymapNotify, X11DRV_KeymapNotify },
92 { Expose, X11DRV_Expose },
93 /* GraphicsExpose */
94 /* NoExpose */
95 /* VisibilityNotify */
96 /* CreateNotify */
97 /* DestroyNotify */
98 { UnmapNotify, X11DRV_UnmapNotify },
99 { MapNotify, X11DRV_MapNotify },
100 /* MapRequest */
101 /* ReparentNotify */
102 { ConfigureNotify, X11DRV_ConfigureNotify },
103 /* ConfigureRequest */
104 /* GravityNotify */
105 /* ResizeRequest */
106 /* CirculateNotify */
107 /* CirculateRequest */
108 { PropertyNotify, EVENT_PropertyNotify },
109 { SelectionClear, X11DRV_SelectionClear },
110 { SelectionRequest, X11DRV_SelectionRequest },
111 /* SelectionNotify */
112 /* ColormapNotify */
113 { ClientMessage, EVENT_ClientMessage },
114 { MappingNotify, X11DRV_MappingNotify },
117 static int nb_event_handlers = 18; /* change this if you add handlers above */
120 /* return the name of an X event */
121 static const char *dbgstr_event( int type )
123 static const char * const event_names[] =
125 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
126 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
127 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
128 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
129 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
130 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
131 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
132 "ClientMessage", "MappingNotify"
135 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
136 return wine_dbg_sprintf( "Extension event %d", type );
140 /***********************************************************************
141 * find_handler
143 * Find the handler for a given event type. Caller must hold the x11 lock.
145 static inline x11drv_event_handler find_handler( int type )
147 int min = 0, max = nb_event_handlers - 1;
149 while (min <= max)
151 int pos = (min + max) / 2;
152 if (handlers[pos].type == type) return handlers[pos].handler;
153 if (handlers[pos].type > type) max = pos - 1;
154 else min = pos + 1;
156 return NULL;
160 /***********************************************************************
161 * X11DRV_register_event_handler
163 * Register a handler for a given event type.
164 * If already registered, overwrite the previous handler.
166 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
168 int min, max;
170 wine_tsx11_lock();
171 min = 0;
172 max = nb_event_handlers - 1;
173 while (min <= max)
175 int pos = (min + max) / 2;
176 if (handlers[pos].type == type)
178 handlers[pos].handler = handler;
179 goto done;
181 if (handlers[pos].type > type) max = pos - 1;
182 else min = pos + 1;
184 /* insert it between max and min */
185 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
186 handlers[min].type = type;
187 handlers[min].handler = handler;
188 nb_event_handlers++;
189 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
190 done:
191 wine_tsx11_unlock();
192 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
196 /***********************************************************************
197 * filter_event
199 static Bool filter_event( Display *display, XEvent *event, char *arg )
201 ULONG_PTR mask = (ULONG_PTR)arg;
203 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
205 switch(event->type)
207 case KeyPress:
208 case KeyRelease:
209 case KeymapNotify:
210 case MappingNotify:
211 return (mask & QS_KEY) != 0;
212 case ButtonPress:
213 case ButtonRelease:
214 return (mask & QS_MOUSEBUTTON) != 0;
215 case MotionNotify:
216 case EnterNotify:
217 case LeaveNotify:
218 return (mask & QS_MOUSEMOVE) != 0;
219 case Expose:
220 return (mask & QS_PAINT) != 0;
221 case FocusIn:
222 case FocusOut:
223 case MapNotify:
224 case UnmapNotify:
225 case ConfigureNotify:
226 case PropertyNotify:
227 case ClientMessage:
228 return (mask & QS_POSTMESSAGE) != 0;
229 default:
230 return (mask & QS_SENDMESSAGE) != 0;
235 /***********************************************************************
236 * process_events
238 static int process_events( Display *display, ULONG_PTR mask )
240 XEvent event;
241 HWND hwnd;
242 int count = 0;
243 x11drv_event_handler handler;
245 wine_tsx11_lock();
246 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
248 count++;
249 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
251 if (!(handler = find_handler( event.type )))
253 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
254 continue; /* no handler, ignore it */
257 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
258 hwnd = 0; /* not for a registered window */
259 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
261 wine_tsx11_unlock();
262 TRACE( "%s for hwnd/window %p/%lx\n",
263 dbgstr_event( event.type ), hwnd, event.xany.window );
264 handler( hwnd, &event );
265 wine_tsx11_lock();
267 XFlush( gdi_display );
268 wine_tsx11_unlock();
269 if (count) TRACE( "processed %d events\n", count );
270 return count;
274 /***********************************************************************
275 * MsgWaitForMultipleObjectsEx (X11DRV.@)
277 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
278 DWORD timeout, DWORD mask, DWORD flags )
280 DWORD ret;
281 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
283 if (!data)
285 if (!count && !timeout) return WAIT_TIMEOUT;
286 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
287 timeout, flags & MWMO_ALERTABLE );
290 if (data->process_event_count) mask = 0; /* don't process nested events */
292 data->process_event_count++;
294 if (process_events( data->display, mask )) ret = count - 1;
295 else if (count || timeout)
297 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
298 timeout, flags & MWMO_ALERTABLE );
299 if (ret == count - 1) process_events( data->display, mask );
301 else ret = WAIT_TIMEOUT;
303 data->process_event_count--;
304 return ret;
307 /***********************************************************************
308 * EVENT_x11_time_to_win32_time
310 * Make our timer and the X timer line up as best we can
311 * Pass 0 to retrieve the current adjustment value (times -1)
313 DWORD EVENT_x11_time_to_win32_time(Time time)
315 static DWORD adjust = 0;
316 DWORD now = GetTickCount();
317 DWORD ret;
319 if (! adjust && time != 0)
321 ret = now;
322 adjust = time - now;
324 else
326 /* If we got an event in the 'future', then our clock is clearly wrong.
327 If we got it more than 10000 ms in the future, then it's most likely
328 that the clock has wrapped. */
330 ret = time - adjust;
331 if (ret > now && ((ret - now) < 10000) && time != 0)
333 adjust += ret - now;
334 ret -= ret - now;
338 return ret;
342 /*******************************************************************
343 * can_activate_window
345 * Check if we can activate the specified window.
347 static inline BOOL can_activate_window( HWND hwnd )
349 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
350 if (!(style & WS_VISIBLE)) return FALSE;
351 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
352 return !(style & WS_DISABLED);
356 /**********************************************************************
357 * set_focus
359 static void set_focus( HWND hwnd, Time time )
361 HWND focus;
362 Window win;
364 TRACE( "setting foreground window to %p\n", hwnd );
365 SetForegroundWindow( hwnd );
367 focus = GetFocus();
368 if (focus) focus = GetAncestor( focus, GA_ROOT );
369 win = X11DRV_get_whole_window(focus);
371 if (win)
373 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
374 wine_tsx11_lock();
375 XSetInputFocus( thread_display(), win, RevertToParent, time );
376 wine_tsx11_unlock();
381 /**********************************************************************
382 * handle_wm_protocols
384 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
386 Atom protocol = (Atom)event->data.l[0];
388 if (!protocol) return;
390 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
392 /* Ignore the delete window request if the window has been disabled
393 * and we are in managed mode. This is to disallow applications from
394 * being closed by the window manager while in a modal state.
396 if (IsWindowEnabled(hwnd))
398 HMENU hSysMenu;
400 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
401 hSysMenu = GetSystemMenu(hwnd, FALSE);
402 if (hSysMenu)
404 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
405 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
406 return;
408 if (GetActiveWindow() != hwnd)
410 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
411 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
412 MAKELONG(HTCLOSE,WM_LBUTTONDOWN) );
413 switch(ma)
415 case MA_NOACTIVATEANDEAT:
416 case MA_ACTIVATEANDEAT:
417 return;
418 case MA_NOACTIVATE:
419 break;
420 case MA_ACTIVATE:
421 case 0:
422 SetActiveWindow(hwnd);
423 break;
424 default:
425 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
426 break;
429 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
432 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
434 Time event_time = (Time)event->data.l[1];
435 HWND last_focus = x11drv_thread_data()->last_focus;
437 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
438 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
439 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
441 if (can_activate_window(hwnd))
443 /* simulate a mouse click on the caption to find out
444 * whether the window wants to be activated */
445 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
446 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
447 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
448 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
450 set_focus( hwnd, event_time );
451 return;
454 /* try to find some other window to give the focus to */
455 hwnd = GetFocus();
456 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
457 if (!hwnd) hwnd = GetActiveWindow();
458 if (!hwnd) hwnd = last_focus;
459 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
461 else if (protocol == x11drv_atom(_NET_WM_PING))
463 XClientMessageEvent xev;
464 xev = *event;
466 TRACE("NET_WM Ping\n");
467 wine_tsx11_lock();
468 xev.window = DefaultRootWindow(xev.display);
469 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
470 wine_tsx11_unlock();
471 /* this line is semi-stolen from gtk2 */
472 TRACE("NET_WM Pong\n");
477 static const char * const focus_details[] =
479 "NotifyAncestor",
480 "NotifyVirtual",
481 "NotifyInferior",
482 "NotifyNonlinear",
483 "NotifyNonlinearVirtual",
484 "NotifyPointer",
485 "NotifyPointerRoot",
486 "NotifyDetailNone"
489 /**********************************************************************
490 * EVENT_FocusIn
492 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
494 XFocusChangeEvent *event = &xev->xfocus;
495 XIC xic;
497 if (!hwnd) return;
499 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
501 if (event->detail == NotifyPointer) return;
503 if ((xic = X11DRV_get_ic( hwnd )))
505 wine_tsx11_lock();
506 XSetICFocus( xic );
507 wine_tsx11_unlock();
509 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
511 if (!can_activate_window(hwnd))
513 HWND hwnd = GetFocus();
514 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
515 if (!hwnd) hwnd = GetActiveWindow();
516 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
517 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
519 else SetForegroundWindow( hwnd );
523 /**********************************************************************
524 * EVENT_FocusOut
526 * Note: only top-level windows get FocusOut events.
528 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
530 XFocusChangeEvent *event = &xev->xfocus;
531 HWND hwnd_tmp;
532 Window focus_win;
533 int revert;
534 XIC xic;
536 if (!hwnd) return;
538 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
540 if (event->detail == NotifyPointer) return;
541 if (ximInComposeMode) return;
543 x11drv_thread_data()->last_focus = hwnd;
544 if ((xic = X11DRV_get_ic( hwnd )))
546 wine_tsx11_lock();
547 XUnsetICFocus( xic );
548 wine_tsx11_unlock();
550 if (hwnd != GetForegroundWindow()) return;
551 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
553 /* don't reset the foreground window, if the window which is
554 getting the focus is a Wine window */
556 wine_tsx11_lock();
557 XGetInputFocus( thread_display(), &focus_win, &revert );
558 if (focus_win)
560 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
561 focus_win = 0;
563 wine_tsx11_unlock();
565 if (!focus_win)
567 /* Abey : 6-Oct-99. Check again if the focus out window is the
568 Foreground window, because in most cases the messages sent
569 above must have already changed the foreground window, in which
570 case we don't have to change the foreground window to 0 */
571 if (hwnd == GetForegroundWindow())
573 TRACE( "lost focus, setting fg to 0\n" );
574 SetForegroundWindow( 0 );
580 /***********************************************************************
581 * EVENT_PropertyNotify
582 * We use this to release resources like Pixmaps when a selection
583 * client no longer needs them.
585 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
587 XPropertyEvent *event = &xev->xproperty;
588 /* Check if we have any resources to free */
589 TRACE("Received PropertyNotify event:\n");
591 switch(event->state)
593 case PropertyDelete:
595 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
596 event->atom, (long)event->window);
597 break;
600 case PropertyNewValue:
602 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
603 event->atom, (long)event->window);
604 break;
607 default:
608 break;
612 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
614 RECT tempRect;
616 if (!IsWindowEnabled(hQueryWnd)) return 0;
618 GetWindowRect(hQueryWnd, &tempRect);
620 if(!PtInRect(&tempRect, *lpPt)) return 0;
622 if (!IsIconic( hQueryWnd ))
624 POINT pt = *lpPt;
625 ScreenToClient( hQueryWnd, &pt );
626 GetClientRect( hQueryWnd, &tempRect );
628 if (PtInRect( &tempRect, pt))
630 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
631 if (ret && ret != hQueryWnd)
633 ret = find_drop_window( ret, lpPt );
634 if (ret) return ret;
639 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
641 ScreenToClient(hQueryWnd, lpPt);
643 return hQueryWnd;
646 /**********************************************************************
647 * EVENT_DropFromOffix
649 * don't know if it still works (last Changlog is from 96/11/04)
651 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
653 unsigned long data_length;
654 unsigned long aux_long;
655 unsigned char* p_data = NULL;
656 Atom atom_aux;
657 int x, y, dummy;
658 BOOL bAccept;
659 Window win, w_aux_root, w_aux_child;
660 WND* pWnd;
661 HWND hScope = hWnd;
663 win = X11DRV_get_whole_window(hWnd);
664 wine_tsx11_lock();
665 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
666 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
667 x += virtual_screen_rect.left;
668 y += virtual_screen_rect.top;
669 wine_tsx11_unlock();
671 pWnd = WIN_GetPtr(hWnd);
673 /* find out drop point and drop window */
674 if( x < 0 || y < 0 ||
675 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
676 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
678 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
679 x = 0;
680 y = 0;
682 else
684 POINT pt = { x, y };
685 HWND hwndDrop = find_drop_window( hWnd, &pt );
686 if (hwndDrop)
688 x = pt.x;
689 y = pt.y;
690 hScope = hwndDrop;
691 bAccept = TRUE;
693 else
695 bAccept = FALSE;
698 WIN_ReleasePtr(pWnd);
700 if (!bAccept) return;
702 wine_tsx11_lock();
703 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
704 x11drv_atom(DndSelection), 0, 65535, FALSE,
705 AnyPropertyType, &atom_aux, &dummy,
706 &data_length, &aux_long, &p_data);
707 wine_tsx11_unlock();
709 if( !aux_long && p_data) /* don't bother if > 64K */
711 char *p = (char *)p_data;
712 char *p_drop;
714 aux_long = 0;
715 while( *p ) /* calculate buffer size */
717 INT len = GetShortPathNameA( p, NULL, 0 );
718 if (len) aux_long += len + 1;
719 p += strlen(p) + 1;
721 if( aux_long && aux_long < 65535 )
723 HDROP hDrop;
724 DROPFILES *lpDrop;
726 aux_long += sizeof(DROPFILES) + 1;
727 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
728 lpDrop = (DROPFILES*)GlobalLock( hDrop );
730 if( lpDrop )
732 WND *pDropWnd = WIN_GetPtr( hScope );
733 lpDrop->pFiles = sizeof(DROPFILES);
734 lpDrop->pt.x = x;
735 lpDrop->pt.y = y;
736 lpDrop->fNC =
737 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
738 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
739 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
740 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
741 lpDrop->fWide = FALSE;
742 WIN_ReleasePtr(pDropWnd);
743 p_drop = (char *)(lpDrop + 1);
744 p = (char *)p_data;
745 while(*p)
747 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
748 p_drop += strlen( p_drop ) + 1;
749 p += strlen(p) + 1;
751 *p_drop = '\0';
752 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
756 wine_tsx11_lock();
757 if( p_data ) XFree(p_data);
758 wine_tsx11_unlock();
761 /**********************************************************************
762 * EVENT_DropURLs
764 * drop items are separated by \n
765 * each item is prefixed by its mime type
767 * event->data.l[3], event->data.l[4] contains drop x,y position
769 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
771 unsigned long data_length;
772 unsigned long aux_long, drop_len = 0;
773 unsigned char *p_data = NULL; /* property data */
774 char *p_drop = NULL;
775 char *p, *next;
776 int x, y;
777 DROPFILES *lpDrop;
778 HDROP hDrop;
779 union {
780 Atom atom_aux;
781 int i;
782 Window w_aux;
783 unsigned int u;
784 } u; /* unused */
786 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
788 wine_tsx11_lock();
789 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
790 x11drv_atom(DndSelection), 0, 65535, FALSE,
791 AnyPropertyType, &u.atom_aux, &u.i,
792 &data_length, &aux_long, &p_data);
793 wine_tsx11_unlock();
794 if (aux_long)
795 WARN("property too large, truncated!\n");
796 TRACE("urls=%s\n", p_data);
798 if( !aux_long && p_data) { /* don't bother if > 64K */
799 /* calculate length */
800 p = (char*) p_data;
801 next = strchr(p, '\n');
802 while (p) {
803 if (next) *next=0;
804 if (strncmp(p,"file:",5) == 0 ) {
805 INT len = GetShortPathNameA( p+5, NULL, 0 );
806 if (len) drop_len += len + 1;
808 if (next) {
809 *next = '\n';
810 p = next + 1;
811 next = strchr(p, '\n');
812 } else {
813 p = NULL;
817 if( drop_len && drop_len < 65535 ) {
818 wine_tsx11_lock();
819 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
820 &x, &y, &u.i, &u.i, &u.u);
821 x += virtual_screen_rect.left;
822 y += virtual_screen_rect.top;
823 wine_tsx11_unlock();
825 drop_len += sizeof(DROPFILES) + 1;
826 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
827 lpDrop = (DROPFILES *) GlobalLock( hDrop );
829 if( lpDrop ) {
830 WND *pDropWnd = WIN_GetPtr( hWnd );
831 lpDrop->pFiles = sizeof(DROPFILES);
832 lpDrop->pt.x = (INT)x;
833 lpDrop->pt.y = (INT)y;
834 lpDrop->fNC =
835 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
836 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
837 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
838 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
839 lpDrop->fWide = FALSE;
840 p_drop = (char*)(lpDrop + 1);
841 WIN_ReleasePtr(pDropWnd);
844 /* create message content */
845 if (p_drop) {
846 p = (char*) p_data;
847 next = strchr(p, '\n');
848 while (p) {
849 if (next) *next=0;
850 if (strncmp(p,"file:",5) == 0 ) {
851 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
852 if (len) {
853 TRACE("drop file %s as %s\n", p+5, p_drop);
854 p_drop += len+1;
855 } else {
856 WARN("can't convert file %s to dos name\n", p+5);
858 } else {
859 WARN("unknown mime type %s\n", p);
861 if (next) {
862 *next = '\n';
863 p = next + 1;
864 next = strchr(p, '\n');
865 } else {
866 p = NULL;
868 *p_drop = '\0';
871 GlobalUnlock(hDrop);
872 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
875 wine_tsx11_lock();
876 if( p_data ) XFree(p_data);
877 wine_tsx11_unlock();
881 /**********************************************************************
882 * handle_dnd_protocol
884 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
886 Window root, child;
887 int root_x, root_y, child_x, child_y;
888 unsigned int u;
890 /* query window (drag&drop event contains only drag window) */
891 wine_tsx11_lock();
892 XQueryPointer( event->display, root_window, &root, &child,
893 &root_x, &root_y, &child_x, &child_y, &u);
894 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
895 wine_tsx11_unlock();
896 if (!hwnd) return;
897 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
898 EVENT_DropFromOffiX(hwnd, event);
899 else if (event->data.l[0] == DndURL)
900 EVENT_DropURLs(hwnd, event);
904 struct client_message_handler
906 int atom; /* protocol atom */
907 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
910 static const struct client_message_handler client_messages[] =
912 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
913 { XATOM_DndProtocol, handle_dnd_protocol },
914 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
915 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
916 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
917 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
921 /**********************************************************************
922 * EVENT_ClientMessage
924 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
926 XClientMessageEvent *event = &xev->xclient;
927 unsigned int i;
929 if (!hwnd) return;
931 if (event->format != 32)
933 WARN( "Don't know how to handle format %d\n", event->format );
934 return;
937 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
939 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
941 client_messages[i].handler( hwnd, event );
942 return;
945 TRACE( "no handler found for %ld\n", event->message_type );
949 /**********************************************************************
950 * X11DRV_WindowMessage (X11DRV.@)
952 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
954 switch(msg)
956 case WM_X11DRV_ACQUIRE_SELECTION:
957 return X11DRV_AcquireClipboard( hwnd );
958 case WM_X11DRV_DELETE_WINDOW:
959 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
960 default:
961 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
962 return 0;
967 /***********************************************************************
968 * X11DRV_SendInput (X11DRV.@)
970 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
972 UINT i;
974 for (i = 0; i < count; i++, inputs++)
976 switch(inputs->type)
978 case INPUT_MOUSE:
979 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
980 inputs->u.mi.mouseData, inputs->u.mi.time,
981 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
982 break;
983 case INPUT_KEYBOARD:
984 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
985 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
986 break;
987 case INPUT_HARDWARE:
988 FIXME( "INPUT_HARDWARE not supported\n" );
989 break;
992 return count;