Make the standard create_file request handle serial ports too, and
[wine.git] / dlls / x11drv / event.c
blob3187d9f62e9d3ca664e2da85341e7083335612e9
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>
37 #include "wine/winuser16.h"
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "wingdi.h"
42 #include "shlobj.h" /* DROPFILES */
44 #include "win.h"
45 #include "winpos.h"
46 #include "winreg.h"
47 #include "x11drv.h"
48 #include "shellapi.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(event);
52 WINE_DECLARE_DEBUG_CHANNEL(clipboard);
54 /* X context to associate a hwnd to an X window */
55 extern XContext winContext;
57 extern BOOL ximInComposeMode;
59 #define DndNotDnd -1 /* OffiX drag&drop */
60 #define DndUnknown 0
61 #define DndRawData 1
62 #define DndFile 2
63 #define DndFiles 3
64 #define DndText 4
65 #define DndDir 5
66 #define DndLink 6
67 #define DndExe 7
69 #define DndEND 8
71 #define DndURL 128 /* KDE drag&drop */
73 static const char * const event_names[] =
75 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
76 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
77 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
78 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
79 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
80 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
81 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
82 "ClientMessage", "MappingNotify"
86 static void EVENT_ProcessEvent( XEvent *event );
88 /* Event handlers */
89 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
90 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
91 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
92 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
93 static void EVENT_PropertyNotify( XPropertyEvent *event );
94 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
96 extern void X11DRV_ButtonPress( HWND hwnd, XButtonEvent *event );
97 extern void X11DRV_ButtonRelease( HWND hwnd, XButtonEvent *event );
98 extern void X11DRV_MotionNotify( HWND hwnd, XMotionEvent *event );
99 extern void X11DRV_EnterNotify( HWND hwnd, XCrossingEvent *event );
100 extern void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event );
101 extern void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event );
102 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
103 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
104 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
105 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
106 extern void X11DRV_MappingNotify( XMappingEvent *event );
108 #ifdef HAVE_LIBXXF86DGA2
109 static int DGAMotionEventType;
110 static int DGAButtonPressEventType;
111 static int DGAButtonReleaseEventType;
112 static int DGAKeyPressEventType;
113 static int DGAKeyReleaseEventType;
115 static BOOL DGAUsed = FALSE;
116 static HWND DGAhwnd = 0;
118 extern void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event );
119 extern void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event );
120 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event );
121 #endif
123 /* Static used for the current input method */
124 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
125 static BOOL in_transition = FALSE; /* This is not used as for today */
128 /***********************************************************************
129 * process_events
131 static int process_events( struct x11drv_thread_data *data )
133 XEvent event;
134 int count = 0;
136 wine_tsx11_lock();
137 while ( XPending( data->display ) )
139 Bool ignore;
141 XNextEvent( data->display, &event );
142 ignore = XFilterEvent( &event, None );
143 wine_tsx11_unlock();
144 if (!ignore) EVENT_ProcessEvent( &event );
145 count++;
146 wine_tsx11_lock();
148 wine_tsx11_unlock();
149 return count;
153 /***********************************************************************
154 * MsgWaitForMultipleObjectsEx (X11DRV.@)
156 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
157 DWORD timeout, DWORD mask, DWORD flags )
159 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
160 DWORD i, ret;
161 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
163 if (!data || data->process_event_count)
164 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
165 timeout, flags & MWMO_ALERTABLE );
167 /* check whether only server queue handle was passed in */
168 if (count < 2) flags &= ~MWMO_WAITALL;
170 for (i = 0; i < count; i++) new_handles[i] = handles[i];
171 new_handles[count] = data->display_fd;
173 wine_tsx11_lock();
174 XFlush( gdi_display );
175 XFlush( data->display );
176 wine_tsx11_unlock();
178 data->process_event_count++;
179 if (process_events( data )) ret = count;
180 else
182 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
183 timeout, flags & MWMO_ALERTABLE );
184 if (ret == count) process_events( data );
186 data->process_event_count--;
187 return ret;
191 /***********************************************************************
192 * EVENT_ProcessEvent
194 * Process an X event.
196 static void EVENT_ProcessEvent( XEvent *event )
198 HWND hWnd;
199 Display *display = event->xany.display;
201 TRACE( "called.\n" );
203 switch (event->type)
205 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
206 FIXME("Got SelectionNotify - must not happen!\n");
207 /* fall through */
209 /* We get all these because of StructureNotifyMask.
210 This check is placed here to avoid getting error messages below,
211 as X might send some of these even for windows that have already
212 been deleted ... */
213 case CirculateNotify:
214 case CreateNotify:
215 case DestroyNotify:
216 case GravityNotify:
217 case ReparentNotify:
218 return;
221 #ifdef HAVE_LIBXXF86DGA2
222 if (DGAUsed) {
223 if (event->type == DGAMotionEventType) {
224 TRACE("DGAMotionEvent received.\n");
225 X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
226 return;
228 if (event->type == DGAButtonPressEventType) {
229 TRACE("DGAButtonPressEvent received.\n");
230 X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
231 return;
233 if (event->type == DGAButtonReleaseEventType) {
234 TRACE("DGAButtonReleaseEvent received.\n");
235 X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
236 return;
238 if ((event->type == DGAKeyPressEventType) ||
239 (event->type == DGAKeyReleaseEventType)) {
240 /* Fill a XKeyEvent to send to EVENT_Key */
241 XKeyEvent ke;
242 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
244 TRACE("DGAKeyPress/ReleaseEvent received.\n");
246 if (evt->type == DGAKeyReleaseEventType)
247 ke.type = KeyRelease;
248 else
249 ke.type = KeyPress;
250 ke.serial = evt->serial;
251 ke.send_event = FALSE;
252 ke.display = evt->display;
253 ke.window = 0;
254 ke.root = 0;
255 ke.subwindow = 0;
256 ke.time = evt->time;
257 ke.x = -1;
258 ke.y = -1;
259 ke.x_root = -1;
260 ke.y_root = -1;
261 ke.state = evt->state;
262 ke.keycode = evt->keycode;
263 ke.same_screen = TRUE;
264 X11DRV_KeyEvent( 0, &ke );
265 return;
268 #endif
270 wine_tsx11_lock();
271 if (XFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
272 hWnd = 0; /* Not for a registered window */
273 wine_tsx11_unlock();
274 if (!hWnd && event->xany.window == root_window) hWnd = GetDesktopWindow();
276 if (!hWnd && event->type != PropertyNotify && event->type != MappingNotify)
277 WARN( "Got event %s for unknown Window %08lx\n",
278 event_names[event->type], event->xany.window );
279 else if (event->type <= MappingNotify)
280 TRACE("Got event %s for hwnd/window %p/%lx, GetFocus()=%p\n",
281 event_names[event->type], hWnd, event->xany.window, GetFocus() );
282 else
283 TRACE("Got extension event for hwnd/window %p/%lx, GetFocus()=%p\n",
284 hWnd, event->xany.window, GetFocus() );
286 if (X11DRV_ProcessTabletEvent(hWnd, event))
288 TRACE("Return: filtered by tablet\n");
289 return;
292 switch(event->type)
294 case KeyPress:
295 case KeyRelease:
296 /* FIXME: should generate a motion event if event point is different from current pos */
297 X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
298 break;
300 case ButtonPress:
301 X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
302 break;
304 case ButtonRelease:
305 X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
306 break;
308 case MotionNotify:
309 X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
310 break;
312 case EnterNotify:
313 X11DRV_EnterNotify( hWnd, (XCrossingEvent*)event );
314 break;
316 case FocusIn:
317 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
318 break;
320 case FocusOut:
321 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
322 break;
324 case Expose:
325 X11DRV_Expose( hWnd, &event->xexpose );
326 break;
328 case ConfigureNotify:
329 if (!hWnd) return;
330 X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
331 break;
333 case SelectionRequest:
334 if (!hWnd) return;
335 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
336 break;
338 case SelectionClear:
339 if (!hWnd) return;
340 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
341 break;
343 case PropertyNotify:
344 EVENT_PropertyNotify( (XPropertyEvent *)event );
345 break;
347 case ClientMessage:
348 if (!hWnd) return;
349 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
350 break;
352 case NoExpose:
353 break;
355 case MapNotify:
356 X11DRV_MapNotify( hWnd, (XMapEvent *)event );
357 break;
359 case UnmapNotify:
360 X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
361 break;
363 case KeymapNotify:
364 X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
365 break;
367 case MappingNotify:
368 X11DRV_MappingNotify( (XMappingEvent *) event );
369 break;
371 default:
372 WARN("Unprocessed event %s for hwnd %p\n", event_names[event->type], hWnd );
373 break;
375 TRACE( "returns.\n" );
379 /*******************************************************************
380 * can_activate_window
382 * Check if we can activate the specified window.
384 inline static BOOL can_activate_window( HWND hwnd )
386 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
387 if (!(style & WS_VISIBLE)) return FALSE;
388 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
389 return !(style & WS_DISABLED);
393 /**********************************************************************
394 * set_focus
396 static void set_focus( HWND hwnd, Time time )
398 HWND focus;
399 Window win;
401 TRACE( "setting foreground window to %p\n", hwnd );
402 SetForegroundWindow( hwnd );
404 focus = GetFocus();
405 if (focus) focus = GetAncestor( focus, GA_ROOT );
406 win = X11DRV_get_whole_window(focus);
408 if (win)
410 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
411 wine_tsx11_lock();
412 XSetInputFocus( thread_display(), win, RevertToParent, time );
413 wine_tsx11_unlock();
418 /**********************************************************************
419 * handle_wm_protocols_message
421 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
423 Atom protocol = (Atom)event->data.l[0];
425 if (!protocol) return;
427 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
429 /* Ignore the delete window request if the window has been disabled
430 * and we are in managed mode. This is to disallow applications from
431 * being closed by the window manager while in a modal state.
433 if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
435 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
437 Time event_time = (Time)event->data.l[1];
438 HWND last_focus = x11drv_thread_data()->last_focus;
440 TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
441 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
442 GetForegroundWindow(), last_focus );
444 if (can_activate_window(hwnd))
446 /* simulate a mouse click on the caption to find out
447 * whether the window wants to be activated */
448 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
449 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
450 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
451 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
452 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
454 else
456 hwnd = GetFocus();
457 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
458 if (!hwnd) hwnd = GetActiveWindow();
459 if (!hwnd) hwnd = last_focus;
460 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
463 else if (protocol == x11drv_atom(_NET_WM_PING))
465 XClientMessageEvent xev;
466 xev = *event;
468 TRACE("NET_WM Ping\n");
469 xev.window = DefaultRootWindow(xev.display);
470 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
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, XFocusChangeEvent *event )
494 XIC xic;
496 if (!hwnd) return;
498 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
500 if (event->detail == NotifyPointer) return;
502 if ((xic = X11DRV_get_ic( hwnd )))
504 wine_tsx11_lock();
505 XSetICFocus( xic );
506 wine_tsx11_unlock();
508 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
510 if (!can_activate_window(hwnd))
512 HWND hwnd = GetFocus();
513 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
514 if (!hwnd) hwnd = GetActiveWindow();
515 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
516 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
518 else SetForegroundWindow( hwnd );
522 /**********************************************************************
523 * EVENT_FocusOut
525 * Note: only top-level windows get FocusOut events.
527 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
529 HWND hwnd_tmp;
530 Window focus_win;
531 int revert;
532 XIC xic;
534 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
536 if (event->detail == NotifyPointer) return;
537 if (ximInComposeMode) return;
539 x11drv_thread_data()->last_focus = hwnd;
540 if ((xic = X11DRV_get_ic( hwnd )))
542 wine_tsx11_lock();
543 XUnsetICFocus( xic );
544 wine_tsx11_unlock();
546 if (hwnd != GetForegroundWindow()) return;
547 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
549 /* don't reset the foreground window, if the window which is
550 getting the focus is a Wine window */
552 wine_tsx11_lock();
553 XGetInputFocus( thread_display(), &focus_win, &revert );
554 if (focus_win)
556 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
557 focus_win = 0;
559 wine_tsx11_unlock();
561 if (!focus_win)
563 /* Abey : 6-Oct-99. Check again if the focus out window is the
564 Foreground window, because in most cases the messages sent
565 above must have already changed the foreground window, in which
566 case we don't have to change the foreground window to 0 */
567 if (hwnd == GetForegroundWindow())
569 TRACE( "lost focus, setting fg to 0\n" );
570 SetForegroundWindow( 0 );
576 /***********************************************************************
577 * EVENT_SelectionRequest_AddTARGETS
578 * Utility function for EVENT_SelectionRequest_TARGETS.
580 static void EVENT_SelectionRequest_AddTARGETS(Atom* targets, unsigned long* cTargets, Atom prop)
582 int i;
583 BOOL bExists;
585 /* Scan through what we have so far to avoid duplicates */
586 for (i = 0, bExists = FALSE; i < *cTargets; i++)
588 if (targets[i] == prop)
590 bExists = TRUE;
591 break;
595 if (!bExists)
596 targets[(*cTargets)++] = prop;
600 /***********************************************************************
601 * EVENT_SelectionRequest_TARGETS
602 * Service a TARGETS selection request event
604 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
605 Atom target, Atom rprop )
607 Atom* targets;
608 UINT wFormat;
609 UINT alias;
610 ULONG cTargets;
611 LPWINE_CLIPFORMAT lpFormat;
614 * Count the number of items we wish to expose as selection targets.
615 * We include the TARGETS item, and propery aliases
617 cTargets = X11DRV_CountClipboardFormats() + 1;
619 for (wFormat = 0; (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
621 lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
623 if (lpFormat)
625 if (!lpFormat->lpDrvExportFunc)
626 cTargets--;
628 if (X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData))
629 cTargets++;
633 TRACE_(clipboard)(" found %ld formats\n", cTargets);
635 /* Allocate temp buffer */
636 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
637 if(targets == NULL)
638 return None;
640 /* Create TARGETS property list (First item in list is TARGETS itself) */
641 for (targets[0] = x11drv_atom(TARGETS), cTargets = 1, wFormat = 0;
642 (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
644 lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
646 if (lpFormat->lpDrvExportFunc)
647 EVENT_SelectionRequest_AddTARGETS(targets, &cTargets, lpFormat->drvData);
649 /* Check if any alias should be listed */
650 alias = X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData);
651 if (alias)
652 EVENT_SelectionRequest_AddTARGETS(targets, &cTargets, alias);
655 wine_tsx11_lock();
657 if (TRACE_ON(clipboard))
659 int i;
660 for ( i = 0; i < cTargets; i++)
662 if (targets[i])
664 char *itemFmtName = XGetAtomName(display, targets[i]);
665 TRACE_(clipboard)("\tAtom# %d: Property %ld Type %s\n", i, targets[i], itemFmtName);
666 XFree(itemFmtName);
671 /* We may want to consider setting the type to xaTargets instead,
672 * in case some apps expect this instead of XA_ATOM */
673 XChangeProperty(display, requestor, rprop, XA_ATOM, 32,
674 PropModeReplace, (unsigned char *)targets, cTargets);
675 wine_tsx11_unlock();
677 HeapFree(GetProcessHeap(), 0, targets);
679 return rprop;
683 /***********************************************************************
684 * EVENT_SelectionRequest_MULTIPLE
685 * Service a MULTIPLE selection request event
686 * rprop contains a list of (target,property) atom pairs.
687 * The first atom names a target and the second names a property.
688 * The effect is as if we have received a sequence of SelectionRequest events
689 * (one for each atom pair) except that:
690 * 1. We reply with a SelectionNotify only when all the requested conversions
691 * have been performed.
692 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
693 * we replace the atom in the property by None.
695 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
697 Display *display = pevent->display;
698 Atom rprop;
699 Atom atype=AnyPropertyType;
700 int aformat;
701 unsigned long remain;
702 Atom* targetPropList=NULL;
703 unsigned long cTargetPropList = 0;
705 /* If the specified property is None the requestor is an obsolete client.
706 * We support these by using the specified target atom as the reply property.
708 rprop = pevent->property;
709 if( rprop == None )
710 rprop = pevent->target;
711 if (!rprop)
712 goto END;
714 /* Read the MULTIPLE property contents. This should contain a list of
715 * (target,property) atom pairs.
717 wine_tsx11_lock();
718 if(XGetWindowProperty(display, pevent->requestor, rprop,
719 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
720 &cTargetPropList, &remain,
721 (unsigned char**)&targetPropList) != Success)
723 wine_tsx11_unlock();
724 TRACE("\tCouldn't read MULTIPLE property\n");
726 else
728 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
729 XGetAtomName(display, atype), aformat, cTargetPropList, remain);
730 wine_tsx11_unlock();
733 * Make sure we got what we expect.
734 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
735 * in a MULTIPLE selection request should be of type ATOM_PAIR.
736 * However some X apps(such as XPaint) are not compliant with this and return
737 * a user defined atom in atype when XGetWindowProperty is called.
738 * The data *is* an atom pair but is not denoted as such.
740 if(aformat == 32 /* atype == xAtomPair */ )
742 int i;
744 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
745 * for each (target,property) pair */
747 for (i = 0; i < cTargetPropList; i+=2)
749 XSelectionRequestEvent event;
751 if (TRACE_ON(event))
753 char *targetName, *propName;
754 wine_tsx11_lock();
755 targetName = XGetAtomName(display, targetPropList[i]);
756 propName = XGetAtomName(display, targetPropList[i+1]);
757 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
758 i/2, targetName, propName);
759 XFree(targetName);
760 XFree(propName);
761 wine_tsx11_unlock();
764 /* We must have a non "None" property to service a MULTIPLE target atom */
765 if ( !targetPropList[i+1] )
767 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
768 continue;
771 /* Set up an XSelectionRequestEvent for this (target,property) pair */
772 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
773 event.target = targetPropList[i];
774 event.property = targetPropList[i+1];
776 /* Fire a SelectionRequest, informing the handler that we are processing
777 * a MULTIPLE selection request event.
779 EVENT_SelectionRequest( hWnd, &event, TRUE );
783 /* Free the list of targets/properties */
784 wine_tsx11_lock();
785 XFree(targetPropList);
786 wine_tsx11_unlock();
789 END:
790 return rprop;
794 /***********************************************************************
795 * EVENT_SelectionRequest
796 * Process an event selection request event.
797 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
798 * recursively while servicing a "MULTIPLE" selection target.
800 * Note: We only receive this event when WINE owns the X selection
802 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
804 Display *display = event->display;
805 XSelectionEvent result;
806 Atom rprop = None;
807 Window request = event->requestor;
809 TRACE_(clipboard)("\n");
812 * We can only handle the selection request if :
813 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
814 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
815 * since this has been already done.
817 if ( !bIsMultiple )
819 if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
820 goto END;
823 /* If the specified property is None the requestor is an obsolete client.
824 * We support these by using the specified target atom as the reply property.
826 rprop = event->property;
827 if( rprop == None )
828 rprop = event->target;
830 if(event->target == x11drv_atom(TARGETS)) /* Return a list of all supported targets */
832 /* TARGETS selection request */
833 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
835 else if(event->target == x11drv_atom(MULTIPLE)) /* rprop contains a list of (target, property) atom pairs */
837 /* MULTIPLE selection request */
838 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
840 else
842 LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(event->target);
844 if (!lpFormat)
845 lpFormat = X11DRV_CLIPBOARD_LookupAliasProperty(event->target);
847 if (lpFormat && lpFormat->lpDrvExportFunc)
849 LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(lpFormat->wFormatID);
851 if (lpData)
853 unsigned char* lpClipData;
854 DWORD cBytes;
855 HANDLE hClipData = lpFormat->lpDrvExportFunc(request, event->target,
856 rprop, lpData, &cBytes);
858 if (hClipData && (lpClipData = GlobalLock(hClipData)))
860 TRACE_(clipboard)("\tUpdating property %s, %ld bytes\n",
861 lpFormat->Name, cBytes);
863 wine_tsx11_lock();
864 XChangeProperty(display, request, rprop, event->target,
865 8, PropModeReplace, (unsigned char *)lpClipData, cBytes);
866 wine_tsx11_unlock();
868 GlobalUnlock(hClipData);
869 GlobalFree(hClipData);
875 END:
876 /* reply to sender
877 * SelectionNotify should be sent only at the end of a MULTIPLE request
879 if ( !bIsMultiple )
881 result.type = SelectionNotify;
882 result.display = display;
883 result.requestor = request;
884 result.selection = event->selection;
885 result.property = rprop;
886 result.target = event->target;
887 result.time = event->time;
888 TRACE("Sending SelectionNotify event...\n");
889 wine_tsx11_lock();
890 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
891 wine_tsx11_unlock();
895 /***********************************************************************
896 * EVENT_SelectionClear
898 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
900 if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
901 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
904 /***********************************************************************
905 * EVENT_PropertyNotify
906 * We use this to release resources like Pixmaps when a selection
907 * client no longer needs them.
909 static void EVENT_PropertyNotify( XPropertyEvent *event )
911 /* Check if we have any resources to free */
912 TRACE("Received PropertyNotify event: \n");
914 switch(event->state)
916 case PropertyDelete:
918 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
919 event->atom, (long)event->window);
920 break;
923 case PropertyNewValue:
925 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
926 event->atom, (long)event->window);
927 break;
930 default:
931 break;
935 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
937 RECT tempRect;
939 if (!IsWindowEnabled(hQueryWnd)) return 0;
941 GetWindowRect(hQueryWnd, &tempRect);
943 if(!PtInRect(&tempRect, *lpPt)) return 0;
945 if (!IsIconic( hQueryWnd ))
947 GetClientRect( hQueryWnd, &tempRect );
948 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
950 if (PtInRect( &tempRect, *lpPt))
952 HWND *list = WIN_ListChildren( hQueryWnd );
953 HWND bResult = 0;
955 if (list)
957 int i;
959 for (i = 0; list[i]; i++)
961 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
963 GetWindowRect( list[i], &tempRect );
964 if (PtInRect( &tempRect, *lpPt )) break;
967 if (list[i])
969 if (IsWindowEnabled( list[i] ))
970 bResult = find_drop_window( list[i], lpPt );
972 HeapFree( GetProcessHeap(), 0, list );
974 if(bResult) return bResult;
978 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
980 ScreenToClient(hQueryWnd, lpPt);
982 return hQueryWnd;
985 /**********************************************************************
986 * EVENT_DropFromOffix
988 * don't know if it still works (last Changlog is from 96/11/04)
990 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
992 unsigned long data_length;
993 unsigned long aux_long;
994 unsigned char* p_data = NULL;
995 union {
996 Atom atom_aux;
997 struct {
998 int x;
999 int y;
1000 } pt_aux;
1001 int i;
1002 } u;
1003 int x, y;
1004 BOOL bAccept;
1005 Window w_aux_root, w_aux_child;
1006 WND* pWnd;
1007 HWND hScope = hWnd;
1009 pWnd = WIN_FindWndPtr(hWnd);
1011 wine_tsx11_lock();
1012 XQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1013 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1014 (unsigned int*)&aux_long);
1015 wine_tsx11_unlock();
1017 /* find out drop point and drop window */
1018 if( x < 0 || y < 0 ||
1019 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1020 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1022 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
1023 x = 0;
1024 y = 0;
1026 else
1028 POINT pt = { x, y };
1029 HWND hwndDrop = find_drop_window( hWnd, &pt );
1030 if (hwndDrop)
1032 x = pt.x;
1033 y = pt.y;
1034 hScope = hwndDrop;
1035 bAccept = TRUE;
1037 else
1039 bAccept = FALSE;
1042 WIN_ReleaseWndPtr(pWnd);
1044 if (!bAccept) return;
1046 wine_tsx11_lock();
1047 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1048 x11drv_atom(DndSelection), 0, 65535, FALSE,
1049 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1050 &data_length, &aux_long, &p_data);
1051 wine_tsx11_unlock();
1053 if( !aux_long && p_data) /* don't bother if > 64K */
1055 signed char *p = (signed char*) p_data;
1056 char *p_drop;
1058 aux_long = 0;
1059 while( *p ) /* calculate buffer size */
1061 p_drop = p;
1062 if((u.i = *p) != -1 )
1064 INT len = GetShortPathNameA( p, NULL, 0 );
1065 if (len) aux_long += len + 1;
1066 else *p = -1;
1068 p += strlen(p) + 1;
1070 if( aux_long && aux_long < 65535 )
1072 HDROP hDrop;
1073 DROPFILES *lpDrop;
1075 aux_long += sizeof(DROPFILES) + 1;
1076 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1077 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1079 if( lpDrop )
1081 WND *pDropWnd = WIN_FindWndPtr( hScope );
1082 lpDrop->pFiles = sizeof(DROPFILES);
1083 lpDrop->pt.x = x;
1084 lpDrop->pt.y = y;
1085 lpDrop->fNC =
1086 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1087 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1088 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1089 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1090 lpDrop->fWide = FALSE;
1091 WIN_ReleaseWndPtr(pDropWnd);
1092 p_drop = (char *)(lpDrop + 1);
1093 p = p_data;
1094 while(*p)
1096 if( *p != -1 ) /* use only "good" entries */
1098 GetShortPathNameA( p, p_drop, 65535 );
1099 p_drop += strlen( p_drop ) + 1;
1101 p += strlen(p) + 1;
1103 *p_drop = '\0';
1104 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1108 wine_tsx11_lock();
1109 if( p_data ) XFree(p_data);
1110 wine_tsx11_unlock();
1113 /**********************************************************************
1114 * EVENT_DropURLs
1116 * drop items are separated by \n
1117 * each item is prefixed by its mime type
1119 * event->data.l[3], event->data.l[4] contains drop x,y position
1121 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1123 unsigned long data_length;
1124 unsigned long aux_long, drop_len = 0;
1125 unsigned char *p_data = NULL; /* property data */
1126 char *p_drop = NULL;
1127 char *p, *next;
1128 int x, y;
1129 DROPFILES *lpDrop;
1130 HDROP hDrop;
1131 union {
1132 Atom atom_aux;
1133 int i;
1134 Window w_aux;
1135 } u; /* unused */
1137 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1139 wine_tsx11_lock();
1140 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1141 x11drv_atom(DndSelection), 0, 65535, FALSE,
1142 AnyPropertyType, &u.atom_aux, &u.i,
1143 &data_length, &aux_long, &p_data);
1144 wine_tsx11_unlock();
1145 if (aux_long)
1146 WARN("property too large, truncated!\n");
1147 TRACE("urls=%s\n", p_data);
1149 if( !aux_long && p_data) { /* don't bother if > 64K */
1150 /* calculate length */
1151 p = p_data;
1152 next = strchr(p, '\n');
1153 while (p) {
1154 if (next) *next=0;
1155 if (strncmp(p,"file:",5) == 0 ) {
1156 INT len = GetShortPathNameA( p+5, NULL, 0 );
1157 if (len) drop_len += len + 1;
1159 if (next) {
1160 *next = '\n';
1161 p = next + 1;
1162 next = strchr(p, '\n');
1163 } else {
1164 p = NULL;
1168 if( drop_len && drop_len < 65535 ) {
1169 wine_tsx11_lock();
1170 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1171 &x, &y, &u.i, &u.i, &u.i);
1172 wine_tsx11_unlock();
1174 drop_len += sizeof(DROPFILES) + 1;
1175 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1176 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1178 if( lpDrop ) {
1179 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1180 lpDrop->pFiles = sizeof(DROPFILES);
1181 lpDrop->pt.x = (INT)x;
1182 lpDrop->pt.y = (INT)y;
1183 lpDrop->fNC =
1184 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1185 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1186 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1187 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1188 lpDrop->fWide = FALSE;
1189 p_drop = (char*)(lpDrop + 1);
1190 WIN_ReleaseWndPtr(pDropWnd);
1193 /* create message content */
1194 if (p_drop) {
1195 p = p_data;
1196 next = strchr(p, '\n');
1197 while (p) {
1198 if (next) *next=0;
1199 if (strncmp(p,"file:",5) == 0 ) {
1200 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1201 if (len) {
1202 TRACE("drop file %s as %s\n", p+5, p_drop);
1203 p_drop += len+1;
1204 } else {
1205 WARN("can't convert file %s to dos name \n", p+5);
1207 } else {
1208 WARN("unknown mime type %s\n", p);
1210 if (next) {
1211 *next = '\n';
1212 p = next + 1;
1213 next = strchr(p, '\n');
1214 } else {
1215 p = NULL;
1217 *p_drop = '\0';
1220 GlobalUnlock(hDrop);
1221 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1224 wine_tsx11_lock();
1225 if( p_data ) XFree(p_data);
1226 wine_tsx11_unlock();
1230 /**********************************************************************
1231 * EVENT_ClientMessage
1233 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1235 if (event->message_type != None && event->format == 32) {
1236 if (event->message_type == x11drv_atom(WM_PROTOCOLS))
1237 handle_wm_protocols_message( hWnd, event );
1238 else if (event->message_type == x11drv_atom(DndProtocol))
1240 /* query window (drag&drop event contains only drag window) */
1241 Window root, child;
1242 int root_x, root_y, child_x, child_y;
1243 unsigned int u;
1245 wine_tsx11_lock();
1246 XQueryPointer( event->display, root_window, &root, &child,
1247 &root_x, &root_y, &child_x, &child_y, &u);
1248 if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1249 wine_tsx11_unlock();
1250 if (!hWnd) return;
1251 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1252 EVENT_DropFromOffiX(hWnd, event);
1253 else if (event->data.l[0] == DndURL)
1254 EVENT_DropURLs(hWnd, event);
1256 else if (!X11DRV_XDND_Event(hWnd, event))
1258 #if 0
1259 /* enable this if you want to see the message */
1260 unsigned char* p_data = NULL;
1261 union {
1262 unsigned long l;
1263 int i;
1264 Atom atom;
1265 } u; /* unused */
1266 wine_tsx11_lock();
1267 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1268 dndSelection, 0, 65535, FALSE,
1269 AnyPropertyType, &u.atom, &u.i,
1270 &u.l, &u.l, &p_data);
1271 wine_tsx11_unlock();
1272 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1273 event->message_type, event->data.l[0], event->data.l[1],
1274 event->data.l[2], event->data.l[3], event->data.l[4],
1275 p_data);
1276 #endif
1277 TRACE("unrecognized ClientMessage\n" );
1283 /**********************************************************************
1284 * X11DRV_EVENT_SetInputMethod
1286 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1288 INPUT_TYPE prev = current_input_type;
1290 /* Flag not used yet */
1291 in_transition = FALSE;
1292 current_input_type = type;
1294 return prev;
1297 #ifdef HAVE_LIBXXF86DGA2
1298 /**********************************************************************
1299 * X11DRV_EVENT_SetDGAStatus
1301 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1303 if (event_base < 0) {
1304 DGAUsed = FALSE;
1305 DGAhwnd = 0;
1306 } else {
1307 DGAUsed = TRUE;
1308 DGAhwnd = hwnd;
1309 DGAMotionEventType = event_base + MotionNotify;
1310 DGAButtonPressEventType = event_base + ButtonPress;
1311 DGAButtonReleaseEventType = event_base + ButtonRelease;
1312 DGAKeyPressEventType = event_base + KeyPress;
1313 DGAKeyReleaseEventType = event_base + KeyRelease;
1316 #endif