4 * Copyright 1993 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define COM_NO_WINDOWS_H
25 #include <X11/Xatom.h>
26 #include <X11/keysym.h>
29 #include <X11/Xresource.h>
30 #include <X11/Xutil.h>
31 #ifdef HAVE_LIBXXF86DGA2
32 #include <X11/extensions/xf86dga.h>
37 #include "wine/winuser16.h"
38 #include "shlobj.h" /* DROPFILES */
40 #include "clipboard.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(event
);
51 /* X context to associate a hwnd to an X window */
52 extern XContext winContext
;
54 extern Atom wmProtocols
;
55 extern Atom wmDeleteWindow
;
56 extern Atom dndProtocol
;
57 extern Atom dndSelection
;
59 #define DndNotDnd -1 /* OffiX drag&drop */
71 #define DndURL 128 /* KDE drag&drop */
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
);
89 static void EVENT_FocusIn( HWND hWnd
, XFocusChangeEvent
*event
);
90 static void EVENT_FocusOut( HWND hWnd
, XFocusChangeEvent
*event
);
91 static void EVENT_SelectionRequest( HWND hWnd
, XSelectionRequestEvent
*event
, BOOL bIsMultiple
);
92 static void EVENT_SelectionClear( HWND hWnd
, XSelectionClearEvent
*event
);
93 static void EVENT_PropertyNotify( XPropertyEvent
*event
);
94 static void EVENT_ClientMessage( HWND hWnd
, XClientMessageEvent
*event
);
96 extern void X11DRV_ButtonPress( HWND hwnd
, XButtonEvent
*event
);
97 extern void X11DRV_ButtonRelease( HWND hwnd
, XButtonEvent
*event
);
98 extern void X11DRV_MotionNotify( HWND hwnd
, XMotionEvent
*event
);
99 extern void X11DRV_EnterNotify( HWND hwnd
, XCrossingEvent
*event
);
100 extern void X11DRV_KeyEvent( HWND hwnd
, XKeyEvent
*event
);
101 extern void X11DRV_KeymapNotify( HWND hwnd
, XKeymapEvent
*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
);
106 extern void X11DRV_MappingNotify( XMappingEvent
*event
);
108 #ifdef HAVE_LIBXXF86DGA2
109 static int DGAMotionEventType
;
110 static int DGAButtonPressEventType
;
111 static int DGAButtonReleaseEventType
;
112 static int DGAKeyPressEventType
;
113 static int DGAKeyReleaseEventType
;
115 static BOOL DGAUsed
= FALSE
;
116 static HWND DGAhwnd
= 0;
118 extern void X11DRV_DGAMotionEvent( HWND hwnd
, XDGAMotionEvent
*event
);
119 extern void X11DRV_DGAButtonPressEvent( HWND hwnd
, XDGAButtonEvent
*event
);
120 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd
, XDGAButtonEvent
*event
);
123 /* Static used for the current input method */
124 static INPUT_TYPE current_input_type
= X11DRV_INPUT_ABSOLUTE
;
125 static BOOL in_transition
= FALSE
; /* This is not used as for today */
128 /***********************************************************************
131 static int process_events( struct x11drv_thread_data
*data
)
137 while ( XPending( data
->display
) )
139 XNextEvent( data
->display
, &event
);
141 EVENT_ProcessEvent( &event
);
150 /***********************************************************************
151 * MsgWaitForMultipleObjectsEx (X11DRV.@)
153 DWORD
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
154 DWORD timeout
, DWORD mask
, DWORD flags
)
156 HANDLE new_handles
[MAXIMUM_WAIT_OBJECTS
+1]; /* FIXME! */
158 struct x11drv_thread_data
*data
= NtCurrentTeb()->driver_data
;
160 if (!data
|| data
->process_event_count
)
161 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
162 timeout
, flags
& MWMO_ALERTABLE
);
164 for (i
= 0; i
< count
; i
++) new_handles
[i
] = handles
[i
];
165 new_handles
[count
] = data
->display_fd
;
168 XFlush( gdi_display
);
169 XFlush( data
->display
);
172 data
->process_event_count
++;
173 if (process_events( data
)) ret
= count
;
176 ret
= WaitForMultipleObjectsEx( count
+1, new_handles
, flags
& MWMO_WAITALL
,
177 timeout
, flags
& MWMO_ALERTABLE
);
178 if (ret
== count
) process_events( data
);
180 data
->process_event_count
--;
185 /***********************************************************************
188 * Process an X event.
190 static void EVENT_ProcessEvent( XEvent
*event
)
193 Display
*display
= event
->xany
.display
;
195 TRACE( "called.\n" );
199 case SelectionNotify
: /* all of these should be caught by XCheckTypedWindowEvent() */
200 FIXME("Got SelectionNotify - must not happen!\n");
203 /* We get all these because of StructureNotifyMask.
204 This check is placed here to avoid getting error messages below,
205 as X might send some of these even for windows that have already
207 case CirculateNotify
:
215 #ifdef HAVE_LIBXXF86DGA2
217 if (event
->type
== DGAMotionEventType
) {
218 TRACE("DGAMotionEvent received.\n");
219 X11DRV_DGAMotionEvent( DGAhwnd
, (XDGAMotionEvent
*)event
);
222 if (event
->type
== DGAButtonPressEventType
) {
223 TRACE("DGAButtonPressEvent received.\n");
224 X11DRV_DGAButtonPressEvent( DGAhwnd
, (XDGAButtonEvent
*)event
);
227 if (event
->type
== DGAButtonReleaseEventType
) {
228 TRACE("DGAButtonReleaseEvent received.\n");
229 X11DRV_DGAButtonReleaseEvent( DGAhwnd
, (XDGAButtonEvent
*)event
);
232 if ((event
->type
== DGAKeyPressEventType
) ||
233 (event
->type
== DGAKeyReleaseEventType
)) {
234 /* Fill a XKeyEvent to send to EVENT_Key */
236 XDGAKeyEvent
*evt
= (XDGAKeyEvent
*) event
;
238 TRACE("DGAKeyPress/ReleaseEvent received.\n");
240 if (evt
->type
== DGAKeyReleaseEventType
)
241 ke
.type
= KeyRelease
;
244 ke
.serial
= evt
->serial
;
245 ke
.send_event
= FALSE
;
246 ke
.display
= evt
->display
;
255 ke
.state
= evt
->state
;
256 ke
.keycode
= evt
->keycode
;
257 ke
.same_screen
= TRUE
;
258 X11DRV_KeyEvent( 0, &ke
);
265 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hWnd
) != 0)
266 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 %p\n",
276 event_names
[event
->type
], hWnd
);
282 /* FIXME: should generate a motion event if event point is different from current pos */
283 X11DRV_KeyEvent( hWnd
, (XKeyEvent
*)event
);
287 X11DRV_ButtonPress( hWnd
, (XButtonEvent
*)event
);
291 X11DRV_ButtonRelease( hWnd
, (XButtonEvent
*)event
);
295 X11DRV_MotionNotify( hWnd
, (XMotionEvent
*)event
);
299 X11DRV_EnterNotify( hWnd
, (XCrossingEvent
*)event
);
303 EVENT_FocusIn( hWnd
, (XFocusChangeEvent
*)event
);
307 EVENT_FocusOut( hWnd
, (XFocusChangeEvent
*)event
);
311 X11DRV_Expose( hWnd
, &event
->xexpose
);
314 case ConfigureNotify
:
316 X11DRV_ConfigureNotify( hWnd
, &event
->xconfigure
);
319 case SelectionRequest
:
321 EVENT_SelectionRequest( hWnd
, (XSelectionRequestEvent
*)event
, FALSE
);
326 EVENT_SelectionClear( hWnd
, (XSelectionClearEvent
*) event
);
330 EVENT_PropertyNotify( (XPropertyEvent
*)event
);
335 EVENT_ClientMessage( hWnd
, (XClientMessageEvent
*) event
);
342 X11DRV_MapNotify( hWnd
, (XMapEvent
*)event
);
346 X11DRV_UnmapNotify( hWnd
, (XUnmapEvent
*)event
);
350 X11DRV_KeymapNotify( hWnd
, (XKeymapEvent
*)event
);
354 X11DRV_MappingNotify( (XMappingEvent
*) event
);
358 WARN("Unprocessed event %s for hwnd %p\n", event_names
[event
->type
], hWnd
);
361 TRACE( "returns.\n" );
365 /*******************************************************************
366 * can_activate_window
368 * Check if we can activate the specified window.
370 inline static BOOL
can_activate_window( HWND hwnd
)
372 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
373 if (!(style
& WS_VISIBLE
)) return FALSE
;
374 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
375 return !(style
& WS_DISABLED
);
379 /**********************************************************************
380 * set_focus_error_handler
382 * Handler for X errors happening during XSetInputFocus call.
384 static int set_focus_error_handler( Display
*display
, XErrorEvent
*event
, void *arg
)
386 return (event
->error_code
== BadMatch
);
390 /**********************************************************************
393 static void set_focus( HWND hwnd
, Time time
)
398 TRACE( "setting foreground window to %p\n", hwnd
);
399 SetForegroundWindow( hwnd
);
402 win
= X11DRV_get_whole_window(focus
);
406 Display
*display
= thread_display();
407 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
408 X11DRV_expect_error( display
, set_focus_error_handler
, NULL
);
409 XSetInputFocus( display
, win
, RevertToParent
, time
);
410 if (X11DRV_check_error()) TRACE("got BadMatch, ignoring\n" );
415 /**********************************************************************
416 * handle_wm_protocols_message
418 static void handle_wm_protocols_message( HWND hwnd
, XClientMessageEvent
*event
)
420 Atom protocol
= (Atom
)event
->data
.l
[0];
422 if (!protocol
) return;
424 if (protocol
== wmDeleteWindow
)
426 /* Ignore the delete window request if the window has been disabled
427 * and we are in managed mode. This is to disallow applications from
428 * being closed by the window manager while in a modal state.
430 if (IsWindowEnabled(hwnd
)) PostMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
432 else if (protocol
== wmTakeFocus
)
434 Time event_time
= (Time
)event
->data
.l
[1];
435 HWND last_focus
= x11drv_thread_data()->last_focus
;
437 TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
438 hwnd
, IsWindowEnabled(hwnd
), GetFocus(), GetActiveWindow(),
439 GetForegroundWindow(), last_focus
);
441 if (can_activate_window(hwnd
))
443 /* simulate a mouse click on the caption to find out
444 * whether the window wants to be activated */
445 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
446 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
447 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
448 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
) set_focus( hwnd
, event_time
);
449 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd
, event
->window
, ma
);
454 if (!hwnd
) hwnd
= GetActiveWindow();
455 if (!hwnd
) hwnd
= last_focus
;
456 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, event_time
);
462 static const char * const focus_details
[] =
468 "NotifyNonlinearVirtual",
474 /**********************************************************************
477 static void EVENT_FocusIn( HWND hwnd
, XFocusChangeEvent
*event
)
481 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
483 if (wmTakeFocus
) return; /* ignore FocusIn if we are using take focus */
484 if (event
->detail
== NotifyPointer
) return;
486 if (!can_activate_window(hwnd
))
488 HWND hwnd
= GetFocus();
489 if (!hwnd
) hwnd
= GetActiveWindow();
490 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
491 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, CurrentTime
);
493 else SetForegroundWindow( hwnd
);
497 /**********************************************************************
500 * Note: only top-level windows get FocusOut events.
502 static void EVENT_FocusOut( HWND hwnd
, XFocusChangeEvent
*event
)
508 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
510 if (event
->detail
== NotifyPointer
) return;
511 x11drv_thread_data()->last_focus
= hwnd
;
512 if (hwnd
!= GetForegroundWindow()) return;
513 SendMessageA( hwnd
, WM_CANCELMODE
, 0, 0 );
515 /* don't reset the foreground window, if the window which is
516 getting the focus is a Wine window */
519 XGetInputFocus( thread_display(), &focus_win
, &revert
);
522 if (XFindContext( thread_display(), focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
529 /* Abey : 6-Oct-99. Check again if the focus out window is the
530 Foreground window, because in most cases the messages sent
531 above must have already changed the foreground window, in which
532 case we don't have to change the foreground window to 0 */
533 if (hwnd
== GetForegroundWindow())
535 TRACE( "lost focus, setting fg to 0\n" );
536 SetForegroundWindow( 0 );
542 /***********************************************************************
543 * EVENT_SelectionRequest_TARGETS
544 * Service a TARGETS selection request event
546 static Atom
EVENT_SelectionRequest_TARGETS( Display
*display
, Window requestor
,
547 Atom target
, Atom rprop
)
549 Atom xaTargets
= TSXInternAtom(display
, "TARGETS", False
);
553 unsigned long cTargets
;
557 TRACE("Request for %s\n", TSXGetAtomName(display
, target
));
560 * Count the number of items we wish to expose as selection targets.
561 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
563 cTargets
= CountClipboardFormats() + 1;
564 if ( CLIPBOARD_IsPresent(CF_DIB
) || CLIPBOARD_IsPresent(CF_BITMAP
) )
567 /* Allocate temp buffer */
568 targets
= (Atom
*)HeapAlloc( GetProcessHeap(), 0, cTargets
* sizeof(Atom
));
569 if(targets
== NULL
) return None
;
571 /* Create TARGETS property list (First item in list is TARGETS itself) */
573 for ( targets
[0] = xaTargets
, cTargets
= 1, wFormat
= 0, bHavePixmap
= FALSE
;
574 (wFormat
= EnumClipboardFormats( wFormat
)); )
576 if ( (prop
= X11DRV_CLIPBOARD_MapFormatToProperty(wFormat
)) != None
)
578 /* Scan through what we have so far to avoid duplicates */
581 for (i
= 0, bExists
= FALSE
; i
< cTargets
; i
++)
583 if (targets
[i
] == prop
)
591 targets
[cTargets
++] = prop
;
593 /* Add PIXMAP prop for bitmaps additionally */
594 if ( (wFormat
== CF_DIB
|| wFormat
== CF_BITMAP
)
597 targets
[cTargets
++] = XA_PIXMAP
;
607 for ( i
= 0; i
< cTargets
; i
++)
611 char *itemFmtName
= TSXGetAtomName(display
, targets
[i
]);
612 TRACE("\tAtom# %d: Type %s\n", i
, itemFmtName
);
613 TSXFree(itemFmtName
);
618 /* Update the X property */
619 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display
, rprop
));
621 /* We may want to consider setting the type to xaTargets instead,
622 * in case some apps expect this instead of XA_ATOM */
623 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
624 XA_ATOM
, 32, PropModeReplace
,
625 (unsigned char *)targets
, cTargets
);
626 TRACE("(Rc=%d)\n", xRc
);
628 HeapFree( GetProcessHeap(), 0, targets
);
634 /***********************************************************************
635 * EVENT_SelectionRequest_STRING
636 * Service a STRING selection request event
638 static Atom
EVENT_SelectionRequest_STRING( Display
*display
, Window requestor
,
639 Atom target
, Atom rprop
)
641 static UINT text_cp
= (UINT
)-1;
650 if(text_cp
== (UINT
)-1)
655 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\x11drv", &hkey
))
658 DWORD type
, count
= sizeof(buf
);
659 if(!RegQueryValueExA(hkey
, "TextCP", 0, &type
, buf
, &count
))
666 * Map the requested X selection property type atom name to a
667 * windows clipboard format ID.
669 itemFmtName
= TSXGetAtomName(display
, target
);
670 TRACE("Request for %s (wFormat=%x %s)\n",
671 itemFmtName
, CF_UNICODETEXT
, CLIPBOARD_GetFormatName(CF_UNICODETEXT
, NULL
, 0));
672 TSXFree(itemFmtName
);
674 hUnicodeText
= GetClipboardData(CF_UNICODETEXT
);
677 uni_text
= GlobalLock(hUnicodeText
);
681 size
= WideCharToMultiByte(text_cp
, 0, uni_text
, -1, NULL
, 0, NULL
, NULL
);
682 text
= HeapAlloc(GetProcessHeap(), 0, size
);
685 WideCharToMultiByte(text_cp
, 0, uni_text
, -1, text
, size
, NULL
, NULL
);
687 /* remove carriage returns */
689 lpstr
= (char*)HeapAlloc( GetProcessHeap(), 0, size
-- );
690 if(lpstr
== NULL
) return None
;
691 for(i
=0,j
=0; i
< size
&& text
[i
]; i
++ )
693 if( text
[i
] == '\r' &&
694 (text
[i
+1] == '\n' || text
[i
+1] == '\0') ) continue;
695 lpstr
[j
++] = text
[i
];
699 /* Update the X property */
700 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display
, rprop
));
701 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
702 XA_STRING
, 8, PropModeReplace
,
704 TRACE("(Rc=%d)\n", xRc
);
706 GlobalUnlock(hUnicodeText
);
707 HeapFree(GetProcessHeap(), 0, text
);
708 HeapFree( GetProcessHeap(), 0, lpstr
);
713 /***********************************************************************
714 * EVENT_SelectionRequest_PIXMAP
715 * Service a PIXMAP selection request event
717 static Atom
EVENT_SelectionRequest_PIXMAP( Display
*display
, Window requestor
,
718 Atom target
, Atom rprop
)
720 HANDLE hClipData
= 0;
726 XSetWindowAttributes win_attr
;
727 XWindowAttributes win_attr_src
;
731 * Map the requested X selection property type atom name to a
732 * windows clipboard format ID.
734 itemFmtName
= TSXGetAtomName(display
, target
);
735 wFormat
= X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName
);
736 TRACE("Request for %s (wFormat=%x %s)\n",
737 itemFmtName
, wFormat
, CLIPBOARD_GetFormatName( wFormat
, NULL
, 0 ));
738 TSXFree(itemFmtName
);
740 hClipData
= GetClipboardData(wFormat
);
743 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
744 rprop
= None
; /* Fail the request */
748 if (wFormat
== CF_DIB
)
750 HWND hwnd
= GetOpenClipboardWindow();
751 HDC hdc
= GetDC(hwnd
);
753 /* For convert from packed DIB to Pixmap */
754 pixmap
= X11DRV_DIB_CreatePixmapFromDIB(hClipData
, hdc
);
756 ReleaseDC(hwnd
, hdc
);
758 else if (wFormat
== CF_BITMAP
)
760 HWND hwnd
= GetOpenClipboardWindow();
761 HDC hdc
= GetDC(hwnd
);
763 pixmap
= X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData
, hdc
);
765 ReleaseDC(hwnd
, hdc
);
769 FIXME("%s to PIXMAP conversion not yet implemented!\n",
770 CLIPBOARD_GetFormatName(wFormat
, NULL
, 0));
775 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
776 TSXGetAtomName(display
, rprop
), (long)requestor
,
777 TSXGetAtomName(display
, target
), pixmap
);
779 /* Store the Pixmap handle in the property */
780 xRc
= TSXChangeProperty(display
, requestor
, rprop
, target
,
782 (unsigned char *)&pixmap
, 1);
783 TRACE("(Rc=%d)\n", xRc
);
785 /* Enable the code below if you want to handle destroying Pixmap resources
786 * in response to property notify events. Clients like XPaint don't
787 * appear to be duplicating Pixmaps so they don't like us deleting,
788 * the resource in response to the property being deleted.
791 /* Express interest in property notify events so that we can delete the
792 * pixmap when the client deletes the property atom.
794 xRc
= TSXGetWindowAttributes(display
, requestor
, &win_attr_src
);
795 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
797 win_attr
.event_mask
= win_attr_src
.your_event_mask
| PropertyChangeMask
;
798 TSXChangeWindowAttributes(display
, requestor
, CWEventMask
, &win_attr
);
800 /* Register the Pixmap we created with the request property Atom.
801 * When this property is destroyed we also destroy the Pixmap in
802 * response to the PropertyNotify event.
804 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop
, pixmap
);
812 /***********************************************************************
813 * EVENT_SelectionRequest_WCF
814 * Service a Wine Clipboard Format selection request event.
815 * For <WCF>* data types we simply copy the data to X without conversion.
817 static Atom
EVENT_SelectionRequest_WCF( Display
*display
, Window requestor
,
818 Atom target
, Atom rprop
)
820 HANDLE hClipData
= 0;
829 * Map the requested X selection property type atom name to a
830 * windows clipboard format ID.
832 itemFmtName
= TSXGetAtomName(display
, target
);
833 wFormat
= X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName
);
834 TRACE("Request for %s (wFormat=%x %s)\n",
835 itemFmtName
, wFormat
, CLIPBOARD_GetFormatName( wFormat
, NULL
, 0));
836 TSXFree(itemFmtName
);
838 hClipData
= GetClipboardData(wFormat
);
840 bemf
= wFormat
== CF_METAFILEPICT
|| wFormat
== CF_ENHMETAFILE
;
842 hClipData
= X11DRV_CLIPBOARD_SerializeMetafile(wFormat
, hClipData
, sizeof(hClipData
), TRUE
);
844 if( hClipData
&& (lpClipData
= GlobalLock(hClipData
)) )
846 cBytes
= GlobalSize(hClipData
);
848 TRACE("\tUpdating property %s, %d bytes...\n",
849 TSXGetAtomName(display
, rprop
), cBytes
);
851 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
852 target
, 8, PropModeReplace
,
853 (unsigned char *)lpClipData
, cBytes
);
854 TRACE("(Rc=%d)\n", xRc
);
856 GlobalUnlock(hClipData
);
860 TRACE("\tCould not retrieve native format!\n");
861 rprop
= None
; /* Fail the request */
864 if (bemf
) /* We must free serialized metafile data */
865 GlobalFree(hClipData
);
871 /***********************************************************************
872 * EVENT_SelectionRequest_MULTIPLE
873 * Service a MULTIPLE selection request event
874 * rprop contains a list of (target,property) atom pairs.
875 * The first atom names a target and the second names a property.
876 * The effect is as if we have received a sequence of SelectionRequest events
877 * (one for each atom pair) except that:
878 * 1. We reply with a SelectionNotify only when all the requested conversions
879 * have been performed.
880 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
881 * we replace the atom in the property by None.
883 static Atom
EVENT_SelectionRequest_MULTIPLE( HWND hWnd
, XSelectionRequestEvent
*pevent
)
885 Display
*display
= pevent
->display
;
887 Atom atype
=AnyPropertyType
;
889 unsigned long remain
;
890 Atom
* targetPropList
=NULL
;
891 unsigned long cTargetPropList
= 0;
892 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
894 /* If the specified property is None the requestor is an obsolete client.
895 * We support these by using the specified target atom as the reply property.
897 rprop
= pevent
->property
;
899 rprop
= pevent
->target
;
903 /* Read the MULTIPLE property contents. This should contain a list of
904 * (target,property) atom pairs.
906 if(TSXGetWindowProperty(display
, pevent
->requestor
, rprop
,
907 0, 0x3FFF, False
, AnyPropertyType
, &atype
,&aformat
,
908 &cTargetPropList
, &remain
,
909 (unsigned char**)&targetPropList
) != Success
)
910 TRACE("\tCouldn't read MULTIPLE property\n");
913 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
914 TSXGetAtomName(display
, atype
), aformat
, cTargetPropList
, remain
);
917 * Make sure we got what we expect.
918 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
919 * in a MULTIPLE selection request should be of type ATOM_PAIR.
920 * However some X apps(such as XPaint) are not compliant with this and return
921 * a user defined atom in atype when XGetWindowProperty is called.
922 * The data *is* an atom pair but is not denoted as such.
924 if(aformat
== 32 /* atype == xAtomPair */ )
928 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
929 * for each (target,property) pair */
931 for (i
= 0; i
< cTargetPropList
; i
+=2)
933 char *targetName
= TSXGetAtomName(display
, targetPropList
[i
]);
934 char *propName
= TSXGetAtomName(display
, targetPropList
[i
+1]);
935 XSelectionRequestEvent event
;
937 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
938 i
/2, targetName
, propName
);
942 /* We must have a non "None" property to service a MULTIPLE target atom */
943 if ( !targetPropList
[i
+1] )
945 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i
);
949 /* Set up an XSelectionRequestEvent for this (target,property) pair */
950 memcpy( &event
, pevent
, sizeof(XSelectionRequestEvent
) );
951 event
.target
= targetPropList
[i
];
952 event
.property
= targetPropList
[i
+1];
954 /* Fire a SelectionRequest, informing the handler that we are processing
955 * a MULTIPLE selection request event.
957 EVENT_SelectionRequest( hWnd
, &event
, TRUE
);
961 /* Free the list of targets/properties */
962 TSXFree(targetPropList
);
970 /***********************************************************************
971 * EVENT_SelectionRequest
972 * Process an event selection request event.
973 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
974 * recursively while servicing a "MULTIPLE" selection target.
976 * Note: We only receive this event when WINE owns the X selection
978 static void EVENT_SelectionRequest( HWND hWnd
, XSelectionRequestEvent
*event
, BOOL bIsMultiple
)
980 Display
*display
= event
->display
;
981 XSelectionEvent result
;
983 Window request
= event
->requestor
;
984 BOOL couldOpen
= FALSE
;
985 Atom xaClipboard
= TSXInternAtom(display
, "CLIPBOARD", False
);
986 Atom xaTargets
= TSXInternAtom(display
, "TARGETS", False
);
987 Atom xaMultiple
= TSXInternAtom(display
, "MULTIPLE", False
);
990 * We can only handle the selection request if :
991 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
992 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
993 * since this has been already done.
997 if ( ( (event
->selection
!= XA_PRIMARY
) && (event
->selection
!= xaClipboard
) )
998 || !(couldOpen
= OpenClipboard(hWnd
)) )
1002 /* If the specified property is None the requestor is an obsolete client.
1003 * We support these by using the specified target atom as the reply property.
1005 rprop
= event
->property
;
1007 rprop
= event
->target
;
1009 if(event
->target
== xaTargets
) /* Return a list of all supported targets */
1011 /* TARGETS selection request */
1012 rprop
= EVENT_SelectionRequest_TARGETS( display
, request
, event
->target
, rprop
);
1014 else if(event
->target
== xaMultiple
) /* rprop contains a list of (target, property) atom pairs */
1016 /* MULTIPLE selection request */
1017 rprop
= EVENT_SelectionRequest_MULTIPLE( hWnd
, event
);
1019 else if(event
->target
== XA_STRING
) /* treat CF_TEXT as Unix text */
1021 /* XA_STRING selection request */
1022 rprop
= EVENT_SelectionRequest_STRING( display
, request
, event
->target
, rprop
);
1024 else if(event
->target
== XA_PIXMAP
) /* Convert DIB's to Pixmaps */
1026 /* XA_PIXMAP selection request */
1027 rprop
= EVENT_SelectionRequest_PIXMAP( display
, request
, event
->target
, rprop
);
1029 else if(event
->target
== XA_BITMAP
) /* Convert DIB's to 1-bit Pixmaps */
1031 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1032 rprop
= EVENT_SelectionRequest_PIXMAP( display
, request
, XA_PIXMAP
, rprop
);
1034 else if(X11DRV_CLIPBOARD_IsNativeProperty(event
->target
)) /* <WCF>* */
1036 /* All <WCF> selection requests */
1037 rprop
= EVENT_SelectionRequest_WCF( display
, request
, event
->target
, rprop
);
1040 rprop
= None
; /* Don't support this format */
1043 /* close clipboard only if we opened before */
1044 if(couldOpen
) CloseClipboard();
1047 TRACE("\tRequest ignored\n");
1050 * SelectionNotify should be sent only at the end of a MULTIPLE request
1054 result
.type
= SelectionNotify
;
1055 result
.display
= display
;
1056 result
.requestor
= request
;
1057 result
.selection
= event
->selection
;
1058 result
.property
= rprop
;
1059 result
.target
= event
->target
;
1060 result
.time
= event
->time
;
1061 TRACE("Sending SelectionNotify event...\n");
1062 TSXSendEvent(display
,event
->requestor
,False
,NoEventMask
,(XEvent
*)&result
);
1066 /***********************************************************************
1067 * EVENT_SelectionClear
1069 static void EVENT_SelectionClear( HWND hWnd
, XSelectionClearEvent
*event
)
1071 Atom xaClipboard
= TSXInternAtom(event
->display
, "CLIPBOARD", False
);
1073 if (event
->selection
== XA_PRIMARY
|| event
->selection
== xaClipboard
)
1074 X11DRV_CLIPBOARD_ReleaseSelection( event
->selection
, event
->window
, hWnd
);
1077 /***********************************************************************
1078 * EVENT_PropertyNotify
1079 * We use this to release resources like Pixmaps when a selection
1080 * client no longer needs them.
1082 static void EVENT_PropertyNotify( XPropertyEvent
*event
)
1084 /* Check if we have any resources to free */
1085 TRACE("Received PropertyNotify event: \n");
1087 switch(event
->state
)
1089 case PropertyDelete
:
1091 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1092 TSXGetAtomName(event
->display
, event
->atom
), (long)event
->window
);
1094 if (X11DRV_IsSelectionOwner())
1095 X11DRV_CLIPBOARD_FreeResources( event
->atom
);
1099 case PropertyNewValue
:
1101 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1102 TSXGetAtomName(event
->display
, event
->atom
), (long)event
->window
);
1111 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
1115 if (!IsWindowEnabled(hQueryWnd
)) return 0;
1117 GetWindowRect(hQueryWnd
, &tempRect
);
1119 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
1121 if (!IsIconic( hQueryWnd
))
1123 GetClientRect( hQueryWnd
, &tempRect
);
1124 MapWindowPoints( hQueryWnd
, 0, (LPPOINT
)&tempRect
, 2 );
1126 if (PtInRect( &tempRect
, *lpPt
))
1128 HWND
*list
= WIN_ListChildren( hQueryWnd
);
1135 for (i
= 0; list
[i
]; i
++)
1137 if (GetWindowLongW( list
[i
], GWL_STYLE
) & WS_VISIBLE
)
1139 GetWindowRect( list
[i
], &tempRect
);
1140 if (PtInRect( &tempRect
, *lpPt
)) break;
1145 if (IsWindowEnabled( list
[i
] ))
1146 bResult
= find_drop_window( list
[i
], lpPt
);
1148 HeapFree( GetProcessHeap(), 0, list
);
1150 if(bResult
) return bResult
;
1154 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
1156 ScreenToClient(hQueryWnd
, lpPt
);
1161 /**********************************************************************
1162 * EVENT_DropFromOffix
1164 * don't know if it still works (last Changlog is from 96/11/04)
1166 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1168 unsigned long data_length
;
1169 unsigned long aux_long
;
1170 unsigned char* p_data
= NULL
;
1181 Window w_aux_root
, w_aux_child
;
1185 pWnd
= WIN_FindWndPtr(hWnd
);
1187 TSXQueryPointer( event
->display
, get_whole_window(pWnd
), &w_aux_root
, &w_aux_child
,
1188 &x
, &y
, (int *) &u
.pt_aux
.x
, (int *) &u
.pt_aux
.y
,
1189 (unsigned int*)&aux_long
);
1191 /* find out drop point and drop window */
1192 if( x
< 0 || y
< 0 ||
1193 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
1194 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
1196 bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
;
1202 POINT pt
= { x
, y
};
1203 HWND hwndDrop
= find_drop_window( hWnd
, &pt
);
1216 WIN_ReleaseWndPtr(pWnd
);
1218 if (!bAccept
) return;
1220 TSXGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1221 dndSelection
, 0, 65535, FALSE
,
1222 AnyPropertyType
, &u
.atom_aux
, (int *) &u
.pt_aux
.y
,
1223 &data_length
, &aux_long
, &p_data
);
1225 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1227 signed char *p
= (signed char*) p_data
;
1231 while( *p
) /* calculate buffer size */
1234 if((u
.i
= *p
) != -1 )
1236 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1237 if (len
) aux_long
+= len
+ 1;
1242 if( aux_long
&& aux_long
< 65535 )
1247 aux_long
+= sizeof(DROPFILES
) + 1;
1248 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1249 lpDrop
= (DROPFILES
*)GlobalLock( hDrop
);
1253 WND
*pDropWnd
= WIN_FindWndPtr( hScope
);
1254 lpDrop
->pFiles
= sizeof(DROPFILES
);
1258 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1259 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1260 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1261 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1262 lpDrop
->fWide
= FALSE
;
1263 WIN_ReleaseWndPtr(pDropWnd
);
1264 p_drop
= (char *)(lpDrop
+ 1);
1268 if( *p
!= -1 ) /* use only "good" entries */
1270 GetShortPathNameA( p
, p_drop
, 65535 );
1271 p_drop
+= strlen( p_drop
) + 1;
1276 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1280 if( p_data
) TSXFree(p_data
);
1283 /**********************************************************************
1286 * drop items are separated by \n
1287 * each item is prefixed by its mime type
1289 * event->data.l[3], event->data.l[4] contains drop x,y position
1291 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1293 unsigned long data_length
;
1294 unsigned long aux_long
, drop_len
= 0;
1295 unsigned char *p_data
= NULL
; /* property data */
1296 char *p_drop
= NULL
;
1307 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1309 TSXGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1310 dndSelection
, 0, 65535, FALSE
,
1311 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1312 &data_length
, &aux_long
, &p_data
);
1314 WARN("property too large, truncated!\n");
1315 TRACE("urls=%s\n", p_data
);
1317 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1318 /* calculate length */
1320 next
= strchr(p
, '\n');
1323 if (strncmp(p
,"file:",5) == 0 ) {
1324 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1325 if (len
) drop_len
+= len
+ 1;
1330 next
= strchr(p
, '\n');
1336 if( drop_len
&& drop_len
< 65535 ) {
1337 TSXQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1338 &x
, &y
, &u
.i
, &u
.i
, &u
.i
);
1340 drop_len
+= sizeof(DROPFILES
) + 1;
1341 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1342 lpDrop
= (DROPFILES
*) GlobalLock( hDrop
);
1345 WND
*pDropWnd
= WIN_FindWndPtr( hWnd
);
1346 lpDrop
->pFiles
= sizeof(DROPFILES
);
1347 lpDrop
->pt
.x
= (INT
)x
;
1348 lpDrop
->pt
.y
= (INT
)y
;
1350 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1351 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1352 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1353 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1354 lpDrop
->fWide
= FALSE
;
1355 p_drop
= (char*)(lpDrop
+ 1);
1356 WIN_ReleaseWndPtr(pDropWnd
);
1359 /* create message content */
1362 next
= strchr(p
, '\n');
1365 if (strncmp(p
,"file:",5) == 0 ) {
1366 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1368 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1371 WARN("can't convert file %s to dos name \n", p
+5);
1374 WARN("unknown mime type %s\n", p
);
1379 next
= strchr(p
, '\n');
1386 GlobalUnlock(hDrop
);
1387 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1390 if( p_data
) TSXFree(p_data
);
1394 /**********************************************************************
1395 * EVENT_ClientMessage
1397 static void EVENT_ClientMessage( HWND hWnd
, XClientMessageEvent
*event
)
1399 if (event
->message_type
!= None
&& event
->format
== 32) {
1400 if (event
->message_type
== wmProtocols
)
1401 handle_wm_protocols_message( hWnd
, event
);
1402 else if (event
->message_type
== dndProtocol
)
1404 /* query window (drag&drop event contains only drag window) */
1406 int root_x
, root_y
, child_x
, child_y
;
1410 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1411 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1412 if (XFindContext( event
->display
, child
, winContext
, (char **)&hWnd
) != 0) hWnd
= 0;
1413 wine_tsx11_unlock();
1415 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1416 EVENT_DropFromOffiX(hWnd
, event
);
1417 else if (event
->data
.l
[0] == DndURL
)
1418 EVENT_DropURLs(hWnd
, event
);
1422 /* enable this if you want to see the message */
1423 unsigned char* p_data
= NULL
;
1429 TSXGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1430 dndSelection
, 0, 65535, FALSE
,
1431 AnyPropertyType
, &u
.atom
, &u
.i
,
1432 &u
.l
, &u
.l
, &p_data
);
1433 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1434 event
->message_type
, event
->data
.l
[0], event
->data
.l
[1],
1435 event
->data
.l
[2], event
->data
.l
[3], event
->data
.l
[4],
1438 TRACE("unrecognized ClientMessage\n" );
1444 /**********************************************************************
1445 * X11DRV_EVENT_SetInputMethod
1447 INPUT_TYPE
X11DRV_EVENT_SetInputMethod(INPUT_TYPE type
)
1449 INPUT_TYPE prev
= current_input_type
;
1451 /* Flag not used yet */
1452 in_transition
= FALSE
;
1453 current_input_type
= type
;
1458 #ifdef HAVE_LIBXXF86DGA2
1459 /**********************************************************************
1460 * X11DRV_EVENT_SetDGAStatus
1462 void X11DRV_EVENT_SetDGAStatus(HWND hwnd
, int event_base
)
1464 if (event_base
< 0) {
1470 DGAMotionEventType
= event_base
+ MotionNotify
;
1471 DGAButtonPressEventType
= event_base
+ ButtonPress
;
1472 DGAButtonReleaseEventType
= event_base
+ ButtonRelease
;
1473 DGAKeyPressEventType
= event_base
+ KeyPress
;
1474 DGAKeyReleaseEventType
= event_base
+ KeyRelease
;