[PATCH 3/6] winex11.drv: Implement cloaking using window opacity and Xshape.

Gabriel Ivăncescu gabrielopcode at gmail.com
Fri Nov 6 10:03:32 CST 2020


Cloaking is implemented by setting the opacity of a window to zero, and
setting an empty shape using libXshape. This makes it transparent to mouse
input and completely invisible, while otherwise still processing the exact
same messages/events as a visible window would, to match what Windows does.

While a cloaked window still has a taskbar visible, it also has the same
traits as a normal window. For example, a minimized cloaked window will show
the "Restore" or "Unminimize" function when right-clicking on its taskbar
icon. So that means unmapping the window would *not* be the same behavior
as Windows, since it even removes the taskbar item in the first place.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

The reason the GetWindow( hwnd, GW_OWNER ) check is done in this patch,
rather than in user32, is because it must not be checked for shell-cloaked
windows (last patch in the series). The shell has full control over what
windows it hides and doesn't abide by that, at least on Wine, because of
how virtual desktops work.

 dlls/winex11.drv/window.c         | 106 ++++++++++++++++++++++++++++--
 dlls/winex11.drv/winex11.drv.spec |   1 +
 dlls/winex11.drv/x11drv.h         |  41 ++++++++++++
 3 files changed, 141 insertions(+), 7 deletions(-)

diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index 4571739..3e4f9eb 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -44,6 +44,7 @@
 #include "wine/unicode.h"
 
 #include "x11drv.h"
+#include "dwmapi.h"
 #include "wine/debug.h"
 #include "wine/server.h"
 #include "mwm.h"
@@ -390,7 +391,7 @@ static void sync_window_region( struct x11drv_win_data *data, HRGN win_region )
     if (!data->whole_window) return;
     data->shaped = FALSE;
 
-    if (IsRectEmpty( &data->window_rect ))  /* set an empty shape */
+    if (IsRectEmpty( &data->window_rect ) || data->cloaked)  /* set an empty shape */
     {
         static XRectangle empty_rect;
         XShapeCombineRectangles( data->display, data->whole_window, ShapeBounding, 0, 0,
@@ -1581,7 +1582,13 @@ static void create_whole_window( struct x11drv_win_data *data )
     if (win_rgn || IsRectEmpty( &data->window_rect )) sync_window_region( data, win_rgn );
 
     /* set the window opacity */
-    if (!GetLayeredWindowAttributes( data->hwnd, &key, &alpha, &layered_flags )) layered_flags = 0;
+    if (data->cloaked)
+    {
+        key = 0;
+        alpha = 0;
+        layered_flags = LWA_ALPHA;
+    }
+    else if (!GetLayeredWindowAttributes( data->hwnd, &key, &alpha, &layered_flags )) layered_flags = 0;
     sync_window_opacity( data->display, data->whole_window, key, alpha, layered_flags );
 
     XFlush( data->display );  /* make sure the window exists before we start painting to it */
@@ -1714,7 +1721,7 @@ void CDECL X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style )
     {
         data->layered = FALSE;
         set_window_visual( data, &default_visual, FALSE );
-        sync_window_opacity( data->display, data->whole_window, 0, 0, 0 );
+        if (!data->cloaked) sync_window_opacity( data->display, data->whole_window, 0, 0, 0 );
         if (data->surface) set_surface_color_key( data->surface, CLR_INVALID );
     }
 done:
@@ -2572,6 +2579,80 @@ done:
 }
 
 
+/**********************************************************************
+ *		SetWindowCompositionAttribute  (X11DRV.@)
+ */
+DWORD CDECL X11DRV_SetWindowCompositionAttribute( HWND hwnd, DWORD attribute, void *attr_data )
+{
+    struct x11drv_win_data *data;
+    DWORD ret = 0;
+    HWND owner;
+
+    switch (attribute)
+    {
+    case WCA_CLOAK:
+        if (!(data = get_win_data( hwnd )))
+        {
+            SetLastError( ERROR_INVALID_HANDLE );
+            return ~0;
+        }
+        ret = *(BOOL*)attr_data ? SET_WINDOW_CLOAKED_ON : 0;
+
+        /* If the owner is cloaked, manual uncloaking is not allowed */
+        if (!ret && (owner = GetWindow( hwnd, GW_OWNER )))
+        {
+            struct x11drv_win_data *owner_data = get_win_data( owner );
+            DWORD cloaked = 0;
+            if (owner_data)
+            {
+                cloaked = owner_data->cloaked ? DWM_CLOAKED_APP : 0;
+                release_win_data( owner_data );
+            }
+            else
+            {
+                SERVER_START_REQ( get_window_cloaked )
+                {
+                    req->handle = wine_server_user_handle( owner );
+                    if (!wine_server_call( req )) cloaked = reply->cloaked;
+                }
+                SERVER_END_REQ;
+            }
+            if (cloaked)
+            {
+                release_win_data( data );
+                SetLastError( ERROR_INVALID_PARAMETER );
+                return ~0;
+            }
+        }
+
+        if (!data->cloaked != !ret)
+        {
+#ifdef HAVE_LIBXSHAPE
+            DWORD layered_flags = LWA_ALPHA;
+            COLORREF key = 0;
+            BYTE alpha = 0;
+
+            data->cloaked = ret;
+            if (!ret && !GetLayeredWindowAttributes( hwnd, &key, &alpha, &layered_flags ))
+                layered_flags = 0;
+
+            sync_window_opacity( data->display, data->whole_window, key, alpha, layered_flags );
+            sync_window_region( data, (HRGN)1 );
+#else
+            FIXME("libXshape is not available, but cloaking requires it.\n");
+            SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
+            ret = ~0;
+#endif
+        }
+        release_win_data( data );
+        break;
+    default:
+        break;
+    }
+    return ret;
+}
+
+
 /**********************************************************************
  *		SetWindowIcon (X11DRV.@)
  *
@@ -2631,7 +2712,7 @@ void CDECL X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alph
     {
         set_window_visual( data, &default_visual, FALSE );
 
-        if (data->whole_window)
+        if (data->whole_window && !data->cloaked)
             sync_window_opacity( data->display, data->whole_window, key, alpha, flags );
         if (data->surface)
             set_surface_color_key( data->surface, (flags & LWA_COLORKEY) ? key : CLR_INVALID );
@@ -2656,9 +2737,20 @@ void CDECL X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alph
         Window win = X11DRV_get_whole_window( hwnd );
         if (win)
         {
-            sync_window_opacity( gdi_display, win, key, alpha, flags );
-            if (flags & LWA_COLORKEY)
-                FIXME( "LWA_COLORKEY not supported on foreign process window %p\n", hwnd );
+            DWORD cloaked = 0;
+
+            SERVER_START_REQ( get_window_cloaked )
+            {
+                req->handle = wine_server_user_handle( hwnd );
+                if (!wine_server_call( req )) cloaked = reply->cloaked;
+            }
+            SERVER_END_REQ;
+            if (!cloaked)
+            {
+                sync_window_opacity( gdi_display, win, key, alpha, flags );
+                if (flags & LWA_COLORKEY)
+                    FIXME( "LWA_COLORKEY not supported on foreign process window %p\n", hwnd );
+            }
         }
     }
 }
diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec
index c0e24d8..3d8c267 100644
--- a/dlls/winex11.drv/winex11.drv.spec
+++ b/dlls/winex11.drv/winex11.drv.spec
@@ -33,6 +33,7 @@
 @ cdecl SetFocus(long) X11DRV_SetFocus
 @ cdecl SetLayeredWindowAttributes(long long long long) X11DRV_SetLayeredWindowAttributes
 @ cdecl SetParent(long long long) X11DRV_SetParent
+@ cdecl SetWindowCompositionAttribute(long long ptr) X11DRV_SetWindowCompositionAttribute
 @ cdecl SetWindowIcon(long long long) X11DRV_SetWindowIcon
 @ cdecl SetWindowRgn(long long long) X11DRV_SetWindowRgn
 @ cdecl SetWindowStyle(ptr long ptr) X11DRV_SetWindowStyle
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 173d94b..d62fcfd 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -570,6 +570,7 @@ struct x11drv_win_data
     BOOL        managed : 1;    /* is window managed? */
     BOOL        mapped : 1;     /* is window mapped? (in either normal or iconic state) */
     BOOL        iconic : 1;     /* is window in iconic state? */
+    BOOL        cloaked : 1;    /* is window cloaked manually? */
     BOOL        embedded : 1;   /* is window an XEMBED client? */
     BOOL        shaped : 1;     /* is window using a custom region shape? */
     BOOL        layered : 1;    /* is window layered and with valid attributes? */
@@ -824,4 +825,44 @@ static inline BOOL is_window_rect_mapped( const RECT *rect )
             max( rect->bottom, rect->top + 1 ) > virtual_rect.top);
 }
 
+/* Undocumented structure for (Get|Set)WindowCompositionAttribute */
+struct WINCOMPATTRDATA
+{
+    DWORD attribute;
+    void *pData;
+    ULONG dataSize;
+};
+enum
+{
+    WCA_UNDEFINED = 0,
+    WCA_NCRENDERING_ENABLED = 1,
+    WCA_NCRENDERING_POLICY = 2,
+    WCA_TRANSITIONS_FORCEDISABLED = 3,
+    WCA_ALLOW_NCPAINT = 4,
+    WCA_CAPTION_BUTTON_BOUNDS = 5,
+    WCA_NONCLIENT_RTL_LAYOUT = 6,
+    WCA_FORCE_ICONIC_REPRESENTATION = 7,
+    WCA_EXTENDED_FRAME_BOUNDS = 8,
+    WCA_HAS_ICONIC_BITMAP = 9,
+    WCA_THEME_ATTRIBUTES = 10,
+    WCA_NCRENDERING_EXILED = 11,
+    WCA_NCADORNMENTINFO = 12,
+    WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
+    WCA_VIDEO_OVERLAY_ACTIVE = 14,
+    WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
+    WCA_DISALLOW_PEEK = 16,
+    WCA_CLOAK = 17,
+    WCA_CLOAKED = 18,
+    WCA_ACCENT_POLICY = 19,
+    WCA_FREEZE_REPRESENTATION = 20,
+    WCA_EVER_UNCLOAKED = 21,
+    WCA_VISUAL_OWNER = 22,
+    WCA_HOLOGRAPHIC = 23,
+    WCA_EXCLUDED_FROM_DDA = 24,
+    WCA_PASSIVEUPDATEMODE = 25,
+    WCA_USEDARKMODECOLORS = 26,
+    WCA_LAST
+};
+BOOL WINAPI SetWindowCompositionAttribute(HWND, const struct WINCOMPATTRDATA*);
+
 #endif  /* __WINE_X11DRV_H */
-- 
2.21.0




More information about the wine-devel mailing list