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"
41 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(event);
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;
60 #define DndNotDnd -1 /* OffiX drag&drop */
72 #define DndURL 128 /* KDE drag&drop */
74 static const char * const event_names[] =
76 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
77 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
78 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
79 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
80 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
81 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
82 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
83 "ClientMessage", "MappingNotify"
87 static void EVENT_ProcessEvent( XEvent *event );
90 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
91 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
92 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
93 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
94 static void EVENT_PropertyNotify( XPropertyEvent *event );
95 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
97 extern void X11DRV_ButtonPress( HWND hwnd, XButtonEvent *event );
98 extern void X11DRV_ButtonRelease( HWND hwnd, XButtonEvent *event );
99 extern void X11DRV_MotionNotify( HWND hwnd, XMotionEvent *event );
100 extern void X11DRV_EnterNotify( HWND hwnd, XCrossingEvent *event );
101 extern void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event );
102 extern void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event );
103 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
104 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
105 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
106 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
107 extern void X11DRV_MappingNotify( XMappingEvent *event );
109 #ifdef HAVE_LIBXXF86DGA2
110 static int DGAMotionEventType;
111 static int DGAButtonPressEventType;
112 static int DGAButtonReleaseEventType;
113 static int DGAKeyPressEventType;
114 static int DGAKeyReleaseEventType;
116 static BOOL DGAUsed = FALSE;
117 static HWND DGAhwnd = 0;
119 extern void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event );
120 extern void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event );
121 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event );
124 /* Static used for the current input method */
125 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
126 static BOOL in_transition = FALSE; /* This is not used as for today */
129 /***********************************************************************
132 static int process_events( struct x11drv_thread_data *data )
138 while ( XPending( data->display ) )
140 XNextEvent( data->display, &event );
142 EVENT_ProcessEvent( &event );
151 /***********************************************************************
152 * MsgWaitForMultipleObjectsEx (X11DRV.@)
154 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
155 DWORD timeout, DWORD mask, DWORD flags )
157 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
159 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
161 if (!data || data->process_event_count)
162 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
163 timeout, flags & MWMO_ALERTABLE );
165 for (i = 0; i < count; i++) new_handles[i] = handles[i];
166 new_handles[count] = data->display_fd;
169 XFlush( gdi_display );
170 XFlush( data->display );
173 data->process_event_count++;
174 if (process_events( data )) ret = count;
177 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
178 timeout, flags & MWMO_ALERTABLE );
179 if (ret == count) process_events( data );
181 data->process_event_count--;
186 /***********************************************************************
189 * Process an X event.
191 static void EVENT_ProcessEvent( XEvent *event )
194 Display *display = event->xany.display;
196 TRACE( "called.\n" );
200 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
201 FIXME("Got SelectionNotify - must not happen!\n");
204 /* We get all these because of StructureNotifyMask.
205 This check is placed here to avoid getting error messages below,
206 as X might send some of these even for windows that have already
208 case CirculateNotify:
216 #ifdef HAVE_LIBXXF86DGA2
218 if (event->type == DGAMotionEventType) {
219 TRACE("DGAMotionEvent received.\n");
220 X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
223 if (event->type == DGAButtonPressEventType) {
224 TRACE("DGAButtonPressEvent received.\n");
225 X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
228 if (event->type == DGAButtonReleaseEventType) {
229 TRACE("DGAButtonReleaseEvent received.\n");
230 X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
233 if ((event->type == DGAKeyPressEventType) ||
234 (event->type == DGAKeyReleaseEventType)) {
235 /* Fill a XKeyEvent to send to EVENT_Key */
237 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
239 TRACE("DGAKeyPress/ReleaseEvent received.\n");
241 if (evt->type == DGAKeyReleaseEventType)
242 ke.type = KeyRelease;
245 ke.serial = evt->serial;
246 ke.send_event = FALSE;
247 ke.display = evt->display;
256 ke.state = evt->state;
257 ke.keycode = evt->keycode;
258 ke.same_screen = TRUE;
259 X11DRV_KeyEvent( 0, &ke );
266 if (XFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
267 hWnd = 0; /* Not for a registered window */
270 if ( !hWnd && event->xany.window != root_window
271 && event->type != PropertyNotify
272 && event->type != MappingNotify)
273 WARN( "Got event %s for unknown Window %08lx\n",
274 event_names[event->type], event->xany.window );
276 TRACE("Got event %s for hwnd %04x\n",
277 event_names[event->type], hWnd );
283 /* FIXME: should generate a motion event if event point is different from current pos */
284 X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
288 X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
292 X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
296 X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
300 X11DRV_EnterNotify( hWnd, (XCrossingEvent*)event );
304 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
308 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
312 X11DRV_Expose( hWnd, &event->xexpose );
315 case ConfigureNotify:
317 X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
320 case SelectionRequest:
322 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
327 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
331 EVENT_PropertyNotify( (XPropertyEvent *)event );
336 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
343 X11DRV_MapNotify( hWnd, (XMapEvent *)event );
347 X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
351 X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
355 X11DRV_MappingNotify( (XMappingEvent *) event );
359 WARN("Unprocessed event %s for hwnd %04x\n",
360 event_names[event->type], hWnd );
363 TRACE( "returns.\n" );
367 /*******************************************************************
368 * can_activate_window
370 * Check if we can activate the specified window.
372 inline static BOOL can_activate_window( HWND hwnd )
374 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
375 if (!(style & WS_VISIBLE)) return FALSE;
376 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
377 return !(style & WS_DISABLED);
381 /**********************************************************************
382 * set_focus_error_handler
384 * Handler for X errors happening during XSetInputFocus call.
386 static int set_focus_error_handler( Display *display, XErrorEvent *event, void *arg )
388 return (event->error_code == BadMatch);
392 /**********************************************************************
395 static void set_focus( HWND hwnd, Time time )
400 TRACE( "setting foreground window to %x\n", hwnd );
401 SetForegroundWindow( hwnd );
404 win = X11DRV_get_whole_window(focus);
408 Display *display = thread_display();
409 TRACE( "setting focus to %x (%lx) time=%ld\n", focus, win, time );
410 X11DRV_expect_error( display, set_focus_error_handler, NULL );
411 XSetInputFocus( display, win, RevertToParent, time );
412 if (X11DRV_check_error()) TRACE("got BadMatch, ignoring\n" );
417 /**********************************************************************
418 * handle_wm_protocols_message
420 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
422 Atom protocol = (Atom)event->data.l[0];
424 if (!protocol) return;
426 if (protocol == wmDeleteWindow)
428 /* Ignore the delete window request if the window has been disabled
429 * and we are in managed mode. This is to disallow applications from
430 * being closed by the window manager while in a modal state.
432 if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
434 else if (protocol == wmTakeFocus)
436 Time event_time = (Time)event->data.l[1];
437 HWND last_focus = x11drv_thread_data()->last_focus;
439 TRACE( "got take focus msg for %x, enabled=%d, focus=%x, active=%x, fg=%x, last=%x\n",
440 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
441 GetForegroundWindow(), last_focus );
443 if (can_activate_window(hwnd))
445 /* simulate a mouse click on the caption to find out
446 * whether the window wants to be activated */
447 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
448 GetAncestor( hwnd, GA_ROOT ),
449 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
450 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
451 else TRACE( "not setting focus to %x (%lx), ma=%ld\n", hwnd, event->window, ma );
456 if (!hwnd) hwnd = GetActiveWindow();
457 if (!hwnd) hwnd = last_focus;
458 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
464 static const char * const focus_details[] =
470 "NotifyNonlinearVirtual",
476 /**********************************************************************
479 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
483 TRACE( "win %x xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
485 if (wmTakeFocus) return; /* ignore FocusIn if we are using take focus */
486 if (event->detail == NotifyPointer) return;
488 if (!can_activate_window(hwnd))
490 HWND hwnd = GetFocus();
491 if (!hwnd) hwnd = GetActiveWindow();
492 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
493 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
495 else SetForegroundWindow( hwnd );
499 /**********************************************************************
502 * Note: only top-level windows get FocusOut events.
504 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
510 TRACE( "win %x xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
512 if (event->detail == NotifyPointer) return;
513 x11drv_thread_data()->last_focus = hwnd;
514 if (hwnd != GetForegroundWindow()) return;
515 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
517 /* don't reset the foreground window, if the window which is
518 getting the focus is a Wine window */
521 XGetInputFocus( thread_display(), &focus_win, &revert );
524 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
531 /* Abey : 6-Oct-99. Check again if the focus out window is the
532 Foreground window, because in most cases the messages sent
533 above must have already changed the foreground window, in which
534 case we don't have to change the foreground window to 0 */
535 if (hwnd == GetForegroundWindow())
537 TRACE( "lost focus, setting fg to 0\n" );
538 SetForegroundWindow( 0 );
544 /***********************************************************************
545 * EVENT_SelectionRequest_TARGETS
546 * Service a TARGETS selection request event
548 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
549 Atom target, Atom rprop )
551 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
555 unsigned long cTargets;
559 TRACE("Request for %s\n", TSXGetAtomName(display, target));
562 * Count the number of items we wish to expose as selection targets.
563 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
565 cTargets = CountClipboardFormats() + 1;
566 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
569 /* Allocate temp buffer */
570 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
571 if(targets == NULL) return None;
573 /* Create TARGETS property list (First item in list is TARGETS itself) */
575 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
576 (wFormat = EnumClipboardFormats( wFormat )); )
578 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
580 /* Scan through what we have so far to avoid duplicates */
583 for (i = 0, bExists = FALSE; i < cTargets; i++)
585 if (targets[i] == prop)
593 targets[cTargets++] = prop;
595 /* Add PIXMAP prop for bitmaps additionally */
596 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
599 targets[cTargets++] = XA_PIXMAP;
609 for ( i = 0; i < cTargets; i++)
613 char *itemFmtName = TSXGetAtomName(display, targets[i]);
614 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
615 TSXFree(itemFmtName);
620 /* Update the X property */
621 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
623 /* We may want to consider setting the type to xaTargets instead,
624 * in case some apps expect this instead of XA_ATOM */
625 xRc = TSXChangeProperty(display, requestor, rprop,
626 XA_ATOM, 32, PropModeReplace,
627 (unsigned char *)targets, cTargets);
628 TRACE("(Rc=%d)\n", xRc);
630 HeapFree( GetProcessHeap(), 0, targets );
636 /***********************************************************************
637 * EVENT_SelectionRequest_STRING
638 * Service a STRING selection request event
640 static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
641 Atom target, Atom rprop )
643 static UINT text_cp = (UINT)-1;
652 if(text_cp == (UINT)-1)
657 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
660 DWORD type, count = sizeof(buf);
661 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
668 * Map the requested X selection property type atom name to a
669 * windows clipboard format ID.
671 itemFmtName = TSXGetAtomName(display, target);
672 TRACE("Request for %s (wFormat=%x %s)\n",
673 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT, NULL, 0));
674 TSXFree(itemFmtName);
676 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
679 uni_text = GlobalLock(hUnicodeText);
683 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
684 text = HeapAlloc(GetProcessHeap(), 0, size);
687 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
689 /* remove carriage returns */
691 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
692 if(lpstr == NULL) return None;
693 for(i=0,j=0; i < size && text[i]; i++ )
695 if( text[i] == '\r' &&
696 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
697 lpstr[j++] = text[i];
701 /* Update the X property */
702 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
703 xRc = TSXChangeProperty(display, requestor, rprop,
704 XA_STRING, 8, PropModeReplace,
706 TRACE("(Rc=%d)\n", xRc);
708 GlobalUnlock(hUnicodeText);
709 HeapFree(GetProcessHeap(), 0, text);
710 HeapFree( GetProcessHeap(), 0, lpstr );
715 /***********************************************************************
716 * EVENT_SelectionRequest_PIXMAP
717 * Service a PIXMAP selection request event
719 static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
720 Atom target, Atom rprop )
722 HANDLE hClipData = 0;
728 XSetWindowAttributes win_attr;
729 XWindowAttributes win_attr_src;
733 * Map the requested X selection property type atom name to a
734 * windows clipboard format ID.
736 itemFmtName = TSXGetAtomName(display, target);
737 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
738 TRACE("Request for %s (wFormat=%x %s)\n",
739 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0 ));
740 TSXFree(itemFmtName);
742 hClipData = GetClipboardData(wFormat);
745 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
746 rprop = None; /* Fail the request */
750 if (wFormat == CF_DIB)
752 HWND hwnd = GetOpenClipboardWindow();
753 HDC hdc = GetDC(hwnd);
755 /* For convert from packed DIB to Pixmap */
756 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
758 ReleaseDC(hwnd, hdc);
760 else if (wFormat == CF_BITMAP)
762 HWND hwnd = GetOpenClipboardWindow();
763 HDC hdc = GetDC(hwnd);
765 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
767 ReleaseDC(hwnd, hdc);
771 FIXME("%s to PIXMAP conversion not yet implemented!\n",
772 CLIPBOARD_GetFormatName(wFormat, NULL, 0));
777 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
778 TSXGetAtomName(display, rprop), (long)requestor,
779 TSXGetAtomName(display, target), pixmap);
781 /* Store the Pixmap handle in the property */
782 xRc = TSXChangeProperty(display, requestor, rprop, target,
784 (unsigned char *)&pixmap, 1);
785 TRACE("(Rc=%d)\n", xRc);
787 /* Enable the code below if you want to handle destroying Pixmap resources
788 * in response to property notify events. Clients like XPaint don't
789 * appear to be duplicating Pixmaps so they don't like us deleting,
790 * the resource in response to the property being deleted.
793 /* Express interest in property notify events so that we can delete the
794 * pixmap when the client deletes the property atom.
796 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
797 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
799 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
800 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
802 /* Register the Pixmap we created with the request property Atom.
803 * When this property is destroyed we also destroy the Pixmap in
804 * response to the PropertyNotify event.
806 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
814 /***********************************************************************
815 * EVENT_SelectionRequest_WCF
816 * Service a Wine Clipboard Format selection request event.
817 * For <WCF>* data types we simply copy the data to X without conversion.
819 static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
820 Atom target, Atom rprop )
822 HANDLE hClipData = 0;
831 * Map the requested X selection property type atom name to a
832 * windows clipboard format ID.
834 itemFmtName = TSXGetAtomName(display, target);
835 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
836 TRACE("Request for %s (wFormat=%x %s)\n",
837 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0));
838 TSXFree(itemFmtName);
840 hClipData = GetClipboardData(wFormat);
842 bemf = wFormat == CF_METAFILEPICT || wFormat == CF_ENHMETAFILE;
844 hClipData = X11DRV_CLIPBOARD_SerializeMetafile(wFormat, hClipData, sizeof(hClipData), TRUE);
846 if( hClipData && (lpClipData = GlobalLock(hClipData)) )
848 cBytes = GlobalSize(hClipData);
850 TRACE("\tUpdating property %s, %d bytes...\n",
851 TSXGetAtomName(display, rprop), cBytes);
853 xRc = TSXChangeProperty(display, requestor, rprop,
854 target, 8, PropModeReplace,
855 (unsigned char *)lpClipData, cBytes);
856 TRACE("(Rc=%d)\n", xRc);
858 GlobalUnlock(hClipData);
862 TRACE("\tCould not retrieve native format!\n");
863 rprop = None; /* Fail the request */
866 if (bemf) /* We must free serialized metafile data */
867 GlobalFree(hClipData);
873 /***********************************************************************
874 * EVENT_SelectionRequest_MULTIPLE
875 * Service a MULTIPLE selection request event
876 * rprop contains a list of (target,property) atom pairs.
877 * The first atom names a target and the second names a property.
878 * The effect is as if we have received a sequence of SelectionRequest events
879 * (one for each atom pair) except that:
880 * 1. We reply with a SelectionNotify only when all the requested conversions
881 * have been performed.
882 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
883 * we replace the atom in the property by None.
885 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
887 Display *display = pevent->display;
889 Atom atype=AnyPropertyType;
891 unsigned long remain;
892 Atom* targetPropList=NULL;
893 unsigned long cTargetPropList = 0;
894 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
896 /* If the specified property is None the requestor is an obsolete client.
897 * We support these by using the specified target atom as the reply property.
899 rprop = pevent->property;
901 rprop = pevent->target;
905 /* Read the MULTIPLE property contents. This should contain a list of
906 * (target,property) atom pairs.
908 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
909 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
910 &cTargetPropList, &remain,
911 (unsigned char**)&targetPropList) != Success)
912 TRACE("\tCouldn't read MULTIPLE property\n");
915 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
916 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
919 * Make sure we got what we expect.
920 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
921 * in a MULTIPLE selection request should be of type ATOM_PAIR.
922 * However some X apps(such as XPaint) are not compliant with this and return
923 * a user defined atom in atype when XGetWindowProperty is called.
924 * The data *is* an atom pair but is not denoted as such.
926 if(aformat == 32 /* atype == xAtomPair */ )
930 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
931 * for each (target,property) pair */
933 for (i = 0; i < cTargetPropList; i+=2)
935 char *targetName = TSXGetAtomName(display, targetPropList[i]);
936 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
937 XSelectionRequestEvent event;
939 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
940 i/2, targetName, propName);
944 /* We must have a non "None" property to service a MULTIPLE target atom */
945 if ( !targetPropList[i+1] )
947 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
951 /* Set up an XSelectionRequestEvent for this (target,property) pair */
952 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
953 event.target = targetPropList[i];
954 event.property = targetPropList[i+1];
956 /* Fire a SelectionRequest, informing the handler that we are processing
957 * a MULTIPLE selection request event.
959 EVENT_SelectionRequest( hWnd, &event, TRUE );
963 /* Free the list of targets/properties */
964 TSXFree(targetPropList);
972 /***********************************************************************
973 * EVENT_SelectionRequest
974 * Process an event selection request event.
975 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
976 * recursively while servicing a "MULTIPLE" selection target.
978 * Note: We only receive this event when WINE owns the X selection
980 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
982 Display *display = event->display;
983 XSelectionEvent result;
985 Window request = event->requestor;
986 BOOL couldOpen = FALSE;
987 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
988 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
989 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
992 * We can only handle the selection request if :
993 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
994 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
995 * since this has been already done.
999 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1000 || !(couldOpen = OpenClipboard(hWnd)) )
1004 /* If the specified property is None the requestor is an obsolete client.
1005 * We support these by using the specified target atom as the reply property.
1007 rprop = event->property;
1009 rprop = event->target;
1011 if(event->target == xaTargets) /* Return a list of all supported targets */
1013 /* TARGETS selection request */
1014 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
1016 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1018 /* MULTIPLE selection request */
1019 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1021 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1023 /* XA_STRING selection request */
1024 rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
1026 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1028 /* XA_PIXMAP selection request */
1029 rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
1031 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1033 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1034 rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
1036 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1038 /* All <WCF> selection requests */
1039 rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
1042 rprop = None; /* Don't support this format */
1045 /* close clipboard only if we opened before */
1046 if(couldOpen) CloseClipboard();
1049 TRACE("\tRequest ignored\n");
1052 * SelectionNotify should be sent only at the end of a MULTIPLE request
1056 result.type = SelectionNotify;
1057 result.display = display;
1058 result.requestor = request;
1059 result.selection = event->selection;
1060 result.property = rprop;
1061 result.target = event->target;
1062 result.time = event->time;
1063 TRACE("Sending SelectionNotify event...\n");
1064 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1068 /***********************************************************************
1069 * EVENT_SelectionClear
1071 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1073 Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
1075 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1076 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1079 /***********************************************************************
1080 * EVENT_PropertyNotify
1081 * We use this to release resources like Pixmaps when a selection
1082 * client no longer needs them.
1084 static void EVENT_PropertyNotify( XPropertyEvent *event )
1086 /* Check if we have any resources to free */
1087 TRACE("Received PropertyNotify event: \n");
1089 switch(event->state)
1091 case PropertyDelete:
1093 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1094 TSXGetAtomName(event->display, event->atom), (long)event->window);
1096 if (X11DRV_IsSelectionOwner())
1097 X11DRV_CLIPBOARD_FreeResources( event->atom );
1101 case PropertyNewValue:
1103 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1104 TSXGetAtomName(event->display, event->atom), (long)event->window);
1113 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1117 if (!IsWindowEnabled(hQueryWnd)) return 0;
1119 GetWindowRect(hQueryWnd, &tempRect);
1121 if(!PtInRect(&tempRect, *lpPt)) return 0;
1123 if (!IsIconic( hQueryWnd ))
1125 GetClientRect( hQueryWnd, &tempRect );
1126 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
1128 if (PtInRect( &tempRect, *lpPt))
1130 HWND *list = WIN_ListChildren( hQueryWnd );
1137 for (i = 0; list[i]; i++)
1139 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
1141 GetWindowRect( list[i], &tempRect );
1142 if (PtInRect( &tempRect, *lpPt )) break;
1147 if (IsWindowEnabled( list[i] ))
1148 bResult = find_drop_window( list[i], lpPt );
1150 HeapFree( GetProcessHeap(), 0, list );
1152 if(bResult) return bResult;
1156 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1158 ScreenToClient(hQueryWnd, lpPt);
1163 /**********************************************************************
1164 * EVENT_DropFromOffix
1166 * don't know if it still works (last Changlog is from 96/11/04)
1168 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1170 unsigned long data_length;
1171 unsigned long aux_long;
1172 unsigned char* p_data = NULL;
1183 Window w_aux_root, w_aux_child;
1187 pWnd = WIN_FindWndPtr(hWnd);
1189 TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1190 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1191 (unsigned int*)&aux_long);
1193 /* find out drop point and drop window */
1194 if( x < 0 || y < 0 ||
1195 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1196 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1198 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
1204 POINT pt = { x, y };
1205 HWND hwndDrop = find_drop_window( hWnd, &pt );
1218 WIN_ReleaseWndPtr(pWnd);
1220 if (!bAccept) return;
1222 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1223 dndSelection, 0, 65535, FALSE,
1224 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1225 &data_length, &aux_long, &p_data);
1227 if( !aux_long && p_data) /* don't bother if > 64K */
1229 signed char *p = (signed char*) p_data;
1233 while( *p ) /* calculate buffer size */
1236 if((u.i = *p) != -1 )
1238 INT len = GetShortPathNameA( p, NULL, 0 );
1239 if (len) aux_long += len + 1;
1244 if( aux_long && aux_long < 65535 )
1249 aux_long += sizeof(DROPFILES) + 1;
1250 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1251 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1255 WND *pDropWnd = WIN_FindWndPtr( hScope );
1256 lpDrop->pFiles = sizeof(DROPFILES);
1260 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1261 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1262 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1263 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1264 lpDrop->fWide = FALSE;
1265 WIN_ReleaseWndPtr(pDropWnd);
1266 p_drop = (char *)(lpDrop + 1);
1270 if( *p != -1 ) /* use only "good" entries */
1272 GetShortPathNameA( p, p_drop, 65535 );
1273 p_drop += strlen( p_drop ) + 1;
1278 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1282 if( p_data ) TSXFree(p_data);
1285 /**********************************************************************
1288 * drop items are separated by \n
1289 * each item is prefixed by its mime type
1291 * event->data.l[3], event->data.l[4] contains drop x,y position
1293 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1295 unsigned long data_length;
1296 unsigned long aux_long, drop_len = 0;
1297 unsigned char *p_data = NULL; /* property data */
1298 char *p_drop = NULL;
1309 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1311 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1312 dndSelection, 0, 65535, FALSE,
1313 AnyPropertyType, &u.atom_aux, &u.i,
1314 &data_length, &aux_long, &p_data);
1316 WARN("property too large, truncated!\n");
1317 TRACE("urls=%s\n", p_data);
1319 if( !aux_long && p_data) { /* don't bother if > 64K */
1320 /* calculate length */
1322 next = strchr(p, '\n');
1325 if (strncmp(p,"file:",5) == 0 ) {
1326 INT len = GetShortPathNameA( p+5, NULL, 0 );
1327 if (len) drop_len += len + 1;
1332 next = strchr(p, '\n');
1338 if( drop_len && drop_len < 65535 ) {
1339 TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1340 &x, &y, &u.i, &u.i, &u.i);
1342 drop_len += sizeof(DROPFILES) + 1;
1343 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1344 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1347 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1348 lpDrop->pFiles = sizeof(DROPFILES);
1349 lpDrop->pt.x = (INT)x;
1350 lpDrop->pt.y = (INT)y;
1352 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1353 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1354 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1355 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1356 lpDrop->fWide = FALSE;
1357 p_drop = (char*)(lpDrop + 1);
1358 WIN_ReleaseWndPtr(pDropWnd);
1361 /* create message content */
1364 next = strchr(p, '\n');
1367 if (strncmp(p,"file:",5) == 0 ) {
1368 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1370 TRACE("drop file %s as %s\n", p+5, p_drop);
1373 WARN("can't convert file %s to dos name \n", p+5);
1376 WARN("unknown mime type %s\n", p);
1381 next = strchr(p, '\n');
1388 GlobalUnlock(hDrop);
1389 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1392 if( p_data ) TSXFree(p_data);
1396 /**********************************************************************
1397 * EVENT_ClientMessage
1399 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1401 if (event->message_type != None && event->format == 32) {
1402 if (event->message_type == wmProtocols)
1403 handle_wm_protocols_message( hWnd, event );
1404 else if (event->message_type == dndProtocol)
1406 /* query window (drag&drop event contains only drag window) */
1408 int root_x, root_y, child_x, child_y;
1412 XQueryPointer( event->display, root_window, &root, &child,
1413 &root_x, &root_y, &child_x, &child_y, &u);
1414 if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1415 wine_tsx11_unlock();
1417 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1418 EVENT_DropFromOffiX(hWnd, event);
1419 else if (event->data.l[0] == DndURL)
1420 EVENT_DropURLs(hWnd, event);
1424 /* enable this if you want to see the message */
1425 unsigned char* p_data = NULL;
1431 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1432 dndSelection, 0, 65535, FALSE,
1433 AnyPropertyType, &u.atom, &u.i,
1434 &u.l, &u.l, &p_data);
1435 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1436 event->message_type, event->data.l[0], event->data.l[1],
1437 event->data.l[2], event->data.l[3], event->data.l[4],
1440 TRACE("unrecognized ClientMessage\n" );
1446 /**********************************************************************
1447 * X11DRV_EVENT_SetInputMethod
1449 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1451 INPUT_TYPE prev = current_input_type;
1453 /* Flag not used yet */
1454 in_transition = FALSE;
1455 current_input_type = type;
1460 #ifdef HAVE_LIBXXF86DGA2
1461 /**********************************************************************
1462 * X11DRV_EVENT_SetDGAStatus
1464 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1466 if (event_base < 0) {
1472 DGAMotionEventType = event_base + MotionNotify;
1473 DGAButtonPressEventType = event_base + ButtonPress;
1474 DGAButtonReleaseEventType = event_base + ButtonRelease;
1475 DGAKeyPressEventType = event_base + KeyPress;
1476 DGAKeyReleaseEventType = event_base + KeyRelease;