thanks for wine
Ulrich Czekalla
ulrich.czekalla at utoronto.ca
Fri May 19 12:23:48 CDT 2006
The attached patch should help. It's a bit of a hack and it's mostly
untested but copy and paste in MSVC6 seems to work fine.
/Ulrich
On Wed, May 17, 2006 at 07:21:55AM +0800, qingdoa daoo wrote:
>
> --- Ulrich Czekalla <ulrich.czekalla at utoronto.ca> wrote:
>
> >
> > I still don't understand why it would set the clipboard owner to
> > GetDesktopWindow(). A quick hack would be to detect that case and instead
> > set it to NULL.
>
> It looks like in Windows we can set hwnd to any window of any process.
> So some apps are going to rely on it. Desktop window is just an example.
>
> >
> > Either way I think we should first understand what is really happening
>
> Me neither, unfortunately :-(
>
> > before we come up with an alternative implementation for this one bug. I
> > have MSVC6. I can install it and investigate. What do I need to do to
> > reproduce the bug?
>
> Basically if you can install MSVC6 you can see the bug. There's an entry
> in AppDB that might be helpful.
>
>
>
>
> __________________________________________________
> ?????????????????????????????
> http://cn.mail.yahoo.com
-------------- next part --------------
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 );
More information about the wine-devel
mailing list