Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / winex11.drv / event.c
blob92b001a1c403e89a174100aaa527ae0bd65dc01d
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #include <X11/Xatom.h>
25 #include <X11/keysym.h>
26 #include <X11/Xlib.h>
27 #include <X11/Xresource.h>
28 #include <X11/Xutil.h>
30 #include <assert.h>
31 #include <stdarg.h>
32 #include <string.h>
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winuser.h"
39 #include "wingdi.h"
40 #include "shlobj.h" /* DROPFILES */
42 #include "win.h"
43 #include "winreg.h"
44 #include "x11drv.h"
45 #include "shellapi.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(event);
50 extern BOOL ximInComposeMode;
52 #define DndNotDnd -1 /* OffiX drag&drop */
53 #define DndUnknown 0
54 #define DndRawData 1
55 #define DndFile 2
56 #define DndFiles 3
57 #define DndText 4
58 #define DndDir 5
59 #define DndLink 6
60 #define DndExe 7
62 #define DndEND 8
64 #define DndURL 128 /* KDE drag&drop */
66 /* Event handlers */
67 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
68 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
69 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
70 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
71 static void EVENT_GravityNotify( 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, X11DRV_DestroyNotify },
100 { UnmapNotify, X11DRV_UnmapNotify },
101 { MapNotify, X11DRV_MapNotify },
102 /* MapRequest */
103 /* ReparentNotify */
104 { ConfigureNotify, X11DRV_ConfigureNotify },
105 /* ConfigureRequest */
106 { GravityNotify, EVENT_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 = 20; /* change this if you add handlers above */
121 /* return the name of an X event */
122 static const char *dbgstr_event( int type )
124 static const char * const event_names[] =
126 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
127 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
128 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
129 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
130 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
131 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
132 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
133 "ClientMessage", "MappingNotify"
136 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
137 return wine_dbg_sprintf( "Extension event %d", type );
141 /***********************************************************************
142 * find_handler
144 * Find the handler for a given event type. Caller must hold the x11 lock.
146 static inline x11drv_event_handler find_handler( int type )
148 int min = 0, max = nb_event_handlers - 1;
150 while (min <= max)
152 int pos = (min + max) / 2;
153 if (handlers[pos].type == type) return handlers[pos].handler;
154 if (handlers[pos].type > type) max = pos - 1;
155 else min = pos + 1;
157 return NULL;
161 /***********************************************************************
162 * X11DRV_register_event_handler
164 * Register a handler for a given event type.
165 * If already registered, overwrite the previous handler.
167 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
169 int min, max;
171 wine_tsx11_lock();
172 min = 0;
173 max = nb_event_handlers - 1;
174 while (min <= max)
176 int pos = (min + max) / 2;
177 if (handlers[pos].type == type)
179 handlers[pos].handler = handler;
180 goto done;
182 if (handlers[pos].type > type) max = pos - 1;
183 else min = pos + 1;
185 /* insert it between max and min */
186 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
187 handlers[min].type = type;
188 handlers[min].handler = handler;
189 nb_event_handlers++;
190 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
191 done:
192 wine_tsx11_unlock();
193 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
197 /***********************************************************************
198 * filter_event
200 static Bool filter_event( Display *display, XEvent *event, char *arg )
202 ULONG_PTR mask = (ULONG_PTR)arg;
204 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
206 switch(event->type)
208 case KeyPress:
209 case KeyRelease:
210 case KeymapNotify:
211 case MappingNotify:
212 return (mask & QS_KEY) != 0;
213 case ButtonPress:
214 case ButtonRelease:
215 return (mask & QS_MOUSEBUTTON) != 0;
216 case MotionNotify:
217 case EnterNotify:
218 case LeaveNotify:
219 return (mask & QS_MOUSEMOVE) != 0;
220 case Expose:
221 return (mask & QS_PAINT) != 0;
222 case FocusIn:
223 case FocusOut:
224 case MapNotify:
225 case UnmapNotify:
226 case ConfigureNotify:
227 case PropertyNotify:
228 case ClientMessage:
229 return (mask & QS_POSTMESSAGE) != 0;
230 default:
231 return (mask & QS_SENDMESSAGE) != 0;
236 /***********************************************************************
237 * process_events
239 static int process_events( Display *display, ULONG_PTR mask )
241 XEvent event;
242 HWND hwnd;
243 int count = 0;
244 x11drv_event_handler handler;
246 wine_tsx11_lock();
247 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
249 count++;
250 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
252 if (!(handler = find_handler( event.type )))
254 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
255 continue; /* no handler, ignore it */
258 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
259 hwnd = 0; /* not for a registered window */
260 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
262 wine_tsx11_unlock();
263 TRACE( "%s for hwnd/window %p/%lx\n",
264 dbgstr_event( event.type ), hwnd, event.xany.window );
265 handler( hwnd, &event );
266 wine_tsx11_lock();
268 XFlush( gdi_display );
269 wine_tsx11_unlock();
270 if (count) TRACE( "processed %d events\n", count );
271 return count;
275 /***********************************************************************
276 * MsgWaitForMultipleObjectsEx (X11DRV.@)
278 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
279 DWORD timeout, DWORD mask, DWORD flags )
281 DWORD i, ret;
282 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
284 if (!data || data->process_event_count)
286 if (!count && !timeout) return WAIT_TIMEOUT;
287 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
288 timeout, flags & MWMO_ALERTABLE );
291 /* check whether only server queue handle was passed in */
292 if (count < 2) flags &= ~MWMO_WAITALL;
294 data->process_event_count++;
296 if (process_events( data->display, mask )) ret = count;
297 else if (count || timeout)
299 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
301 for (i = 0; i < count; i++) new_handles[i] = handles[i];
302 new_handles[count] = data->display_fd;
304 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
305 timeout, flags & MWMO_ALERTABLE );
306 if (ret == count) process_events( data->display, mask );
308 else ret = WAIT_TIMEOUT;
310 data->process_event_count--;
311 return ret;
314 /***********************************************************************
315 * EVENT_x11_time_to_win32_time
317 * Make our timer and the X timer line up as best we can
318 * Pass 0 to retrieve the current adjustment value (times -1)
320 DWORD EVENT_x11_time_to_win32_time(Time time)
322 static DWORD adjust = 0;
323 DWORD now = GetTickCount();
324 DWORD ret;
326 if (! adjust && time != 0)
328 ret = now;
329 adjust = time - now;
331 else
333 /* If we got an event in the 'future', then our clock is clearly wrong.
334 If we got it more than 10000 ms in the future, then it's most likely
335 that the clock has wrapped. */
337 ret = time - adjust;
338 if (ret > now && ((ret - now) < 10000) && time != 0)
340 adjust += ret - now;
341 ret -= ret - now;
345 return ret;
349 /*******************************************************************
350 * can_activate_window
352 * Check if we can activate the specified window.
354 static inline BOOL can_activate_window( HWND hwnd )
356 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
357 if (!(style & WS_VISIBLE)) return FALSE;
358 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
359 return !(style & WS_DISABLED);
363 /**********************************************************************
364 * set_focus
366 static void set_focus( HWND hwnd, Time time )
368 HWND focus;
369 Window win;
371 TRACE( "setting foreground window to %p\n", hwnd );
372 SetForegroundWindow( hwnd );
374 focus = GetFocus();
375 if (focus) focus = GetAncestor( focus, GA_ROOT );
376 win = X11DRV_get_whole_window(focus);
378 if (win)
380 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
381 wine_tsx11_lock();
382 XSetInputFocus( thread_display(), win, RevertToParent, time );
383 wine_tsx11_unlock();
388 /**********************************************************************
389 * handle_wm_protocols
391 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
393 Atom protocol = (Atom)event->data.l[0];
395 if (!protocol) return;
397 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
399 /* Ignore the delete window request if the window has been disabled
400 * and we are in managed mode. This is to disallow applications from
401 * being closed by the window manager while in a modal state.
403 if (IsWindowEnabled(hwnd))
405 HMENU hSysMenu;
407 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
408 hSysMenu = GetSystemMenu(hwnd, FALSE);
409 if (hSysMenu)
411 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
412 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
413 return;
415 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
418 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
420 Time event_time = (Time)event->data.l[1];
421 HWND last_focus = x11drv_thread_data()->last_focus;
423 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
424 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
425 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
427 if (can_activate_window(hwnd))
429 /* simulate a mouse click on the caption to find out
430 * whether the window wants to be activated */
431 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
432 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
433 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
434 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
435 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
437 else
439 hwnd = GetFocus();
440 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
441 if (!hwnd) hwnd = GetActiveWindow();
442 if (!hwnd) hwnd = last_focus;
443 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
446 else if (protocol == x11drv_atom(_NET_WM_PING))
448 XClientMessageEvent xev;
449 xev = *event;
451 TRACE("NET_WM Ping\n");
452 wine_tsx11_lock();
453 xev.window = DefaultRootWindow(xev.display);
454 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
455 wine_tsx11_unlock();
456 /* this line is semi-stolen from gtk2 */
457 TRACE("NET_WM Pong\n");
462 static const char * const focus_details[] =
464 "NotifyAncestor",
465 "NotifyVirtual",
466 "NotifyInferior",
467 "NotifyNonlinear",
468 "NotifyNonlinearVirtual",
469 "NotifyPointer",
470 "NotifyPointerRoot",
471 "NotifyDetailNone"
474 /**********************************************************************
475 * EVENT_FocusIn
477 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
479 XFocusChangeEvent *event = &xev->xfocus;
480 XIC xic;
482 if (!hwnd) return;
484 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
486 if (event->detail == NotifyPointer) return;
488 if ((xic = X11DRV_get_ic( hwnd )))
490 wine_tsx11_lock();
491 XSetICFocus( xic );
492 wine_tsx11_unlock();
494 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
496 if (!can_activate_window(hwnd))
498 HWND hwnd = GetFocus();
499 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
500 if (!hwnd) hwnd = GetActiveWindow();
501 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
502 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
504 else SetForegroundWindow( hwnd );
508 /**********************************************************************
509 * EVENT_FocusOut
511 * Note: only top-level windows get FocusOut events.
513 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
515 XFocusChangeEvent *event = &xev->xfocus;
516 HWND hwnd_tmp;
517 Window focus_win;
518 int revert;
519 XIC xic;
521 if (!hwnd) return;
523 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
525 if (event->detail == NotifyPointer) return;
526 if (ximInComposeMode) return;
528 x11drv_thread_data()->last_focus = hwnd;
529 if ((xic = X11DRV_get_ic( hwnd )))
531 wine_tsx11_lock();
532 XUnsetICFocus( xic );
533 wine_tsx11_unlock();
535 if (hwnd != GetForegroundWindow()) return;
536 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
538 /* don't reset the foreground window, if the window which is
539 getting the focus is a Wine window */
541 wine_tsx11_lock();
542 XGetInputFocus( thread_display(), &focus_win, &revert );
543 if (focus_win)
545 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
546 focus_win = 0;
548 wine_tsx11_unlock();
550 if (!focus_win)
552 /* Abey : 6-Oct-99. Check again if the focus out window is the
553 Foreground window, because in most cases the messages sent
554 above must have already changed the foreground window, in which
555 case we don't have to change the foreground window to 0 */
556 if (hwnd == GetForegroundWindow())
558 TRACE( "lost focus, setting fg to 0\n" );
559 SetForegroundWindow( 0 );
562 if (forcealtrelease && GetAsyncKeyState(VK_MENU)<0)
564 INPUT fake_alt_release;
565 fake_alt_release.type = INPUT_KEYBOARD;
566 fake_alt_release.u.ki.wVk = VK_MENU;
567 fake_alt_release.u.ki.wScan = 0;
568 fake_alt_release.u.ki.dwFlags = KEYEVENTF_KEYUP;
569 fake_alt_release.u.ki.time = GetTickCount(); /* is it really this kind of timestamp ? */
570 fake_alt_release.u.ki.dwExtraInfo = 0;
571 SendInput(1, &fake_alt_release, sizeof(INPUT));
577 /***********************************************************************
578 * EVENT_PropertyNotify
579 * We use this to release resources like Pixmaps when a selection
580 * client no longer needs them.
582 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
584 XPropertyEvent *event = &xev->xproperty;
585 /* Check if we have any resources to free */
586 TRACE("Received PropertyNotify event:\n");
588 switch(event->state)
590 case PropertyDelete:
592 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
593 event->atom, (long)event->window);
594 break;
597 case PropertyNewValue:
599 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
600 event->atom, (long)event->window);
601 break;
604 default:
605 break;
609 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
611 RECT tempRect;
613 if (!IsWindowEnabled(hQueryWnd)) return 0;
615 GetWindowRect(hQueryWnd, &tempRect);
617 if(!PtInRect(&tempRect, *lpPt)) return 0;
619 if (!IsIconic( hQueryWnd ))
621 POINT pt = *lpPt;
622 ScreenToClient( hQueryWnd, &pt );
623 GetClientRect( hQueryWnd, &tempRect );
625 if (PtInRect( &tempRect, pt))
627 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
628 if (ret && ret != hQueryWnd)
630 ret = find_drop_window( ret, lpPt );
631 if (ret) return ret;
636 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
638 ScreenToClient(hQueryWnd, lpPt);
640 return hQueryWnd;
643 /**********************************************************************
644 * EVENT_DropFromOffix
646 * don't know if it still works (last Changlog is from 96/11/04)
648 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
650 unsigned long data_length;
651 unsigned long aux_long;
652 unsigned char* p_data = NULL;
653 Atom atom_aux;
654 int x, y, dummy;
655 BOOL bAccept;
656 Window win, w_aux_root, w_aux_child;
657 WND* pWnd;
658 HWND hScope = hWnd;
660 win = X11DRV_get_whole_window(hWnd);
661 wine_tsx11_lock();
662 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
663 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
664 x += virtual_screen_rect.left;
665 y += virtual_screen_rect.top;
666 wine_tsx11_unlock();
668 pWnd = WIN_GetPtr(hWnd);
670 /* find out drop point and drop window */
671 if( x < 0 || y < 0 ||
672 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
673 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
675 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
676 x = 0;
677 y = 0;
679 else
681 POINT pt = { x, y };
682 HWND hwndDrop = find_drop_window( hWnd, &pt );
683 if (hwndDrop)
685 x = pt.x;
686 y = pt.y;
687 hScope = hwndDrop;
688 bAccept = TRUE;
690 else
692 bAccept = FALSE;
695 WIN_ReleasePtr(pWnd);
697 if (!bAccept) return;
699 wine_tsx11_lock();
700 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
701 x11drv_atom(DndSelection), 0, 65535, FALSE,
702 AnyPropertyType, &atom_aux, &dummy,
703 &data_length, &aux_long, &p_data);
704 wine_tsx11_unlock();
706 if( !aux_long && p_data) /* don't bother if > 64K */
708 char *p = (char *)p_data;
709 char *p_drop;
711 aux_long = 0;
712 while( *p ) /* calculate buffer size */
714 INT len = GetShortPathNameA( p, NULL, 0 );
715 if (len) aux_long += len + 1;
716 p += strlen(p) + 1;
718 if( aux_long && aux_long < 65535 )
720 HDROP hDrop;
721 DROPFILES *lpDrop;
723 aux_long += sizeof(DROPFILES) + 1;
724 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
725 lpDrop = (DROPFILES*)GlobalLock( hDrop );
727 if( lpDrop )
729 WND *pDropWnd = WIN_GetPtr( hScope );
730 lpDrop->pFiles = sizeof(DROPFILES);
731 lpDrop->pt.x = x;
732 lpDrop->pt.y = y;
733 lpDrop->fNC =
734 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
735 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
736 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
737 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
738 lpDrop->fWide = FALSE;
739 WIN_ReleasePtr(pDropWnd);
740 p_drop = (char *)(lpDrop + 1);
741 p = (char *)p_data;
742 while(*p)
744 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
745 p_drop += strlen( p_drop ) + 1;
746 p += strlen(p) + 1;
748 *p_drop = '\0';
749 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
753 wine_tsx11_lock();
754 if( p_data ) XFree(p_data);
755 wine_tsx11_unlock();
758 /**********************************************************************
759 * EVENT_DropURLs
761 * drop items are separated by \n
762 * each item is prefixed by its mime type
764 * event->data.l[3], event->data.l[4] contains drop x,y position
766 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
768 unsigned long data_length;
769 unsigned long aux_long, drop_len = 0;
770 unsigned char *p_data = NULL; /* property data */
771 char *p_drop = NULL;
772 char *p, *next;
773 int x, y;
774 DROPFILES *lpDrop;
775 HDROP hDrop;
776 union {
777 Atom atom_aux;
778 int i;
779 Window w_aux;
780 unsigned int u;
781 } u; /* unused */
783 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
785 wine_tsx11_lock();
786 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
787 x11drv_atom(DndSelection), 0, 65535, FALSE,
788 AnyPropertyType, &u.atom_aux, &u.i,
789 &data_length, &aux_long, &p_data);
790 wine_tsx11_unlock();
791 if (aux_long)
792 WARN("property too large, truncated!\n");
793 TRACE("urls=%s\n", p_data);
795 if( !aux_long && p_data) { /* don't bother if > 64K */
796 /* calculate length */
797 p = (char*) p_data;
798 next = strchr(p, '\n');
799 while (p) {
800 if (next) *next=0;
801 if (strncmp(p,"file:",5) == 0 ) {
802 INT len = GetShortPathNameA( p+5, NULL, 0 );
803 if (len) drop_len += len + 1;
805 if (next) {
806 *next = '\n';
807 p = next + 1;
808 next = strchr(p, '\n');
809 } else {
810 p = NULL;
814 if( drop_len && drop_len < 65535 ) {
815 wine_tsx11_lock();
816 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
817 &x, &y, &u.i, &u.i, &u.u);
818 x += virtual_screen_rect.left;
819 y += virtual_screen_rect.top;
820 wine_tsx11_unlock();
822 drop_len += sizeof(DROPFILES) + 1;
823 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
824 lpDrop = (DROPFILES *) GlobalLock( hDrop );
826 if( lpDrop ) {
827 WND *pDropWnd = WIN_GetPtr( hWnd );
828 lpDrop->pFiles = sizeof(DROPFILES);
829 lpDrop->pt.x = (INT)x;
830 lpDrop->pt.y = (INT)y;
831 lpDrop->fNC =
832 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
833 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
834 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
835 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
836 lpDrop->fWide = FALSE;
837 p_drop = (char*)(lpDrop + 1);
838 WIN_ReleasePtr(pDropWnd);
841 /* create message content */
842 if (p_drop) {
843 p = (char*) p_data;
844 next = strchr(p, '\n');
845 while (p) {
846 if (next) *next=0;
847 if (strncmp(p,"file:",5) == 0 ) {
848 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
849 if (len) {
850 TRACE("drop file %s as %s\n", p+5, p_drop);
851 p_drop += len+1;
852 } else {
853 WARN("can't convert file %s to dos name\n", p+5);
855 } else {
856 WARN("unknown mime type %s\n", p);
858 if (next) {
859 *next = '\n';
860 p = next + 1;
861 next = strchr(p, '\n');
862 } else {
863 p = NULL;
865 *p_drop = '\0';
868 GlobalUnlock(hDrop);
869 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
872 wine_tsx11_lock();
873 if( p_data ) XFree(p_data);
874 wine_tsx11_unlock();
878 /**********************************************************************
879 * handle_dnd_protocol
881 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
883 Window root, child;
884 int root_x, root_y, child_x, child_y;
885 unsigned int u;
887 /* query window (drag&drop event contains only drag window) */
888 wine_tsx11_lock();
889 XQueryPointer( event->display, root_window, &root, &child,
890 &root_x, &root_y, &child_x, &child_y, &u);
891 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
892 wine_tsx11_unlock();
893 if (!hwnd) return;
894 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
895 EVENT_DropFromOffiX(hwnd, event);
896 else if (event->data.l[0] == DndURL)
897 EVENT_DropURLs(hwnd, event);
901 struct client_message_handler
903 int atom; /* protocol atom */
904 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
907 static const struct client_message_handler client_messages[] =
909 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
910 { XATOM_DndProtocol, handle_dnd_protocol },
911 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
912 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
913 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
914 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
918 /**********************************************************************
919 * EVENT_ClientMessage
921 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
923 XClientMessageEvent *event = &xev->xclient;
924 unsigned int i;
926 if (!hwnd) return;
928 if (event->format != 32)
930 WARN( "Don't know how to handle format %d\n", event->format );
931 return;
934 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
936 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
938 client_messages[i].handler( hwnd, event );
939 return;
942 TRACE( "no handler found for %ld\n", event->message_type );
946 /**********************************************************************
947 * EVENT_GravityNotify
949 static void EVENT_GravityNotify( HWND hwnd, XEvent *event )
951 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
953 /* In this case we don't get a ConfigureNotify so we fake it */
954 if (data)
956 int flags = SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE;
957 WND *pWnd = WIN_GetPtr(hwnd);
959 if (event->xgravity.x == pWnd->rectWindow.left && event->xgravity.y == pWnd->rectWindow.top)
960 flags |= SWP_NOMOVE;
962 WIN_ReleasePtr( pWnd );
964 if (~flags & SWP_NOMOVE)
966 data->lock_changes++;
967 SetWindowPos( hwnd, 0, event->xgravity.x, event->xgravity.y, 0, 0, flags );
968 data->lock_changes--;
974 /**********************************************************************
975 * X11DRV_WindowMessage (X11DRV.@)
977 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
979 switch(msg)
981 case WM_X11DRV_ACQUIRE_SELECTION:
982 return X11DRV_AcquireClipboard( hwnd );
983 case WM_X11DRV_DELETE_WINDOW:
984 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
985 default:
986 FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
987 return 0;
992 /***********************************************************************
993 * X11DRV_SendInput (X11DRV.@)
995 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
997 UINT i;
999 for (i = 0; i < count; i++, inputs++)
1001 switch(inputs->type)
1003 case INPUT_MOUSE:
1004 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
1005 inputs->u.mi.mouseData, inputs->u.mi.time,
1006 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
1007 break;
1008 case INPUT_KEYBOARD:
1009 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
1010 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
1011 break;
1012 case INPUT_HARDWARE:
1013 FIXME( "INPUT_HARDWARE not supported\n" );
1014 break;
1017 return count;