4 * Copyright 1993 Alexandre Julliard
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
24 #include <X11/Xatom.h>
25 #include <X11/keysym.h>
28 #include <X11/Xresource.h>
29 #include <X11/Xutil.h>
30 #ifdef HAVE_LIBXXF86DGA2
31 #include <X11/extensions/xf86dga.h>
36 #include "wine/winuser16.h"
37 #include "shlobj.h" /* DROPFILES */
39 #include "clipboard.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(event);
50 /* X context to associate a hwnd to an X window */
51 extern XContext winContext;
53 extern Atom wmProtocols;
54 extern Atom wmDeleteWindow;
55 extern Atom dndProtocol;
56 extern Atom dndSelection;
58 #define DndNotDnd -1 /* OffiX drag&drop */
70 #define DndURL 128 /* KDE drag&drop */
72 static const char * const event_names[] =
74 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
75 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
76 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
77 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
78 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
79 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
80 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
81 "ClientMessage", "MappingNotify"
85 static void EVENT_ProcessEvent( XEvent *event );
88 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
89 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
90 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
91 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
92 static void EVENT_PropertyNotify( XPropertyEvent *event );
93 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
95 extern void X11DRV_ButtonPress( HWND hwnd, XButtonEvent *event );
96 extern void X11DRV_ButtonRelease( HWND hwnd, XButtonEvent *event );
97 extern void X11DRV_MotionNotify( HWND hwnd, XMotionEvent *event );
98 extern void X11DRV_EnterNotify( HWND hwnd, XCrossingEvent *event );
99 extern void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event );
100 extern void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event );
101 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
102 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
103 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
104 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
105 extern void X11DRV_MappingNotify( XMappingEvent *event );
107 #ifdef HAVE_LIBXXF86DGA2
108 static int DGAMotionEventType;
109 static int DGAButtonPressEventType;
110 static int DGAButtonReleaseEventType;
111 static int DGAKeyPressEventType;
112 static int DGAKeyReleaseEventType;
114 static BOOL DGAUsed = FALSE;
115 static HWND DGAhwnd = 0;
117 extern void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event );
118 extern void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event );
119 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event );
122 /* Static used for the current input method */
123 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
124 static BOOL in_transition = FALSE; /* This is not used as for today */
127 /***********************************************************************
130 static int process_events( struct x11drv_thread_data *data )
136 while ( XPending( data->display ) )
138 XNextEvent( data->display, &event );
140 EVENT_ProcessEvent( &event );
149 /***********************************************************************
150 * MsgWaitForMultipleObjectsEx (X11DRV.@)
152 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
153 DWORD timeout, DWORD mask, DWORD flags )
155 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
157 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
159 if (!data || data->process_event_count)
160 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
161 timeout, flags & MWMO_ALERTABLE );
163 for (i = 0; i < count; i++) new_handles[i] = handles[i];
164 new_handles[count] = data->display_fd;
167 XFlush( gdi_display );
168 XFlush( data->display );
171 data->process_event_count++;
172 if (process_events( data )) ret = count;
175 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
176 timeout, flags & MWMO_ALERTABLE );
177 if (ret == count) process_events( data );
179 data->process_event_count--;
184 /***********************************************************************
187 * Process an X event.
189 static void EVENT_ProcessEvent( XEvent *event )
192 Display *display = event->xany.display;
194 TRACE( "called.\n" );
198 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
199 FIXME("Got SelectionNotify - must not happen!\n");
202 /* We get all these because of StructureNotifyMask.
203 This check is placed here to avoid getting error messages below,
204 as X might send some of these even for windows that have already
206 case CirculateNotify:
214 #ifdef HAVE_LIBXXF86DGA2
216 if (event->type == DGAMotionEventType) {
217 TRACE("DGAMotionEvent received.\n");
218 X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
221 if (event->type == DGAButtonPressEventType) {
222 TRACE("DGAButtonPressEvent received.\n");
223 X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
226 if (event->type == DGAButtonReleaseEventType) {
227 TRACE("DGAButtonReleaseEvent received.\n");
228 X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
231 if ((event->type == DGAKeyPressEventType) ||
232 (event->type == DGAKeyReleaseEventType)) {
233 /* Fill a XKeyEvent to send to EVENT_Key */
235 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
237 TRACE("DGAKeyPress/ReleaseEvent received.\n");
239 if (evt->type == DGAKeyReleaseEventType)
240 ke.type = KeyRelease;
243 ke.serial = evt->serial;
244 ke.send_event = FALSE;
245 ke.display = evt->display;
254 ke.state = evt->state;
255 ke.keycode = evt->keycode;
256 ke.same_screen = TRUE;
257 X11DRV_KeyEvent( 0, &ke );
264 if (XFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
265 hWnd = 0; /* Not for a registered window */
268 if ( !hWnd && event->xany.window != root_window
269 && event->type != PropertyNotify
270 && event->type != MappingNotify)
271 WARN( "Got event %s for unknown Window %08lx\n",
272 event_names[event->type], event->xany.window );
274 TRACE("Got event %s for hwnd %p\n",
275 event_names[event->type], hWnd );
281 /* FIXME: should generate a motion event if event point is different from current pos */
282 X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
286 X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
290 X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
294 X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
298 X11DRV_EnterNotify( hWnd, (XCrossingEvent*)event );
302 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
306 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
310 X11DRV_Expose( hWnd, &event->xexpose );
313 case ConfigureNotify:
315 X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
318 case SelectionRequest:
320 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
325 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
329 EVENT_PropertyNotify( (XPropertyEvent *)event );
334 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
341 X11DRV_MapNotify( hWnd, (XMapEvent *)event );
345 X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
349 X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
353 X11DRV_MappingNotify( (XMappingEvent *) event );
357 WARN("Unprocessed event %s for hwnd %p\n", event_names[event->type], hWnd );
360 TRACE( "returns.\n" );
364 /*******************************************************************
365 * can_activate_window
367 * Check if we can activate the specified window.
369 inline static BOOL can_activate_window( HWND hwnd )
371 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
372 if (!(style & WS_VISIBLE)) return FALSE;
373 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
374 return !(style & WS_DISABLED);
378 /**********************************************************************
379 * set_focus_error_handler
381 * Handler for X errors happening during XSetInputFocus call.
383 static int set_focus_error_handler( Display *display, XErrorEvent *event, void *arg )
385 return (event->error_code == BadMatch);
389 /**********************************************************************
392 static void set_focus( HWND hwnd, Time time )
397 TRACE( "setting foreground window to %p\n", hwnd );
398 SetForegroundWindow( hwnd );
401 win = X11DRV_get_whole_window(focus);
405 Display *display = thread_display();
406 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
407 X11DRV_expect_error( display, set_focus_error_handler, NULL );
408 XSetInputFocus( display, win, RevertToParent, time );
409 if (X11DRV_check_error()) TRACE("got BadMatch, ignoring\n" );
414 /**********************************************************************
415 * handle_wm_protocols_message
417 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
419 Atom protocol = (Atom)event->data.l[0];
421 if (!protocol) return;
423 if (protocol == wmDeleteWindow)
425 /* Ignore the delete window request if the window has been disabled
426 * and we are in managed mode. This is to disallow applications from
427 * being closed by the window manager while in a modal state.
429 if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
431 else if (protocol == wmTakeFocus)
433 Time event_time = (Time)event->data.l[1];
434 HWND last_focus = x11drv_thread_data()->last_focus;
436 TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
437 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
438 GetForegroundWindow(), last_focus );
440 if (can_activate_window(hwnd))
442 /* simulate a mouse click on the caption to find out
443 * whether the window wants to be activated */
444 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
445 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
446 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
447 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
448 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
453 if (!hwnd) hwnd = GetActiveWindow();
454 if (!hwnd) hwnd = last_focus;
455 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
461 static const char * const focus_details[] =
467 "NotifyNonlinearVirtual",
473 /**********************************************************************
476 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
480 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
482 if (wmTakeFocus) return; /* ignore FocusIn if we are using take focus */
483 if (event->detail == NotifyPointer) return;
485 if (!can_activate_window(hwnd))
487 HWND hwnd = GetFocus();
488 if (!hwnd) hwnd = GetActiveWindow();
489 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
490 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
492 else SetForegroundWindow( hwnd );
496 /**********************************************************************
499 * Note: only top-level windows get FocusOut events.
501 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
507 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
509 if (event->detail == NotifyPointer) return;
510 x11drv_thread_data()->last_focus = hwnd;
511 if (hwnd != GetForegroundWindow()) return;
512 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
514 /* don't reset the foreground window, if the window which is
515 getting the focus is a Wine window */
518 XGetInputFocus( thread_display(), &focus_win, &revert );
521 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
528 /* Abey : 6-Oct-99. Check again if the focus out window is the
529 Foreground window, because in most cases the messages sent
530 above must have already changed the foreground window, in which
531 case we don't have to change the foreground window to 0 */
532 if (hwnd == GetForegroundWindow())
534 TRACE( "lost focus, setting fg to 0\n" );
535 SetForegroundWindow( 0 );
541 /***********************************************************************
542 * EVENT_SelectionRequest_TARGETS
543 * Service a TARGETS selection request event
545 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
546 Atom target, Atom rprop )
548 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
552 unsigned long cTargets;
556 TRACE("Request for %s\n", TSXGetAtomName(display, target));
559 * Count the number of items we wish to expose as selection targets.
560 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
562 cTargets = CountClipboardFormats() + 1;
563 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
566 /* Allocate temp buffer */
567 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
568 if(targets == NULL) return None;
570 /* Create TARGETS property list (First item in list is TARGETS itself) */
572 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
573 (wFormat = EnumClipboardFormats( wFormat )); )
575 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
577 /* Scan through what we have so far to avoid duplicates */
580 for (i = 0, bExists = FALSE; i < cTargets; i++)
582 if (targets[i] == prop)
590 targets[cTargets++] = prop;
592 /* Add PIXMAP prop for bitmaps additionally */
593 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
596 targets[cTargets++] = XA_PIXMAP;
606 for ( i = 0; i < cTargets; i++)
610 char *itemFmtName = TSXGetAtomName(display, targets[i]);
611 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
612 TSXFree(itemFmtName);
617 /* Update the X property */
618 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
620 /* We may want to consider setting the type to xaTargets instead,
621 * in case some apps expect this instead of XA_ATOM */
622 xRc = TSXChangeProperty(display, requestor, rprop,
623 XA_ATOM, 32, PropModeReplace,
624 (unsigned char *)targets, cTargets);
625 TRACE("(Rc=%d)\n", xRc);
627 HeapFree( GetProcessHeap(), 0, targets );
633 /***********************************************************************
634 * EVENT_SelectionRequest_STRING
635 * Service a STRING selection request event
637 static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
638 Atom target, Atom rprop )
640 static UINT text_cp = (UINT)-1;
649 if(text_cp == (UINT)-1)
654 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
657 DWORD type, count = sizeof(buf);
658 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
665 * Map the requested X selection property type atom name to a
666 * windows clipboard format ID.
668 itemFmtName = TSXGetAtomName(display, target);
669 TRACE("Request for %s (wFormat=%x %s)\n",
670 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT, NULL, 0));
671 TSXFree(itemFmtName);
673 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
676 uni_text = GlobalLock(hUnicodeText);
680 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
681 text = HeapAlloc(GetProcessHeap(), 0, size);
684 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
686 /* remove carriage returns */
688 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
689 if(lpstr == NULL) return None;
690 for(i=0,j=0; i < size && text[i]; i++ )
692 if( text[i] == '\r' &&
693 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
694 lpstr[j++] = text[i];
698 /* Update the X property */
699 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
700 xRc = TSXChangeProperty(display, requestor, rprop,
701 XA_STRING, 8, PropModeReplace,
703 TRACE("(Rc=%d)\n", xRc);
705 GlobalUnlock(hUnicodeText);
706 HeapFree(GetProcessHeap(), 0, text);
707 HeapFree( GetProcessHeap(), 0, lpstr );
712 /***********************************************************************
713 * EVENT_SelectionRequest_PIXMAP
714 * Service a PIXMAP selection request event
716 static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
717 Atom target, Atom rprop )
719 HANDLE hClipData = 0;
725 XSetWindowAttributes win_attr;
726 XWindowAttributes win_attr_src;
730 * Map the requested X selection property type atom name to a
731 * windows clipboard format ID.
733 itemFmtName = TSXGetAtomName(display, target);
734 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
735 TRACE("Request for %s (wFormat=%x %s)\n",
736 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0 ));
737 TSXFree(itemFmtName);
739 hClipData = GetClipboardData(wFormat);
742 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
743 rprop = None; /* Fail the request */
747 if (wFormat == CF_DIB)
749 HWND hwnd = GetOpenClipboardWindow();
750 HDC hdc = GetDC(hwnd);
752 /* For convert from packed DIB to Pixmap */
753 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
755 ReleaseDC(hwnd, hdc);
757 else if (wFormat == CF_BITMAP)
759 HWND hwnd = GetOpenClipboardWindow();
760 HDC hdc = GetDC(hwnd);
762 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
764 ReleaseDC(hwnd, hdc);
768 FIXME("%s to PIXMAP conversion not yet implemented!\n",
769 CLIPBOARD_GetFormatName(wFormat, NULL, 0));
774 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
775 TSXGetAtomName(display, rprop), (long)requestor,
776 TSXGetAtomName(display, target), pixmap);
778 /* Store the Pixmap handle in the property */
779 xRc = TSXChangeProperty(display, requestor, rprop, target,
781 (unsigned char *)&pixmap, 1);
782 TRACE("(Rc=%d)\n", xRc);
784 /* Enable the code below if you want to handle destroying Pixmap resources
785 * in response to property notify events. Clients like XPaint don't
786 * appear to be duplicating Pixmaps so they don't like us deleting,
787 * the resource in response to the property being deleted.
790 /* Express interest in property notify events so that we can delete the
791 * pixmap when the client deletes the property atom.
793 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
794 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
796 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
797 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
799 /* Register the Pixmap we created with the request property Atom.
800 * When this property is destroyed we also destroy the Pixmap in
801 * response to the PropertyNotify event.
803 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
811 /***********************************************************************
812 * EVENT_SelectionRequest_WCF
813 * Service a Wine Clipboard Format selection request event.
814 * For <WCF>* data types we simply copy the data to X without conversion.
816 static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
817 Atom target, Atom rprop )
819 HANDLE hClipData = 0;
828 * Map the requested X selection property type atom name to a
829 * windows clipboard format ID.
831 itemFmtName = TSXGetAtomName(display, target);
832 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
833 TRACE("Request for %s (wFormat=%x %s)\n",
834 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0));
835 TSXFree(itemFmtName);
837 hClipData = GetClipboardData(wFormat);
839 bemf = wFormat == CF_METAFILEPICT || wFormat == CF_ENHMETAFILE;
841 hClipData = X11DRV_CLIPBOARD_SerializeMetafile(wFormat, hClipData, sizeof(hClipData), TRUE);
843 if( hClipData && (lpClipData = GlobalLock(hClipData)) )
845 cBytes = GlobalSize(hClipData);
847 TRACE("\tUpdating property %s, %d bytes...\n",
848 TSXGetAtomName(display, rprop), cBytes);
850 xRc = TSXChangeProperty(display, requestor, rprop,
851 target, 8, PropModeReplace,
852 (unsigned char *)lpClipData, cBytes);
853 TRACE("(Rc=%d)\n", xRc);
855 GlobalUnlock(hClipData);
859 TRACE("\tCould not retrieve native format!\n");
860 rprop = None; /* Fail the request */
863 if (bemf) /* We must free serialized metafile data */
864 GlobalFree(hClipData);
870 /***********************************************************************
871 * EVENT_SelectionRequest_MULTIPLE
872 * Service a MULTIPLE selection request event
873 * rprop contains a list of (target,property) atom pairs.
874 * The first atom names a target and the second names a property.
875 * The effect is as if we have received a sequence of SelectionRequest events
876 * (one for each atom pair) except that:
877 * 1. We reply with a SelectionNotify only when all the requested conversions
878 * have been performed.
879 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
880 * we replace the atom in the property by None.
882 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
884 Display *display = pevent->display;
886 Atom atype=AnyPropertyType;
888 unsigned long remain;
889 Atom* targetPropList=NULL;
890 unsigned long cTargetPropList = 0;
891 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
893 /* If the specified property is None the requestor is an obsolete client.
894 * We support these by using the specified target atom as the reply property.
896 rprop = pevent->property;
898 rprop = pevent->target;
902 /* Read the MULTIPLE property contents. This should contain a list of
903 * (target,property) atom pairs.
905 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
906 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
907 &cTargetPropList, &remain,
908 (unsigned char**)&targetPropList) != Success)
909 TRACE("\tCouldn't read MULTIPLE property\n");
912 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
913 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
916 * Make sure we got what we expect.
917 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
918 * in a MULTIPLE selection request should be of type ATOM_PAIR.
919 * However some X apps(such as XPaint) are not compliant with this and return
920 * a user defined atom in atype when XGetWindowProperty is called.
921 * The data *is* an atom pair but is not denoted as such.
923 if(aformat == 32 /* atype == xAtomPair */ )
927 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
928 * for each (target,property) pair */
930 for (i = 0; i < cTargetPropList; i+=2)
932 char *targetName = TSXGetAtomName(display, targetPropList[i]);
933 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
934 XSelectionRequestEvent event;
936 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
937 i/2, targetName, propName);
941 /* We must have a non "None" property to service a MULTIPLE target atom */
942 if ( !targetPropList[i+1] )
944 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
948 /* Set up an XSelectionRequestEvent for this (target,property) pair */
949 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
950 event.target = targetPropList[i];
951 event.property = targetPropList[i+1];
953 /* Fire a SelectionRequest, informing the handler that we are processing
954 * a MULTIPLE selection request event.
956 EVENT_SelectionRequest( hWnd, &event, TRUE );
960 /* Free the list of targets/properties */
961 TSXFree(targetPropList);
969 /***********************************************************************
970 * EVENT_SelectionRequest
971 * Process an event selection request event.
972 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
973 * recursively while servicing a "MULTIPLE" selection target.
975 * Note: We only receive this event when WINE owns the X selection
977 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
979 Display *display = event->display;
980 XSelectionEvent result;
982 Window request = event->requestor;
983 BOOL couldOpen = FALSE;
984 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
985 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
986 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
989 * We can only handle the selection request if :
990 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
991 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
992 * since this has been already done.
996 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
997 || !(couldOpen = OpenClipboard(hWnd)) )
1001 /* If the specified property is None the requestor is an obsolete client.
1002 * We support these by using the specified target atom as the reply property.
1004 rprop = event->property;
1006 rprop = event->target;
1008 if(event->target == xaTargets) /* Return a list of all supported targets */
1010 /* TARGETS selection request */
1011 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
1013 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1015 /* MULTIPLE selection request */
1016 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1018 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1020 /* XA_STRING selection request */
1021 rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
1023 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1025 /* XA_PIXMAP selection request */
1026 rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
1028 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1030 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1031 rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
1033 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1035 /* All <WCF> selection requests */
1036 rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
1039 rprop = None; /* Don't support this format */
1042 /* close clipboard only if we opened before */
1043 if(couldOpen) CloseClipboard();
1046 TRACE("\tRequest ignored\n");
1049 * SelectionNotify should be sent only at the end of a MULTIPLE request
1053 result.type = SelectionNotify;
1054 result.display = display;
1055 result.requestor = request;
1056 result.selection = event->selection;
1057 result.property = rprop;
1058 result.target = event->target;
1059 result.time = event->time;
1060 TRACE("Sending SelectionNotify event...\n");
1061 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1065 /***********************************************************************
1066 * EVENT_SelectionClear
1068 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1070 Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
1072 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1073 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1076 /***********************************************************************
1077 * EVENT_PropertyNotify
1078 * We use this to release resources like Pixmaps when a selection
1079 * client no longer needs them.
1081 static void EVENT_PropertyNotify( XPropertyEvent *event )
1083 /* Check if we have any resources to free */
1084 TRACE("Received PropertyNotify event: \n");
1086 switch(event->state)
1088 case PropertyDelete:
1090 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1091 TSXGetAtomName(event->display, event->atom), (long)event->window);
1093 if (X11DRV_IsSelectionOwner())
1094 X11DRV_CLIPBOARD_FreeResources( event->atom );
1098 case PropertyNewValue:
1100 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1101 TSXGetAtomName(event->display, event->atom), (long)event->window);
1110 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1114 if (!IsWindowEnabled(hQueryWnd)) return 0;
1116 GetWindowRect(hQueryWnd, &tempRect);
1118 if(!PtInRect(&tempRect, *lpPt)) return 0;
1120 if (!IsIconic( hQueryWnd ))
1122 GetClientRect( hQueryWnd, &tempRect );
1123 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
1125 if (PtInRect( &tempRect, *lpPt))
1127 HWND *list = WIN_ListChildren( hQueryWnd );
1134 for (i = 0; list[i]; i++)
1136 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
1138 GetWindowRect( list[i], &tempRect );
1139 if (PtInRect( &tempRect, *lpPt )) break;
1144 if (IsWindowEnabled( list[i] ))
1145 bResult = find_drop_window( list[i], lpPt );
1147 HeapFree( GetProcessHeap(), 0, list );
1149 if(bResult) return bResult;
1153 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1155 ScreenToClient(hQueryWnd, lpPt);
1160 /**********************************************************************
1161 * EVENT_DropFromOffix
1163 * don't know if it still works (last Changlog is from 96/11/04)
1165 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1167 unsigned long data_length;
1168 unsigned long aux_long;
1169 unsigned char* p_data = NULL;
1180 Window w_aux_root, w_aux_child;
1184 pWnd = WIN_FindWndPtr(hWnd);
1186 TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1187 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1188 (unsigned int*)&aux_long);
1190 /* find out drop point and drop window */
1191 if( x < 0 || y < 0 ||
1192 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1193 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1195 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
1201 POINT pt = { x, y };
1202 HWND hwndDrop = find_drop_window( hWnd, &pt );
1215 WIN_ReleaseWndPtr(pWnd);
1217 if (!bAccept) return;
1219 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1220 dndSelection, 0, 65535, FALSE,
1221 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1222 &data_length, &aux_long, &p_data);
1224 if( !aux_long && p_data) /* don't bother if > 64K */
1226 signed char *p = (signed char*) p_data;
1230 while( *p ) /* calculate buffer size */
1233 if((u.i = *p) != -1 )
1235 INT len = GetShortPathNameA( p, NULL, 0 );
1236 if (len) aux_long += len + 1;
1241 if( aux_long && aux_long < 65535 )
1246 aux_long += sizeof(DROPFILES) + 1;
1247 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1248 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1252 WND *pDropWnd = WIN_FindWndPtr( hScope );
1253 lpDrop->pFiles = sizeof(DROPFILES);
1257 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1258 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1259 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1260 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1261 lpDrop->fWide = FALSE;
1262 WIN_ReleaseWndPtr(pDropWnd);
1263 p_drop = (char *)(lpDrop + 1);
1267 if( *p != -1 ) /* use only "good" entries */
1269 GetShortPathNameA( p, p_drop, 65535 );
1270 p_drop += strlen( p_drop ) + 1;
1275 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1279 if( p_data ) TSXFree(p_data);
1282 /**********************************************************************
1285 * drop items are separated by \n
1286 * each item is prefixed by its mime type
1288 * event->data.l[3], event->data.l[4] contains drop x,y position
1290 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1292 unsigned long data_length;
1293 unsigned long aux_long, drop_len = 0;
1294 unsigned char *p_data = NULL; /* property data */
1295 char *p_drop = NULL;
1306 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1308 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1309 dndSelection, 0, 65535, FALSE,
1310 AnyPropertyType, &u.atom_aux, &u.i,
1311 &data_length, &aux_long, &p_data);
1313 WARN("property too large, truncated!\n");
1314 TRACE("urls=%s\n", p_data);
1316 if( !aux_long && p_data) { /* don't bother if > 64K */
1317 /* calculate length */
1319 next = strchr(p, '\n');
1322 if (strncmp(p,"file:",5) == 0 ) {
1323 INT len = GetShortPathNameA( p+5, NULL, 0 );
1324 if (len) drop_len += len + 1;
1329 next = strchr(p, '\n');
1335 if( drop_len && drop_len < 65535 ) {
1336 TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1337 &x, &y, &u.i, &u.i, &u.i);
1339 drop_len += sizeof(DROPFILES) + 1;
1340 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1341 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1344 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1345 lpDrop->pFiles = sizeof(DROPFILES);
1346 lpDrop->pt.x = (INT)x;
1347 lpDrop->pt.y = (INT)y;
1349 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1350 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1351 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1352 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1353 lpDrop->fWide = FALSE;
1354 p_drop = (char*)(lpDrop + 1);
1355 WIN_ReleaseWndPtr(pDropWnd);
1358 /* create message content */
1361 next = strchr(p, '\n');
1364 if (strncmp(p,"file:",5) == 0 ) {
1365 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1367 TRACE("drop file %s as %s\n", p+5, p_drop);
1370 WARN("can't convert file %s to dos name \n", p+5);
1373 WARN("unknown mime type %s\n", p);
1378 next = strchr(p, '\n');
1385 GlobalUnlock(hDrop);
1386 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1389 if( p_data ) TSXFree(p_data);
1393 /**********************************************************************
1394 * EVENT_ClientMessage
1396 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1398 if (event->message_type != None && event->format == 32) {
1399 if (event->message_type == wmProtocols)
1400 handle_wm_protocols_message( hWnd, event );
1401 else if (event->message_type == dndProtocol)
1403 /* query window (drag&drop event contains only drag window) */
1405 int root_x, root_y, child_x, child_y;
1409 XQueryPointer( event->display, root_window, &root, &child,
1410 &root_x, &root_y, &child_x, &child_y, &u);
1411 if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1412 wine_tsx11_unlock();
1414 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1415 EVENT_DropFromOffiX(hWnd, event);
1416 else if (event->data.l[0] == DndURL)
1417 EVENT_DropURLs(hWnd, event);
1421 /* enable this if you want to see the message */
1422 unsigned char* p_data = NULL;
1428 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1429 dndSelection, 0, 65535, FALSE,
1430 AnyPropertyType, &u.atom, &u.i,
1431 &u.l, &u.l, &p_data);
1432 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1433 event->message_type, event->data.l[0], event->data.l[1],
1434 event->data.l[2], event->data.l[3], event->data.l[4],
1437 TRACE("unrecognized ClientMessage\n" );
1443 /**********************************************************************
1444 * X11DRV_EVENT_SetInputMethod
1446 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1448 INPUT_TYPE prev = current_input_type;
1450 /* Flag not used yet */
1451 in_transition = FALSE;
1452 current_input_type = type;
1457 #ifdef HAVE_LIBXXF86DGA2
1458 /**********************************************************************
1459 * X11DRV_EVENT_SetDGAStatus
1461 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1463 if (event_base < 0) {
1469 DGAMotionEventType = event_base + MotionNotify;
1470 DGAButtonPressEventType = event_base + ButtonPress;
1471 DGAButtonReleaseEventType = event_base + ButtonRelease;
1472 DGAKeyPressEventType = event_base + KeyPress;
1473 DGAKeyReleaseEventType = event_base + KeyRelease;