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 * set_focus_error_handler
370 * Handler for X errors happening during XSetInputFocus call.
372 static int set_focus_error_handler( Display *display, XErrorEvent *event, void *arg )
374 return (event->error_code == BadValue);
378 /**********************************************************************
381 static void set_focus( HWND hwnd, Time time )
383 HWND focus = GetFocus();
386 if (hwnd != focus && !IsChild( hwnd, focus ))
388 TRACE( "changing window focus to %x\n", hwnd );
392 /* focus window might be changed by the above SetFocus() call */
394 win = X11DRV_get_whole_window(focus);
398 Display *display = thread_display();
399 TRACE( "setting focus to %x (%lx) time=%ld\n", focus, win, time );
400 X11DRV_expect_error( display, set_focus_error_handler, NULL );
401 XSetInputFocus( display, win, RevertToParent, time );
402 if (X11DRV_check_error()) ERR("got BadMatch, ignoring\n" );
407 /**********************************************************************
408 * handle_wm_protocols_message
410 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
412 Atom protocol = (Atom)event->data.l[0];
414 if (!protocol) return;
416 if (protocol == wmDeleteWindow)
418 /* Ignore the delete window request if the window has been disabled
419 * and we are in managed mode. This is to disallow applications from
420 * being closed by the window manager while in a modal state.
422 if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
424 else if (protocol == wmTakeFocus)
426 Time event_time = (Time)event->data.l[1];
427 HWND last_focus = x11drv_thread_data()->last_focus;
429 TRACE( "got take focus msg for %x, enabled=%d, focus=%x, active=%x, fg=%x, last=%x\n",
430 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
431 GetForegroundWindow(), last_focus );
433 if (IsWindowEnabled(hwnd))
435 /* simulate a mouse click on the caption to find out
436 * whether the window wants to be activated */
437 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
438 GetAncestor( hwnd, GA_ROOT ),
439 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
440 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
441 else TRACE( "not setting focus to %x (%lx), ma=%ld\n", hwnd, event->window, ma );
446 if (!hwnd) hwnd = GetActiveWindow();
447 if (!hwnd) hwnd = last_focus;
448 if (hwnd && IsWindowEnabled(hwnd)) set_focus( hwnd, event_time );
454 static const char * const focus_details[] =
460 "NotifyNonlinearVirtual",
466 /**********************************************************************
469 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
473 TRACE( "win %x xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
475 if (wmTakeFocus) return; /* ignore FocusIn if we are using take focus */
476 if (event->detail == NotifyPointer) return;
478 if (!IsWindowEnabled(hwnd))
480 HWND hwnd = GetFocus();
481 if (!hwnd) hwnd = GetActiveWindow();
482 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
483 if (hwnd && IsWindowEnabled(hwnd)) set_focus( hwnd, CurrentTime );
485 else if (hwnd != GetForegroundWindow())
487 SetForegroundWindow( hwnd );
492 /**********************************************************************
495 * Note: only top-level windows get FocusOut events.
497 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
503 TRACE( "win %x xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
505 if (event->detail == NotifyPointer) return;
506 if (hwnd != GetForegroundWindow()) return;
507 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
509 /* don't reset the foreground window, if the window which is
510 getting the focus is a Wine window */
513 XGetInputFocus( thread_display(), &focus_win, &revert );
516 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
523 /* Abey : 6-Oct-99. Check again if the focus out window is the
524 Foreground window, because in most cases the messages sent
525 above must have already changed the foreground window, in which
526 case we don't have to change the foreground window to 0 */
527 if (hwnd == GetForegroundWindow())
529 TRACE( "lost focus, setting fg to 0\n" );
530 x11drv_thread_data()->last_focus = hwnd;
531 SetForegroundWindow( 0 );
537 /***********************************************************************
538 * EVENT_SelectionRequest_TARGETS
539 * Service a TARGETS selection request event
541 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
542 Atom target, Atom rprop )
544 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
548 unsigned long cTargets;
552 TRACE("Request for %s\n", TSXGetAtomName(display, target));
555 * Count the number of items we wish to expose as selection targets.
556 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
558 cTargets = CountClipboardFormats() + 1;
559 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
562 /* Allocate temp buffer */
563 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
564 if(targets == NULL) return None;
566 /* Create TARGETS property list (First item in list is TARGETS itself) */
568 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
569 (wFormat = EnumClipboardFormats( wFormat )); )
571 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
573 /* Scan through what we have so far to avoid duplicates */
576 for (i = 0, bExists = FALSE; i < cTargets; i++)
578 if (targets[i] == prop)
586 targets[cTargets++] = prop;
588 /* Add PIXMAP prop for bitmaps additionally */
589 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
592 targets[cTargets++] = XA_PIXMAP;
602 for ( i = 0; i < cTargets; i++)
606 char *itemFmtName = TSXGetAtomName(display, targets[i]);
607 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
608 TSXFree(itemFmtName);
613 /* Update the X property */
614 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
616 /* We may want to consider setting the type to xaTargets instead,
617 * in case some apps expect this instead of XA_ATOM */
618 xRc = TSXChangeProperty(display, requestor, rprop,
619 XA_ATOM, 32, PropModeReplace,
620 (unsigned char *)targets, cTargets);
621 TRACE("(Rc=%d)\n", xRc);
623 HeapFree( GetProcessHeap(), 0, targets );
629 /***********************************************************************
630 * EVENT_SelectionRequest_STRING
631 * Service a STRING selection request event
633 static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
634 Atom target, Atom rprop )
636 static UINT text_cp = (UINT)-1;
645 if(text_cp == (UINT)-1)
650 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
653 DWORD type, count = sizeof(buf);
654 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
661 * Map the requested X selection property type atom name to a
662 * windows clipboard format ID.
664 itemFmtName = TSXGetAtomName(display, target);
665 TRACE("Request for %s (wFormat=%x %s)\n",
666 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT, NULL, 0));
667 TSXFree(itemFmtName);
669 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
672 uni_text = GlobalLock(hUnicodeText);
676 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
677 text = HeapAlloc(GetProcessHeap(), 0, size);
680 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
682 /* remove carriage returns */
684 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
685 if(lpstr == NULL) return None;
686 for(i=0,j=0; i < size && text[i]; i++ )
688 if( text[i] == '\r' &&
689 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
690 lpstr[j++] = text[i];
694 /* Update the X property */
695 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
696 xRc = TSXChangeProperty(display, requestor, rprop,
697 XA_STRING, 8, PropModeReplace,
699 TRACE("(Rc=%d)\n", xRc);
701 GlobalUnlock(hUnicodeText);
702 HeapFree(GetProcessHeap(), 0, text);
703 HeapFree( GetProcessHeap(), 0, lpstr );
708 /***********************************************************************
709 * EVENT_SelectionRequest_PIXMAP
710 * Service a PIXMAP selection request event
712 static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
713 Atom target, Atom rprop )
715 HANDLE hClipData = 0;
721 XSetWindowAttributes win_attr;
722 XWindowAttributes win_attr_src;
726 * Map the requested X selection property type atom name to a
727 * windows clipboard format ID.
729 itemFmtName = TSXGetAtomName(display, target);
730 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
731 TRACE("Request for %s (wFormat=%x %s)\n",
732 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0 ));
733 TSXFree(itemFmtName);
735 hClipData = GetClipboardData(wFormat);
738 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
739 rprop = None; /* Fail the request */
743 if (wFormat == CF_DIB)
745 HWND hwnd = GetOpenClipboardWindow();
746 HDC hdc = GetDC(hwnd);
748 /* For convert from packed DIB to Pixmap */
749 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
751 ReleaseDC(hwnd, hdc);
753 else if (wFormat == CF_BITMAP)
755 HWND hwnd = GetOpenClipboardWindow();
756 HDC hdc = GetDC(hwnd);
758 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
760 ReleaseDC(hwnd, hdc);
764 FIXME("%s to PIXMAP conversion not yet implemented!\n",
765 CLIPBOARD_GetFormatName(wFormat, NULL, 0));
770 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
771 TSXGetAtomName(display, rprop), (long)requestor,
772 TSXGetAtomName(display, target), pixmap);
774 /* Store the Pixmap handle in the property */
775 xRc = TSXChangeProperty(display, requestor, rprop, target,
777 (unsigned char *)&pixmap, 1);
778 TRACE("(Rc=%d)\n", xRc);
780 /* Enable the code below if you want to handle destroying Pixmap resources
781 * in response to property notify events. Clients like XPaint don't
782 * appear to be duplicating Pixmaps so they don't like us deleting,
783 * the resource in response to the property being deleted.
786 /* Express interest in property notify events so that we can delete the
787 * pixmap when the client deletes the property atom.
789 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
790 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
792 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
793 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
795 /* Register the Pixmap we created with the request property Atom.
796 * When this property is destroyed we also destroy the Pixmap in
797 * response to the PropertyNotify event.
799 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
807 /***********************************************************************
808 * EVENT_SelectionRequest_WCF
809 * Service a Wine Clipboard Format selection request event.
810 * For <WCF>* data types we simply copy the data to X without conversion.
812 static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
813 Atom target, Atom rprop )
815 HANDLE hClipData = 0;
824 * Map the requested X selection property type atom name to a
825 * windows clipboard format ID.
827 itemFmtName = TSXGetAtomName(display, target);
828 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
829 TRACE("Request for %s (wFormat=%x %s)\n",
830 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0));
831 TSXFree(itemFmtName);
833 hClipData = GetClipboardData(wFormat);
835 bemf = wFormat == CF_METAFILEPICT || wFormat == CF_ENHMETAFILE;
837 hClipData = X11DRV_CLIPBOARD_SerializeMetafile(wFormat, hClipData, sizeof(hClipData), TRUE);
839 if( hClipData && (lpClipData = GlobalLock(hClipData)) )
841 cBytes = GlobalSize(hClipData);
843 TRACE("\tUpdating property %s, %d bytes...\n",
844 TSXGetAtomName(display, rprop), cBytes);
846 xRc = TSXChangeProperty(display, requestor, rprop,
847 target, 8, PropModeReplace,
848 (unsigned char *)lpClipData, cBytes);
849 TRACE("(Rc=%d)\n", xRc);
851 GlobalUnlock(hClipData);
855 TRACE("\tCould not retrieve native format!\n");
856 rprop = None; /* Fail the request */
859 if (bemf) /* We must free serialized metafile data */
860 GlobalFree(hClipData);
866 /***********************************************************************
867 * EVENT_SelectionRequest_MULTIPLE
868 * Service a MULTIPLE selection request event
869 * rprop contains a list of (target,property) atom pairs.
870 * The first atom names a target and the second names a property.
871 * The effect is as if we have received a sequence of SelectionRequest events
872 * (one for each atom pair) except that:
873 * 1. We reply with a SelectionNotify only when all the requested conversions
874 * have been performed.
875 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
876 * we replace the atom in the property by None.
878 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
880 Display *display = pevent->display;
882 Atom atype=AnyPropertyType;
884 unsigned long remain;
885 Atom* targetPropList=NULL;
886 unsigned long cTargetPropList = 0;
887 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
889 /* If the specified property is None the requestor is an obsolete client.
890 * We support these by using the specified target atom as the reply property.
892 rprop = pevent->property;
894 rprop = pevent->target;
898 /* Read the MULTIPLE property contents. This should contain a list of
899 * (target,property) atom pairs.
901 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
902 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
903 &cTargetPropList, &remain,
904 (unsigned char**)&targetPropList) != Success)
905 TRACE("\tCouldn't read MULTIPLE property\n");
908 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
909 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
912 * Make sure we got what we expect.
913 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
914 * in a MULTIPLE selection request should be of type ATOM_PAIR.
915 * However some X apps(such as XPaint) are not compliant with this and return
916 * a user defined atom in atype when XGetWindowProperty is called.
917 * The data *is* an atom pair but is not denoted as such.
919 if(aformat == 32 /* atype == xAtomPair */ )
923 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
924 * for each (target,property) pair */
926 for (i = 0; i < cTargetPropList; i+=2)
928 char *targetName = TSXGetAtomName(display, targetPropList[i]);
929 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
930 XSelectionRequestEvent event;
932 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
933 i/2, targetName, propName);
937 /* We must have a non "None" property to service a MULTIPLE target atom */
938 if ( !targetPropList[i+1] )
940 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
944 /* Set up an XSelectionRequestEvent for this (target,property) pair */
945 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
946 event.target = targetPropList[i];
947 event.property = targetPropList[i+1];
949 /* Fire a SelectionRequest, informing the handler that we are processing
950 * a MULTIPLE selection request event.
952 EVENT_SelectionRequest( hWnd, &event, TRUE );
956 /* Free the list of targets/properties */
957 TSXFree(targetPropList);
965 /***********************************************************************
966 * EVENT_SelectionRequest
967 * Process an event selection request event.
968 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
969 * recursively while servicing a "MULTIPLE" selection target.
971 * Note: We only receive this event when WINE owns the X selection
973 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
975 Display *display = event->display;
976 XSelectionEvent result;
978 Window request = event->requestor;
979 BOOL couldOpen = FALSE;
980 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
981 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
982 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
985 * We can only handle the selection request if :
986 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
987 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
988 * since this has been already done.
992 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
993 || !(couldOpen = OpenClipboard(hWnd)) )
997 /* If the specified property is None the requestor is an obsolete client.
998 * We support these by using the specified target atom as the reply property.
1000 rprop = event->property;
1002 rprop = event->target;
1004 if(event->target == xaTargets) /* Return a list of all supported targets */
1006 /* TARGETS selection request */
1007 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
1009 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1011 /* MULTIPLE selection request */
1012 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1014 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1016 /* XA_STRING selection request */
1017 rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
1019 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1021 /* XA_PIXMAP selection request */
1022 rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
1024 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1026 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1027 rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
1029 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1031 /* All <WCF> selection requests */
1032 rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
1035 rprop = None; /* Don't support this format */
1038 /* close clipboard only if we opened before */
1039 if(couldOpen) CloseClipboard();
1042 TRACE("\tRequest ignored\n");
1045 * SelectionNotify should be sent only at the end of a MULTIPLE request
1049 result.type = SelectionNotify;
1050 result.display = display;
1051 result.requestor = request;
1052 result.selection = event->selection;
1053 result.property = rprop;
1054 result.target = event->target;
1055 result.time = event->time;
1056 TRACE("Sending SelectionNotify event...\n");
1057 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1061 /***********************************************************************
1062 * EVENT_SelectionClear
1064 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1066 Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
1068 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1069 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1072 /***********************************************************************
1073 * EVENT_PropertyNotify
1074 * We use this to release resources like Pixmaps when a selection
1075 * client no longer needs them.
1077 static void EVENT_PropertyNotify( XPropertyEvent *event )
1079 /* Check if we have any resources to free */
1080 TRACE("Received PropertyNotify event: \n");
1082 switch(event->state)
1084 case PropertyDelete:
1086 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1087 TSXGetAtomName(event->display, event->atom), (long)event->window);
1089 if (X11DRV_IsSelectionOwner())
1090 X11DRV_CLIPBOARD_FreeResources( event->atom );
1094 case PropertyNewValue:
1096 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1097 TSXGetAtomName(event->display, event->atom), (long)event->window);
1106 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1110 if (!IsWindowEnabled(hQueryWnd)) return 0;
1112 GetWindowRect(hQueryWnd, &tempRect);
1114 if(!PtInRect(&tempRect, *lpPt)) return 0;
1116 if (!IsIconic( hQueryWnd ))
1118 GetClientRect( hQueryWnd, &tempRect );
1119 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
1121 if (PtInRect( &tempRect, *lpPt))
1123 HWND *list = WIN_ListChildren( hQueryWnd );
1130 for (i = 0; list[i]; i++)
1132 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
1134 GetWindowRect( list[i], &tempRect );
1135 if (PtInRect( &tempRect, *lpPt )) break;
1140 if (IsWindowEnabled( list[i] ))
1141 bResult = find_drop_window( list[i], lpPt );
1143 HeapFree( GetProcessHeap(), 0, list );
1145 if(bResult) return bResult;
1149 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1151 ScreenToClient(hQueryWnd, lpPt);
1156 /**********************************************************************
1157 * EVENT_DropFromOffix
1159 * don't know if it still works (last Changlog is from 96/11/04)
1161 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1163 unsigned long data_length;
1164 unsigned long aux_long;
1165 unsigned char* p_data = NULL;
1176 Window w_aux_root, w_aux_child;
1180 pWnd = WIN_FindWndPtr(hWnd);
1182 TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1183 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1184 (unsigned int*)&aux_long);
1186 /* find out drop point and drop window */
1187 if( x < 0 || y < 0 ||
1188 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1189 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1191 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
1197 POINT pt = { x, y };
1198 HWND hwndDrop = find_drop_window( hWnd, &pt );
1211 WIN_ReleaseWndPtr(pWnd);
1213 if (!bAccept) return;
1215 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1216 dndSelection, 0, 65535, FALSE,
1217 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1218 &data_length, &aux_long, &p_data);
1220 if( !aux_long && p_data) /* don't bother if > 64K */
1222 signed char *p = (signed char*) p_data;
1226 while( *p ) /* calculate buffer size */
1229 if((u.i = *p) != -1 )
1231 INT len = GetShortPathNameA( p, NULL, 0 );
1232 if (len) aux_long += len + 1;
1237 if( aux_long && aux_long < 65535 )
1242 aux_long += sizeof(DROPFILES) + 1;
1243 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1244 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1248 WND *pDropWnd = WIN_FindWndPtr( hScope );
1249 lpDrop->pFiles = sizeof(DROPFILES);
1253 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1254 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1255 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1256 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1257 lpDrop->fWide = FALSE;
1258 WIN_ReleaseWndPtr(pDropWnd);
1259 p_drop = (char *)(lpDrop + 1);
1263 if( *p != -1 ) /* use only "good" entries */
1265 GetShortPathNameA( p, p_drop, 65535 );
1266 p_drop += strlen( p_drop ) + 1;
1271 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1275 if( p_data ) TSXFree(p_data);
1278 /**********************************************************************
1281 * drop items are separated by \n
1282 * each item is prefixed by its mime type
1284 * event->data.l[3], event->data.l[4] contains drop x,y position
1286 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1288 unsigned long data_length;
1289 unsigned long aux_long, drop_len = 0;
1290 unsigned char *p_data = NULL; /* property data */
1291 char *p_drop = NULL;
1302 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1304 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1305 dndSelection, 0, 65535, FALSE,
1306 AnyPropertyType, &u.atom_aux, &u.i,
1307 &data_length, &aux_long, &p_data);
1309 WARN("property too large, truncated!\n");
1310 TRACE("urls=%s\n", p_data);
1312 if( !aux_long && p_data) { /* don't bother if > 64K */
1313 /* calculate length */
1315 next = strchr(p, '\n');
1318 if (strncmp(p,"file:",5) == 0 ) {
1319 INT len = GetShortPathNameA( p+5, NULL, 0 );
1320 if (len) drop_len += len + 1;
1325 next = strchr(p, '\n');
1331 if( drop_len && drop_len < 65535 ) {
1332 TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1333 &x, &y, &u.i, &u.i, &u.i);
1335 drop_len += sizeof(DROPFILES) + 1;
1336 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1337 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1340 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1341 lpDrop->pFiles = sizeof(DROPFILES);
1342 lpDrop->pt.x = (INT)x;
1343 lpDrop->pt.y = (INT)y;
1345 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1346 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1347 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1348 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1349 lpDrop->fWide = FALSE;
1350 p_drop = (char*)(lpDrop + 1);
1351 WIN_ReleaseWndPtr(pDropWnd);
1354 /* create message content */
1357 next = strchr(p, '\n');
1360 if (strncmp(p,"file:",5) == 0 ) {
1361 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1363 TRACE("drop file %s as %s\n", p+5, p_drop);
1366 WARN("can't convert file %s to dos name \n", p+5);
1369 WARN("unknown mime type %s\n", p);
1374 next = strchr(p, '\n');
1381 GlobalUnlock(hDrop);
1382 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1385 if( p_data ) TSXFree(p_data);
1389 /**********************************************************************
1390 * EVENT_ClientMessage
1392 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1394 if (event->message_type != None && event->format == 32) {
1395 if (event->message_type == wmProtocols)
1396 handle_wm_protocols_message( hWnd, event );
1397 else if (event->message_type == dndProtocol)
1399 /* query window (drag&drop event contains only drag window) */
1401 int root_x, root_y, child_x, child_y;
1405 XQueryPointer( event->display, root_window, &root, &child,
1406 &root_x, &root_y, &child_x, &child_y, &u);
1407 if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1408 wine_tsx11_unlock();
1410 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1411 EVENT_DropFromOffiX(hWnd, event);
1412 else if (event->data.l[0] == DndURL)
1413 EVENT_DropURLs(hWnd, event);
1417 /* enable this if you want to see the message */
1418 unsigned char* p_data = NULL;
1424 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1425 dndSelection, 0, 65535, FALSE,
1426 AnyPropertyType, &u.atom, &u.i,
1427 &u.l, &u.l, &p_data);
1428 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1429 event->message_type, event->data.l[0], event->data.l[1],
1430 event->data.l[2], event->data.l[3], event->data.l[4],
1433 TRACE("unrecognized ClientMessage\n" );
1439 /**********************************************************************
1440 * X11DRV_EVENT_SetInputMethod
1442 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1444 INPUT_TYPE prev = current_input_type;
1446 /* Flag not used yet */
1447 in_transition = FALSE;
1448 current_input_type = type;
1453 #ifdef HAVE_LIBXXF86DGA2
1454 /**********************************************************************
1455 * X11DRV_EVENT_SetDGAStatus
1457 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1459 if (event_base < 0) {
1465 DGAMotionEventType = event_base + MotionNotify;
1466 DGAButtonPressEventType = event_base + ButtonPress;
1467 DGAButtonReleaseEventType = event_base + ButtonRelease;
1468 DGAKeyPressEventType = event_base + KeyPress;
1469 DGAKeyReleaseEventType = event_base + KeyRelease;