- use global atoms for the format ids
[wine/multimedia.git] / dlls / x11drv / event.c
blobfebad5cd0a98a01ce7fba70a173726c008635750
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>
28 #include "ts_xlib.h"
29 #include <X11/Xresource.h>
30 #include <X11/Xutil.h>
31 #ifdef HAVE_LIBXXF86DGA2
32 #include <X11/extensions/xf86dga.h>
33 #endif
35 #include <assert.h>
36 #include <string.h>
37 #include "wine/winuser16.h"
38 #include "shlobj.h" /* DROPFILES */
40 #include "clipboard.h"
41 #include "win.h"
42 #include "winpos.h"
43 #include "windef.h"
44 #include "winreg.h"
45 #include "x11drv.h"
46 #include "shellapi.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(event);
50 WINE_DECLARE_DEBUG_CHANNEL(clipboard);
52 /* X context to associate a hwnd to an X window */
53 extern XContext winContext;
55 extern Atom wmProtocols;
56 extern Atom wmDeleteWindow;
57 extern Atom dndProtocol;
58 extern Atom dndSelection;
59 extern Atom netwmPing;
61 #define DndNotDnd -1 /* OffiX drag&drop */
62 #define DndUnknown 0
63 #define DndRawData 1
64 #define DndFile 2
65 #define DndFiles 3
66 #define DndText 4
67 #define DndDir 5
68 #define DndLink 6
69 #define DndExe 7
71 #define DndEND 8
73 #define DndURL 128 /* KDE drag&drop */
75 static const char * const event_names[] =
77 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
78 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
79 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
80 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
81 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
82 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
83 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
84 "ClientMessage", "MappingNotify"
88 static void EVENT_ProcessEvent( XEvent *event );
90 /* Event handlers */
91 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
92 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
93 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
94 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
95 static void EVENT_PropertyNotify( XPropertyEvent *event );
96 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
98 extern void X11DRV_ButtonPress( HWND hwnd, XButtonEvent *event );
99 extern void X11DRV_ButtonRelease( HWND hwnd, XButtonEvent *event );
100 extern void X11DRV_MotionNotify( HWND hwnd, XMotionEvent *event );
101 extern void X11DRV_EnterNotify( HWND hwnd, XCrossingEvent *event );
102 extern void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event );
103 extern void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event );
104 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
105 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
106 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
107 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
108 extern void X11DRV_MappingNotify( XMappingEvent *event );
110 #ifdef HAVE_LIBXXF86DGA2
111 static int DGAMotionEventType;
112 static int DGAButtonPressEventType;
113 static int DGAButtonReleaseEventType;
114 static int DGAKeyPressEventType;
115 static int DGAKeyReleaseEventType;
117 static BOOL DGAUsed = FALSE;
118 static HWND DGAhwnd = 0;
120 extern void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event );
121 extern void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event );
122 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event );
123 #endif
125 /* Static used for the current input method */
126 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
127 static BOOL in_transition = FALSE; /* This is not used as for today */
130 /***********************************************************************
131 * process_events
133 static int process_events( struct x11drv_thread_data *data )
135 XEvent event;
136 int count = 0;
138 wine_tsx11_lock();
139 while ( XPending( data->display ) )
141 Bool ignore;
143 XNextEvent( data->display, &event );
144 ignore = XFilterEvent( &event, None );
145 wine_tsx11_unlock();
146 if (!ignore) EVENT_ProcessEvent( &event );
147 count++;
148 wine_tsx11_lock();
150 wine_tsx11_unlock();
151 return count;
155 /***********************************************************************
156 * MsgWaitForMultipleObjectsEx (X11DRV.@)
158 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
159 DWORD timeout, DWORD mask, DWORD flags )
161 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
162 DWORD i, ret;
163 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
165 if (!data || data->process_event_count)
166 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
167 timeout, flags & MWMO_ALERTABLE );
169 /* check whether only server queue handle was passed in */
170 if (count < 2) flags &= ~MWMO_WAITALL;
172 for (i = 0; i < count; i++) new_handles[i] = handles[i];
173 new_handles[count] = data->display_fd;
175 wine_tsx11_lock();
176 XFlush( gdi_display );
177 XFlush( data->display );
178 wine_tsx11_unlock();
180 data->process_event_count++;
181 if (process_events( data )) ret = count;
182 else
184 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
185 timeout, flags & MWMO_ALERTABLE );
186 if (ret == count) process_events( data );
188 data->process_event_count--;
189 return ret;
193 /***********************************************************************
194 * EVENT_ProcessEvent
196 * Process an X event.
198 static void EVENT_ProcessEvent( XEvent *event )
200 HWND hWnd;
201 Display *display = event->xany.display;
203 TRACE( "called.\n" );
205 switch (event->type)
207 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
208 FIXME("Got SelectionNotify - must not happen!\n");
209 /* fall through */
211 /* We get all these because of StructureNotifyMask.
212 This check is placed here to avoid getting error messages below,
213 as X might send some of these even for windows that have already
214 been deleted ... */
215 case CirculateNotify:
216 case CreateNotify:
217 case DestroyNotify:
218 case GravityNotify:
219 case ReparentNotify:
220 return;
223 #ifdef HAVE_LIBXXF86DGA2
224 if (DGAUsed) {
225 if (event->type == DGAMotionEventType) {
226 TRACE("DGAMotionEvent received.\n");
227 X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
228 return;
230 if (event->type == DGAButtonPressEventType) {
231 TRACE("DGAButtonPressEvent received.\n");
232 X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
233 return;
235 if (event->type == DGAButtonReleaseEventType) {
236 TRACE("DGAButtonReleaseEvent received.\n");
237 X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
238 return;
240 if ((event->type == DGAKeyPressEventType) ||
241 (event->type == DGAKeyReleaseEventType)) {
242 /* Fill a XKeyEvent to send to EVENT_Key */
243 XKeyEvent ke;
244 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
246 TRACE("DGAKeyPress/ReleaseEvent received.\n");
248 if (evt->type == DGAKeyReleaseEventType)
249 ke.type = KeyRelease;
250 else
251 ke.type = KeyPress;
252 ke.serial = evt->serial;
253 ke.send_event = FALSE;
254 ke.display = evt->display;
255 ke.window = 0;
256 ke.root = 0;
257 ke.subwindow = 0;
258 ke.time = evt->time;
259 ke.x = -1;
260 ke.y = -1;
261 ke.x_root = -1;
262 ke.y_root = -1;
263 ke.state = evt->state;
264 ke.keycode = evt->keycode;
265 ke.same_screen = TRUE;
266 X11DRV_KeyEvent( 0, &ke );
267 return;
270 #endif
272 wine_tsx11_lock();
273 if (XFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
274 hWnd = 0; /* Not for a registered window */
275 wine_tsx11_unlock();
276 if (!hWnd && event->xany.window == root_window) hWnd = GetDesktopWindow();
278 if (!hWnd && event->type != PropertyNotify && event->type != MappingNotify)
279 WARN( "Got event %s for unknown Window %08lx\n",
280 event_names[event->type], event->xany.window );
281 else
282 TRACE("Got event %s for hwnd %p\n",
283 event_names[event->type], hWnd );
285 switch(event->type)
287 case KeyPress:
288 case KeyRelease:
289 /* FIXME: should generate a motion event if event point is different from current pos */
290 X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
291 break;
293 case ButtonPress:
294 X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
295 break;
297 case ButtonRelease:
298 X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
299 break;
301 case MotionNotify:
302 X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
303 break;
305 case EnterNotify:
306 X11DRV_EnterNotify( hWnd, (XCrossingEvent*)event );
307 break;
309 case FocusIn:
310 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
311 break;
313 case FocusOut:
314 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
315 break;
317 case Expose:
318 X11DRV_Expose( hWnd, &event->xexpose );
319 break;
321 case ConfigureNotify:
322 if (!hWnd) return;
323 X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
324 break;
326 case SelectionRequest:
327 if (!hWnd) return;
328 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
329 break;
331 case SelectionClear:
332 if (!hWnd) return;
333 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
334 break;
336 case PropertyNotify:
337 EVENT_PropertyNotify( (XPropertyEvent *)event );
338 break;
340 case ClientMessage:
341 if (!hWnd) return;
342 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
343 break;
345 case NoExpose:
346 break;
348 case MapNotify:
349 X11DRV_MapNotify( hWnd, (XMapEvent *)event );
350 break;
352 case UnmapNotify:
353 X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
354 break;
356 case KeymapNotify:
357 X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
358 break;
360 case MappingNotify:
361 X11DRV_MappingNotify( (XMappingEvent *) event );
362 break;
364 default:
365 WARN("Unprocessed event %s for hwnd %p\n", event_names[event->type], hWnd );
366 break;
368 TRACE( "returns.\n" );
372 /*******************************************************************
373 * can_activate_window
375 * Check if we can activate the specified window.
377 inline static BOOL can_activate_window( HWND hwnd )
379 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
380 if (!(style & WS_VISIBLE)) return FALSE;
381 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
382 return !(style & WS_DISABLED);
386 /**********************************************************************
387 * set_focus_error_handler
389 * Handler for X errors happening during XSetInputFocus call.
391 static int set_focus_error_handler( Display *display, XErrorEvent *event, void *arg )
393 return (event->error_code == BadMatch);
397 /**********************************************************************
398 * set_focus
400 static void set_focus( HWND hwnd, Time time )
402 HWND focus;
403 Window win;
405 TRACE( "setting foreground window to %p\n", hwnd );
406 SetForegroundWindow( hwnd );
408 focus = GetFocus();
409 if (focus) focus = GetAncestor( focus, GA_ROOT );
410 win = X11DRV_get_whole_window(focus);
412 if (win)
414 Display *display = thread_display();
415 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
416 X11DRV_expect_error( display, set_focus_error_handler, NULL );
417 XSetInputFocus( display, win, RevertToParent, time );
418 if (X11DRV_check_error()) TRACE("got BadMatch, ignoring\n" );
423 /**********************************************************************
424 * handle_wm_protocols_message
426 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
428 Atom protocol = (Atom)event->data.l[0];
430 if (!protocol) return;
432 if (protocol == wmDeleteWindow)
434 /* Ignore the delete window request if the window has been disabled
435 * and we are in managed mode. This is to disallow applications from
436 * being closed by the window manager while in a modal state.
438 if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
440 else if (protocol == wmTakeFocus)
442 Time event_time = (Time)event->data.l[1];
443 HWND last_focus = x11drv_thread_data()->last_focus;
445 TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
446 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
447 GetForegroundWindow(), last_focus );
449 if (can_activate_window(hwnd))
451 /* simulate a mouse click on the caption to find out
452 * whether the window wants to be activated */
453 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
454 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
455 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
456 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
457 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
459 else
461 hwnd = GetFocus();
462 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
463 if (!hwnd) hwnd = GetActiveWindow();
464 if (!hwnd) hwnd = last_focus;
465 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
467 } else if (protocol == netwmPing) {
468 XClientMessageEvent xev;
469 xev = *event;
471 TRACE("NET_WM Ping\n");
472 xev.window = DefaultRootWindow(xev.display);
473 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
474 /* this line is semi-stolen from gtk2 */
475 TRACE("NET_WM Pong\n");
480 static const char * const focus_details[] =
482 "NotifyAncestor",
483 "NotifyVirtual",
484 "NotifyInferior",
485 "NotifyNonlinear",
486 "NotifyNonlinearVirtual",
487 "NotifyPointer",
488 "NotifyPointerRoot",
489 "NotifyDetailNone"
492 /**********************************************************************
493 * EVENT_FocusIn
495 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
497 XIC xic;
499 if (!hwnd) return;
501 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
503 if (event->detail == NotifyPointer) return;
505 if ((xic = X11DRV_get_ic( hwnd )))
507 wine_tsx11_lock();
508 XSetICFocus( xic );
509 wine_tsx11_unlock();
511 if (wmTakeFocus) return; /* ignore FocusIn if we are using take focus */
513 if (!can_activate_window(hwnd))
515 HWND hwnd = GetFocus();
516 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
517 if (!hwnd) hwnd = GetActiveWindow();
518 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
519 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
521 else SetForegroundWindow( hwnd );
525 /**********************************************************************
526 * EVENT_FocusOut
528 * Note: only top-level windows get FocusOut events.
530 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
532 HWND hwnd_tmp;
533 Window focus_win;
534 int revert;
535 XIC xic;
537 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
539 if (event->detail == NotifyPointer) return;
540 x11drv_thread_data()->last_focus = hwnd;
541 if ((xic = X11DRV_get_ic( hwnd )))
543 wine_tsx11_lock();
544 XUnsetICFocus( xic );
545 wine_tsx11_unlock();
547 if (hwnd != GetForegroundWindow()) return;
548 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
550 /* don't reset the foreground window, if the window which is
551 getting the focus is a Wine window */
553 wine_tsx11_lock();
554 XGetInputFocus( thread_display(), &focus_win, &revert );
555 if (focus_win)
557 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
558 focus_win = 0;
560 wine_tsx11_unlock();
562 if (!focus_win)
564 /* Abey : 6-Oct-99. Check again if the focus out window is the
565 Foreground window, because in most cases the messages sent
566 above must have already changed the foreground window, in which
567 case we don't have to change the foreground window to 0 */
568 if (hwnd == GetForegroundWindow())
570 TRACE( "lost focus, setting fg to 0\n" );
571 SetForegroundWindow( 0 );
577 /***********************************************************************
578 * EVENT_SelectionRequest_AddTARGETS
579 * Utility function for EVENT_SelectionRequest_TARGETS.
581 static void EVENT_SelectionRequest_AddTARGETS(Atom* targets, unsigned long* cTargets, Atom prop)
583 int i;
584 BOOL bExists;
586 /* Scan through what we have so far to avoid duplicates */
587 for (i = 0, bExists = FALSE; i < *cTargets; i++)
589 if (targets[i] == prop)
591 bExists = TRUE;
592 break;
596 if (!bExists)
597 targets[(*cTargets)++] = prop;
601 /***********************************************************************
602 * EVENT_SelectionRequest_TARGETS
603 * Service a TARGETS selection request event
605 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
606 Atom target, Atom rprop )
608 Atom* targets;
609 UINT wFormat;
610 UINT alias;
611 ULONG cTargets;
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 LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
622 if (lpFormat && X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData))
623 cTargets++;
626 TRACE_(clipboard)(" found %ld formats\n", cTargets);
628 /* Allocate temp buffer */
629 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
630 if(targets == NULL)
631 return None;
633 /* Create TARGETS property list (First item in list is TARGETS itself) */
634 for (targets[0] = xaTargets, cTargets = 1, wFormat = 0;
635 (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
637 LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
639 EVENT_SelectionRequest_AddTARGETS(targets, &cTargets, lpFormat->drvData);
641 /* Check if any alias should be listed */
642 alias = X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData);
643 if (alias)
644 EVENT_SelectionRequest_AddTARGETS(targets, &cTargets, alias);
647 if (TRACE_ON(clipboard))
649 int i;
650 for ( i = 0; i < cTargets; i++)
652 if (targets[i])
654 char *itemFmtName = TSXGetAtomName(display, targets[i]);
655 TRACE_(clipboard)("\tAtom# %d: Property %ld Type %s\n", i, targets[i], itemFmtName);
656 TSXFree(itemFmtName);
661 /* We may want to consider setting the type to xaTargets instead,
662 * in case some apps expect this instead of XA_ATOM */
663 TSXChangeProperty(display, requestor, rprop, XA_ATOM, 32,
664 PropModeReplace, (unsigned char *)targets, cTargets);
666 HeapFree(GetProcessHeap(), 0, targets);
668 return rprop;
672 /***********************************************************************
673 * EVENT_SelectionRequest_MULTIPLE
674 * Service a MULTIPLE selection request event
675 * rprop contains a list of (target,property) atom pairs.
676 * The first atom names a target and the second names a property.
677 * The effect is as if we have received a sequence of SelectionRequest events
678 * (one for each atom pair) except that:
679 * 1. We reply with a SelectionNotify only when all the requested conversions
680 * have been performed.
681 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
682 * we replace the atom in the property by None.
684 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
686 Display *display = pevent->display;
687 Atom rprop;
688 Atom atype=AnyPropertyType;
689 int aformat;
690 unsigned long remain;
691 Atom* targetPropList=NULL;
692 unsigned long cTargetPropList = 0;
693 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
695 /* If the specified property is None the requestor is an obsolete client.
696 * We support these by using the specified target atom as the reply property.
698 rprop = pevent->property;
699 if( rprop == None )
700 rprop = pevent->target;
701 if (!rprop)
702 goto END;
704 /* Read the MULTIPLE property contents. This should contain a list of
705 * (target,property) atom pairs.
707 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
708 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
709 &cTargetPropList, &remain,
710 (unsigned char**)&targetPropList) != Success)
711 TRACE("\tCouldn't read MULTIPLE property\n");
712 else
714 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
715 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
718 * Make sure we got what we expect.
719 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
720 * in a MULTIPLE selection request should be of type ATOM_PAIR.
721 * However some X apps(such as XPaint) are not compliant with this and return
722 * a user defined atom in atype when XGetWindowProperty is called.
723 * The data *is* an atom pair but is not denoted as such.
725 if(aformat == 32 /* atype == xAtomPair */ )
727 int i;
729 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
730 * for each (target,property) pair */
732 for (i = 0; i < cTargetPropList; i+=2)
734 char *targetName = TSXGetAtomName(display, targetPropList[i]);
735 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
736 XSelectionRequestEvent event;
738 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
739 i/2, targetName, propName);
740 TSXFree(targetName);
741 TSXFree(propName);
743 /* We must have a non "None" property to service a MULTIPLE target atom */
744 if ( !targetPropList[i+1] )
746 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
747 continue;
750 /* Set up an XSelectionRequestEvent for this (target,property) pair */
751 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
752 event.target = targetPropList[i];
753 event.property = targetPropList[i+1];
755 /* Fire a SelectionRequest, informing the handler that we are processing
756 * a MULTIPLE selection request event.
758 EVENT_SelectionRequest( hWnd, &event, TRUE );
762 /* Free the list of targets/properties */
763 TSXFree(targetPropList);
766 END:
767 return rprop;
771 /***********************************************************************
772 * EVENT_SelectionRequest
773 * Process an event selection request event.
774 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
775 * recursively while servicing a "MULTIPLE" selection target.
777 * Note: We only receive this event when WINE owns the X selection
779 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
781 Display *display = event->display;
782 XSelectionEvent result;
783 Atom rprop = None;
784 Window request = event->requestor;
786 TRACE_(clipboard)("\n");
789 * We can only handle the selection request if :
790 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
791 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
792 * since this has been already done.
794 if ( !bIsMultiple )
796 if (((event->selection != XA_PRIMARY) && (event->selection != xaClipboard)))
797 goto END;
800 /* If the specified property is None the requestor is an obsolete client.
801 * We support these by using the specified target atom as the reply property.
803 rprop = event->property;
804 if( rprop == None )
805 rprop = event->target;
807 if(event->target == xaTargets) /* Return a list of all supported targets */
809 /* TARGETS selection request */
810 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
812 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
814 /* MULTIPLE selection request */
815 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
817 else
819 LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(event->target);
821 if (!lpFormat)
822 lpFormat = X11DRV_CLIPBOARD_LookupAliasProperty(event->target);
824 if (lpFormat)
826 LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(lpFormat->wFormatID);
828 if (lpData)
830 unsigned char* lpClipData;
831 DWORD cBytes;
832 HANDLE hClipData = lpFormat->lpDrvExportFunc(lpData, &cBytes);
834 if (hClipData && (lpClipData = GlobalLock(hClipData)))
837 TRACE_(clipboard)("\tUpdating property %s, %ld bytes\n",
838 lpFormat->Name, cBytes);
840 TSXChangeProperty(display, request, rprop, event->target,
841 8, PropModeReplace, (unsigned char *)lpClipData, cBytes);
843 GlobalUnlock(hClipData);
844 GlobalFree(hClipData);
848 else
850 if (TRACE_ON(clipboard))
852 TRACE_(clipboard)("Request for property %s (%ld) failed\n",
853 TSXGetAtomName(display, event->target), event->target);
858 END:
859 /* reply to sender
860 * SelectionNotify should be sent only at the end of a MULTIPLE request
862 if ( !bIsMultiple )
864 result.type = SelectionNotify;
865 result.display = display;
866 result.requestor = request;
867 result.selection = event->selection;
868 result.property = rprop;
869 result.target = event->target;
870 result.time = event->time;
871 TRACE("Sending SelectionNotify event...\n");
872 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
876 /***********************************************************************
877 * EVENT_SelectionClear
879 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
881 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
882 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
885 /***********************************************************************
886 * EVENT_PropertyNotify
887 * We use this to release resources like Pixmaps when a selection
888 * client no longer needs them.
890 static void EVENT_PropertyNotify( XPropertyEvent *event )
892 /* Check if we have any resources to free */
893 TRACE("Received PropertyNotify event: \n");
895 switch(event->state)
897 case PropertyDelete:
899 TRACE("\tPropertyDelete for atom %s on window %ld\n",
900 TSXGetAtomName(event->display, event->atom), (long)event->window);
901 break;
904 case PropertyNewValue:
906 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
907 TSXGetAtomName(event->display, event->atom), (long)event->window);
908 break;
911 default:
912 break;
916 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
918 RECT tempRect;
920 if (!IsWindowEnabled(hQueryWnd)) return 0;
922 GetWindowRect(hQueryWnd, &tempRect);
924 if(!PtInRect(&tempRect, *lpPt)) return 0;
926 if (!IsIconic( hQueryWnd ))
928 GetClientRect( hQueryWnd, &tempRect );
929 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
931 if (PtInRect( &tempRect, *lpPt))
933 HWND *list = WIN_ListChildren( hQueryWnd );
934 HWND bResult = 0;
936 if (list)
938 int i;
940 for (i = 0; list[i]; i++)
942 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
944 GetWindowRect( list[i], &tempRect );
945 if (PtInRect( &tempRect, *lpPt )) break;
948 if (list[i])
950 if (IsWindowEnabled( list[i] ))
951 bResult = find_drop_window( list[i], lpPt );
953 HeapFree( GetProcessHeap(), 0, list );
955 if(bResult) return bResult;
959 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
961 ScreenToClient(hQueryWnd, lpPt);
963 return hQueryWnd;
966 /**********************************************************************
967 * EVENT_DropFromOffix
969 * don't know if it still works (last Changlog is from 96/11/04)
971 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
973 unsigned long data_length;
974 unsigned long aux_long;
975 unsigned char* p_data = NULL;
976 union {
977 Atom atom_aux;
978 struct {
979 int x;
980 int y;
981 } pt_aux;
982 int i;
983 } u;
984 int x, y;
985 BOOL bAccept;
986 Window w_aux_root, w_aux_child;
987 WND* pWnd;
988 HWND hScope = hWnd;
990 pWnd = WIN_FindWndPtr(hWnd);
992 TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
993 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
994 (unsigned int*)&aux_long);
996 /* find out drop point and drop window */
997 if( x < 0 || y < 0 ||
998 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
999 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1001 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
1002 x = 0;
1003 y = 0;
1005 else
1007 POINT pt = { x, y };
1008 HWND hwndDrop = find_drop_window( hWnd, &pt );
1009 if (hwndDrop)
1011 x = pt.x;
1012 y = pt.y;
1013 hScope = hwndDrop;
1014 bAccept = TRUE;
1016 else
1018 bAccept = FALSE;
1021 WIN_ReleaseWndPtr(pWnd);
1023 if (!bAccept) return;
1025 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1026 dndSelection, 0, 65535, FALSE,
1027 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1028 &data_length, &aux_long, &p_data);
1030 if( !aux_long && p_data) /* don't bother if > 64K */
1032 signed char *p = (signed char*) p_data;
1033 char *p_drop;
1035 aux_long = 0;
1036 while( *p ) /* calculate buffer size */
1038 p_drop = p;
1039 if((u.i = *p) != -1 )
1041 INT len = GetShortPathNameA( p, NULL, 0 );
1042 if (len) aux_long += len + 1;
1043 else *p = -1;
1045 p += strlen(p) + 1;
1047 if( aux_long && aux_long < 65535 )
1049 HDROP hDrop;
1050 DROPFILES *lpDrop;
1052 aux_long += sizeof(DROPFILES) + 1;
1053 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1054 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1056 if( lpDrop )
1058 WND *pDropWnd = WIN_FindWndPtr( hScope );
1059 lpDrop->pFiles = sizeof(DROPFILES);
1060 lpDrop->pt.x = x;
1061 lpDrop->pt.y = y;
1062 lpDrop->fNC =
1063 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1064 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1065 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1066 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1067 lpDrop->fWide = FALSE;
1068 WIN_ReleaseWndPtr(pDropWnd);
1069 p_drop = (char *)(lpDrop + 1);
1070 p = p_data;
1071 while(*p)
1073 if( *p != -1 ) /* use only "good" entries */
1075 GetShortPathNameA( p, p_drop, 65535 );
1076 p_drop += strlen( p_drop ) + 1;
1078 p += strlen(p) + 1;
1080 *p_drop = '\0';
1081 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1085 if( p_data ) TSXFree(p_data);
1088 /**********************************************************************
1089 * EVENT_DropURLs
1091 * drop items are separated by \n
1092 * each item is prefixed by its mime type
1094 * event->data.l[3], event->data.l[4] contains drop x,y position
1096 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1098 unsigned long data_length;
1099 unsigned long aux_long, drop_len = 0;
1100 unsigned char *p_data = NULL; /* property data */
1101 char *p_drop = NULL;
1102 char *p, *next;
1103 int x, y;
1104 DROPFILES *lpDrop;
1105 HDROP hDrop;
1106 union {
1107 Atom atom_aux;
1108 int i;
1109 Window w_aux;
1110 } u; /* unused */
1112 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1114 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1115 dndSelection, 0, 65535, FALSE,
1116 AnyPropertyType, &u.atom_aux, &u.i,
1117 &data_length, &aux_long, &p_data);
1118 if (aux_long)
1119 WARN("property too large, truncated!\n");
1120 TRACE("urls=%s\n", p_data);
1122 if( !aux_long && p_data) { /* don't bother if > 64K */
1123 /* calculate length */
1124 p = p_data;
1125 next = strchr(p, '\n');
1126 while (p) {
1127 if (next) *next=0;
1128 if (strncmp(p,"file:",5) == 0 ) {
1129 INT len = GetShortPathNameA( p+5, NULL, 0 );
1130 if (len) drop_len += len + 1;
1132 if (next) {
1133 *next = '\n';
1134 p = next + 1;
1135 next = strchr(p, '\n');
1136 } else {
1137 p = NULL;
1141 if( drop_len && drop_len < 65535 ) {
1142 TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1143 &x, &y, &u.i, &u.i, &u.i);
1145 drop_len += sizeof(DROPFILES) + 1;
1146 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1147 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1149 if( lpDrop ) {
1150 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1151 lpDrop->pFiles = sizeof(DROPFILES);
1152 lpDrop->pt.x = (INT)x;
1153 lpDrop->pt.y = (INT)y;
1154 lpDrop->fNC =
1155 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1156 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1157 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1158 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1159 lpDrop->fWide = FALSE;
1160 p_drop = (char*)(lpDrop + 1);
1161 WIN_ReleaseWndPtr(pDropWnd);
1164 /* create message content */
1165 if (p_drop) {
1166 p = p_data;
1167 next = strchr(p, '\n');
1168 while (p) {
1169 if (next) *next=0;
1170 if (strncmp(p,"file:",5) == 0 ) {
1171 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1172 if (len) {
1173 TRACE("drop file %s as %s\n", p+5, p_drop);
1174 p_drop += len+1;
1175 } else {
1176 WARN("can't convert file %s to dos name \n", p+5);
1178 } else {
1179 WARN("unknown mime type %s\n", p);
1181 if (next) {
1182 *next = '\n';
1183 p = next + 1;
1184 next = strchr(p, '\n');
1185 } else {
1186 p = NULL;
1188 *p_drop = '\0';
1191 GlobalUnlock(hDrop);
1192 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1195 if( p_data ) TSXFree(p_data);
1199 /**********************************************************************
1200 * EVENT_ClientMessage
1202 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1204 if (event->message_type != None && event->format == 32) {
1205 if (event->message_type == wmProtocols)
1206 handle_wm_protocols_message( hWnd, event );
1207 else if (event->message_type == dndProtocol)
1209 /* query window (drag&drop event contains only drag window) */
1210 Window root, child;
1211 int root_x, root_y, child_x, child_y;
1212 unsigned int u;
1214 wine_tsx11_lock();
1215 XQueryPointer( event->display, root_window, &root, &child,
1216 &root_x, &root_y, &child_x, &child_y, &u);
1217 if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1218 wine_tsx11_unlock();
1219 if (!hWnd) return;
1220 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1221 EVENT_DropFromOffiX(hWnd, event);
1222 else if (event->data.l[0] == DndURL)
1223 EVENT_DropURLs(hWnd, event);
1225 else {
1226 #if 0
1227 /* enable this if you want to see the message */
1228 unsigned char* p_data = NULL;
1229 union {
1230 unsigned long l;
1231 int i;
1232 Atom atom;
1233 } u; /* unused */
1234 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1235 dndSelection, 0, 65535, FALSE,
1236 AnyPropertyType, &u.atom, &u.i,
1237 &u.l, &u.l, &p_data);
1238 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1239 event->message_type, event->data.l[0], event->data.l[1],
1240 event->data.l[2], event->data.l[3], event->data.l[4],
1241 p_data);
1242 #endif
1243 TRACE("unrecognized ClientMessage\n" );
1249 /**********************************************************************
1250 * X11DRV_EVENT_SetInputMethod
1252 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1254 INPUT_TYPE prev = current_input_type;
1256 /* Flag not used yet */
1257 in_transition = FALSE;
1258 current_input_type = type;
1260 return prev;
1263 #ifdef HAVE_LIBXXF86DGA2
1264 /**********************************************************************
1265 * X11DRV_EVENT_SetDGAStatus
1267 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1269 if (event_base < 0) {
1270 DGAUsed = FALSE;
1271 DGAhwnd = 0;
1272 } else {
1273 DGAUsed = TRUE;
1274 DGAhwnd = hwnd;
1275 DGAMotionEventType = event_base + MotionNotify;
1276 DGAButtonPressEventType = event_base + ButtonPress;
1277 DGAButtonReleaseEventType = event_base + ButtonRelease;
1278 DGAKeyPressEventType = event_base + KeyPress;
1279 DGAKeyReleaseEventType = event_base + KeyRelease;
1282 #endif