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_EnterNotify( HWND hwnd, XCrossingEvent *event );
106 extern void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event );
107 extern void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event );
108 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
109 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
110 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
111 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
112 extern void X11DRV_MappingNotify( XMappingEvent *event );
114 #ifdef HAVE_LIBXXF86DGA2
115 static int DGAMotionEventType;
116 static int DGAButtonPressEventType;
117 static int DGAButtonReleaseEventType;
118 static int DGAKeyPressEventType;
119 static int DGAKeyReleaseEventType;
121 static BOOL DGAUsed = FALSE;
122 static HWND DGAhwnd = 0;
124 extern void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event );
125 extern void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event );
126 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event );
129 /* Static used for the current input method */
130 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
131 static BOOL in_transition = FALSE; /* This is not used as for today */
134 /***********************************************************************
137 static int process_events( struct x11drv_thread_data *data )
143 while ( XPending( data->display ) )
145 XNextEvent( data->display, &event );
147 EVENT_ProcessEvent( &event );
156 /***********************************************************************
157 * MsgWaitForMultipleObjectsEx (X11DRV.@)
159 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
160 DWORD timeout, DWORD mask, DWORD flags )
162 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
164 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
166 if (!data || data->process_event_count)
167 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
168 timeout, flags & MWMO_ALERTABLE );
170 for (i = 0; i < count; i++) new_handles[i] = handles[i];
171 new_handles[count] = data->display_fd;
174 XFlush( gdi_display );
175 XFlush( data->display );
178 data->process_event_count++;
179 if (process_events( data )) ret = count;
182 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
183 timeout, flags & MWMO_ALERTABLE );
184 if (ret == count) process_events( data );
186 data->process_event_count--;
191 /***********************************************************************
194 * Process an X event.
196 static void EVENT_ProcessEvent( XEvent *event )
199 Display *display = event->xany.display;
201 TRACE( "called.\n" );
205 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
206 FIXME("Got SelectionNotify - must not happen!\n");
209 /* We get all these because of StructureNotifyMask.
210 This check is placed here to avoid getting error messages below,
211 as X might send some of these even for windows that have already
213 case CirculateNotify:
221 #ifdef HAVE_LIBXXF86DGA2
223 if (event->type == DGAMotionEventType) {
224 TRACE("DGAMotionEvent received.\n");
225 X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
228 if (event->type == DGAButtonPressEventType) {
229 TRACE("DGAButtonPressEvent received.\n");
230 X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
233 if (event->type == DGAButtonReleaseEventType) {
234 TRACE("DGAButtonReleaseEvent received.\n");
235 X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
238 if ((event->type == DGAKeyPressEventType) ||
239 (event->type == DGAKeyReleaseEventType)) {
240 /* Fill a XKeyEvent to send to EVENT_Key */
242 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
244 TRACE("DGAKeyPress/ReleaseEvent received.\n");
246 if (evt->type == DGAKeyReleaseEventType)
247 ke.type = KeyRelease;
250 ke.serial = evt->serial;
251 ke.send_event = FALSE;
252 ke.display = evt->display;
261 ke.state = evt->state;
262 ke.keycode = evt->keycode;
263 ke.same_screen = TRUE;
264 X11DRV_KeyEvent( 0, &ke );
270 if (TSXFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
271 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 %04x\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 %04x\n",
363 event_names[event->type], hWnd );
366 TRACE( "returns.\n" );
370 /**********************************************************************
373 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
376 XWindowAttributes win_attr;
381 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
383 /* If the window has been disabled, revert the X focus back to the last
384 * focus window. This is to disallow the window manager from switching
385 * focus away while the app is in a modal state.
387 if (bIsDisabled && glastXFocusWin)
389 /* Change focus only if saved focus window is registered and viewable */
391 if (XFindContext( event->display, glastXFocusWin, winContext,
392 (char **)&pWndLastFocus ) == 0 )
394 if (XGetWindowAttributes( event->display, glastXFocusWin, &win_attr ) &&
395 (win_attr.map_state == IsViewable) )
397 XSetInputFocus( event->display, glastXFocusWin, RevertToParent, CurrentTime );
405 if (event->detail != NotifyPointer && hWnd != GetForegroundWindow())
406 SetForegroundWindow( hWnd );
410 /**********************************************************************
413 * Note: only top-level override-redirect windows get FocusOut events.
415 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
417 /* Save the last window which had the focus */
418 glastXFocusWin = event->window;
420 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
422 if (event->detail != NotifyPointer && hWnd == GetForegroundWindow())
424 /* don't reset the foreground window, if the window which is
425 getting the focus is a Wine window */
426 if (!X11DRV_CheckFocus())
428 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
429 /* Abey : 6-Oct-99. Check again if the focus out window is the
430 Foreground window, because in most cases the messages sent
431 above must have already changed the foreground window, in which
432 case we don't have to change the foreground window to 0 */
434 if (hWnd == GetForegroundWindow())
435 SetForegroundWindow( 0 );
440 /**********************************************************************
441 * CheckFocus (X11DRV.@)
443 static BOOL X11DRV_CheckFocus(void)
445 Display *display = thread_display();
450 TSXGetInputFocus(display, &xW, &state);
452 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
458 /***********************************************************************
459 * EVENT_SelectionRequest_TARGETS
460 * Service a TARGETS selection request event
462 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
463 Atom target, Atom rprop )
465 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
469 unsigned long cTargets;
473 TRACE("Request for %s\n", TSXGetAtomName(display, target));
476 * Count the number of items we wish to expose as selection targets.
477 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
479 cTargets = CountClipboardFormats() + 1;
480 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
483 /* Allocate temp buffer */
484 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
485 if(targets == NULL) return None;
487 /* Create TARGETS property list (First item in list is TARGETS itself) */
489 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
490 (wFormat = EnumClipboardFormats( wFormat )); )
492 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
494 /* Scan through what we have so far to avoid duplicates */
497 for (i = 0, bExists = FALSE; i < cTargets; i++)
499 if (targets[i] == prop)
507 targets[cTargets++] = prop;
509 /* Add PIXMAP prop for bitmaps additionally */
510 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
513 targets[cTargets++] = XA_PIXMAP;
523 for ( i = 0; i < cTargets; i++)
527 char *itemFmtName = TSXGetAtomName(display, targets[i]);
528 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
529 TSXFree(itemFmtName);
534 /* Update the X property */
535 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
537 /* We may want to consider setting the type to xaTargets instead,
538 * in case some apps expect this instead of XA_ATOM */
539 xRc = TSXChangeProperty(display, requestor, rprop,
540 XA_ATOM, 32, PropModeReplace,
541 (unsigned char *)targets, cTargets);
542 TRACE("(Rc=%d)\n", xRc);
544 HeapFree( GetProcessHeap(), 0, targets );
550 /***********************************************************************
551 * EVENT_SelectionRequest_STRING
552 * Service a STRING selection request event
554 static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
555 Atom target, Atom rprop )
557 static UINT text_cp = (UINT)-1;
566 if(text_cp == (UINT)-1)
571 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
574 DWORD type, count = sizeof(buf);
575 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
582 * Map the requested X selection property type atom name to a
583 * windows clipboard format ID.
585 itemFmtName = TSXGetAtomName(display, target);
586 TRACE("Request for %s (wFormat=%x %s)\n",
587 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT, NULL, 0));
588 TSXFree(itemFmtName);
590 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
593 uni_text = GlobalLock(hUnicodeText);
597 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
598 text = HeapAlloc(GetProcessHeap(), 0, size);
601 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
603 /* remove carriage returns */
605 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
606 if(lpstr == NULL) return None;
607 for(i=0,j=0; i < size && text[i]; i++ )
609 if( text[i] == '\r' &&
610 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
611 lpstr[j++] = text[i];
615 /* Update the X property */
616 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
617 xRc = TSXChangeProperty(display, requestor, rprop,
618 XA_STRING, 8, PropModeReplace,
620 TRACE("(Rc=%d)\n", xRc);
622 GlobalUnlock(hUnicodeText);
623 HeapFree(GetProcessHeap(), 0, text);
624 HeapFree( GetProcessHeap(), 0, lpstr );
629 /***********************************************************************
630 * EVENT_SelectionRequest_PIXMAP
631 * Service a PIXMAP selection request event
633 static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
634 Atom target, Atom rprop )
636 HANDLE hClipData = 0;
642 XSetWindowAttributes win_attr;
643 XWindowAttributes win_attr_src;
647 * Map the requested X selection property type atom name to a
648 * windows clipboard format ID.
650 itemFmtName = TSXGetAtomName(display, target);
651 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
652 TRACE("Request for %s (wFormat=%x %s)\n",
653 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0 ));
654 TSXFree(itemFmtName);
656 hClipData = GetClipboardData(wFormat);
659 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
660 rprop = None; /* Fail the request */
664 if (wFormat == CF_DIB)
666 HWND hwnd = GetOpenClipboardWindow();
667 HDC hdc = GetDC(hwnd);
669 /* For convert from packed DIB to Pixmap */
670 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
672 ReleaseDC(hwnd, hdc);
674 else if (wFormat == CF_BITMAP)
676 HWND hwnd = GetOpenClipboardWindow();
677 HDC hdc = GetDC(hwnd);
679 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
681 ReleaseDC(hwnd, hdc);
685 FIXME("%s to PIXMAP conversion not yet implemented!\n",
686 CLIPBOARD_GetFormatName(wFormat, NULL, 0));
691 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
692 TSXGetAtomName(display, rprop), (long)requestor,
693 TSXGetAtomName(display, target), pixmap);
695 /* Store the Pixmap handle in the property */
696 xRc = TSXChangeProperty(display, requestor, rprop, target,
698 (unsigned char *)&pixmap, 1);
699 TRACE("(Rc=%d)\n", xRc);
701 /* Enable the code below if you want to handle destroying Pixmap resources
702 * in response to property notify events. Clients like XPaint don't
703 * appear to be duplicating Pixmaps so they don't like us deleting,
704 * the resource in response to the property being deleted.
707 /* Express interest in property notify events so that we can delete the
708 * pixmap when the client deletes the property atom.
710 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
711 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
713 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
714 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
716 /* Register the Pixmap we created with the request property Atom.
717 * When this property is destroyed we also destroy the Pixmap in
718 * response to the PropertyNotify event.
720 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
728 /***********************************************************************
729 * EVENT_SelectionRequest_WCF
730 * Service a Wine Clipboard Format selection request event.
731 * For <WCF>* data types we simply copy the data to X without conversion.
733 static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
734 Atom target, Atom rprop )
736 HANDLE hClipData = 0;
745 * Map the requested X selection property type atom name to a
746 * windows clipboard format ID.
748 itemFmtName = TSXGetAtomName(display, target);
749 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
750 TRACE("Request for %s (wFormat=%x %s)\n",
751 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat, NULL, 0));
752 TSXFree(itemFmtName);
754 hClipData = GetClipboardData(wFormat);
756 bemf = wFormat == CF_METAFILEPICT || wFormat == CF_ENHMETAFILE;
758 hClipData = X11DRV_CLIPBOARD_SerializeMetafile(wFormat, hClipData, sizeof(hClipData), TRUE);
760 if( hClipData && (lpClipData = GlobalLock(hClipData)) )
762 cBytes = GlobalSize(hClipData);
764 TRACE("\tUpdating property %s, %d bytes...\n",
765 TSXGetAtomName(display, rprop), cBytes);
767 xRc = TSXChangeProperty(display, requestor, rprop,
768 target, 8, PropModeReplace,
769 (unsigned char *)lpClipData, cBytes);
770 TRACE("(Rc=%d)\n", xRc);
772 GlobalUnlock(hClipData);
776 TRACE("\tCould not retrieve native format!\n");
777 rprop = None; /* Fail the request */
780 if (bemf) /* We must free serialized metafile data */
781 GlobalFree(hClipData);
787 /***********************************************************************
788 * EVENT_SelectionRequest_MULTIPLE
789 * Service a MULTIPLE selection request event
790 * rprop contains a list of (target,property) atom pairs.
791 * The first atom names a target and the second names a property.
792 * The effect is as if we have received a sequence of SelectionRequest events
793 * (one for each atom pair) except that:
794 * 1. We reply with a SelectionNotify only when all the requested conversions
795 * have been performed.
796 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
797 * we replace the atom in the property by None.
799 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
801 Display *display = pevent->display;
803 Atom atype=AnyPropertyType;
805 unsigned long remain;
806 Atom* targetPropList=NULL;
807 unsigned long cTargetPropList = 0;
808 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
810 /* If the specified property is None the requestor is an obsolete client.
811 * We support these by using the specified target atom as the reply property.
813 rprop = pevent->property;
815 rprop = pevent->target;
819 /* Read the MULTIPLE property contents. This should contain a list of
820 * (target,property) atom pairs.
822 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
823 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
824 &cTargetPropList, &remain,
825 (unsigned char**)&targetPropList) != Success)
826 TRACE("\tCouldn't read MULTIPLE property\n");
829 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
830 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
833 * Make sure we got what we expect.
834 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
835 * in a MULTIPLE selection request should be of type ATOM_PAIR.
836 * However some X apps(such as XPaint) are not compliant with this and return
837 * a user defined atom in atype when XGetWindowProperty is called.
838 * The data *is* an atom pair but is not denoted as such.
840 if(aformat == 32 /* atype == xAtomPair */ )
844 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
845 * for each (target,property) pair */
847 for (i = 0; i < cTargetPropList; i+=2)
849 char *targetName = TSXGetAtomName(display, targetPropList[i]);
850 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
851 XSelectionRequestEvent event;
853 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
854 i/2, targetName, propName);
858 /* We must have a non "None" property to service a MULTIPLE target atom */
859 if ( !targetPropList[i+1] )
861 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
865 /* Set up an XSelectionRequestEvent for this (target,property) pair */
866 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
867 event.target = targetPropList[i];
868 event.property = targetPropList[i+1];
870 /* Fire a SelectionRequest, informing the handler that we are processing
871 * a MULTIPLE selection request event.
873 EVENT_SelectionRequest( hWnd, &event, TRUE );
877 /* Free the list of targets/properties */
878 TSXFree(targetPropList);
886 /***********************************************************************
887 * EVENT_SelectionRequest
888 * Process an event selection request event.
889 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
890 * recursively while servicing a "MULTIPLE" selection target.
892 * Note: We only receive this event when WINE owns the X selection
894 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
896 Display *display = event->display;
897 XSelectionEvent result;
899 Window request = event->requestor;
900 BOOL couldOpen = FALSE;
901 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
902 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
903 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
906 * We can only handle the selection request if :
907 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
908 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
909 * since this has been already done.
913 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
914 || !(couldOpen = OpenClipboard(hWnd)) )
918 /* If the specified property is None the requestor is an obsolete client.
919 * We support these by using the specified target atom as the reply property.
921 rprop = event->property;
923 rprop = event->target;
925 if(event->target == xaTargets) /* Return a list of all supported targets */
927 /* TARGETS selection request */
928 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
930 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
932 /* MULTIPLE selection request */
933 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
935 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
937 /* XA_STRING selection request */
938 rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
940 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
942 /* XA_PIXMAP selection request */
943 rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
945 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
947 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
948 rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
950 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
952 /* All <WCF> selection requests */
953 rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
956 rprop = None; /* Don't support this format */
959 /* close clipboard only if we opened before */
960 if(couldOpen) CloseClipboard();
963 TRACE("\tRequest ignored\n");
966 * SelectionNotify should be sent only at the end of a MULTIPLE request
970 result.type = SelectionNotify;
971 result.display = display;
972 result.requestor = request;
973 result.selection = event->selection;
974 result.property = rprop;
975 result.target = event->target;
976 result.time = event->time;
977 TRACE("Sending SelectionNotify event...\n");
978 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
982 /***********************************************************************
983 * EVENT_SelectionClear
985 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
987 Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
989 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
990 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
993 /***********************************************************************
994 * EVENT_PropertyNotify
995 * We use this to release resources like Pixmaps when a selection
996 * client no longer needs them.
998 static void EVENT_PropertyNotify( XPropertyEvent *event )
1000 /* Check if we have any resources to free */
1001 TRACE("Received PropertyNotify event: \n");
1003 switch(event->state)
1005 case PropertyDelete:
1007 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1008 TSXGetAtomName(event->display, event->atom), (long)event->window);
1010 if (X11DRV_IsSelectionOwner())
1011 X11DRV_CLIPBOARD_FreeResources( event->atom );
1015 case PropertyNewValue:
1017 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1018 TSXGetAtomName(event->display, event->atom), (long)event->window);
1027 /**********************************************************************
1028 * EVENT_DropFromOffix
1030 * don't know if it still works (last Changlog is from 96/11/04)
1032 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1034 unsigned long data_length;
1035 unsigned long aux_long;
1036 unsigned char* p_data = NULL;
1047 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO16));
1048 LPDRAGINFO16 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
1049 SEGPTR spDragInfo = K32WOWGlobalLock16(hDragInfo);
1050 Window w_aux_root, w_aux_child;
1053 if( !lpDragInfo || !spDragInfo ) return;
1055 pWnd = WIN_FindWndPtr(hWnd);
1057 TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1058 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1059 (unsigned int*)&aux_long);
1061 lpDragInfo->hScope = HWND_16(hWnd);
1062 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1064 /* find out drop point and drop window */
1065 if( x < 0 || y < 0 ||
1066 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1067 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1068 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1071 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1072 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1074 WIN_ReleaseWndPtr(pWnd);
1076 GlobalFree16( hDragInfo );
1078 if (!bAccept) return;
1080 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1081 dndSelection, 0, 65535, FALSE,
1082 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1083 &data_length, &aux_long, &p_data);
1085 if( !aux_long && p_data) /* don't bother if > 64K */
1087 signed char *p = (signed char*) p_data;
1091 while( *p ) /* calculate buffer size */
1094 if((u.i = *p) != -1 )
1096 INT len = GetShortPathNameA( p, NULL, 0 );
1097 if (len) aux_long += len + 1;
1102 if( aux_long && aux_long < 65535 )
1107 aux_long += sizeof(DROPFILES) + 1;
1108 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1109 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1113 WND *pDropWnd = WIN_FindWndPtr( HWND_32(lpDragInfo->hScope) );
1114 lpDrop->pFiles = sizeof(DROPFILES);
1118 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1119 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1120 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1121 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1122 lpDrop->fWide = FALSE;
1123 WIN_ReleaseWndPtr(pDropWnd);
1124 p_drop = (char *)(lpDrop + 1);
1128 if( *p != -1 ) /* use only "good" entries */
1130 GetShortPathNameA( p, p_drop, 65535 );
1131 p_drop += strlen( p_drop ) + 1;
1136 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1140 if( p_data ) TSXFree(p_data);
1143 /**********************************************************************
1146 * drop items are separated by \n
1147 * each item is prefixed by its mime type
1149 * event->data.l[3], event->data.l[4] contains drop x,y position
1151 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1153 unsigned long data_length;
1154 unsigned long aux_long, drop_len = 0;
1155 unsigned char *p_data = NULL; /* property data */
1156 char *p_drop = NULL;
1167 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1169 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1170 dndSelection, 0, 65535, FALSE,
1171 AnyPropertyType, &u.atom_aux, &u.i,
1172 &data_length, &aux_long, &p_data);
1174 WARN("property too large, truncated!\n");
1175 TRACE("urls=%s\n", p_data);
1177 if( !aux_long && p_data) { /* don't bother if > 64K */
1178 /* calculate length */
1180 next = strchr(p, '\n');
1183 if (strncmp(p,"file:",5) == 0 ) {
1184 INT len = GetShortPathNameA( p+5, NULL, 0 );
1185 if (len) drop_len += len + 1;
1190 next = strchr(p, '\n');
1196 if( drop_len && drop_len < 65535 ) {
1197 TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1198 &x, &y, &u.i, &u.i, &u.i);
1200 drop_len += sizeof(DROPFILES) + 1;
1201 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1202 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1205 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1206 lpDrop->pFiles = sizeof(DROPFILES);
1207 lpDrop->pt.x = (INT)x;
1208 lpDrop->pt.y = (INT)y;
1210 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1211 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1212 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1213 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1214 lpDrop->fWide = FALSE;
1215 p_drop = (char*)(lpDrop + 1);
1216 WIN_ReleaseWndPtr(pDropWnd);
1219 /* create message content */
1222 next = strchr(p, '\n');
1225 if (strncmp(p,"file:",5) == 0 ) {
1226 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1228 TRACE("drop file %s as %s\n", p+5, p_drop);
1231 WARN("can't convert file %s to dos name \n", p+5);
1234 WARN("unknown mime type %s\n", p);
1239 next = strchr(p, '\n');
1246 GlobalUnlock(hDrop);
1247 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1250 if( p_data ) TSXFree(p_data);
1254 /**********************************************************************
1255 * EVENT_ClientMessage
1257 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1259 if (event->message_type != None && event->format == 32) {
1260 if ((event->message_type == wmProtocols) &&
1261 (((Atom) event->data.l[0]) == wmDeleteWindow))
1263 /* Ignore the delete window request if the window has been disabled */
1264 if (!(GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED))
1265 PostMessageA( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1267 else if (event->message_type == dndProtocol)
1269 /* query window (drag&drop event contains only drag window) */
1271 int root_x, root_y, child_x, child_y;
1273 TSXQueryPointer( event->display, root_window, &root, &child,
1274 &root_x, &root_y, &child_x, &child_y, &u);
1275 if (TSXFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) return;
1276 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1277 EVENT_DropFromOffiX(hWnd, event);
1278 else if (event->data.l[0] == DndURL)
1279 EVENT_DropURLs(hWnd, event);
1283 /* enable this if you want to see the message */
1284 unsigned char* p_data = NULL;
1290 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1291 dndSelection, 0, 65535, FALSE,
1292 AnyPropertyType, &u.atom, &u.i,
1293 &u.l, &u.l, &p_data);
1294 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1295 event->message_type, event->data.l[0], event->data.l[1],
1296 event->data.l[2], event->data.l[3], event->data.l[4],
1299 TRACE("unrecognized ClientMessage\n" );
1305 /**********************************************************************
1306 * X11DRV_EVENT_SetInputMethod
1308 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1310 INPUT_TYPE prev = current_input_type;
1312 /* Flag not used yet */
1313 in_transition = FALSE;
1314 current_input_type = type;
1319 #ifdef HAVE_LIBXXF86DGA2
1320 /**********************************************************************
1321 * X11DRV_EVENT_SetDGAStatus
1323 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1325 if (event_base < 0) {
1331 DGAMotionEventType = event_base + MotionNotify;
1332 DGAButtonPressEventType = event_base + ButtonPress;
1333 DGAButtonReleaseEventType = event_base + ButtonRelease;
1334 DGAKeyPressEventType = event_base + KeyPress;
1335 DGAKeyReleaseEventType = event_base + KeyRelease;