Append .dll extension in all cases (spotted by Mike Hearn).
[wine/wine-kai.git] / dlls / x11drv / event.c
blobd4c88174101a97f9622f780c0f42b89ca1ed82c6
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 &&
277 event->type != MappingNotify && event->type != KeymapNotify)
278 WARN( "Got event %s for unknown Window %08lx\n",
279 event_names[event->type], event->xany.window );
280 else if (event->type <= MappingNotify)
281 TRACE("Got event %s for hwnd/window %p/%lx, GetFocus()=%p\n",
282 event_names[event->type], hWnd, event->xany.window, GetFocus() );
283 else
284 TRACE("Got extension event for hwnd/window %p/%lx, GetFocus()=%p\n",
285 hWnd, event->xany.window, GetFocus() );
287 if (X11DRV_ProcessTabletEvent(hWnd, event))
289 TRACE("Return: filtered by tablet\n");
290 return;
293 switch(event->type)
295 case KeyPress:
296 case KeyRelease:
297 /* FIXME: should generate a motion event if event point is different from current pos */
298 X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
299 break;
301 case ButtonPress:
302 X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
303 break;
305 case ButtonRelease:
306 X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
307 break;
309 case MotionNotify:
310 X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
311 break;
313 case EnterNotify:
314 X11DRV_EnterNotify( hWnd, (XCrossingEvent*)event );
315 break;
317 case FocusIn:
318 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
319 break;
321 case FocusOut:
322 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
323 break;
325 case Expose:
326 X11DRV_Expose( hWnd, &event->xexpose );
327 break;
329 case ConfigureNotify:
330 if (!hWnd) return;
331 X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
332 break;
334 case SelectionRequest:
335 if (!hWnd) return;
336 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
337 break;
339 case SelectionClear:
340 if (!hWnd) return;
341 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
342 break;
344 case PropertyNotify:
345 EVENT_PropertyNotify( (XPropertyEvent *)event );
346 break;
348 case ClientMessage:
349 if (!hWnd) return;
350 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
351 break;
353 case NoExpose:
354 break;
356 case MapNotify:
357 X11DRV_MapNotify( hWnd, (XMapEvent *)event );
358 break;
360 case UnmapNotify:
361 X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
362 break;
364 case KeymapNotify:
365 X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
366 break;
368 case MappingNotify:
369 X11DRV_MappingNotify( (XMappingEvent *) event );
370 break;
372 default:
373 WARN("Unprocessed event %s for hwnd %p\n", event_names[event->type], hWnd );
374 break;
376 TRACE( "returns.\n" );
380 /*******************************************************************
381 * can_activate_window
383 * Check if we can activate the specified window.
385 inline static BOOL can_activate_window( HWND hwnd )
387 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
388 if (!(style & WS_VISIBLE)) return FALSE;
389 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
390 return !(style & WS_DISABLED);
394 /**********************************************************************
395 * set_focus
397 static void set_focus( HWND hwnd, Time time )
399 HWND focus;
400 Window win;
402 TRACE( "setting foreground window to %p\n", hwnd );
403 SetForegroundWindow( hwnd );
405 focus = GetFocus();
406 if (focus) focus = GetAncestor( focus, GA_ROOT );
407 win = X11DRV_get_whole_window(focus);
409 if (win)
411 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
412 wine_tsx11_lock();
413 XSetInputFocus( thread_display(), win, RevertToParent, time );
414 wine_tsx11_unlock();
419 /**********************************************************************
420 * handle_wm_protocols_message
422 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
424 Atom protocol = (Atom)event->data.l[0];
426 if (!protocol) return;
428 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
430 /* Ignore the delete window request if the window has been disabled
431 * and we are in managed mode. This is to disallow applications from
432 * being closed by the window manager while in a modal state.
434 if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
436 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
438 Time event_time = (Time)event->data.l[1];
439 HWND last_focus = x11drv_thread_data()->last_focus;
441 TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
442 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
443 GetForegroundWindow(), last_focus );
445 if (can_activate_window(hwnd))
447 /* simulate a mouse click on the caption to find out
448 * whether the window wants to be activated */
449 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
450 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
451 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
452 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
453 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
455 else
457 hwnd = GetFocus();
458 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
459 if (!hwnd) hwnd = GetActiveWindow();
460 if (!hwnd) hwnd = last_focus;
461 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
464 else if (protocol == x11drv_atom(_NET_WM_PING))
466 XClientMessageEvent xev;
467 xev = *event;
469 TRACE("NET_WM Ping\n");
470 xev.window = DefaultRootWindow(xev.display);
471 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
472 /* this line is semi-stolen from gtk2 */
473 TRACE("NET_WM Pong\n");
478 static const char * const focus_details[] =
480 "NotifyAncestor",
481 "NotifyVirtual",
482 "NotifyInferior",
483 "NotifyNonlinear",
484 "NotifyNonlinearVirtual",
485 "NotifyPointer",
486 "NotifyPointerRoot",
487 "NotifyDetailNone"
490 /**********************************************************************
491 * EVENT_FocusIn
493 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
495 XIC xic;
497 if (!hwnd) return;
499 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
501 if (event->detail == NotifyPointer) return;
503 if ((xic = X11DRV_get_ic( hwnd )))
505 wine_tsx11_lock();
506 XSetICFocus( xic );
507 wine_tsx11_unlock();
509 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
511 if (!can_activate_window(hwnd))
513 HWND hwnd = GetFocus();
514 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
515 if (!hwnd) hwnd = GetActiveWindow();
516 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
517 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
519 else SetForegroundWindow( hwnd );
523 /**********************************************************************
524 * EVENT_FocusOut
526 * Note: only top-level windows get FocusOut events.
528 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
530 HWND hwnd_tmp;
531 Window focus_win;
532 int revert;
533 XIC xic;
535 if (!hwnd) return;
537 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
539 if (event->detail == NotifyPointer) return;
540 if (ximInComposeMode) return;
542 x11drv_thread_data()->last_focus = hwnd;
543 if ((xic = X11DRV_get_ic( hwnd )))
545 wine_tsx11_lock();
546 XUnsetICFocus( xic );
547 wine_tsx11_unlock();
549 if (hwnd != GetForegroundWindow()) return;
550 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
552 /* don't reset the foreground window, if the window which is
553 getting the focus is a Wine window */
555 wine_tsx11_lock();
556 XGetInputFocus( thread_display(), &focus_win, &revert );
557 if (focus_win)
559 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
560 focus_win = 0;
562 wine_tsx11_unlock();
564 if (!focus_win)
566 /* Abey : 6-Oct-99. Check again if the focus out window is the
567 Foreground window, because in most cases the messages sent
568 above must have already changed the foreground window, in which
569 case we don't have to change the foreground window to 0 */
570 if (hwnd == GetForegroundWindow())
572 TRACE( "lost focus, setting fg to 0\n" );
573 SetForegroundWindow( 0 );
579 /***********************************************************************
580 * EVENT_SelectionRequest_AddTARGETS
581 * Utility function for EVENT_SelectionRequest_TARGETS.
583 static BOOL EVENT_SelectionRequest_AddTARGETS(Atom* targets, unsigned long cTargets, Atom prop)
585 unsigned int i;
586 BOOL bExists;
588 /* Scan through what we have so far to avoid duplicates */
589 for (i = 0, bExists = FALSE; i < cTargets; i++)
591 if (targets[i] == prop)
593 bExists = TRUE;
594 break;
598 if (!bExists)
599 targets[cTargets] = prop;
601 return !bExists;
605 /***********************************************************************
606 * EVENT_SelectionRequest_TARGETS
607 * Service a TARGETS selection request event
609 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
610 Atom target, Atom rprop )
612 Atom* targets;
613 UINT wFormat;
614 UINT alias;
615 ULONG cTargets;
616 LPWINE_CLIPFORMAT lpFormat;
619 * Count the number of items we wish to expose as selection targets.
620 * We include the TARGETS item, and property aliases
622 cTargets = X11DRV_CountClipboardFormats() + 1;
624 for (wFormat = 0; (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
626 lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
628 if (lpFormat)
630 if (!lpFormat->lpDrvExportFunc)
631 cTargets--;
633 if (X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData))
634 cTargets++;
636 /* else most likely unregistered format such as CF_PRIVATE or CF_GDIOBJ */
639 TRACE_(clipboard)(" found %ld formats\n", cTargets);
641 /* Allocate temp buffer */
642 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
643 if(targets == NULL)
644 return None;
646 /* Create TARGETS property list (First item in list is TARGETS itself) */
647 for (targets[0] = x11drv_atom(TARGETS), cTargets = 1, wFormat = 0;
648 (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
650 lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
652 if (lpFormat)
654 if (lpFormat->lpDrvExportFunc)
656 if (EVENT_SelectionRequest_AddTARGETS(targets, cTargets, lpFormat->drvData))
657 cTargets++;
660 /* Check if any alias should be listed */
661 alias = X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData);
662 if (alias)
664 if (EVENT_SelectionRequest_AddTARGETS(targets, cTargets, alias))
665 cTargets++;
670 wine_tsx11_lock();
672 if (TRACE_ON(clipboard))
674 unsigned int i;
675 for ( i = 0; i < cTargets; i++)
677 if (targets[i])
679 char *itemFmtName = XGetAtomName(display, targets[i]);
680 TRACE_(clipboard)("\tAtom# %d: Property %ld Type %s\n", i, targets[i], itemFmtName);
681 XFree(itemFmtName);
686 /* We may want to consider setting the type to xaTargets instead,
687 * in case some apps expect this instead of XA_ATOM */
688 XChangeProperty(display, requestor, rprop, XA_ATOM, 32,
689 PropModeReplace, (unsigned char *)targets, cTargets);
690 wine_tsx11_unlock();
692 HeapFree(GetProcessHeap(), 0, targets);
694 return rprop;
698 /***********************************************************************
699 * EVENT_SelectionRequest_MULTIPLE
700 * Service a MULTIPLE selection request event
701 * rprop contains a list of (target,property) atom pairs.
702 * The first atom names a target and the second names a property.
703 * The effect is as if we have received a sequence of SelectionRequest events
704 * (one for each atom pair) except that:
705 * 1. We reply with a SelectionNotify only when all the requested conversions
706 * have been performed.
707 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
708 * we replace the atom in the property by None.
710 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
712 Display *display = pevent->display;
713 Atom rprop;
714 Atom atype=AnyPropertyType;
715 int aformat;
716 unsigned long remain;
717 Atom* targetPropList=NULL;
718 unsigned long cTargetPropList = 0;
720 /* If the specified property is None the requestor is an obsolete client.
721 * We support these by using the specified target atom as the reply property.
723 rprop = pevent->property;
724 if( rprop == None )
725 rprop = pevent->target;
726 if (!rprop)
727 goto END;
729 /* Read the MULTIPLE property contents. This should contain a list of
730 * (target,property) atom pairs.
732 wine_tsx11_lock();
733 if(XGetWindowProperty(display, pevent->requestor, rprop,
734 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
735 &cTargetPropList, &remain,
736 (unsigned char**)&targetPropList) != Success)
738 wine_tsx11_unlock();
739 TRACE("\tCouldn't read MULTIPLE property\n");
741 else
743 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
744 XGetAtomName(display, atype), aformat, cTargetPropList, remain);
745 wine_tsx11_unlock();
748 * Make sure we got what we expect.
749 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
750 * in a MULTIPLE selection request should be of type ATOM_PAIR.
751 * However some X apps(such as XPaint) are not compliant with this and return
752 * a user defined atom in atype when XGetWindowProperty is called.
753 * The data *is* an atom pair but is not denoted as such.
755 if(aformat == 32 /* atype == xAtomPair */ )
757 unsigned int i;
759 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
760 * for each (target,property) pair */
762 for (i = 0; i < cTargetPropList; i+=2)
764 XSelectionRequestEvent event;
766 if (TRACE_ON(event))
768 char *targetName, *propName;
769 wine_tsx11_lock();
770 targetName = XGetAtomName(display, targetPropList[i]);
771 propName = XGetAtomName(display, targetPropList[i+1]);
772 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
773 i/2, targetName, propName);
774 XFree(targetName);
775 XFree(propName);
776 wine_tsx11_unlock();
779 /* We must have a non "None" property to service a MULTIPLE target atom */
780 if ( !targetPropList[i+1] )
782 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
783 continue;
786 /* Set up an XSelectionRequestEvent for this (target,property) pair */
787 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
788 event.target = targetPropList[i];
789 event.property = targetPropList[i+1];
791 /* Fire a SelectionRequest, informing the handler that we are processing
792 * a MULTIPLE selection request event.
794 EVENT_SelectionRequest( hWnd, &event, TRUE );
798 /* Free the list of targets/properties */
799 wine_tsx11_lock();
800 XFree(targetPropList);
801 wine_tsx11_unlock();
804 END:
805 return rprop;
809 /***********************************************************************
810 * EVENT_SelectionRequest
811 * Process an event selection request event.
812 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
813 * recursively while servicing a "MULTIPLE" selection target.
815 * Note: We only receive this event when WINE owns the X selection
817 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
819 Display *display = event->display;
820 XSelectionEvent result;
821 Atom rprop = None;
822 Window request = event->requestor;
824 TRACE_(clipboard)("\n");
827 * We can only handle the selection request if :
828 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
829 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
830 * since this has been already done.
832 if ( !bIsMultiple )
834 if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
835 goto END;
838 /* If the specified property is None the requestor is an obsolete client.
839 * We support these by using the specified target atom as the reply property.
841 rprop = event->property;
842 if( rprop == None )
843 rprop = event->target;
845 if(event->target == x11drv_atom(TARGETS)) /* Return a list of all supported targets */
847 /* TARGETS selection request */
848 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
850 else if(event->target == x11drv_atom(MULTIPLE)) /* rprop contains a list of (target, property) atom pairs */
852 /* MULTIPLE selection request */
853 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
855 else
857 LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(event->target);
859 if (!lpFormat)
860 lpFormat = X11DRV_CLIPBOARD_LookupAliasProperty(event->target);
862 if (lpFormat && lpFormat->lpDrvExportFunc)
864 LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(lpFormat->wFormatID);
866 if (lpData)
868 unsigned char* lpClipData;
869 DWORD cBytes;
870 HANDLE hClipData = lpFormat->lpDrvExportFunc(request, event->target,
871 rprop, lpData, &cBytes);
873 if (hClipData && (lpClipData = GlobalLock(hClipData)))
875 TRACE_(clipboard)("\tUpdating property %s, %ld bytes\n",
876 lpFormat->Name, cBytes);
878 wine_tsx11_lock();
879 XChangeProperty(display, request, rprop, event->target,
880 8, PropModeReplace, (unsigned char *)lpClipData, cBytes);
881 wine_tsx11_unlock();
883 GlobalUnlock(hClipData);
884 GlobalFree(hClipData);
890 END:
891 /* reply to sender
892 * SelectionNotify should be sent only at the end of a MULTIPLE request
894 if ( !bIsMultiple )
896 result.type = SelectionNotify;
897 result.display = display;
898 result.requestor = request;
899 result.selection = event->selection;
900 result.property = rprop;
901 result.target = event->target;
902 result.time = event->time;
903 TRACE("Sending SelectionNotify event...\n");
904 wine_tsx11_lock();
905 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
906 wine_tsx11_unlock();
910 /***********************************************************************
911 * EVENT_SelectionClear
913 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
915 if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
916 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
919 /***********************************************************************
920 * EVENT_PropertyNotify
921 * We use this to release resources like Pixmaps when a selection
922 * client no longer needs them.
924 static void EVENT_PropertyNotify( XPropertyEvent *event )
926 /* Check if we have any resources to free */
927 TRACE("Received PropertyNotify event: \n");
929 switch(event->state)
931 case PropertyDelete:
933 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
934 event->atom, (long)event->window);
935 break;
938 case PropertyNewValue:
940 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
941 event->atom, (long)event->window);
942 break;
945 default:
946 break;
950 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
952 RECT tempRect;
954 if (!IsWindowEnabled(hQueryWnd)) return 0;
956 GetWindowRect(hQueryWnd, &tempRect);
958 if(!PtInRect(&tempRect, *lpPt)) return 0;
960 if (!IsIconic( hQueryWnd ))
962 GetClientRect( hQueryWnd, &tempRect );
963 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
965 if (PtInRect( &tempRect, *lpPt))
967 HWND *list = WIN_ListChildren( hQueryWnd );
968 HWND bResult = 0;
970 if (list)
972 int i;
974 for (i = 0; list[i]; i++)
976 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
978 GetWindowRect( list[i], &tempRect );
979 if (PtInRect( &tempRect, *lpPt )) break;
982 if (list[i])
984 if (IsWindowEnabled( list[i] ))
985 bResult = find_drop_window( list[i], lpPt );
987 HeapFree( GetProcessHeap(), 0, list );
989 if(bResult) return bResult;
993 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
995 ScreenToClient(hQueryWnd, lpPt);
997 return hQueryWnd;
1000 /**********************************************************************
1001 * EVENT_DropFromOffix
1003 * don't know if it still works (last Changlog is from 96/11/04)
1005 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1007 unsigned long data_length;
1008 unsigned long aux_long;
1009 unsigned char* p_data = NULL;
1010 union {
1011 Atom atom_aux;
1012 struct {
1013 int x;
1014 int y;
1015 } pt_aux;
1016 int i;
1017 } u;
1018 int x, y;
1019 BOOL bAccept;
1020 Window w_aux_root, w_aux_child;
1021 WND* pWnd;
1022 HWND hScope = hWnd;
1024 pWnd = WIN_FindWndPtr(hWnd);
1026 wine_tsx11_lock();
1027 XQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1028 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1029 (unsigned int*)&aux_long);
1030 wine_tsx11_unlock();
1032 /* find out drop point and drop window */
1033 if( x < 0 || y < 0 ||
1034 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1035 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1037 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
1038 x = 0;
1039 y = 0;
1041 else
1043 POINT pt = { x, y };
1044 HWND hwndDrop = find_drop_window( hWnd, &pt );
1045 if (hwndDrop)
1047 x = pt.x;
1048 y = pt.y;
1049 hScope = hwndDrop;
1050 bAccept = TRUE;
1052 else
1054 bAccept = FALSE;
1057 WIN_ReleaseWndPtr(pWnd);
1059 if (!bAccept) return;
1061 wine_tsx11_lock();
1062 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1063 x11drv_atom(DndSelection), 0, 65535, FALSE,
1064 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1065 &data_length, &aux_long, &p_data);
1066 wine_tsx11_unlock();
1068 if( !aux_long && p_data) /* don't bother if > 64K */
1070 signed char *p = (signed char*) p_data;
1071 char *p_drop;
1073 aux_long = 0;
1074 while( *p ) /* calculate buffer size */
1076 p_drop = p;
1077 if((u.i = *p) != -1 )
1079 INT len = GetShortPathNameA( p, NULL, 0 );
1080 if (len) aux_long += len + 1;
1081 else *p = -1;
1083 p += strlen(p) + 1;
1085 if( aux_long && aux_long < 65535 )
1087 HDROP hDrop;
1088 DROPFILES *lpDrop;
1090 aux_long += sizeof(DROPFILES) + 1;
1091 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1092 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1094 if( lpDrop )
1096 WND *pDropWnd = WIN_FindWndPtr( hScope );
1097 lpDrop->pFiles = sizeof(DROPFILES);
1098 lpDrop->pt.x = x;
1099 lpDrop->pt.y = y;
1100 lpDrop->fNC =
1101 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1102 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1103 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1104 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1105 lpDrop->fWide = FALSE;
1106 WIN_ReleaseWndPtr(pDropWnd);
1107 p_drop = (char *)(lpDrop + 1);
1108 p = p_data;
1109 while(*p)
1111 if( *p != -1 ) /* use only "good" entries */
1113 GetShortPathNameA( p, p_drop, 65535 );
1114 p_drop += strlen( p_drop ) + 1;
1116 p += strlen(p) + 1;
1118 *p_drop = '\0';
1119 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1123 wine_tsx11_lock();
1124 if( p_data ) XFree(p_data);
1125 wine_tsx11_unlock();
1128 /**********************************************************************
1129 * EVENT_DropURLs
1131 * drop items are separated by \n
1132 * each item is prefixed by its mime type
1134 * event->data.l[3], event->data.l[4] contains drop x,y position
1136 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1138 unsigned long data_length;
1139 unsigned long aux_long, drop_len = 0;
1140 unsigned char *p_data = NULL; /* property data */
1141 char *p_drop = NULL;
1142 char *p, *next;
1143 int x, y;
1144 DROPFILES *lpDrop;
1145 HDROP hDrop;
1146 union {
1147 Atom atom_aux;
1148 int i;
1149 Window w_aux;
1150 } u; /* unused */
1152 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1154 wine_tsx11_lock();
1155 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1156 x11drv_atom(DndSelection), 0, 65535, FALSE,
1157 AnyPropertyType, &u.atom_aux, &u.i,
1158 &data_length, &aux_long, &p_data);
1159 wine_tsx11_unlock();
1160 if (aux_long)
1161 WARN("property too large, truncated!\n");
1162 TRACE("urls=%s\n", p_data);
1164 if( !aux_long && p_data) { /* don't bother if > 64K */
1165 /* calculate length */
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, NULL, 0 );
1172 if (len) drop_len += len + 1;
1174 if (next) {
1175 *next = '\n';
1176 p = next + 1;
1177 next = strchr(p, '\n');
1178 } else {
1179 p = NULL;
1183 if( drop_len && drop_len < 65535 ) {
1184 wine_tsx11_lock();
1185 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1186 &x, &y, &u.i, &u.i, &u.i);
1187 wine_tsx11_unlock();
1189 drop_len += sizeof(DROPFILES) + 1;
1190 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1191 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1193 if( lpDrop ) {
1194 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1195 lpDrop->pFiles = sizeof(DROPFILES);
1196 lpDrop->pt.x = (INT)x;
1197 lpDrop->pt.y = (INT)y;
1198 lpDrop->fNC =
1199 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1200 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1201 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1202 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1203 lpDrop->fWide = FALSE;
1204 p_drop = (char*)(lpDrop + 1);
1205 WIN_ReleaseWndPtr(pDropWnd);
1208 /* create message content */
1209 if (p_drop) {
1210 p = p_data;
1211 next = strchr(p, '\n');
1212 while (p) {
1213 if (next) *next=0;
1214 if (strncmp(p,"file:",5) == 0 ) {
1215 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1216 if (len) {
1217 TRACE("drop file %s as %s\n", p+5, p_drop);
1218 p_drop += len+1;
1219 } else {
1220 WARN("can't convert file %s to dos name \n", p+5);
1222 } else {
1223 WARN("unknown mime type %s\n", p);
1225 if (next) {
1226 *next = '\n';
1227 p = next + 1;
1228 next = strchr(p, '\n');
1229 } else {
1230 p = NULL;
1232 *p_drop = '\0';
1235 GlobalUnlock(hDrop);
1236 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1239 wine_tsx11_lock();
1240 if( p_data ) XFree(p_data);
1241 wine_tsx11_unlock();
1245 /**********************************************************************
1246 * EVENT_ClientMessage
1248 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1250 if (event->message_type != None && event->format == 32) {
1251 if (event->message_type == x11drv_atom(WM_PROTOCOLS))
1252 handle_wm_protocols_message( hWnd, event );
1253 else if (event->message_type == x11drv_atom(DndProtocol))
1255 /* query window (drag&drop event contains only drag window) */
1256 Window root, child;
1257 int root_x, root_y, child_x, child_y;
1258 unsigned int u;
1260 wine_tsx11_lock();
1261 XQueryPointer( event->display, root_window, &root, &child,
1262 &root_x, &root_y, &child_x, &child_y, &u);
1263 if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1264 wine_tsx11_unlock();
1265 if (!hWnd) return;
1266 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1267 EVENT_DropFromOffiX(hWnd, event);
1268 else if (event->data.l[0] == DndURL)
1269 EVENT_DropURLs(hWnd, event);
1271 else if (!X11DRV_XDND_Event(hWnd, event))
1273 #if 0
1274 /* enable this if you want to see the message */
1275 unsigned char* p_data = NULL;
1276 union {
1277 unsigned long l;
1278 int i;
1279 Atom atom;
1280 } u; /* unused */
1281 wine_tsx11_lock();
1282 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1283 dndSelection, 0, 65535, FALSE,
1284 AnyPropertyType, &u.atom, &u.i,
1285 &u.l, &u.l, &p_data);
1286 wine_tsx11_unlock();
1287 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1288 event->message_type, event->data.l[0], event->data.l[1],
1289 event->data.l[2], event->data.l[3], event->data.l[4],
1290 p_data);
1291 #endif
1292 TRACE("unrecognized ClientMessage\n" );
1298 /**********************************************************************
1299 * X11DRV_EVENT_SetInputMethod
1301 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1303 INPUT_TYPE prev = current_input_type;
1305 /* Flag not used yet */
1306 in_transition = FALSE;
1307 current_input_type = type;
1309 return prev;
1312 #ifdef HAVE_LIBXXF86DGA2
1313 /**********************************************************************
1314 * X11DRV_EVENT_SetDGAStatus
1316 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1318 if (event_base < 0) {
1319 DGAUsed = FALSE;
1320 DGAhwnd = 0;
1321 } else {
1322 DGAUsed = TRUE;
1323 DGAhwnd = hwnd;
1324 DGAMotionEventType = event_base + MotionNotify;
1325 DGAButtonPressEventType = event_base + ButtonPress;
1326 DGAButtonReleaseEventType = event_base + ButtonRelease;
1327 DGAKeyPressEventType = event_base + KeyPress;
1328 DGAKeyReleaseEventType = event_base + KeyRelease;
1331 #endif