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