x11drv: clipboard
Ulrich Czekalla
ulrich.czekalla at utoronto.ca
Mon Jun 5 10:55:14 CDT 2006
This patch improves the way we handle grabbing the clipboard with a window
belonging to another thread or process.
This is really more of a work-around to avoid the issue. We now use a
clipboard specific X window to own the selection. To handle this properly
we need to shift more functionality into the wineserver and explorer
process.
ChangeLog:
Ulrich Czekalla <ulrich at codeweavers.com>
Improve handling of the case where the clipboard is opened with a
window from another thread or process
---
dlls/user/driver.c | 16 ---
dlls/user/user_private.h | 3 -
dlls/user/win.c | 3 -
dlls/x11drv/clipboard.c | 200 +++++++++++++++---------------------------
dlls/x11drv/event.c | 3 -
dlls/x11drv/winex11.drv.spec | 1
dlls/x11drv/x11drv.h | 3 -
dlls/x11drv/x11drv_main.c | 1
8 files changed, 80 insertions(+), 150 deletions(-)
a74f56d0fbfd3f09cda63a425abac0b429a6bcdd
diff --git a/dlls/user/driver.c b/dlls/user/driver.c
index 278dd1d..1f87205 100644
--- a/dlls/user/driver.c
+++ b/dlls/user/driver.c
@@ -102,7 +102,6 @@ static const USER_DRIVER *load_driver(vo
GET_USER_FUNC(RegisterClipboardFormat);
GET_USER_FUNC(GetClipboardFormatName);
GET_USER_FUNC(EndClipboardUpdate);
- GET_USER_FUNC(ResetSelectionOwner);
GET_USER_FUNC(ChangeDisplaySettingsEx);
GET_USER_FUNC(EnumDisplaySettingsEx);
GET_USER_FUNC(CreateDesktopWindow);
@@ -239,7 +238,7 @@ static void nulldrv_SetScreenSaveActive(
{
}
-static void nulldrv_AcquireClipboard( HWND hwnd )
+static INT nulldrv_AcquireClipboard( HWND hwnd )
{
}
@@ -281,10 +280,6 @@ static UINT nulldrv_RegisterClipboardFor
return 0;
}
-static void nulldrv_ResetSelectionOwner( HWND hwnd, BOOL flag )
-{
-}
-
static BOOL nulldrv_SetClipboardData( UINT format, HANDLE16 h16, HANDLE h32, BOOL owner )
{
return FALSE;
@@ -438,7 +433,6 @@ static const USER_DRIVER null_driver =
nulldrv_GetClipboardFormatName,
nulldrv_IsClipboardFormatAvailable,
nulldrv_RegisterClipboardFormat,
- nulldrv_ResetSelectionOwner,
nulldrv_SetClipboardData,
/* display modes */
nulldrv_ChangeDisplaySettingsEx,
@@ -563,7 +557,7 @@ static void loaderdrv_SetScreenSaveActiv
load_driver()->pSetScreenSaveActive( on );
}
-static void loaderdrv_AcquireClipboard( HWND hwnd )
+static INT loaderdrv_AcquireClipboard( HWND hwnd )
{
load_driver()->pAcquireClipboard( hwnd );
}
@@ -608,11 +602,6 @@ static UINT loaderdrv_RegisterClipboardF
return load_driver()->pRegisterClipboardFormat( name );
}
-static void loaderdrv_ResetSelectionOwner( HWND hwnd, BOOL flag )
-{
- load_driver()->pResetSelectionOwner( hwnd, flag );
-}
-
static BOOL loaderdrv_SetClipboardData( UINT format, HANDLE16 h16, HANDLE h32, BOOL owner )
{
return load_driver()->pSetClipboardData( format, h16, h32, owner );
@@ -754,7 +743,6 @@ static const USER_DRIVER lazy_load_drive
loaderdrv_GetClipboardFormatName,
loaderdrv_IsClipboardFormatAvailable,
loaderdrv_RegisterClipboardFormat,
- loaderdrv_ResetSelectionOwner,
loaderdrv_SetClipboardData,
/* display modes */
loaderdrv_ChangeDisplaySettingsEx,
diff --git a/dlls/user/user_private.h b/dlls/user/user_private.h
index a58ba5e..ffb2796 100644
--- a/dlls/user/user_private.h
+++ b/dlls/user/user_private.h
@@ -122,7 +122,7 @@ typedef struct tagUSER_DRIVER {
BOOL (*pGetScreenSaveActive)(void);
void (*pSetScreenSaveActive)(BOOL);
/* clipboard functions */
- void (*pAcquireClipboard)(HWND); /* Acquire selection */
+ INT (*pAcquireClipboard)(HWND); /* Acquire selection */
BOOL (*pCountClipboardFormats)(void); /* Count available clipboard formats */
void (*pEmptyClipboard)(BOOL); /* Empty clipboard data */
void (*pEndClipboardUpdate)(void); /* End clipboard update */
@@ -131,7 +131,6 @@ typedef struct tagUSER_DRIVER {
INT (*pGetClipboardFormatName)(UINT, LPWSTR, UINT); /* Get a clipboard format name */
BOOL (*pIsClipboardFormatAvailable)(UINT); /* Check if specified format is available */
UINT (*pRegisterClipboardFormat)(LPCWSTR); /* Register a clipboard format */
- void (*pResetSelectionOwner)(HWND, BOOL);
BOOL (*pSetClipboardData)(UINT, HANDLE16, HANDLE, BOOL); /* Set specified selection data */
/* display modes */
LONG (*pChangeDisplaySettingsEx)(LPCWSTR,LPDEVMODEW,HWND,DWORD,LPVOID);
diff --git a/dlls/user/win.c b/dlls/user/win.c
index 08c5677..3d5fecb 100644
--- a/dlls/user/win.c
+++ b/dlls/user/win.c
@@ -1292,7 +1292,6 @@ static void WIN_SendDestroyMsg( HWND hwn
if (hwnd == info.hwndCaret) DestroyCaret();
if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
}
- USER_Driver->pResetSelectionOwner( hwnd, TRUE );
/*
* Send the WM_DESTROY to the window.
@@ -1358,8 +1357,6 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
if (!IsWindow(hwnd)) return TRUE;
- USER_Driver->pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
-
/* Hide the window */
if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
{
diff --git a/dlls/x11drv/clipboard.c b/dlls/x11drv/clipboard.c
index f773b3e..cd063ff 100644
--- a/dlls/x11drv/clipboard.c
+++ b/dlls/x11drv/clipboard.c
@@ -334,9 +334,14 @@ static Window thread_selection_wnd(void)
if (!w)
{
+ XSetWindowAttributes attr;
+
+ attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
+ ButtonPressMask | ButtonReleaseMask | EnterWindowMask);
+
wine_tsx11_lock();
w = XCreateWindow(thread_display(), root_window, 0, 0, 1, 1, 0, screen_depth,
- InputOutput, CopyFromParent, 0, NULL);
+ InputOutput, CopyFromParent, CWEventMask, &attr);
wine_tsx11_unlock();
if (w)
@@ -2304,70 +2309,67 @@ INT X11DRV_GetClipboardFormatName(UINT w
/**************************************************************************
* AcquireClipboard (X11DRV.@)
*/
-void X11DRV_AcquireClipboard(HWND hWndClipWindow)
+int X11DRV_AcquireClipboard(HWND hWndClipWindow)
{
+ DWORD procid;
+ Window owner;
Display *display = thread_display();
+ TRACE(" %p\n", hWndClipWindow);
+
/*
- * Acquire X selection if we don't already own it.
- * Note that we only acquire the selection if it hasn't been already
- * acquired by us, and ignore the fact that another X window may be
- * asserting ownership. The reason for this is we need *any* top level
- * X window to hold selection ownership. The actual clipboard data requests
- * are made via GetClipboardData from EVENT_SelectionRequest and this
- * ensures that the real HWND owner services the request.
- * If the owning X window gets destroyed the selection ownership is
- * re-cycled to another top level X window in X11DRV_CLIPBOARD_ResetOwner.
- *
+ * It's important that the selection get acquired from the thread
+ * that owns the clipboard window. The primary reason is that we know
+ * it is running a message loop and therefore can process the
+ * X selection events.
*/
- if (!(selectionAcquired == (S_PRIMARY | S_CLIPBOARD)))
+ if (hWndClipWindow &&
+ GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, &procid))
{
- Window owner;
-
- if (!hWndClipWindow)
- hWndClipWindow = GetActiveWindow();
-
- hWndClipWindow = GetAncestor(hWndClipWindow, GA_ROOT);
-
- if (GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, NULL))
+ if (procid != GetCurrentProcessId())
+ {
+ WARN("Setting clipboard owner to other process is not supported\n");
+ hWndClipWindow = NULL;
+ }
+ else
{
TRACE("Thread %lx is acquiring selection with thread %lx's window %p\n",
GetCurrentThreadId(),
- GetWindowThreadProcessId(hWndClipWindow, NULL),
- hWndClipWindow);
- if (!SendMessageW(hWndClipWindow, WM_X11DRV_ACQUIRE_SELECTION, 0, 0))
- ERR("Failed to acquire selection\n");
- return;
+ GetWindowThreadProcessId(hWndClipWindow, NULL), hWndClipWindow);
+
+ return SendMessageW(hWndClipWindow, WM_X11DRV_ACQUIRE_SELECTION, 0, 0);
}
+ }
- owner = X11DRV_get_whole_window(hWndClipWindow);
+ owner = thread_selection_wnd();
- wine_tsx11_lock();
- /* Grab PRIMARY selection if not owned */
- if (use_primary_selection && !(selectionAcquired & S_PRIMARY))
- XSetSelectionOwner(display, XA_PRIMARY, owner, CurrentTime);
-
- /* Grab CLIPBOARD selection if not owned */
- if (!(selectionAcquired & S_CLIPBOARD))
- XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), owner, CurrentTime);
+ wine_tsx11_lock();
- if (use_primary_selection && XGetSelectionOwner(display,XA_PRIMARY) == owner)
- selectionAcquired |= S_PRIMARY;
+ selectionAcquired = 0;
+ selectionWindow = 0;
- if (XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)) == owner)
- selectionAcquired |= S_CLIPBOARD;
- wine_tsx11_unlock();
+ /* Grab PRIMARY selection if not owned */
+ if (use_primary_selection)
+ XSetSelectionOwner(display, XA_PRIMARY, owner, CurrentTime);
- if (selectionAcquired)
- {
- selectionWindow = owner;
- TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
- }
- }
- else
+ /* Grab CLIPBOARD selection if not owned */
+ XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), owner, CurrentTime);
+
+ if (use_primary_selection && XGetSelectionOwner(display, XA_PRIMARY) == owner)
+ selectionAcquired |= S_PRIMARY;
+
+ if (XGetSelectionOwner(display,x11drv_atom(CLIPBOARD)) == owner)
+ selectionAcquired |= S_CLIPBOARD;
+
+ wine_tsx11_unlock();
+
+ if (selectionAcquired)
{
- ERR("Received request to acquire selection but process is already owner=(%08x)\n", (unsigned) selectionWindow);
+ selectionWindow = owner;
+ TRACE("Grabbed X selection, owner=(%08x)\n", (unsigned) owner);
}
+
+ return 1;
}
@@ -2612,94 +2614,40 @@ BOOL X11DRV_GetClipboardData(UINT wForma
/**************************************************************************
* ResetSelectionOwner (X11DRV.@)
*
- * Called from DestroyWindow() to prevent X selection from being lost when
- * a top level window is destroyed, by switching ownership to another top
- * level window.
- * Any top level window can own the selection. See X11DRV_CLIPBOARD_Acquire
- * for a more detailed description of this.
+ * Called when the thread owning the selection is destroyed and we need to
+ * preserve the selection ownership. We look for another top level window
+ * in this process and send it a message to acquire the selection.
*/
-void X11DRV_ResetSelectionOwner(HWND hwnd, BOOL bFooBar)
+void X11DRV_ResetSelectionOwner()
{
- Display *display = thread_display();
- HWND hWndClipOwner = 0;
- HWND tmp;
- Window XWnd = X11DRV_get_whole_window(hwnd);
- BOOL bLostSelection = FALSE;
- Window selectionPrevWindow;
-
- /* There is nothing to do if we don't own the selection,
- * or if the X window which currently owns the selection is different
- * from the one passed in.
- */
- if (!selectionAcquired || XWnd != selectionWindow
- || selectionWindow == None )
- return;
-
- if ((bFooBar && XWnd) || (!bFooBar && !XWnd))
- return;
-
- hWndClipOwner = GetClipboardOwner();
-
- TRACE("clipboard owner = %p, selection window = %08x\n",
- hWndClipOwner, (unsigned)selectionWindow);
-
- /* now try to salvage current selection from being destroyed by X */
- TRACE("checking %08x\n", (unsigned) XWnd);
+ HWND hwnd;
+ DWORD procid;
- selectionPrevWindow = selectionWindow;
- selectionWindow = None;
+ TRACE("\n");
- if (!(tmp = GetWindow(hwnd, GW_HWNDNEXT)))
- tmp = GetWindow(hwnd, GW_HWNDFIRST);
+ if (!selectionAcquired || thread_selection_wnd() != selectionWindow)
+ return;
- if (tmp && tmp != hwnd)
- selectionWindow = X11DRV_get_whole_window(tmp);
+ selectionAcquired = S_NOSELECTION;
+ selectionWindow = 0;
- if (selectionWindow != None)
+ hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
+ do
{
- /* We must pretend that we don't own the selection while making the switch
- * since a SelectionClear event will be sent to the last owner.
- * If there is no owner X11DRV_CLIPBOARD_ReleaseSelection will do nothing.
- */
- int saveSelectionState = selectionAcquired;
- selectionAcquired = S_NOSELECTION;
-
- TRACE("\tswitching selection from %08x to %08x\n",
- (unsigned)selectionPrevWindow, (unsigned)selectionWindow);
-
- wine_tsx11_lock();
-
- /* Assume ownership for the PRIMARY and CLIPBOARD selection */
- if (saveSelectionState & S_PRIMARY)
- XSetSelectionOwner(display, XA_PRIMARY, selectionWindow, CurrentTime);
-
- XSetSelectionOwner(display, x11drv_atom(CLIPBOARD), selectionWindow, CurrentTime);
-
- /* Restore the selection masks */
- selectionAcquired = saveSelectionState;
-
- /* Lose the selection if something went wrong */
- if (((saveSelectionState & S_PRIMARY) &&
- (XGetSelectionOwner(display, XA_PRIMARY) != selectionWindow)) ||
- (XGetSelectionOwner(display, x11drv_atom(CLIPBOARD)) != selectionWindow))
+ if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, &procid))
{
- bLostSelection = TRUE;
+ if (GetCurrentProcessId() == procid)
+ {
+ if (SendMessageW(hwnd, WM_X11DRV_ACQUIRE_SELECTION, 0, 0))
+ return;
+ }
}
- wine_tsx11_unlock();
- }
- else
- {
- bLostSelection = TRUE;
- }
+ } while ((hwnd = GetWindow(hwnd, GW_HWNDNEXT)) != NULL);
- if (bLostSelection)
- {
- TRACE("Lost the selection!\n");
+ WARN("Failed to find another thread to take selection ownership. Clipboard data will be lost.\n");
- X11DRV_CLIPBOARD_ReleaseOwnership();
- selectionAcquired = S_NOSELECTION;
- selectionWindow = 0;
- }
+ X11DRV_CLIPBOARD_ReleaseOwnership();
+ X11DRV_EmptyClipboard(FALSE);
}
@@ -3091,7 +3039,6 @@ END:
*/
void X11DRV_SelectionRequest( HWND hWnd, XEvent *event )
{
- if (!hWnd) return;
X11DRV_HandleSelectionRequest( hWnd, &event->xselectionrequest, FALSE );
}
@@ -3102,7 +3049,6 @@ void X11DRV_SelectionRequest( HWND hWnd,
void X11DRV_SelectionClear( HWND hWnd, XEvent *xev )
{
XSelectionClearEvent *event = &xev->xselectionclear;
- if (!hWnd) return;
if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd, event->time );
}
diff --git a/dlls/x11drv/event.c b/dlls/x11drv/event.c
index b1df567..ae72f16 100644
--- a/dlls/x11drv/event.c
+++ b/dlls/x11drv/event.c
@@ -937,8 +937,7 @@ LRESULT X11DRV_WindowMessage( HWND hwnd,
switch(msg)
{
case WM_X11DRV_ACQUIRE_SELECTION:
- X11DRV_AcquireClipboard( hwnd );
- return 0;
+ return X11DRV_AcquireClipboard( hwnd );
case WM_X11DRV_DELETE_WINDOW:
return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
default:
diff --git a/dlls/x11drv/winex11.drv.spec b/dlls/x11drv/winex11.drv.spec
index 9c33ce4..687aabd 100644
--- a/dlls/x11drv/winex11.drv.spec
+++ b/dlls/x11drv/winex11.drv.spec
@@ -98,7 +98,6 @@
@ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) X11DRV_MsgWaitForMultipleObjectsEx
@ cdecl RegisterClipboardFormat(wstr) X11DRV_RegisterClipboardFormat
@ cdecl ReleaseDC(long long long) X11DRV_ReleaseDC
-@ cdecl ResetSelectionOwner(long long) X11DRV_ResetSelectionOwner
@ cdecl ScrollDC(long long long ptr ptr long ptr) X11DRV_ScrollDC
@ cdecl SetClipboardData(long long long long) X11DRV_SetClipboardData
@ cdecl SetFocus(long) X11DRV_SetFocus
diff --git a/dlls/x11drv/x11drv.h b/dlls/x11drv/x11drv.h
index f1a9e8d..ab55b58 100644
--- a/dlls/x11drv/x11drv.h
+++ b/dlls/x11drv/x11drv.h
@@ -662,7 +662,8 @@ extern void invalidate_dce( HWND hwnd, c
extern XContext winContext;
extern void X11DRV_InitClipboard(void);
-extern void X11DRV_AcquireClipboard(HWND hWndClipWindow);
+extern int X11DRV_AcquireClipboard(HWND hWndClipWindow);
+extern void X11DRV_ResetSelectionOwner();
extern void X11DRV_SetFocus( HWND hwnd );
extern Cursor X11DRV_GetCursor( Display *display, struct tagCURSORICONINFO *ptr );
extern void X11DRV_InitKeyboard(void);
diff --git a/dlls/x11drv/x11drv_main.c b/dlls/x11drv/x11drv_main.c
index 7b0abce..b6fa275 100644
--- a/dlls/x11drv/x11drv_main.c
+++ b/dlls/x11drv/x11drv_main.c
@@ -457,6 +457,7 @@ static void thread_detach(void)
if (data)
{
+ X11DRV_ResetSelectionOwner();
CloseHandle( data->display_fd );
wine_tsx11_lock();
XCloseDisplay( data->display );
--
1.2.4
More information about the wine-patches
mailing list