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 "ts_xresource.h"
30 #ifdef HAVE_LIBXXF86DGA2
31 #include "ts_xf86dga2.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);
51 WINE_DECLARE_DEBUG_CHANNEL(win);
53 /* X context to associate a hwnd to an X window */
54 extern XContext winContext;
56 extern Atom wmProtocols;
57 extern Atom wmDeleteWindow;
58 extern Atom dndProtocol;
59 extern Atom dndSelection;
61 #define DndNotDnd -1 /* OffiX drag&drop */
73 #define DndURL 128 /* KDE drag&drop */
75 /* The last X window which had the focus */
76 static Window glastXFocusWin = 0;
78 static const char * const event_names[] =
80 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
81 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
82 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
83 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
84 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
85 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
86 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
87 "ClientMessage", "MappingNotify"
91 static void EVENT_ProcessEvent( XEvent *event );
92 static BOOL X11DRV_CheckFocus(void);
95 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
96 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
97 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
98 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
99 static void EVENT_PropertyNotify( XPropertyEvent *event );
100 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
102 extern void X11DRV_ButtonPress( HWND hwnd, XButtonEvent *event );
103 extern void X11DRV_ButtonRelease( HWND hwnd, XButtonEvent *event );
104 extern void X11DRV_MotionNotify( HWND hwnd, XMotionEvent *event );
105 extern void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event );
106 extern void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event );
107 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
108 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
109 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
110 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
111 extern void X11DRV_MappingNotify( XMappingEvent *event );
113 #ifdef HAVE_LIBXXF86DGA2
114 static int DGAMotionEventType;
115 static int DGAButtonPressEventType;
116 static int DGAButtonReleaseEventType;
117 static int DGAKeyPressEventType;
118 static int DGAKeyReleaseEventType;
120 static BOOL DGAUsed = FALSE;
121 static HWND DGAhwnd = 0;
123 extern void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event );
124 extern void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event );
125 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event );
128 /* Static used for the current input method */
129 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
130 static BOOL in_transition = FALSE; /* This is not used as for today */
133 /***********************************************************************
136 static int process_events( struct x11drv_thread_data *data )
142 while ( XPending( data->display ) )
144 XNextEvent( data->display, &event );
146 EVENT_ProcessEvent( &event );
155 /***********************************************************************
156 * MsgWaitForMultipleObjectsEx (X11DRV.@)
158 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
159 DWORD timeout, DWORD mask, DWORD flags )
161 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
163 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
165 if (!data || data->process_event_count)
166 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
167 timeout, flags & MWMO_ALERTABLE );
169 for (i = 0; i < count; i++) new_handles[i] = handles[i];
170 new_handles[count] = data->display_fd;
173 XFlush( gdi_display );
174 XFlush( data->display );
177 data->process_event_count++;
178 if (process_events( data )) ret = count;
181 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
182 timeout, flags & MWMO_ALERTABLE );
183 if (ret == count) process_events( data );
185 data->process_event_count--;
190 /***********************************************************************
193 * Process an X event.
195 static void EVENT_ProcessEvent( XEvent *event )
198 Display *display = event->xany.display;
200 TRACE( "called.\n" );
204 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
205 FIXME("Got SelectionNotify - must not happen!\n");
208 /* We get all these because of StructureNotifyMask.
209 This check is placed here to avoid getting error messages below,
210 as X might send some of these even for windows that have already
212 case CirculateNotify:
220 #ifdef HAVE_LIBXXF86DGA2
222 if (event->type == DGAMotionEventType) {
223 TRACE("DGAMotionEvent received.\n");
224 X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
227 if (event->type == DGAButtonPressEventType) {
228 TRACE("DGAButtonPressEvent received.\n");
229 X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
232 if (event->type == DGAButtonReleaseEventType) {
233 TRACE("DGAButtonReleaseEvent received.\n");
234 X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
237 if ((event->type == DGAKeyPressEventType) ||
238 (event->type == DGAKeyReleaseEventType)) {
239 /* Fill a XKeyEvent to send to EVENT_Key */
241 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
243 TRACE("DGAKeyPress/ReleaseEvent received.\n");
245 if (evt->type == DGAKeyReleaseEventType)
246 ke.type = KeyRelease;
249 ke.serial = evt->serial;
250 ke.send_event = FALSE;
251 ke.display = evt->display;
260 ke.state = evt->state;
261 ke.keycode = evt->keycode;
262 ke.same_screen = TRUE;
263 X11DRV_KeyEvent( 0, &ke );
269 if (TSXFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
270 hWnd = 0; /* Not for a registered window */
272 if ( !hWnd && event->xany.window != root_window
273 && event->type != PropertyNotify
274 && event->type != MappingNotify)
275 WARN( "Got event %s for unknown Window %08lx\n",
276 event_names[event->type], event->xany.window );
278 TRACE("Got event %s for hwnd %04x\n",
279 event_names[event->type], hWnd );
285 /* FIXME: should generate a motion event if event point is different from current pos */
286 X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
290 X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
294 X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
298 X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
302 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
306 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
310 X11DRV_Expose( hWnd, &event->xexpose );
313 case ConfigureNotify:
315 X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
318 case SelectionRequest:
320 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
325 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
329 EVENT_PropertyNotify( (XPropertyEvent *)event );
334 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
341 X11DRV_MapNotify( hWnd, (XMapEvent *)event );
345 X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
349 X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
353 X11DRV_MappingNotify( (XMappingEvent *) event );
357 WARN("Unprocessed event %s for hwnd %04x\n",
358 event_names[event->type], hWnd );
361 TRACE( "returns.\n" );
365 /**********************************************************************
368 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
371 XWindowAttributes win_attr;
376 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
378 /* If the window has been disabled, revert the X focus back to the last
379 * focus window. This is to disallow the window manager from switching
380 * focus away while the app is in a modal state.
382 if (bIsDisabled && glastXFocusWin)
384 /* Change focus only if saved focus window is registered and viewable */
386 if (XFindContext( event->display, glastXFocusWin, winContext,
387 (char **)&pWndLastFocus ) == 0 )
389 if (XGetWindowAttributes( event->display, glastXFocusWin, &win_attr ) &&
390 (win_attr.map_state == IsViewable) )
392 XSetInputFocus( event->display, glastXFocusWin, RevertToParent, CurrentTime );
400 if (event->detail != NotifyPointer && hWnd != GetForegroundWindow())
401 SetForegroundWindow( hWnd );
405 /**********************************************************************
408 * Note: only top-level override-redirect windows get FocusOut events.
410 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
412 /* Save the last window which had the focus */
413 glastXFocusWin = event->window;
415 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
417 if (event->detail != NotifyPointer && hWnd == GetForegroundWindow())
419 /* don't reset the foreground window, if the window which is
420 getting the focus is a Wine window */
421 if (!X11DRV_CheckFocus())
423 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
424 /* Abey : 6-Oct-99. Check again if the focus out window is the
425 Foreground window, because in most cases the messages sent
426 above must have already changed the foreground window, in which
427 case we don't have to change the foreground window to 0 */
429 if (hWnd == GetForegroundWindow())
430 SetForegroundWindow( 0 );
435 /**********************************************************************
436 * CheckFocus (X11DRV.@)
438 static BOOL X11DRV_CheckFocus(void)
440 Display *display = thread_display();
445 TSXGetInputFocus(display, &xW, &state);
447 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
453 /***********************************************************************
454 * EVENT_SelectionRequest_TARGETS
455 * Service a TARGETS selection request event
457 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
458 Atom target, Atom rprop )
460 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
464 unsigned long cTargets;
468 TRACE("Request for %s\n", TSXGetAtomName(display, target));
471 * Count the number of items we wish to expose as selection targets.
472 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
474 cTargets = CountClipboardFormats() + 1;
475 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
478 /* Allocate temp buffer */
479 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
480 if(targets == NULL) return None;
482 /* Create TARGETS property list (First item in list is TARGETS itself) */
484 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
485 (wFormat = EnumClipboardFormats( wFormat )); )
487 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
489 /* Scan through what we have so far to avoid duplicates */
492 for (i = 0, bExists = FALSE; i < cTargets; i++)
494 if (targets[i] == prop)
502 targets[cTargets++] = prop;
504 /* Add PIXMAP prop for bitmaps additionally */
505 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
508 targets[cTargets++] = XA_PIXMAP;
518 for ( i = 0; i < cTargets; i++)
522 char *itemFmtName = TSXGetAtomName(display, targets[i]);
523 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
524 TSXFree(itemFmtName);
529 /* Update the X property */
530 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
532 /* We may want to consider setting the type to xaTargets instead,
533 * in case some apps expect this instead of XA_ATOM */
534 xRc = TSXChangeProperty(display, requestor, rprop,
535 XA_ATOM, 32, PropModeReplace,
536 (unsigned char *)targets, cTargets);
537 TRACE("(Rc=%d)\n", xRc);
539 HeapFree( GetProcessHeap(), 0, targets );
545 /***********************************************************************
546 * EVENT_SelectionRequest_STRING
547 * Service a STRING selection request event
549 static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
550 Atom target, Atom rprop )
552 static UINT text_cp = (UINT)-1;
561 if(text_cp == (UINT)-1)
566 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
569 DWORD type, count = sizeof(buf);
570 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
577 * Map the requested X selection property type atom name to a
578 * windows clipboard format ID.
580 itemFmtName = TSXGetAtomName(display, target);
581 TRACE("Request for %s (wFormat=%x %s)\n",
582 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT));
583 TSXFree(itemFmtName);
585 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
588 uni_text = GlobalLock(hUnicodeText);
592 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
593 text = HeapAlloc(GetProcessHeap(), 0, size);
596 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
598 /* remove carriage returns */
600 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
601 if(lpstr == NULL) return None;
602 for(i=0,j=0; i < size && text[i]; i++ )
604 if( text[i] == '\r' &&
605 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
606 lpstr[j++] = text[i];
610 /* Update the X property */
611 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
612 xRc = TSXChangeProperty(display, requestor, rprop,
613 XA_STRING, 8, PropModeReplace,
615 TRACE("(Rc=%d)\n", xRc);
617 GlobalUnlock(hUnicodeText);
618 HeapFree(GetProcessHeap(), 0, text);
619 HeapFree( GetProcessHeap(), 0, lpstr );
624 /***********************************************************************
625 * EVENT_SelectionRequest_PIXMAP
626 * Service a PIXMAP selection request event
628 static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
629 Atom target, Atom rprop )
631 HANDLE hClipData = 0;
637 XSetWindowAttributes win_attr;
638 XWindowAttributes win_attr_src;
642 * Map the requested X selection property type atom name to a
643 * windows clipboard format ID.
645 itemFmtName = TSXGetAtomName(display, target);
646 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
647 TRACE("Request for %s (wFormat=%x %s)\n",
648 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
649 TSXFree(itemFmtName);
651 hClipData = GetClipboardData(wFormat);
654 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
655 rprop = None; /* Fail the request */
659 if (wFormat == CF_DIB)
661 HWND hwnd = GetOpenClipboardWindow();
662 HDC hdc = GetDC(hwnd);
664 /* For convert from packed DIB to Pixmap */
665 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
667 ReleaseDC(hwnd, hdc);
669 else if (wFormat == CF_BITMAP)
671 HWND hwnd = GetOpenClipboardWindow();
672 HDC hdc = GetDC(hwnd);
674 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
676 ReleaseDC(hwnd, hdc);
680 FIXME("%s to PIXMAP conversion not yet implemented!\n",
681 CLIPBOARD_GetFormatName(wFormat));
686 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
687 TSXGetAtomName(display, rprop), (long)requestor,
688 TSXGetAtomName(display, target), pixmap);
690 /* Store the Pixmap handle in the property */
691 xRc = TSXChangeProperty(display, requestor, rprop, target,
693 (unsigned char *)&pixmap, 1);
694 TRACE("(Rc=%d)\n", xRc);
696 /* Enable the code below if you want to handle destroying Pixmap resources
697 * in response to property notify events. Clients like XPaint don't
698 * appear to be duplicating Pixmaps so they don't like us deleting,
699 * the resource in response to the property being deleted.
702 /* Express interest in property notify events so that we can delete the
703 * pixmap when the client deletes the property atom.
705 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
706 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
708 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
709 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
711 /* Register the Pixmap we created with the request property Atom.
712 * When this property is destroyed we also destroy the Pixmap in
713 * response to the PropertyNotify event.
715 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
723 /***********************************************************************
724 * EVENT_SelectionRequest_WCF
725 * Service a Wine Clipboard Format selection request event.
726 * For <WCF>* data types we simply copy the data to X without conversion.
728 static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
729 Atom target, Atom rprop )
731 HANDLE hClipData = 0;
739 * Map the requested X selection property type atom name to a
740 * windows clipboard format ID.
742 itemFmtName = TSXGetAtomName(display, target);
743 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
744 TRACE("Request for %s (wFormat=%x %s)\n",
745 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
746 TSXFree(itemFmtName);
748 hClipData = GetClipboardData(wFormat);
750 if( hClipData && (lpClipData = GlobalLock(hClipData)) )
752 cBytes = GlobalSize(hClipData);
754 TRACE("\tUpdating property %s, %d bytes...\n",
755 TSXGetAtomName(display, rprop), cBytes);
757 xRc = TSXChangeProperty(display, requestor, rprop,
758 target, 8, PropModeReplace,
759 (unsigned char *)lpClipData, cBytes);
760 TRACE("(Rc=%d)\n", xRc);
762 GlobalUnlock(hClipData);
766 TRACE("\tCould not retrieve native format!\n");
767 rprop = None; /* Fail the request */
774 /***********************************************************************
775 * EVENT_SelectionRequest_MULTIPLE
776 * Service a MULTIPLE selection request event
777 * rprop contains a list of (target,property) atom pairs.
778 * The first atom names a target and the second names a property.
779 * The effect is as if we have received a sequence of SelectionRequest events
780 * (one for each atom pair) except that:
781 * 1. We reply with a SelectionNotify only when all the requested conversions
782 * have been performed.
783 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
784 * we replace the atom in the property by None.
786 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
788 Display *display = pevent->display;
790 Atom atype=AnyPropertyType;
792 unsigned long remain;
793 Atom* targetPropList=NULL;
794 unsigned long cTargetPropList = 0;
795 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
797 /* If the specified property is None the requestor is an obsolete client.
798 * We support these by using the specified target atom as the reply property.
800 rprop = pevent->property;
802 rprop = pevent->target;
806 /* Read the MULTIPLE property contents. This should contain a list of
807 * (target,property) atom pairs.
809 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
810 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
811 &cTargetPropList, &remain,
812 (unsigned char**)&targetPropList) != Success)
813 TRACE("\tCouldn't read MULTIPLE property\n");
816 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
817 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
820 * Make sure we got what we expect.
821 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
822 * in a MULTIPLE selection request should be of type ATOM_PAIR.
823 * However some X apps(such as XPaint) are not compliant with this and return
824 * a user defined atom in atype when XGetWindowProperty is called.
825 * The data *is* an atom pair but is not denoted as such.
827 if(aformat == 32 /* atype == xAtomPair */ )
831 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
832 * for each (target,property) pair */
834 for (i = 0; i < cTargetPropList; i+=2)
836 char *targetName = TSXGetAtomName(display, targetPropList[i]);
837 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
838 XSelectionRequestEvent event;
840 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
841 i/2, targetName, propName);
845 /* We must have a non "None" property to service a MULTIPLE target atom */
846 if ( !targetPropList[i+1] )
848 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
852 /* Set up an XSelectionRequestEvent for this (target,property) pair */
853 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
854 event.target = targetPropList[i];
855 event.property = targetPropList[i+1];
857 /* Fire a SelectionRequest, informing the handler that we are processing
858 * a MULTIPLE selection request event.
860 EVENT_SelectionRequest( hWnd, &event, TRUE );
864 /* Free the list of targets/properties */
865 TSXFree(targetPropList);
873 /***********************************************************************
874 * EVENT_SelectionRequest
875 * Process an event selection request event.
876 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
877 * recursively while servicing a "MULTIPLE" selection target.
879 * Note: We only receive this event when WINE owns the X selection
881 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
883 Display *display = event->display;
884 XSelectionEvent result;
886 Window request = event->requestor;
887 BOOL couldOpen = FALSE;
888 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
889 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
890 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
893 * We can only handle the selection request if :
894 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
895 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
896 * since this has been already done.
900 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
901 || !(couldOpen = OpenClipboard(hWnd)) )
905 /* If the specified property is None the requestor is an obsolete client.
906 * We support these by using the specified target atom as the reply property.
908 rprop = event->property;
910 rprop = event->target;
912 if(event->target == xaTargets) /* Return a list of all supported targets */
914 /* TARGETS selection request */
915 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
917 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
919 /* MULTIPLE selection request */
920 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
922 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
924 /* XA_STRING selection request */
925 rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
927 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
929 /* XA_PIXMAP selection request */
930 rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
932 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
934 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
935 rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
937 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
939 /* All <WCF> selection requests */
940 rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
943 rprop = None; /* Don't support this format */
946 /* close clipboard only if we opened before */
947 if(couldOpen) CloseClipboard();
950 TRACE("\tRequest ignored\n");
953 * SelectionNotify should be sent only at the end of a MULTIPLE request
957 result.type = SelectionNotify;
958 result.display = display;
959 result.requestor = request;
960 result.selection = event->selection;
961 result.property = rprop;
962 result.target = event->target;
963 result.time = event->time;
964 TRACE("Sending SelectionNotify event...\n");
965 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
969 /***********************************************************************
970 * EVENT_SelectionClear
972 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
974 Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
976 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
977 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
980 /***********************************************************************
981 * EVENT_PropertyNotify
982 * We use this to release resources like Pixmaps when a selection
983 * client no longer needs them.
985 static void EVENT_PropertyNotify( XPropertyEvent *event )
987 /* Check if we have any resources to free */
988 TRACE("Received PropertyNotify event: \n");
994 TRACE("\tPropertyDelete for atom %s on window %ld\n",
995 TSXGetAtomName(event->display, event->atom), (long)event->window);
997 if (X11DRV_IsSelectionOwner())
998 X11DRV_CLIPBOARD_FreeResources( event->atom );
1002 case PropertyNewValue:
1004 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1005 TSXGetAtomName(event->display, event->atom), (long)event->window);
1014 /**********************************************************************
1015 * EVENT_DropFromOffix
1017 * don't know if it still works (last Changlog is from 96/11/04)
1019 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1021 unsigned long data_length;
1022 unsigned long aux_long;
1023 unsigned char* p_data = NULL;
1034 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO16));
1035 LPDRAGINFO16 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
1036 SEGPTR spDragInfo = K32WOWGlobalLock16(hDragInfo);
1037 Window w_aux_root, w_aux_child;
1040 if( !lpDragInfo || !spDragInfo ) return;
1042 pWnd = WIN_FindWndPtr(hWnd);
1044 TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1045 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1046 (unsigned int*)&aux_long);
1048 lpDragInfo->hScope = hWnd;
1049 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1051 /* find out drop point and drop window */
1052 if( x < 0 || y < 0 ||
1053 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1054 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1055 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1058 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1059 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1061 WIN_ReleaseWndPtr(pWnd);
1063 GlobalFree16( hDragInfo );
1065 if (!bAccept) return;
1067 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1068 dndSelection, 0, 65535, FALSE,
1069 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1070 &data_length, &aux_long, &p_data);
1072 if( !aux_long && p_data) /* don't bother if > 64K */
1074 signed char *p = (signed char*) p_data;
1078 while( *p ) /* calculate buffer size */
1081 if((u.i = *p) != -1 )
1083 INT len = GetShortPathNameA( p, NULL, 0 );
1084 if (len) aux_long += len + 1;
1089 if( aux_long && aux_long < 65535 )
1094 aux_long += sizeof(DROPFILES) + 1;
1095 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1096 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1100 WND *pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1101 lpDrop->pFiles = sizeof(DROPFILES);
1105 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1106 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1107 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1108 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1109 lpDrop->fWide = FALSE;
1110 WIN_ReleaseWndPtr(pDropWnd);
1111 p_drop = (char *)(lpDrop + 1);
1115 if( *p != -1 ) /* use only "good" entries */
1117 GetShortPathNameA( p, p_drop, 65535 );
1118 p_drop += strlen( p_drop ) + 1;
1123 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1127 if( p_data ) TSXFree(p_data);
1130 /**********************************************************************
1133 * drop items are separated by \n
1134 * each item is prefixed by its mime type
1136 * event->data.l[3], event->data.l[4] contains drop x,y position
1138 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1140 unsigned long data_length;
1141 unsigned long aux_long, drop_len = 0;
1142 unsigned char *p_data = NULL; /* property data */
1143 char *p_drop = NULL;
1154 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1156 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1157 dndSelection, 0, 65535, FALSE,
1158 AnyPropertyType, &u.atom_aux, &u.i,
1159 &data_length, &aux_long, &p_data);
1161 WARN("property too large, truncated!\n");
1162 TRACE("urls=%s\n", p_data);
1164 if( !aux_long && p_data) { /* don't bother if > 64K */
1165 /* calculate length */
1167 next = strchr(p, '\n');
1170 if (strncmp(p,"file:",5) == 0 ) {
1171 INT len = GetShortPathNameA( p+5, NULL, 0 );
1172 if (len) drop_len += len + 1;
1177 next = strchr(p, '\n');
1183 if( drop_len && drop_len < 65535 ) {
1184 TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1185 &x, &y, &u.i, &u.i, &u.i);
1187 drop_len += sizeof(DROPFILES) + 1;
1188 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1189 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1192 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1193 lpDrop->pFiles = sizeof(DROPFILES);
1194 lpDrop->pt.x = (INT)x;
1195 lpDrop->pt.y = (INT)y;
1197 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1198 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1199 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1200 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1201 lpDrop->fWide = FALSE;
1202 p_drop = (char*)(lpDrop + 1);
1203 WIN_ReleaseWndPtr(pDropWnd);
1206 /* create message content */
1209 next = strchr(p, '\n');
1212 if (strncmp(p,"file:",5) == 0 ) {
1213 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1215 TRACE("drop file %s as %s\n", p+5, p_drop);
1218 WARN("can't convert file %s to dos name \n", p+5);
1221 WARN("unknown mime type %s\n", p);
1226 next = strchr(p, '\n');
1233 GlobalUnlock(hDrop);
1234 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1237 if( p_data ) TSXFree(p_data);
1241 /**********************************************************************
1242 * EVENT_ClientMessage
1244 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1246 if (event->message_type != None && event->format == 32) {
1247 if ((event->message_type == wmProtocols) &&
1248 (((Atom) event->data.l[0]) == wmDeleteWindow))
1250 /* Ignore the delete window request if the window has been disabled */
1251 if (!(GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED))
1252 PostMessageA( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1254 else if (event->message_type == dndProtocol)
1256 /* query window (drag&drop event contains only drag window) */
1258 int root_x, root_y, child_x, child_y;
1260 TSXQueryPointer( event->display, root_window, &root, &child,
1261 &root_x, &root_y, &child_x, &child_y, &u);
1262 if (TSXFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) return;
1263 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1264 EVENT_DropFromOffiX(hWnd, event);
1265 else if (event->data.l[0] == DndURL)
1266 EVENT_DropURLs(hWnd, event);
1270 /* enable this if you want to see the message */
1271 unsigned char* p_data = NULL;
1277 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1278 dndSelection, 0, 65535, FALSE,
1279 AnyPropertyType, &u.atom, &u.i,
1280 &u.l, &u.l, &p_data);
1281 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1282 event->message_type, event->data.l[0], event->data.l[1],
1283 event->data.l[2], event->data.l[3], event->data.l[4],
1286 TRACE("unrecognized ClientMessage\n" );
1292 /**********************************************************************
1293 * X11DRV_EVENT_SetInputMethod
1295 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1297 INPUT_TYPE prev = current_input_type;
1299 /* Flag not used yet */
1300 in_transition = FALSE;
1301 current_input_type = type;
1306 #ifdef HAVE_LIBXXF86DGA2
1307 /**********************************************************************
1308 * X11DRV_EVENT_SetDGAStatus
1310 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1312 if (event_base < 0) {
1318 DGAMotionEventType = event_base + MotionNotify;
1319 DGAButtonPressEventType = event_base + ButtonPress;
1320 DGAButtonReleaseEventType = event_base + ButtonRelease;
1321 DGAKeyPressEventType = event_base + KeyPress;
1322 DGAKeyReleaseEventType = event_base + KeyRelease;