diff --git a/configure b/configure diff --git a/dlls/user/driver.c b/dlls/user/driver.c index 4a31049..1e024df 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); @@ -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, @@ -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 5d205aa..32f62e1 100644 --- a/dlls/user/user_private.h +++ b/dlls/user/user_private.h @@ -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 618846d..8f7caee 100644 --- a/dlls/user/win.c +++ b/dlls/user/win.c @@ -1291,7 +1291,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. @@ -1357,8 +1356,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 4ea41a8..0dc32a2 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) @@ -2310,37 +2315,37 @@ void X11DRV_AcquireClipboard(HWND hWndCl /* * 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))) { + DWORD procid; Window owner; - if (!hWndClipWindow) - hWndClipWindow = GetActiveWindow(); + if (GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, &procid)) + { + 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); - hWndClipWindow = GetAncestor(hWndClipWindow, GA_ROOT); + if (!SendMessageW(hWndClipWindow, WM_X11DRV_ACQUIRE_SELECTION, 0, 0)) + ERR("Failed to acquire selection\n"); - if (GetCurrentThreadId() != GetWindowThreadProcessId(hWndClipWindow, NULL)) - { - 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; + return; + } } - owner = X11DRV_get_whole_window(hWndClipWindow); + owner = thread_selection_wnd(); wine_tsx11_lock(); /* Grab PRIMARY selection if not owned */ @@ -2612,94 +2617,43 @@ 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; + HWND hwnd; + DWORD procid; /* 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); + if (!selectionAcquired || thread_selection_wnd() != selectionWindow) + return; - selectionPrevWindow = selectionWindow; - selectionWindow = None; - - if (!(tmp = GetWindow(hwnd, GW_HWNDNEXT))) - tmp = GetWindow(hwnd, GW_HWNDFIRST); - - if (tmp && tmp != hwnd) - selectionWindow = X11DRV_get_whole_window(tmp); - - 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"); + /* We failed to find another thread to take ownership. + * To keep things in a consistent state we need to give + * up the selection. */ - X11DRV_CLIPBOARD_ReleaseOwnership(); - selectionAcquired = S_NOSELECTION; - selectionWindow = 0; - } + X11DRV_CLIPBOARD_ReleaseOwnership(); + X11DRV_EmptyClipboard(FALSE); + selectionAcquired = S_NOSELECTION; + selectionWindow = 0; } @@ -3091,7 +3045,6 @@ END: */ void X11DRV_SelectionRequest( HWND hWnd, XEvent *event ) { - if (!hWnd) return; X11DRV_HandleSelectionRequest( hWnd, &event->xselectionrequest, FALSE ); } @@ -3102,7 +3055,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/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 d259c86..6b78cdf 100644 --- a/dlls/x11drv/x11drv.h +++ b/dlls/x11drv/x11drv.h @@ -663,6 +663,7 @@ extern XContext winContext; extern void X11DRV_InitClipboard(void); extern void 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 f0269a9..ea2a48f 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 );