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
22 #define COM_NO_WINDOWS_H
25 #include <X11/Xatom.h>
26 #include <X11/keysym.h>
29 #include <X11/Xresource.h>
30 #include <X11/Xutil.h>
31 #ifdef HAVE_LIBXXF86DGA2
32 #include <X11/extensions/xf86dga.h>
37 #include "wine/winuser16.h"
38 #include "shlobj.h" /* DROPFILES */
40 #include "clipboard.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(event);
51 /* X context to associate a hwnd to an X window */
52 extern XContext winContext;
54 extern Atom wmProtocols;
55 extern Atom wmDeleteWindow;
56 extern Atom dndProtocol;
57 extern Atom dndSelection;
58 extern Atom netwmPing;
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 ) )
142 XNextEvent( data->display, &event );
143 ignore = XFilterEvent( &event, None );
145 if (!ignore) EVENT_ProcessEvent( &event );
154 /***********************************************************************
155 * MsgWaitForMultipleObjectsEx (X11DRV.@)
157 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
158 DWORD timeout, DWORD mask, DWORD flags )
160 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
162 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
164 if (!data || data->process_event_count)
165 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
166 timeout, flags & MWMO_ALERTABLE );
168 for (i = 0; i < count; i++) new_handles[i] = handles[i];
169 new_handles[count] = data->display_fd;
172 XFlush( gdi_display );
173 XFlush( data->display );
176 data->process_event_count++;
177 if (process_events( data )) ret = count;
180 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
181 timeout, flags & MWMO_ALERTABLE );
182 if (ret == count) process_events( data );
184 data->process_event_count--;
189 /***********************************************************************
192 * Process an X event.
194 static void EVENT_ProcessEvent( XEvent *event )
197 Display *display = event->xany.display;
199 TRACE( "called.\n" );
203 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
204 FIXME("Got SelectionNotify - must not happen!\n");
207 /* We get all these because of StructureNotifyMask.
208 This check is placed here to avoid getting error messages below,
209 as X might send some of these even for windows that have already
211 case CirculateNotify:
219 #ifdef HAVE_LIBXXF86DGA2
221 if (event->type == DGAMotionEventType) {
222 TRACE("DGAMotionEvent received.\n");
223 X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
226 if (event->type == DGAButtonPressEventType) {
227 TRACE("DGAButtonPressEvent received.\n");
228 X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
231 if (event->type == DGAButtonReleaseEventType) {
232 TRACE("DGAButtonReleaseEvent received.\n");
233 X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
236 if ((event->type == DGAKeyPressEventType) ||
237 (event->type == DGAKeyReleaseEventType)) {
238 /* Fill a XKeyEvent to send to EVENT_Key */
240 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
242 TRACE("DGAKeyPress/ReleaseEvent received.\n");
244 if (evt->type == DGAKeyReleaseEventType)
245 ke.type = KeyRelease;
248 ke.serial = evt->serial;
249 ke.send_event = FALSE;
250 ke.display = evt->display;
259 ke.state = evt->state;
260 ke.keycode = evt->keycode;
261 ke.same_screen = TRUE;
262 X11DRV_KeyEvent( 0, &ke );
269 if (XFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
270 hWnd = 0; /* Not for a registered window */
273 if ( !hWnd && event->xany.window != root_window
274 && event->type != PropertyNotify
275 && event->type != MappingNotify)
276 WARN( "Got event %s for unknown Window %08lx\n",
277 event_names[event->type], event->xany.window );
279 TRACE("Got event %s for hwnd %p\n",
280 event_names[event->type], hWnd );
286 /* FIXME: should generate a motion event if event point is different from current pos */
287 X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
291 X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
295 X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
299 X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
303 X11DRV_EnterNotify( hWnd, (XCrossingEvent*)event );
307 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
311 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
315 X11DRV_Expose( hWnd, &event->xexpose );
318 case ConfigureNotify:
320 X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
323 case SelectionRequest:
325 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
330 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
334 EVENT_PropertyNotify( (XPropertyEvent *)event );
339 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
346 X11DRV_MapNotify( hWnd, (XMapEvent *)event );
350 X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
354 X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
358 X11DRV_MappingNotify( (XMappingEvent *) event );
362 WARN("Unprocessed event %s for hwnd %p\n", event_names[event->type], hWnd );
365 TRACE( "returns.\n" );
369 /*******************************************************************
370 * can_activate_window
372 * Check if we can activate the specified window.
374 inline static BOOL can_activate_window( HWND hwnd )
376 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
377 if (!(style & WS_VISIBLE)) return FALSE;
378 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
379 return !(style & WS_DISABLED);
383 /**********************************************************************
384 * set_focus_error_handler
386 * Handler for X errors happening during XSetInputFocus call.
388 static int set_focus_error_handler( Display *display, XErrorEvent *event, void *arg )
390 return (event->error_code == BadMatch);
394 /**********************************************************************
397 static void set_focus( HWND hwnd, Time time )
402 TRACE( "setting foreground window to %p\n", hwnd );
403 SetForegroundWindow( hwnd );
406 if (focus) focus = GetAncestor( focus, GA_ROOT );
407 win = X11DRV_get_whole_window(focus);
411 Display *display = thread_display();
412 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
413 X11DRV_expect_error( display, set_focus_error_handler, NULL );
414 XSetInputFocus( display, win, RevertToParent, time );
415 if (X11DRV_check_error()) TRACE("got BadMatch, ignoring\n" );
420 /**********************************************************************
421 * handle_wm_protocols_message
423 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
425 Atom protocol = (Atom)event->data.l[0];
427 if (!protocol) return;
429 if (protocol == wmDeleteWindow)
431 /* Ignore the delete window request if the window has been disabled
432 * and we are in managed mode. This is to disallow applications from
433 * being closed by the window manager while in a modal state.
435 if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
437 else if (protocol == wmTakeFocus)
439 Time event_time = (Time)event->data.l[1];
440 HWND last_focus = x11drv_thread_data()->last_focus;
442 TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
443 hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
444 GetForegroundWindow(), last_focus );
446 if (can_activate_window(hwnd))
448 /* simulate a mouse click on the caption to find out
449 * whether the window wants to be activated */
450 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
451 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
452 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
453 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
454 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
459 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
460 if (!hwnd) hwnd = GetActiveWindow();
461 if (!hwnd) hwnd = last_focus;
462 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
464 } else if (protocol == netwmPing) {
465 XClientMessageEvent xev;
468 TRACE("NET_WM Ping\n");
469 xev.window = DefaultRootWindow(xev.display);
470 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
471 /* this line is semi-stolen from gtk2 */
472 TRACE("NET_WM Pong\n");
477 static const char * const focus_details[] =
483 "NotifyNonlinearVirtual",
489 /**********************************************************************
492 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
498 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
500 if (event->detail == NotifyPointer) return;
502 if ((xic = X11DRV_get_ic( hwnd )))
508 if (wmTakeFocus) return; /* ignore FocusIn if we are using take focus */
510 if (!can_activate_window(hwnd))
512 HWND hwnd = GetFocus();
513 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
514 if (!hwnd) hwnd = GetActiveWindow();
515 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
516 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
518 else SetForegroundWindow( hwnd );
522 /**********************************************************************
525 * Note: only top-level windows get FocusOut events.
527 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
534 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
536 if (event->detail == NotifyPointer) return;
537 x11drv_thread_data()->last_focus = hwnd;
538 if ((xic = X11DRV_get_ic( hwnd )))
541 XUnsetICFocus( xic );
544 if (hwnd != GetForegroundWindow()) return;
545 SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
547 /* don't reset the foreground window, if the window which is
548 getting the focus is a Wine window */
551 XGetInputFocus( thread_display(), &focus_win, &revert );
554 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
561 /* Abey : 6-Oct-99. Check again if the focus out window is the
562 Foreground window, because in most cases the messages sent
563 above must have already changed the foreground window, in which
564 case we don't have to change the foreground window to 0 */
565 if (hwnd == GetForegroundWindow())
567 TRACE( "lost focus, setting fg to 0\n" );
568 SetForegroundWindow( 0 );
574 /***********************************************************************
575 * EVENT_SelectionRequest_TARGETS
576 * Service a TARGETS selection request event
578 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
579 Atom target, Atom rprop )
581 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
585 unsigned long cTargets;
589 TRACE("Request for %s\n", TSXGetAtomName(display, target));
592 * Count the number of items we wish to expose as selection targets.
593 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
595 cTargets = CountClipboardFormats() + 1;
596 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
599 /* Allocate temp buffer */
600 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
601 if(targets == NULL) return None;
603 /* Create TARGETS property list (First item in list is TARGETS itself) */
605 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
606 (wFormat = EnumClipboardFormats( wFormat )); )
608 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
610 /* Scan through what we have so far to avoid duplicates */
613 for (i = 0, bExists = FALSE; i < cTargets; i++)
615 if (targets[i] == prop)
623 targets[cTargets++] = prop;
625 /* Add PIXMAP prop for bitmaps additionally */
626 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
629 targets[cTargets++] = XA_PIXMAP;
639 for ( i = 0; i < cTargets; i++)
643 char *itemFmtName = TSXGetAtomName(display, targets[i]);
644 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
645 TSXFree(itemFmtName);
650 /* Update the X property */
651 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
653 /* We may want to consider setting the type to xaTargets instead,
654 * in case some apps expect this instead of XA_ATOM */
655 xRc = TSXChangeProperty(display, requestor, rprop,
656 XA_ATOM, 32, PropModeReplace,
657 (unsigned char *)targets, cTargets);
658 TRACE("(Rc=%d)\n", xRc);
660 HeapFree( GetProcessHeap(), 0, targets );
666 /***********************************************************************
667 * EVENT_SelectionRequest_STRING
668 * Service a STRING selection request event
670 static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
671 Atom target, Atom rprop )
673 static UINT text_cp = (UINT)-1;
682 if(text_cp == (UINT)-1)
687 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
690 DWORD type, count = sizeof(buf);
691 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
698 * Map the requested X selection property type atom name to a
699 * windows clipboard format ID.
701 itemFmtName = TSXGetAtomName(display, target);
702 TRACE("Request for %s (wFormat=%x %s)\n",
703 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT, NULL, 0));
704 TSXFree(itemFmtName);
706 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
709 uni_text = GlobalLock(hUnicodeText);
713 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
714 text = HeapAlloc(GetProcessHeap(), 0, size);
717 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
719 /* remove carriage returns */
721 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
722 if(lpstr == NULL) return None;
723 for(i=0,j=0; i < size && text[i]; i++ )
725 if( text[i] == '\r' &&
726 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
727 lpstr[j++] = text[i];
731 /* Update the X property */
732 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
733 xRc = TSXChangeProperty(display, requestor, rprop,
734 XA_STRING, 8, PropModeReplace,
736 TRACE("(Rc=%d)\n", xRc);
738 GlobalUnlock(hUnicodeText);
739 HeapFree(GetProcessHeap(), 0, text);
740 HeapFree( GetProcessHeap(), 0, lpstr );
745 /***********************************************************************
746 * EVENT_SelectionRequest_PIXMAP
747 * Service a PIXMAP selection request event
749 static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
750 Atom target, Atom rprop )
752 HANDLE hClipData = 0;
758 XSetWindowAttributes win_attr;
759 XWindowAttributes win_attr_src;
763 * Map the requested X selection property type atom name to a
764 * windows clipboard format ID.
766 itemFmtName = TSXGetAtomName(display, target);
767 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
768 TRACE("Request for %s (wFormat=%x %s)\n",
769 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0 ));
770 TSXFree(itemFmtName);
772 hClipData = GetClipboardData(wFormat);
775 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
776 rprop = None; /* Fail the request */
780 if (wFormat == CF_DIB)
782 HWND hwnd = GetOpenClipboardWindow();
783 HDC hdc = GetDC(hwnd);
785 /* For convert from packed DIB to Pixmap */
786 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
788 ReleaseDC(hwnd, hdc);
790 else if (wFormat == CF_BITMAP)
792 HWND hwnd = GetOpenClipboardWindow();
793 HDC hdc = GetDC(hwnd);
795 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
797 ReleaseDC(hwnd, hdc);
801 FIXME("%s to PIXMAP conversion not yet implemented!\n",
802 CLIPBOARD_GetFormatName(wFormat, NULL, 0));
807 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
808 TSXGetAtomName(display, rprop), (long)requestor,
809 TSXGetAtomName(display, target), pixmap);
811 /* Store the Pixmap handle in the property */
812 xRc = TSXChangeProperty(display, requestor, rprop, target,
814 (unsigned char *)&pixmap, 1);
815 TRACE("(Rc=%d)\n", xRc);
817 /* Enable the code below if you want to handle destroying Pixmap resources
818 * in response to property notify events. Clients like XPaint don't
819 * appear to be duplicating Pixmaps so they don't like us deleting,
820 * the resource in response to the property being deleted.
823 /* Express interest in property notify events so that we can delete the
824 * pixmap when the client deletes the property atom.
826 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
827 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
829 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
830 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
832 /* Register the Pixmap we created with the request property Atom.
833 * When this property is destroyed we also destroy the Pixmap in
834 * response to the PropertyNotify event.
836 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
844 /***********************************************************************
845 * EVENT_SelectionRequest_WCF
846 * Service a Wine Clipboard Format selection request event.
847 * For <WCF>* data types we simply copy the data to X without conversion.
849 static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
850 Atom target, Atom rprop )
852 HANDLE hClipData = 0;
861 * Map the requested X selection property type atom name to a
862 * windows clipboard format ID.
864 itemFmtName = TSXGetAtomName(display, target);
865 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
866 TRACE("Request for %s (wFormat=%x %s)\n",
867 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0));
868 TSXFree(itemFmtName);
870 hClipData = GetClipboardData(wFormat);
872 bemf = wFormat == CF_METAFILEPICT || wFormat == CF_ENHMETAFILE;
874 hClipData = X11DRV_CLIPBOARD_SerializeMetafile(wFormat, hClipData, sizeof(hClipData), TRUE);
876 if( hClipData && (lpClipData = GlobalLock(hClipData)) )
878 cBytes = GlobalSize(hClipData);
880 TRACE("\tUpdating property %s, %d bytes...\n",
881 TSXGetAtomName(display, rprop), cBytes);
883 xRc = TSXChangeProperty(display, requestor, rprop,
884 target, 8, PropModeReplace,
885 (unsigned char *)lpClipData, cBytes);
886 TRACE("(Rc=%d)\n", xRc);
888 GlobalUnlock(hClipData);
892 TRACE("\tCould not retrieve native format!\n");
893 rprop = None; /* Fail the request */
896 if (bemf) /* We must free serialized metafile data */
897 GlobalFree(hClipData);
903 /***********************************************************************
904 * EVENT_SelectionRequest_MULTIPLE
905 * Service a MULTIPLE selection request event
906 * rprop contains a list of (target,property) atom pairs.
907 * The first atom names a target and the second names a property.
908 * The effect is as if we have received a sequence of SelectionRequest events
909 * (one for each atom pair) except that:
910 * 1. We reply with a SelectionNotify only when all the requested conversions
911 * have been performed.
912 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
913 * we replace the atom in the property by None.
915 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
917 Display *display = pevent->display;
919 Atom atype=AnyPropertyType;
921 unsigned long remain;
922 Atom* targetPropList=NULL;
923 unsigned long cTargetPropList = 0;
924 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
926 /* If the specified property is None the requestor is an obsolete client.
927 * We support these by using the specified target atom as the reply property.
929 rprop = pevent->property;
931 rprop = pevent->target;
935 /* Read the MULTIPLE property contents. This should contain a list of
936 * (target,property) atom pairs.
938 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
939 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
940 &cTargetPropList, &remain,
941 (unsigned char**)&targetPropList) != Success)
942 TRACE("\tCouldn't read MULTIPLE property\n");
945 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
946 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
949 * Make sure we got what we expect.
950 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
951 * in a MULTIPLE selection request should be of type ATOM_PAIR.
952 * However some X apps(such as XPaint) are not compliant with this and return
953 * a user defined atom in atype when XGetWindowProperty is called.
954 * The data *is* an atom pair but is not denoted as such.
956 if(aformat == 32 /* atype == xAtomPair */ )
960 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
961 * for each (target,property) pair */
963 for (i = 0; i < cTargetPropList; i+=2)
965 char *targetName = TSXGetAtomName(display, targetPropList[i]);
966 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
967 XSelectionRequestEvent event;
969 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
970 i/2, targetName, propName);
974 /* We must have a non "None" property to service a MULTIPLE target atom */
975 if ( !targetPropList[i+1] )
977 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
981 /* Set up an XSelectionRequestEvent for this (target,property) pair */
982 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
983 event.target = targetPropList[i];
984 event.property = targetPropList[i+1];
986 /* Fire a SelectionRequest, informing the handler that we are processing
987 * a MULTIPLE selection request event.
989 EVENT_SelectionRequest( hWnd, &event, TRUE );
993 /* Free the list of targets/properties */
994 TSXFree(targetPropList);
1002 /***********************************************************************
1003 * EVENT_SelectionRequest
1004 * Process an event selection request event.
1005 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1006 * recursively while servicing a "MULTIPLE" selection target.
1008 * Note: We only receive this event when WINE owns the X selection
1010 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1012 Display *display = event->display;
1013 XSelectionEvent result;
1015 Window request = event->requestor;
1016 BOOL couldOpen = FALSE;
1017 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1018 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
1019 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1022 * We can only handle the selection request if :
1023 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1024 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1025 * since this has been already done.
1029 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1030 || !(couldOpen = OpenClipboard(hWnd)) )
1034 /* If the specified property is None the requestor is an obsolete client.
1035 * We support these by using the specified target atom as the reply property.
1037 rprop = event->property;
1039 rprop = event->target;
1041 if(event->target == xaTargets) /* Return a list of all supported targets */
1043 /* TARGETS selection request */
1044 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
1046 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1048 /* MULTIPLE selection request */
1049 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1051 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1053 /* XA_STRING selection request */
1054 rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
1056 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1058 /* XA_PIXMAP selection request */
1059 rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
1061 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1063 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1064 rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
1066 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1068 /* All <WCF> selection requests */
1069 rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
1072 rprop = None; /* Don't support this format */
1075 /* close clipboard only if we opened before */
1076 if(couldOpen) CloseClipboard();
1079 TRACE("\tRequest ignored\n");
1082 * SelectionNotify should be sent only at the end of a MULTIPLE request
1086 result.type = SelectionNotify;
1087 result.display = display;
1088 result.requestor = request;
1089 result.selection = event->selection;
1090 result.property = rprop;
1091 result.target = event->target;
1092 result.time = event->time;
1093 TRACE("Sending SelectionNotify event...\n");
1094 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1098 /***********************************************************************
1099 * EVENT_SelectionClear
1101 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1103 Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
1105 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1106 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1109 /***********************************************************************
1110 * EVENT_PropertyNotify
1111 * We use this to release resources like Pixmaps when a selection
1112 * client no longer needs them.
1114 static void EVENT_PropertyNotify( XPropertyEvent *event )
1116 /* Check if we have any resources to free */
1117 TRACE("Received PropertyNotify event: \n");
1119 switch(event->state)
1121 case PropertyDelete:
1123 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1124 TSXGetAtomName(event->display, event->atom), (long)event->window);
1126 if (X11DRV_IsSelectionOwner())
1127 X11DRV_CLIPBOARD_FreeResources( event->atom );
1131 case PropertyNewValue:
1133 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1134 TSXGetAtomName(event->display, event->atom), (long)event->window);
1143 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
1147 if (!IsWindowEnabled(hQueryWnd)) return 0;
1149 GetWindowRect(hQueryWnd, &tempRect);
1151 if(!PtInRect(&tempRect, *lpPt)) return 0;
1153 if (!IsIconic( hQueryWnd ))
1155 GetClientRect( hQueryWnd, &tempRect );
1156 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
1158 if (PtInRect( &tempRect, *lpPt))
1160 HWND *list = WIN_ListChildren( hQueryWnd );
1167 for (i = 0; list[i]; i++)
1169 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
1171 GetWindowRect( list[i], &tempRect );
1172 if (PtInRect( &tempRect, *lpPt )) break;
1177 if (IsWindowEnabled( list[i] ))
1178 bResult = find_drop_window( list[i], lpPt );
1180 HeapFree( GetProcessHeap(), 0, list );
1182 if(bResult) return bResult;
1186 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
1188 ScreenToClient(hQueryWnd, lpPt);
1193 /**********************************************************************
1194 * EVENT_DropFromOffix
1196 * don't know if it still works (last Changlog is from 96/11/04)
1198 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1200 unsigned long data_length;
1201 unsigned long aux_long;
1202 unsigned char* p_data = NULL;
1213 Window w_aux_root, w_aux_child;
1217 pWnd = WIN_FindWndPtr(hWnd);
1219 TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1220 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1221 (unsigned int*)&aux_long);
1223 /* find out drop point and drop window */
1224 if( x < 0 || y < 0 ||
1225 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1226 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1228 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
1234 POINT pt = { x, y };
1235 HWND hwndDrop = find_drop_window( hWnd, &pt );
1248 WIN_ReleaseWndPtr(pWnd);
1250 if (!bAccept) return;
1252 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1253 dndSelection, 0, 65535, FALSE,
1254 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1255 &data_length, &aux_long, &p_data);
1257 if( !aux_long && p_data) /* don't bother if > 64K */
1259 signed char *p = (signed char*) p_data;
1263 while( *p ) /* calculate buffer size */
1266 if((u.i = *p) != -1 )
1268 INT len = GetShortPathNameA( p, NULL, 0 );
1269 if (len) aux_long += len + 1;
1274 if( aux_long && aux_long < 65535 )
1279 aux_long += sizeof(DROPFILES) + 1;
1280 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1281 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1285 WND *pDropWnd = WIN_FindWndPtr( hScope );
1286 lpDrop->pFiles = sizeof(DROPFILES);
1290 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1291 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1292 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1293 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1294 lpDrop->fWide = FALSE;
1295 WIN_ReleaseWndPtr(pDropWnd);
1296 p_drop = (char *)(lpDrop + 1);
1300 if( *p != -1 ) /* use only "good" entries */
1302 GetShortPathNameA( p, p_drop, 65535 );
1303 p_drop += strlen( p_drop ) + 1;
1308 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1312 if( p_data ) TSXFree(p_data);
1315 /**********************************************************************
1318 * drop items are separated by \n
1319 * each item is prefixed by its mime type
1321 * event->data.l[3], event->data.l[4] contains drop x,y position
1323 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1325 unsigned long data_length;
1326 unsigned long aux_long, drop_len = 0;
1327 unsigned char *p_data = NULL; /* property data */
1328 char *p_drop = NULL;
1339 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1341 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1342 dndSelection, 0, 65535, FALSE,
1343 AnyPropertyType, &u.atom_aux, &u.i,
1344 &data_length, &aux_long, &p_data);
1346 WARN("property too large, truncated!\n");
1347 TRACE("urls=%s\n", p_data);
1349 if( !aux_long && p_data) { /* don't bother if > 64K */
1350 /* calculate length */
1352 next = strchr(p, '\n');
1355 if (strncmp(p,"file:",5) == 0 ) {
1356 INT len = GetShortPathNameA( p+5, NULL, 0 );
1357 if (len) drop_len += len + 1;
1362 next = strchr(p, '\n');
1368 if( drop_len && drop_len < 65535 ) {
1369 TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1370 &x, &y, &u.i, &u.i, &u.i);
1372 drop_len += sizeof(DROPFILES) + 1;
1373 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1374 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1377 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1378 lpDrop->pFiles = sizeof(DROPFILES);
1379 lpDrop->pt.x = (INT)x;
1380 lpDrop->pt.y = (INT)y;
1382 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1383 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1384 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1385 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1386 lpDrop->fWide = FALSE;
1387 p_drop = (char*)(lpDrop + 1);
1388 WIN_ReleaseWndPtr(pDropWnd);
1391 /* create message content */
1394 next = strchr(p, '\n');
1397 if (strncmp(p,"file:",5) == 0 ) {
1398 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1400 TRACE("drop file %s as %s\n", p+5, p_drop);
1403 WARN("can't convert file %s to dos name \n", p+5);
1406 WARN("unknown mime type %s\n", p);
1411 next = strchr(p, '\n');
1418 GlobalUnlock(hDrop);
1419 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1422 if( p_data ) TSXFree(p_data);
1426 /**********************************************************************
1427 * EVENT_ClientMessage
1429 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1431 if (event->message_type != None && event->format == 32) {
1432 if (event->message_type == wmProtocols)
1433 handle_wm_protocols_message( hWnd, event );
1434 else if (event->message_type == dndProtocol)
1436 /* query window (drag&drop event contains only drag window) */
1438 int root_x, root_y, child_x, child_y;
1442 XQueryPointer( event->display, root_window, &root, &child,
1443 &root_x, &root_y, &child_x, &child_y, &u);
1444 if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1445 wine_tsx11_unlock();
1447 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1448 EVENT_DropFromOffiX(hWnd, event);
1449 else if (event->data.l[0] == DndURL)
1450 EVENT_DropURLs(hWnd, event);
1454 /* enable this if you want to see the message */
1455 unsigned char* p_data = NULL;
1461 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1462 dndSelection, 0, 65535, FALSE,
1463 AnyPropertyType, &u.atom, &u.i,
1464 &u.l, &u.l, &p_data);
1465 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1466 event->message_type, event->data.l[0], event->data.l[1],
1467 event->data.l[2], event->data.l[3], event->data.l[4],
1470 TRACE("unrecognized ClientMessage\n" );
1476 /**********************************************************************
1477 * X11DRV_EVENT_SetInputMethod
1479 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1481 INPUT_TYPE prev = current_input_type;
1483 /* Flag not used yet */
1484 in_transition = FALSE;
1485 current_input_type = type;
1490 #ifdef HAVE_LIBXXF86DGA2
1491 /**********************************************************************
1492 * X11DRV_EVENT_SetDGAStatus
1494 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1496 if (event_base < 0) {
1502 DGAMotionEventType = event_base + MotionNotify;
1503 DGAButtonPressEventType = event_base + ButtonPress;
1504 DGAButtonReleaseEventType = event_base + ButtonRelease;
1505 DGAKeyPressEventType = event_base + KeyPress;
1506 DGAKeyReleaseEventType = event_base + KeyRelease;