4 * Copyright 1993 Alexandre Julliard
10 #include <X11/Xatom.h>
11 #include <X11/keysym.h>
14 #include "ts_xresource.h"
16 #ifdef HAVE_LIBXXF86DGA2
17 #include "ts_xf86dga2.h"
22 #include "wine/winuser16.h"
23 #include "shlobj.h" /* DROPFILES */
25 #include "clipboard.h"
27 #include "debugtools.h"
39 DEFAULT_DEBUG_CHANNEL(event);
40 DECLARE_DEBUG_CHANNEL(win);
42 /* X context to associate a hwnd to an X window */
43 extern XContext winContext;
45 extern Atom wmProtocols;
46 extern Atom wmDeleteWindow;
47 extern Atom dndProtocol;
48 extern Atom dndSelection;
50 extern void X11DRV_KEYBOARD_UpdateState(void);
51 extern void X11DRV_KEYBOARD_HandleEvent( XKeyEvent *event, int x, int y );
53 #define NB_BUTTONS 5 /* Windows can handle 3 buttons and the wheel too */
56 #define DndNotDnd -1 /* OffiX drag&drop */
68 #define DndURL 128 /* KDE drag&drop */
70 /* The last X window which had the focus */
71 static Window glastXFocusWin = 0;
73 static const char * const event_names[] =
75 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
76 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
77 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
78 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
79 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
80 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
81 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
82 "ClientMessage", "MappingNotify"
86 static void EVENT_ProcessEvent( XEvent *event );
87 static BOOL X11DRV_CheckFocus(void);
90 static void EVENT_Key( HWND hWnd, XKeyEvent *event );
91 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event );
92 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event );
93 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event );
94 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
95 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
96 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
97 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
98 static void EVENT_PropertyNotify( XPropertyEvent *event );
99 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
100 static void EVENT_MappingNotify( XMappingEvent *event );
102 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
103 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
104 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
105 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
107 #ifdef HAVE_LIBXXF86DGA2
108 static int DGAMotionEventType;
109 static int DGAButtonPressEventType;
110 static int DGAButtonReleaseEventType;
111 static int DGAKeyPressEventType;
112 static int DGAKeyReleaseEventType;
114 static BOOL DGAUsed = FALSE;
115 static HWND DGAhwnd = 0;
117 static void EVENT_DGAMotionEvent( XDGAMotionEvent *event );
118 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent *event );
119 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent *event );
122 /* Static used for the current input method */
123 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
124 static BOOL in_transition = FALSE; /* This is not used as for today */
127 /***********************************************************************
130 static int process_events( struct x11drv_thread_data *data )
136 while ( XPending( data->display ) )
138 XNextEvent( data->display, &event );
140 EVENT_ProcessEvent( &event );
149 /***********************************************************************
150 * MsgWaitForMultipleObjectsEx (X11DRV.@)
152 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
153 DWORD timeout, DWORD mask, DWORD flags )
155 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
157 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
159 if (!data || data->process_event_count)
160 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
161 timeout, flags & MWMO_ALERTABLE );
163 for (i = 0; i < count; i++) new_handles[i] = handles[i];
164 new_handles[count] = data->display_fd;
167 XFlush( gdi_display );
168 XFlush( data->display );
171 data->process_event_count++;
172 if (process_events( data )) ret = count;
175 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
176 timeout, flags & MWMO_ALERTABLE );
177 if (ret == count) process_events( data );
179 data->process_event_count--;
184 /***********************************************************************
187 * Process an X event.
189 static void EVENT_ProcessEvent( XEvent *event )
192 Display *display = event->xany.display;
194 TRACE( "called.\n" );
198 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
199 FIXME("Got SelectionNotify - must not happen!\n");
202 /* We get all these because of StructureNotifyMask.
203 This check is placed here to avoid getting error messages below,
204 as X might send some of these even for windows that have already
206 case CirculateNotify:
214 #ifdef HAVE_LIBXXF86DGA2
216 if (event->type == DGAMotionEventType) {
217 TRACE("DGAMotionEvent received.\n");
218 EVENT_DGAMotionEvent((XDGAMotionEvent *) event);
221 if (event->type == DGAButtonPressEventType) {
222 TRACE("DGAButtonPressEvent received.\n");
223 EVENT_DGAButtonPressEvent((XDGAButtonEvent *) event);
226 if (event->type == DGAButtonReleaseEventType) {
227 TRACE("DGAButtonReleaseEvent received.\n");
228 EVENT_DGAButtonReleaseEvent((XDGAButtonEvent *) event);
231 if ((event->type == DGAKeyPressEventType) ||
232 (event->type == DGAKeyReleaseEventType)) {
233 /* Fill a XKeyEvent to send to EVENT_Key */
236 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
238 TRACE("DGAKeyPress/ReleaseEvent received.\n");
241 if (evt->type == DGAKeyReleaseEventType)
242 ke.type = KeyRelease;
245 ke.serial = evt->serial;
246 ke.send_event = FALSE;
247 ke.display = evt->display;
256 ke.state = evt->state;
257 ke.keycode = evt->keycode;
258 ke.same_screen = TRUE;
260 X11DRV_KEYBOARD_HandleEvent(&ke,pt.x,pt.y);
266 if (TSXFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
267 hWnd = 0; /* Not for a registered window */
269 if ( !hWnd && event->xany.window != root_window
270 && event->type != PropertyNotify
271 && event->type != MappingNotify)
272 WARN( "Got event %s for unknown Window %08lx\n",
273 event_names[event->type], event->xany.window );
275 TRACE("Got event %s for hwnd %04x\n",
276 event_names[event->type], hWnd );
282 EVENT_Key( hWnd, (XKeyEvent*)event );
286 EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
290 EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
294 EVENT_MotionNotify( hWnd, (XMotionEvent*)event );
298 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
302 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
306 X11DRV_Expose( hWnd, &event->xexpose );
309 case ConfigureNotify:
311 X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
314 case SelectionRequest:
316 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
321 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
325 EVENT_PropertyNotify( (XPropertyEvent *)event );
330 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
337 X11DRV_MapNotify( hWnd, (XMapEvent *)event );
341 X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
345 EVENT_MappingNotify( (XMappingEvent *) event );
349 WARN("Unprocessed event %s for hwnd %04x\n",
350 event_names[event->type], hWnd );
353 TRACE( "returns.\n" );
356 /***********************************************************************
357 * X11DRV_EVENT_XStateToKeyState
359 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
360 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
362 WORD X11DRV_EVENT_XStateToKeyState( int state )
366 if (state & Button1Mask) kstate |= MK_LBUTTON;
367 if (state & Button2Mask) kstate |= MK_MBUTTON;
368 if (state & Button3Mask) kstate |= MK_RBUTTON;
369 if (state & ShiftMask) kstate |= MK_SHIFT;
370 if (state & ControlMask) kstate |= MK_CONTROL;
375 /* get the coordinates of a mouse event */
376 static void get_coords( HWND *hwnd, Window window, int x, int y, POINT *pt )
378 struct x11drv_win_data *data;
381 if (!(win = WIN_FindWndPtr( *hwnd ))) return;
382 data = win->pDriverData;
384 if (window == data->whole_window)
386 x -= data->client_rect.left;
387 y -= data->client_rect.top;
389 while (win->parent && win->parent->hwndSelf != GetDesktopWindow())
391 x += win->rectClient.left;
392 y += win->rectClient.top;
393 WIN_UpdateWndPtr( &win, win->parent );
395 pt->x = x + win->rectClient.left;
396 pt->y = y + win->rectClient.top;
397 *hwnd = win->hwndSelf;
398 WIN_ReleaseWndPtr( win );
402 /***********************************************************************
405 * Handle a X key event
407 static void EVENT_Key( HWND hWnd, XKeyEvent *event )
410 get_coords( &hWnd, event->window, event->x, event->y, &pt );
411 X11DRV_KEYBOARD_HandleEvent( event, pt.x, pt.y );
415 /***********************************************************************
418 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event )
422 if (current_input_type == X11DRV_INPUT_ABSOLUTE)
424 get_coords( &hWnd, event->window, event->x, event->y, &pt );
425 X11DRV_SendEvent( MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, pt.x, pt.y,
426 X11DRV_EVENT_XStateToKeyState( event->state ), 0,
427 event->time - X11DRV_server_startticks, hWnd);
431 X11DRV_SendEvent( MOUSEEVENTF_MOVE,
432 event->x_root, event->y_root,
433 X11DRV_EVENT_XStateToKeyState( event->state ), 0,
434 event->time - X11DRV_server_startticks, hWnd);
439 /***********************************************************************
442 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event )
444 static const WORD statusCodes[NB_BUTTONS] = { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN,
445 MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_WHEEL,
447 int buttonNum = event->button - 1;
448 WORD keystate, wData = 0;
451 if (buttonNum >= NB_BUTTONS) return;
453 get_coords( &hWnd, event->window, event->x, event->y, &pt );
455 /* Get the compatible keystate */
456 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
459 * Make sure that the state of the button that was just
465 keystate |= MK_LBUTTON;
468 keystate |= MK_MBUTTON;
471 keystate |= MK_RBUTTON;
477 wData = -WHEEL_DELTA;
481 X11DRV_SendEvent( statusCodes[buttonNum], pt.x, pt.y,
482 keystate, wData, event->time - X11DRV_server_startticks, hWnd);
486 /***********************************************************************
487 * EVENT_ButtonRelease
489 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event )
491 static const WORD statusCodes[NB_BUTTONS] = { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP,
492 MOUSEEVENTF_RIGHTUP, 0, 0 };
493 int buttonNum = event->button - 1;
497 if (buttonNum >= NB_BUTTONS) return;
499 get_coords( &hWnd, event->window, event->x, event->y, &pt );
501 /* Get the compatible keystate */
502 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
505 * Make sure that the state of the button that was just
511 keystate &= ~MK_LBUTTON;
514 keystate &= ~MK_MBUTTON;
517 keystate &= ~MK_RBUTTON;
522 X11DRV_SendEvent( statusCodes[buttonNum], pt.x, pt.y,
523 keystate, 0, event->time - X11DRV_server_startticks, hWnd);
527 /**********************************************************************
530 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
533 XWindowAttributes win_attr;
538 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
540 /* If the window has been disabled and we are in managed mode,
541 * revert the X focus back to the last focus window. This is to disallow
542 * the window manager from switching focus away while the app is
545 if ( Options.managed && bIsDisabled && glastXFocusWin)
547 /* Change focus only if saved focus window is registered and viewable */
549 if (XFindContext( event->display, glastXFocusWin, winContext,
550 (char **)&pWndLastFocus ) == 0 )
552 if (XGetWindowAttributes( event->display, glastXFocusWin, &win_attr ) &&
553 (win_attr.map_state == IsViewable) )
555 XSetInputFocus( event->display, glastXFocusWin, RevertToParent, CurrentTime );
563 if (event->detail != NotifyPointer && hWnd != GetForegroundWindow())
565 SetForegroundWindow( hWnd );
566 X11DRV_KEYBOARD_UpdateState();
571 /**********************************************************************
574 * Note: only top-level override-redirect windows get FocusOut events.
576 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
578 /* Save the last window which had the focus */
579 glastXFocusWin = event->window;
581 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
583 if (event->detail != NotifyPointer && hWnd == GetForegroundWindow())
585 /* don't reset the foreground window, if the window which is
586 getting the focus is a Wine window */
587 if (!X11DRV_CheckFocus())
589 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
590 /* Abey : 6-Oct-99. Check again if the focus out window is the
591 Foreground window, because in most cases the messages sent
592 above must have already changed the foreground window, in which
593 case we don't have to change the foreground window to 0 */
595 if (hWnd == GetForegroundWindow())
596 SetForegroundWindow( 0 );
601 /**********************************************************************
602 * CheckFocus (X11DRV.@)
604 static BOOL X11DRV_CheckFocus(void)
606 Display *display = thread_display();
611 TSXGetInputFocus(display, &xW, &state);
613 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
619 /***********************************************************************
620 * EVENT_SelectionRequest_TARGETS
621 * Service a TARGETS selection request event
623 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
624 Atom target, Atom rprop )
626 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
630 unsigned long cTargets;
634 TRACE("Request for %s\n", TSXGetAtomName(display, target));
637 * Count the number of items we wish to expose as selection targets.
638 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
640 cTargets = CountClipboardFormats() + 1;
641 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
644 /* Allocate temp buffer */
645 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
646 if(targets == NULL) return None;
648 /* Create TARGETS property list (First item in list is TARGETS itself) */
650 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
651 (wFormat = EnumClipboardFormats( wFormat )); )
653 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
655 /* Scan through what we have so far to avoid duplicates */
658 for (i = 0, bExists = FALSE; i < cTargets; i++)
660 if (targets[i] == prop)
668 targets[cTargets++] = prop;
670 /* Add PIXMAP prop for bitmaps additionally */
671 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
674 targets[cTargets++] = XA_PIXMAP;
684 for ( i = 0; i < cTargets; i++)
688 char *itemFmtName = TSXGetAtomName(display, targets[i]);
689 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
690 TSXFree(itemFmtName);
695 /* Update the X property */
696 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
698 /* We may want to consider setting the type to xaTargets instead,
699 * in case some apps expect this instead of XA_ATOM */
700 xRc = TSXChangeProperty(display, requestor, rprop,
701 XA_ATOM, 32, PropModeReplace,
702 (unsigned char *)targets, cTargets);
703 TRACE("(Rc=%d)\n", xRc);
705 HeapFree( GetProcessHeap(), 0, targets );
711 /***********************************************************************
712 * EVENT_SelectionRequest_STRING
713 * Service a STRING selection request event
715 static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
716 Atom target, Atom rprop )
718 static UINT text_cp = (UINT)-1;
727 if(text_cp == (UINT)-1)
732 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
735 DWORD type, count = sizeof(buf);
736 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
743 * Map the requested X selection property type atom name to a
744 * windows clipboard format ID.
746 itemFmtName = TSXGetAtomName(display, target);
747 TRACE("Request for %s (wFormat=%x %s)\n",
748 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT));
749 TSXFree(itemFmtName);
751 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
754 uni_text = GlobalLock(hUnicodeText);
758 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
759 text = HeapAlloc(GetProcessHeap(), 0, size);
762 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
764 /* remove carriage returns */
766 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
767 if(lpstr == NULL) return None;
768 for(i=0,j=0; i < size && text[i]; i++ )
770 if( text[i] == '\r' &&
771 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
772 lpstr[j++] = text[i];
776 /* Update the X property */
777 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
778 xRc = TSXChangeProperty(display, requestor, rprop,
779 XA_STRING, 8, PropModeReplace,
781 TRACE("(Rc=%d)\n", xRc);
783 GlobalUnlock(hUnicodeText);
784 HeapFree(GetProcessHeap(), 0, text);
785 HeapFree( GetProcessHeap(), 0, lpstr );
790 /***********************************************************************
791 * EVENT_SelectionRequest_PIXMAP
792 * Service a PIXMAP selection request event
794 static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
795 Atom target, Atom rprop )
797 HANDLE hClipData = 0;
803 XSetWindowAttributes win_attr;
804 XWindowAttributes win_attr_src;
808 * Map the requested X selection property type atom name to a
809 * windows clipboard format ID.
811 itemFmtName = TSXGetAtomName(display, target);
812 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
813 TRACE("Request for %s (wFormat=%x %s)\n",
814 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
815 TSXFree(itemFmtName);
817 hClipData = GetClipboardData(wFormat);
820 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
821 rprop = None; /* Fail the request */
825 if (wFormat == CF_DIB)
827 HWND hwnd = GetOpenClipboardWindow();
828 HDC hdc = GetDC(hwnd);
830 /* For convert from packed DIB to Pixmap */
831 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
833 ReleaseDC(hdc, hwnd);
835 else if (wFormat == CF_BITMAP)
837 HWND hwnd = GetOpenClipboardWindow();
838 HDC hdc = GetDC(hwnd);
840 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
842 ReleaseDC(hdc, hwnd);
846 FIXME("%s to PIXMAP conversion not yet implemented!\n",
847 CLIPBOARD_GetFormatName(wFormat));
852 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
853 TSXGetAtomName(display, rprop), (long)requestor,
854 TSXGetAtomName(display, target), pixmap);
856 /* Store the Pixmap handle in the property */
857 xRc = TSXChangeProperty(display, requestor, rprop, target,
859 (unsigned char *)&pixmap, 1);
860 TRACE("(Rc=%d)\n", xRc);
862 /* Enable the code below if you want to handle destroying Pixmap resources
863 * in response to property notify events. Clients like XPaint don't
864 * appear to be duplicating Pixmaps so they don't like us deleting,
865 * the resource in response to the property being deleted.
868 /* Express interest in property notify events so that we can delete the
869 * pixmap when the client deletes the property atom.
871 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
872 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
874 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
875 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
877 /* Register the Pixmap we created with the request property Atom.
878 * When this property is destroyed we also destroy the Pixmap in
879 * response to the PropertyNotify event.
881 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
889 /***********************************************************************
890 * EVENT_SelectionRequest_WCF
891 * Service a Wine Clipboard Format selection request event.
892 * For <WCF>* data types we simply copy the data to X without conversion.
894 static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
895 Atom target, Atom rprop )
897 HANDLE hClipData = 0;
905 * Map the requested X selection property type atom name to a
906 * windows clipboard format ID.
908 itemFmtName = TSXGetAtomName(display, target);
909 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
910 TRACE("Request for %s (wFormat=%x %s)\n",
911 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
912 TSXFree(itemFmtName);
914 hClipData = GetClipboardData(wFormat);
916 if( hClipData && (lpClipData = GlobalLock(hClipData)) )
918 cBytes = GlobalSize(hClipData);
920 TRACE("\tUpdating property %s, %d bytes...\n",
921 TSXGetAtomName(display, rprop), cBytes);
923 xRc = TSXChangeProperty(display, requestor, rprop,
924 target, 8, PropModeReplace,
925 (unsigned char *)lpClipData, cBytes);
926 TRACE("(Rc=%d)\n", xRc);
928 GlobalUnlock(hClipData);
932 TRACE("\tCould not retrieve native format!\n");
933 rprop = None; /* Fail the request */
940 /***********************************************************************
941 * EVENT_SelectionRequest_MULTIPLE
942 * Service a MULTIPLE selection request event
943 * rprop contains a list of (target,property) atom pairs.
944 * The first atom names a target and the second names a property.
945 * The effect is as if we have received a sequence of SelectionRequest events
946 * (one for each atom pair) except that:
947 * 1. We reply with a SelectionNotify only when all the requested conversions
948 * have been performed.
949 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
950 * we replace the atom in the property by None.
952 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
954 Display *display = pevent->display;
956 Atom atype=AnyPropertyType;
958 unsigned long remain;
959 Atom* targetPropList=NULL;
960 unsigned long cTargetPropList = 0;
961 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
963 /* If the specified property is None the requestor is an obsolete client.
964 * We support these by using the specified target atom as the reply property.
966 rprop = pevent->property;
968 rprop = pevent->target;
972 /* Read the MULTIPLE property contents. This should contain a list of
973 * (target,property) atom pairs.
975 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
976 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
977 &cTargetPropList, &remain,
978 (unsigned char**)&targetPropList) != Success)
979 TRACE("\tCouldn't read MULTIPLE property\n");
982 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
983 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
986 * Make sure we got what we expect.
987 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
988 * in a MULTIPLE selection request should be of type ATOM_PAIR.
989 * However some X apps(such as XPaint) are not compliant with this and return
990 * a user defined atom in atype when XGetWindowProperty is called.
991 * The data *is* an atom pair but is not denoted as such.
993 if(aformat == 32 /* atype == xAtomPair */ )
997 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
998 * for each (target,property) pair */
1000 for (i = 0; i < cTargetPropList; i+=2)
1002 char *targetName = TSXGetAtomName(display, targetPropList[i]);
1003 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
1004 XSelectionRequestEvent event;
1006 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
1007 i/2, targetName, propName);
1008 TSXFree(targetName);
1011 /* We must have a non "None" property to service a MULTIPLE target atom */
1012 if ( !targetPropList[i+1] )
1014 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
1018 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1019 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
1020 event.target = targetPropList[i];
1021 event.property = targetPropList[i+1];
1023 /* Fire a SelectionRequest, informing the handler that we are processing
1024 * a MULTIPLE selection request event.
1026 EVENT_SelectionRequest( hWnd, &event, TRUE );
1030 /* Free the list of targets/properties */
1031 TSXFree(targetPropList);
1039 /***********************************************************************
1040 * EVENT_SelectionRequest
1041 * Process an event selection request event.
1042 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1043 * recursively while servicing a "MULTIPLE" selection target.
1045 * Note: We only receive this event when WINE owns the X selection
1047 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1049 Display *display = event->display;
1050 XSelectionEvent result;
1052 Window request = event->requestor;
1053 BOOL couldOpen = FALSE;
1054 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1055 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
1056 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1059 * We can only handle the selection request if :
1060 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1061 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1062 * since this has been already done.
1066 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1067 || !(couldOpen = OpenClipboard(hWnd)) )
1071 /* If the specified property is None the requestor is an obsolete client.
1072 * We support these by using the specified target atom as the reply property.
1074 rprop = event->property;
1076 rprop = event->target;
1078 if(event->target == xaTargets) /* Return a list of all supported targets */
1080 /* TARGETS selection request */
1081 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
1083 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1085 /* MULTIPLE selection request */
1086 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1088 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1090 /* XA_STRING selection request */
1091 rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
1093 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1095 /* XA_PIXMAP selection request */
1096 rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
1098 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1100 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1101 rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
1103 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1105 /* All <WCF> selection requests */
1106 rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
1109 rprop = None; /* Don't support this format */
1112 /* close clipboard only if we opened before */
1113 if(couldOpen) CloseClipboard();
1116 TRACE("\tRequest ignored\n");
1119 * SelectionNotify should be sent only at the end of a MULTIPLE request
1123 result.type = SelectionNotify;
1124 result.display = display;
1125 result.requestor = request;
1126 result.selection = event->selection;
1127 result.property = rprop;
1128 result.target = event->target;
1129 result.time = event->time;
1130 TRACE("Sending SelectionNotify event...\n");
1131 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1135 /***********************************************************************
1136 * EVENT_SelectionClear
1138 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1140 Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
1142 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1143 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1146 /***********************************************************************
1147 * EVENT_PropertyNotify
1148 * We use this to release resources like Pixmaps when a selection
1149 * client no longer needs them.
1151 static void EVENT_PropertyNotify( XPropertyEvent *event )
1153 /* Check if we have any resources to free */
1154 TRACE("Received PropertyNotify event: \n");
1156 switch(event->state)
1158 case PropertyDelete:
1160 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1161 TSXGetAtomName(event->display, event->atom), (long)event->window);
1163 if (X11DRV_IsSelectionOwner())
1164 X11DRV_CLIPBOARD_FreeResources( event->atom );
1168 case PropertyNewValue:
1170 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1171 TSXGetAtomName(event->display, event->atom), (long)event->window);
1180 /**********************************************************************
1181 * EVENT_DropFromOffix
1183 * don't know if it still works (last Changlog is from 96/11/04)
1185 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1187 unsigned long data_length;
1188 unsigned long aux_long;
1189 unsigned char* p_data = NULL;
1200 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO16));
1201 LPDRAGINFO16 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
1202 SEGPTR spDragInfo = K32WOWGlobalLock16(hDragInfo);
1203 Window w_aux_root, w_aux_child;
1207 if( !lpDragInfo || !spDragInfo ) return;
1209 pWnd = WIN_FindWndPtr(hWnd);
1211 TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1212 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1213 (unsigned int*)&aux_long);
1215 lpDragInfo->hScope = hWnd;
1216 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1218 /* find out drop point and drop window */
1219 if( x < 0 || y < 0 ||
1220 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1221 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1222 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1225 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1226 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1228 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1229 WIN_ReleaseWndPtr(pWnd);
1231 GlobalFree16( hDragInfo );
1235 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1236 dndSelection, 0, 65535, FALSE,
1237 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1238 &data_length, &aux_long, &p_data);
1240 if( !aux_long && p_data) /* don't bother if > 64K */
1242 signed char *p = (signed char*) p_data;
1246 while( *p ) /* calculate buffer size */
1249 if((u.i = *p) != -1 )
1251 INT len = GetShortPathNameA( p, NULL, 0 );
1252 if (len) aux_long += len + 1;
1257 if( aux_long && aux_long < 65535 )
1262 aux_long += sizeof(DROPFILES) + 1;
1263 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1264 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1268 lpDrop->pFiles = sizeof(DROPFILES);
1272 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1273 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1274 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1275 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1276 lpDrop->fWide = FALSE;
1277 p_drop = (char *)(lpDrop + 1);
1281 if( *p != -1 ) /* use only "good" entries */
1283 GetShortPathNameA( p, p_drop, 65535 );
1284 p_drop += strlen( p_drop ) + 1;
1289 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1293 if( p_data ) TSXFree(p_data);
1295 } /* WS_EX_ACCEPTFILES */
1297 WIN_ReleaseWndPtr(pDropWnd);
1300 /**********************************************************************
1303 * drop items are separated by \n
1304 * each item is prefixed by its mime type
1306 * event->data.l[3], event->data.l[4] contains drop x,y position
1308 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1312 unsigned long data_length;
1313 unsigned long aux_long, drop_len = 0;
1314 unsigned char *p_data = NULL; /* property data */
1315 char *p_drop = NULL;
1326 pWnd = WIN_FindWndPtr(hWnd);
1328 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1330 WIN_ReleaseWndPtr(pWnd);
1333 WIN_ReleaseWndPtr(pWnd);
1335 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1336 dndSelection, 0, 65535, FALSE,
1337 AnyPropertyType, &u.atom_aux, &u.i,
1338 &data_length, &aux_long, &p_data);
1340 WARN("property too large, truncated!\n");
1341 TRACE("urls=%s\n", p_data);
1343 if( !aux_long && p_data) { /* don't bother if > 64K */
1344 /* calculate length */
1346 next = strchr(p, '\n');
1349 if (strncmp(p,"file:",5) == 0 ) {
1350 INT len = GetShortPathNameA( p+5, NULL, 0 );
1351 if (len) drop_len += len + 1;
1356 next = strchr(p, '\n');
1362 if( drop_len && drop_len < 65535 ) {
1363 TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1364 &x, &y, &u.i, &u.i, &u.i);
1366 pDropWnd = WIN_FindWndPtr( hWnd );
1368 drop_len += sizeof(DROPFILES) + 1;
1369 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1370 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1373 lpDrop->pFiles = sizeof(DROPFILES);
1374 lpDrop->pt.x = (INT)x;
1375 lpDrop->pt.y = (INT)y;
1377 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1378 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1379 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1380 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1381 lpDrop->fWide = FALSE;
1382 p_drop = (char*)(lpDrop + 1);
1385 /* create message content */
1388 next = strchr(p, '\n');
1391 if (strncmp(p,"file:",5) == 0 ) {
1392 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1394 TRACE("drop file %s as %s\n", p+5, p_drop);
1397 WARN("can't convert file %s to dos name \n", p+5);
1400 WARN("unknown mime type %s\n", p);
1405 next = strchr(p, '\n');
1412 GlobalUnlock(hDrop);
1413 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1415 WIN_ReleaseWndPtr(pDropWnd);
1417 if( p_data ) TSXFree(p_data);
1421 /**********************************************************************
1422 * EVENT_ClientMessage
1424 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1426 if (event->message_type != None && event->format == 32) {
1427 if ((event->message_type == wmProtocols) &&
1428 (((Atom) event->data.l[0]) == wmDeleteWindow))
1430 /* Ignore the delete window request if the window has been disabled */
1431 if (!(GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED))
1432 PostMessageA( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
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;
1440 TSXQueryPointer( event->display, root_window, &root, &child,
1441 &root_x, &root_y, &child_x, &child_y, &u);
1442 if (TSXFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) return;
1443 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1444 EVENT_DropFromOffiX(hWnd, event);
1445 else if (event->data.l[0] == DndURL)
1446 EVENT_DropURLs(hWnd, event);
1450 /* enable this if you want to see the message */
1451 unsigned char* p_data = NULL;
1457 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1458 dndSelection, 0, 65535, FALSE,
1459 AnyPropertyType, &u.atom, &u.i,
1460 &u.l, &u.l, &p_data);
1461 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1462 event->message_type, event->data.l[0], event->data.l[1],
1463 event->data.l[2], event->data.l[3], event->data.l[4],
1466 TRACE("unrecognized ClientMessage\n" );
1472 /***********************************************************************
1473 * EVENT_MappingNotify
1475 static void EVENT_MappingNotify( XMappingEvent *event )
1477 TSXRefreshKeyboardMapping(event);
1479 /* reinitialize Wine-X11 driver keyboard table */
1480 X11DRV_InitKeyboard();
1484 /**********************************************************************
1485 * X11DRV_EVENT_SetInputMethod
1487 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1489 INPUT_TYPE prev = current_input_type;
1491 /* Flag not used yet */
1492 in_transition = FALSE;
1493 current_input_type = type;
1498 #ifdef HAVE_LIBXXF86DGA2
1499 /**********************************************************************
1500 * X11DRV_EVENT_SetDGAStatus
1502 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1504 if (event_base < 0) {
1510 DGAMotionEventType = event_base + MotionNotify;
1511 DGAButtonPressEventType = event_base + ButtonPress;
1512 DGAButtonReleaseEventType = event_base + ButtonRelease;
1513 DGAKeyPressEventType = event_base + KeyPress;
1514 DGAKeyReleaseEventType = event_base + KeyRelease;
1518 /* DGA2 event handlers */
1519 static void EVENT_DGAMotionEvent( XDGAMotionEvent *event )
1521 X11DRV_SendEvent( MOUSEEVENTF_MOVE, event->dx, event->dy,
1522 X11DRV_EVENT_XStateToKeyState( event->state ), 0,
1523 event->time - X11DRV_server_startticks, DGAhwnd );
1526 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent *event )
1528 static WORD statusCodes[NB_BUTTONS] =
1529 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
1530 int buttonNum = event->button - 1;
1534 if (buttonNum >= NB_BUTTONS) return;
1536 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1541 keystate |= MK_LBUTTON;
1544 keystate |= MK_MBUTTON;
1547 keystate |= MK_RBUTTON;
1551 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, 0,
1552 event->time - X11DRV_server_startticks, DGAhwnd );
1555 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent *event )
1557 static WORD statusCodes[NB_BUTTONS] =
1558 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
1559 int buttonNum = event->button - 1;
1563 if (buttonNum >= NB_BUTTONS) return;
1565 keystate = X11DRV_EVENT_XStateToKeyState( event->state );
1570 keystate &= ~MK_LBUTTON;
1573 keystate &= ~MK_MBUTTON;
1576 keystate &= ~MK_RBUTTON;
1580 X11DRV_SendEvent( statusCodes[buttonNum], 0, 0, keystate, 0,
1581 event->time - X11DRV_server_startticks, DGAhwnd );