xserver: Branch 'master' - 7 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Jun 17 22:02:46 UTC 2019


 .appveyor.yml                   |    1 
 configure.ac                    |    2 
 doc/c-extensions                |    2 
 hw/xwin/InitOutput.c            |    9 +
 hw/xwin/Makefile.am             |    2 
 hw/xwin/man/XWin.man            |   16 ++
 hw/xwin/meson.build             |    3 
 hw/xwin/win.h                   |   23 +++
 hw/xwin/winglobals.c            |    1 
 hw/xwin/winglobals.h            |    1 
 hw/xwin/winmultiwindowwindow.c  |  256 ++++++++++++++++++++++++++++++++++++++++
 hw/xwin/winmultiwindowwm.c      |   50 +++++++
 hw/xwin/winmultiwindowwndproc.c |  189 ++++++++++++++++++++++-------
 hw/xwin/winprocarg.c            |   39 ++++++
 hw/xwin/winscrinit.c            |   15 ++
 hw/xwin/winshadddnl.c           |    1 
 hw/xwin/winshadgdi.c            |  161 ++++++++++++++++++++++++-
 hw/xwin/winvalargs.c            |    8 +
 hw/xwin/winwindow.h             |    2 
 19 files changed, 713 insertions(+), 68 deletions(-)

New commits:
commit 2afee831a439add6cca5b7fa8c76a9de4326b2b7
Author: Jon Turney <jon.turney at dronecode.org.uk>
Date:   Thu Jan 5 13:17:59 2017 +0000

    hw/xwin: Add an option to use alpha channel in multiwindow mode
    
    Add an option to turn on the use of the X window's alpha channel in
    multiwindow mode, i.e. this uses the X window's alpha channel for
    compositing into the native desktop.
    
    This works on W7/Vista (using DwmEnableBlurBehindWindow()), and Windows
    10 (using the undocumented SetWindowCompositionAttribute()), but not on
    Windows 8/8.1
    
    -compositewm must be enabled for this to be useful, as we only have a
    pixmap with an alpha channel for the X window in that case.  The
    framebuffer/root window doesn't have one (unless perhaps you are using
    the rootless extension, maybe...).
    
    v2:
    Update meson.build
    
    Future work:
    
    A window property to control use of alpha?
    Option to turn off blur on W7/Vista
    Implement _NET_WM_WINDOW_OPACITY

diff --git a/doc/c-extensions b/doc/c-extensions
index e5fde3440..7dc58a215 100644
--- a/doc/c-extensions
+++ b/doc/c-extensions
@@ -62,7 +62,7 @@ TODO: Solaris.
 
 TODO: *BSD.
 
-Windows-dependent code assumes at least NT 5.1.
+Windows-dependent code assumes at least NT 6.0.
 
 OSX support is generally limited to the most recent version.  Currently
 that means 10.5.
diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c
index 00053beb0..250051425 100644
--- a/hw/xwin/InitOutput.c
+++ b/hw/xwin/InitOutput.c
@@ -716,6 +716,8 @@ winUseMsg(void)
            "\tthe updated region when num_boxes, or more, are in the\n"
            "\tupdated region.\n");
 
+    ErrorF("-[no]compositealpha\n"
+           "\tX windows with per-pixel alpha are composited into the Windows desktop.\n");
     ErrorF("-[no]compositewm\n"
            "\tUse the Composite extension to keep a bitmap image of each top-level\n"
            "\tX window, so window contents which are occluded show correctly in\n"
@@ -803,7 +805,7 @@ winUseMsg(void)
            "\tSpecify an optional refresh rate to use in fullscreen mode\n"
            "\twith a DirectDraw engine.\n");
 
-    ErrorF("-resize=none|scrollbars|randr"
+    ErrorF("-resize=none|scrollbars|randr\n"
            "\tIn windowed mode, [don't] allow resizing of the window. 'scrollbars'\n"
            "\tmode gives the window scrollbars as needed, 'randr' mode uses the RANR\n"
            "\textension to resize the X screen.  'randr' is the default.\n");
diff --git a/hw/xwin/Makefile.am b/hw/xwin/Makefile.am
index 42fc9dd68..6ef89196a 100644
--- a/hw/xwin/Makefile.am
+++ b/hw/xwin/Makefile.am
@@ -27,7 +27,7 @@ SRCS_MULTIWINDOW = \
 	winmultiwindowwndproc.c \
 	propertystore.h \
 	winSetAppUserModelID.c
-MULTIWINDOW_SYS_LIBS = -lshlwapi -lole32
+MULTIWINDOW_SYS_LIBS = -lshlwapi -lole32 -ldwmapi
 
 SRCS_RANDR = \
 	winrandr.c
diff --git a/hw/xwin/man/XWin.man b/hw/xwin/man/XWin.man
index e61589e8e..f9305f592 100644
--- a/hw/xwin/man/XWin.man
+++ b/hw/xwin/man/XWin.man
@@ -176,6 +176,15 @@ Use Composite extension redirection to maintain a bitmap image of each top-level
 X window, so window contents which are occluded show correctly in task bar and
 task switcher previews.
 The default is enabled.
+.TP 8
+.B \-[no]compositealpha
+X windows with per-pixel alpha are composited into the \fIWindows\fP desktop
+(i.e. a \fIWindows\fP window can be seen through any transparency in an X window
+placed over it).
+
+This option has no effect on Windows 8 and 8.1.
+This option has no effect if \fB-compositewm\fP is disabled.
+The default is disabled.
 
 .SH OPTIONS CONTROLLING WINDOWS INTEGRATION
 .TP 8
diff --git a/hw/xwin/meson.build b/hw/xwin/meson.build
index 3462c396d..c1a2917b8 100644
--- a/hw/xwin/meson.build
+++ b/hw/xwin/meson.build
@@ -44,7 +44,7 @@ srcs_windows += [
      'propertystore.h',
      'winSetAppUserModelID.c',
 ]
-xwin_sys_libs += ['-lshlwapi', '-lole32']
+xwin_sys_libs += ['-lshlwapi', '-lole32', '-ldwmapi']
 
 srcs_windows += [
      'winrandr.c',
diff --git a/hw/xwin/winglobals.c b/hw/xwin/winglobals.c
index d1a0d4587..3212c6beb 100644
--- a/hw/xwin/winglobals.c
+++ b/hw/xwin/winglobals.c
@@ -59,6 +59,7 @@ HWND g_hDlgAbout = NULL;
 const char *g_pszQueryHost = NULL;
 Bool g_fXdmcpEnabled = FALSE;
 Bool g_fAuthEnabled = FALSE;
+Bool g_fCompositeAlpha = FALSE;
 HICON g_hIconX = NULL;
 HICON g_hSmallIconX = NULL;
 
diff --git a/hw/xwin/winglobals.h b/hw/xwin/winglobals.h
index 82fc1c5ec..77af6125a 100644
--- a/hw/xwin/winglobals.h
+++ b/hw/xwin/winglobals.h
@@ -50,6 +50,7 @@ extern Bool g_fLogInited;
 
 extern Bool g_fAuthEnabled;
 extern Bool g_fXdmcpEnabled;
+extern Bool g_fCompositeAlpha;
 
 extern Bool g_fNoHelpMessageBox;
 extern Bool g_fNativeGl;
diff --git a/hw/xwin/winmultiwindowwndproc.c b/hw/xwin/winmultiwindowwndproc.c
index 48e9f9dd8..587884d11 100644
--- a/hw/xwin/winmultiwindowwndproc.c
+++ b/hw/xwin/winmultiwindowwndproc.c
@@ -35,12 +35,18 @@
 #ifdef HAVE_XWIN_CONFIG_H
 #include <xwin-config.h>
 #endif
+
 #include "win.h"
 #include "dixevents.h"
 #include "winmultiwindowclass.h"
 #include "winprefs.h"
 #include "winmsg.h"
 #include "inputstr.h"
+#include <dwmapi.h>
+
+#ifndef WM_DWMCOMPOSITIONCHANGED
+#define WM_DWMCOMPOSITIONCHANGED 0x031e
+#endif
 
 extern void winUpdateWindowPosition(HWND hWnd, HWND * zstyle);
 
@@ -294,6 +300,113 @@ winStartMousePolling(winPrivScreenPtr s_pScreenPriv)
                                             MOUSE_POLLING_INTERVAL, NULL);
 }
 
+/* Undocumented */
+typedef struct _ACCENTPOLICY
+{
+    ULONG AccentState;
+    ULONG AccentFlags;
+    ULONG GradientColor;
+    ULONG AnimationId;
+} ACCENTPOLICY;
+
+#define ACCENT_ENABLE_BLURBEHIND 3
+
+typedef struct _WINCOMPATTR
+{
+    DWORD attribute;
+    PVOID pData;
+    ULONG dataSize;
+} WINCOMPATTR;
+
+#define WCA_ACCENT_POLICY 19
+
+typedef WINBOOL WINAPI (*PFNSETWINDOWCOMPOSITIONATTRIBUTE)(HWND, WINCOMPATTR *);
+
+static void
+CheckForAlpha(HWND hWnd, WindowPtr pWin, winScreenInfo *pScreenInfo)
+{
+    /* Check (once) which API we should use */
+    static Bool doOnce = TRUE;
+    static PFNSETWINDOWCOMPOSITIONATTRIBUTE pSetWindowCompositionAttribute = NULL;
+    static Bool useDwmEnableBlurBehindWindow = FALSE;
+
+    if (doOnce)
+        {
+            OSVERSIONINFOEX osvi = {0};
+            osvi.dwOSVersionInfoSize = sizeof(osvi);
+            GetVersionEx((LPOSVERSIONINFO)&osvi);
+
+            /* SetWindowCompositionAttribute() exists on Windows 7 and later,
+               but doesn't work for this purpose, so first check for Windows 10
+               or later */
+            if (osvi.dwMajorVersion >= 10)
+                {
+                    HMODULE hUser32 = GetModuleHandle("user32");
+
+                    if (hUser32)
+                        pSetWindowCompositionAttribute = (PFNSETWINDOWCOMPOSITIONATTRIBUTE) GetProcAddress(hUser32, "SetWindowCompositionAttribute");
+                    winDebug("SetWindowCompositionAttribute %s\n", pSetWindowCompositionAttribute ? "found" : "not found");
+                }
+            /* On Windows 7 and Windows Vista, use DwmEnableBlurBehindWindow() */
+            else if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion <= 1))
+                {
+                    useDwmEnableBlurBehindWindow = TRUE;
+                }
+            /* On Windows 8 and Windows 8.1, using the alpha channel on those
+               seems near impossible, so we don't do anything. */
+
+            doOnce = FALSE;
+        }
+
+    /* alpha-channel use is wanted */
+    if (!g_fCompositeAlpha || !pScreenInfo->fCompositeWM)
+        return;
+
+    /* Image has alpha ... */
+    if (pWin->drawable.depth != 32)
+        return;
+
+    /* ... and we can do something useful with it? */
+    if (pSetWindowCompositionAttribute)
+        {
+            WINBOOL rc;
+            /* Use the (undocumented) SetWindowCompositionAttribute, if
+               available, to turn on alpha channel use on Windows 10. */
+            ACCENTPOLICY policy = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 } ;
+            WINCOMPATTR data = { WCA_ACCENT_POLICY,  &policy, sizeof(ACCENTPOLICY) };
+
+            /* This turns on DWM looking at the alpha-channel of this window */
+            winDebug("enabling alpha for XID %08x hWnd %p, using SetWindowCompositionAttribute()\n", (unsigned int)pWin->drawable.id, hWnd);
+            rc = pSetWindowCompositionAttribute(hWnd, &data);
+            if (!rc)
+                ErrorF("SetWindowCompositionAttribute failed: %d\n", (int)GetLastError());
+        }
+    else if (useDwmEnableBlurBehindWindow)
+        {
+            HRESULT rc;
+            WINBOOL enabled;
+
+            rc = DwmIsCompositionEnabled(&enabled);
+            if ((rc == S_OK) && enabled)
+                {
+                    /* Use DwmEnableBlurBehindWindow, to turn on alpha channel
+                       use on Windows Vista and Windows 7 */
+                    DWM_BLURBEHIND bbh;
+                    bbh.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION | DWM_BB_TRANSITIONONMAXIMIZED;
+                    bbh.fEnable = TRUE;
+                    bbh.hRgnBlur = NULL;
+                    bbh.fTransitionOnMaximized = TRUE; /* What does this do ??? */
+
+                    /* This terribly-named function actually controls if DWM
+                       looks at the alpha channel of this window */
+                    winDebug("enabling alpha for XID %08x hWnd %p, using DwmEnableBlurBehindWindow()\n", (unsigned int)pWin->drawable.id, hWnd);
+                    rc = DwmEnableBlurBehindWindow(hWnd, &bbh);
+                    if (rc != S_OK)
+                        ErrorF("DwmEnableBlurBehindWindow failed: %x, %d\n", (int)rc, (int)GetLastError());
+                }
+        }
+}
+
 /*
  * winTopLevelWindowProc - Window procedure for all top-level Windows windows.
  */
@@ -416,6 +529,8 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 
         SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) XMING_SIGNATURE);
 
+        CheckForAlpha(hwnd, pWin, s_pScreenInfo);
+
         return 0;
 
     case WM_INIT_SYS_MENU:
@@ -1114,6 +1229,12 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
         }
         break;
 
+
+    case WM_DWMCOMPOSITIONCHANGED:
+        /* This message is only sent on Vista/W7 */
+        CheckForAlpha(hwnd, pWin, s_pScreenInfo);
+
+        return 0;
     default:
         break;
     }
diff --git a/hw/xwin/winprocarg.c b/hw/xwin/winprocarg.c
index e849cbc97..29e91abc8 100644
--- a/hw/xwin/winprocarg.c
+++ b/hw/xwin/winprocarg.c
@@ -592,6 +592,25 @@ ddxProcessArgument(int argc, char *argv[], int i)
     }
 
     /*
+     * Look for the '-compositealpha' argument
+     */
+    if (IS_OPTION("-compositealpha")) {
+        g_fCompositeAlpha = TRUE;
+
+        /* Indicate that we have processed this argument */
+        return 1;
+    }
+    /*
+     * Look for the '-nocompositealpha' argument
+     */
+    if (IS_OPTION("-nocompositealpha")) {
+        g_fCompositeAlpha  = FALSE;
+
+        /* Indicate that we have processed this argument */
+        return 1;
+    }
+
+    /*
      * Look for the '-multiplemonitors' argument
      */
     if (IS_OPTION("-multiplemonitors")
commit 2e1bc743734cc1e1043c8f2c9497a5a172507bc9
Author: Jon Turney <jon.turney at dronecode.org.uk>
Date:   Tue Dec 1 19:33:38 2015 +0000

    hw/xwin: Set convenience variables for WM_CREATE as well
    
    Set convenience variables in winTopLevelWindowProc() for WM_CREATE as
    well.

diff --git a/hw/xwin/winmultiwindowwndproc.c b/hw/xwin/winmultiwindowwndproc.c
index 1cac4a9f4..48e9f9dd8 100644
--- a/hw/xwin/winmultiwindowwndproc.c
+++ b/hw/xwin/winmultiwindowwndproc.c
@@ -322,6 +322,20 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
                          lParam);
 #endif
 
+    /*
+       If this is WM_CREATE, set up the Windows window properties which point to
+       X window information, before we populate local convenience variables...
+     */
+    if (message == WM_CREATE) {
+        SetProp(hwnd,
+                WIN_WINDOW_PROP,
+                (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams);
+        SetProp(hwnd,
+                WIN_WID_PROP,
+                (HANDLE) (INT_PTR)winGetWindowID(((LPCREATESTRUCT) lParam)->
+                                                 lpCreateParams));
+    }
+
     /* Check if the Windows window property for our X window pointer is valid */
     if ((pWin = GetProp(hwnd, WIN_WINDOW_PROP)) != NULL) {
         /* Our X window pointer is valid */
@@ -382,18 +396,6 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     /* Branch on message type */
     switch (message) {
     case WM_CREATE:
-
-        /* */
-        SetProp(hwnd,
-                WIN_WINDOW_PROP,
-                (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams);
-
-        /* */
-        SetProp(hwnd,
-                WIN_WID_PROP,
-                (HANDLE) (INT_PTR) winGetWindowID(((LPCREATESTRUCT) lParam)->
-                                                  lpCreateParams));
-
         /*
          * Make X windows' Z orders sync with Windows windows because
          * there can be AlwaysOnTop windows overlapped on the window
commit f67918353a14dad8aa75c965e036d106e7d2d1a4
Author: Jon Turney <jon.turney at dronecode.org.uk>
Date:   Sat Nov 7 19:44:09 2015 +0000

    hw/xwin: Improve performance of -compositewm
    
    I think that a major cost in the current implementation is doing a
    CreateDIBSection()/DestroyObject() on every refresh.  So provide our own
    CreatePixmap() instead, which does the CreateDIBSection(), once.
    
    Testcase: glxgears or foobillard with direct swrast
    Testcase: scrolling in a full-screen xterm
    
    v2:
    Fix handling of RENDER Scratch Pixmaps
    (A problem easily shown with gitk or emacs)
    
    v3:
    Note that we don't own screen pixmap to release in DestroyPixmap
    Log if unimplemented slow-path ever gets hit

diff --git a/hw/xwin/win.h b/hw/xwin/win.h
index b667ceb66..8eabeae31 100644
--- a/hw/xwin/win.h
+++ b/hw/xwin/win.h
@@ -296,11 +296,10 @@ typedef Bool (*winCreateScreenResourcesProc) (ScreenPtr);
  */
 
 typedef struct {
-    HDC hdcSelected;
     HBITMAP hBitmap;
-    BYTE *pbBits;
-    DWORD dwScanlineBytes;
+    void *pbBits;
     BITMAPINFOHEADER *pbmih;
+    BOOL owned;
 } winPrivPixmapRec, *winPrivPixmapPtr;
 
 /*
@@ -511,6 +510,7 @@ typedef struct _winPrivScreenRec {
     ResizeWindowProcPtr ResizeWindow;
     MoveWindowProcPtr MoveWindow;
     SetShapeProcPtr SetShape;
+    ModifyPixmapHeaderProcPtr ModifyPixmapHeader;
 
     winCursorRec cursor;
 
@@ -946,6 +946,19 @@ void
 winCopyWindowMultiWindow(WindowPtr pWin, DDXPointRec oldpt,
                          RegionPtr oldRegion);
 
+PixmapPtr
+winCreatePixmapMultiwindow(ScreenPtr pScreen, int width, int height, int depth,
+                           unsigned usage_hint);
+Bool
+winDestroyPixmapMultiwindow(PixmapPtr pPixmap);
+
+Bool
+winModifyPixmapHeaderMultiwindow(PixmapPtr pPixmap,
+                                 int width,
+                                 int height,
+                                 int depth,
+                                 int bitsPerPixel, int devKind, void *pPixData);
+
 XID
  winGetWindowID(WindowPtr pWin);
 
diff --git a/hw/xwin/winmultiwindowwindow.c b/hw/xwin/winmultiwindowwindow.c
index 4ec5634af..4eec72be2 100644
--- a/hw/xwin/winmultiwindowwindow.c
+++ b/hw/xwin/winmultiwindowwindow.c
@@ -960,3 +960,259 @@ winAdjustXWindow(WindowPtr pWin, HWND hwnd)
 #undef WIDTH
 #undef HEIGHT
 }
+
+/*
+  Helper function for creating a DIB to back a pixmap
+ */
+static HBITMAP winCreateDIB(ScreenPtr pScreen, int width, int height, int bpp, void **ppvBits, BITMAPINFOHEADER **ppbmih)
+{
+    winScreenPriv(pScreen);
+    BITMAPV4HEADER *pbmih = NULL;
+    HBITMAP hBitmap = NULL;
+
+    /* Allocate bitmap info header */
+    pbmih = malloc(sizeof(BITMAPV4HEADER) + 256 * sizeof(RGBQUAD));
+    if (pbmih == NULL) {
+        ErrorF("winCreateDIB: malloc() failed\n");
+        return NULL;
+    }
+    memset(pbmih, 0, sizeof(BITMAPV4HEADER) + 256 * sizeof(RGBQUAD));
+
+    /* Describe bitmap to be created */
+    pbmih->bV4Size = sizeof(BITMAPV4HEADER);
+    pbmih->bV4Width = width;
+    pbmih->bV4Height = -height;  /* top-down bitmap */
+    pbmih->bV4Planes = 1;
+    pbmih->bV4BitCount = bpp;
+    if (bpp == 1) {
+        RGBQUAD *bmiColors = (RGBQUAD *)((char *)pbmih + sizeof(BITMAPV4HEADER));
+        pbmih->bV4V4Compression = BI_RGB;
+        bmiColors[1].rgbBlue = 255;
+        bmiColors[1].rgbGreen = 255;
+        bmiColors[1].rgbRed = 255;
+    }
+    else if (bpp == 8) {
+        pbmih->bV4V4Compression = BI_RGB;
+        pbmih->bV4ClrUsed = 0;
+    }
+    else if (bpp == 16) {
+        pbmih->bV4V4Compression = BI_RGB;
+        pbmih->bV4ClrUsed = 0;
+    }
+    else if (bpp == 32) {
+        pbmih->bV4V4Compression = BI_BITFIELDS;
+        pbmih->bV4RedMask = pScreenPriv->dwRedMask;
+        pbmih->bV4GreenMask = pScreenPriv->dwGreenMask;
+        pbmih->bV4BlueMask = pScreenPriv->dwBlueMask;
+        pbmih->bV4AlphaMask = 0;
+    }
+    else {
+        ErrorF("winCreateDIB: %d bpp unhandled\n", bpp);
+    }
+
+    /* Create a DIB with a bit pointer */
+    hBitmap = CreateDIBSection(NULL,
+                               (BITMAPINFO *) pbmih,
+                               DIB_RGB_COLORS, ppvBits, NULL, 0);
+    if (hBitmap == NULL) {
+        ErrorF("winCreateDIB: CreateDIBSection() failed\n");
+        return NULL;
+    }
+
+    /* Store the address of the BMIH in the ppbmih parameter */
+    *ppbmih = (BITMAPINFOHEADER *)pbmih;
+
+    winDebug("winCreateDIB: HBITMAP %p pBMIH %p pBits %p\n", hBitmap, pbmih, *ppvBits);
+
+    return hBitmap;
+}
+
+
+/*
+ * CreatePixmap - See Porting Layer Definition
+ */
+PixmapPtr
+winCreatePixmapMultiwindow(ScreenPtr pScreen, int width, int height, int depth,
+                           unsigned usage_hint)
+{
+    winPrivPixmapPtr pPixmapPriv = NULL;
+    PixmapPtr pPixmap = NULL;
+    int bpp, paddedwidth;
+
+    /* allocate Pixmap header and privates */
+    pPixmap = AllocatePixmap(pScreen, 0);
+    if (!pPixmap)
+        return NullPixmap;
+
+    bpp = BitsPerPixel(depth);
+    /*
+      DIBs have 4-byte aligned rows
+
+      paddedwidth is the width in bytes, padded to align
+
+      i.e. round up the number of bits used by a row so it is a multiple of 32,
+      then convert to bytes
+    */
+    paddedwidth = (((bpp * width) + 31) & ~31)/8;
+
+    /* setup Pixmap header */
+    pPixmap->drawable.type = DRAWABLE_PIXMAP;
+    pPixmap->drawable.class = 0;
+    pPixmap->drawable.pScreen = pScreen;
+    pPixmap->drawable.depth = depth;
+    pPixmap->drawable.bitsPerPixel = bpp;
+    pPixmap->drawable.id = 0;
+    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+    pPixmap->drawable.x = 0;
+    pPixmap->drawable.y = 0;
+    pPixmap->drawable.width = width;
+    pPixmap->drawable.height = height;
+    pPixmap->devKind = paddedwidth;
+    pPixmap->refcnt = 1;
+    pPixmap->devPrivate.ptr = NULL; // later set to pbBits
+    pPixmap->master_pixmap = NULL;
+#ifdef COMPOSITE
+    pPixmap->screen_x = 0;
+    pPixmap->screen_y = 0;
+#endif
+    pPixmap->usage_hint = usage_hint;
+
+    /* Check for zero width or height pixmaps */
+    if (width == 0 || height == 0) {
+        /* DIBs with a dimension of 0 aren't permitted, so don't try to allocate
+           a DIB, just set fields and return */
+        return pPixmap;
+    }
+
+    /* Initialize pixmap privates */
+    pPixmapPriv = winGetPixmapPriv(pPixmap);
+    pPixmapPriv->hBitmap = NULL;
+    pPixmapPriv->pbBits = NULL;
+    pPixmapPriv->pbmih = NULL;
+
+    /* Create a DIB for the pixmap */
+    pPixmapPriv->hBitmap = winCreateDIB(pScreen, width, height, bpp, &pPixmapPriv->pbBits, &pPixmapPriv->pbmih);
+    pPixmapPriv->owned = TRUE;
+
+    winDebug("winCreatePixmap: pPixmap %p HBITMAP %p pBMIH %p pBits %p\n", pPixmap, pPixmapPriv->hBitmap, pPixmapPriv->pbmih, pPixmapPriv->pbBits);
+    /* XXX: so why do we need this in privates ??? */
+    pPixmap->devPrivate.ptr = pPixmapPriv->pbBits;
+
+    return pPixmap;
+}
+
+/*
+ * DestroyPixmap - See Porting Layer Definition
+ */
+Bool
+winDestroyPixmapMultiwindow(PixmapPtr pPixmap)
+{
+    winPrivPixmapPtr pPixmapPriv = NULL;
+
+    /* Bail early if there is not a pixmap to destroy */
+    if (pPixmap == NULL) {
+        return TRUE;
+    }
+
+    /* Decrement reference count, return if nonzero */
+    --pPixmap->refcnt;
+    if (pPixmap->refcnt != 0)
+        return TRUE;
+
+    winDebug("winDestroyPixmap: pPixmap %p\n", pPixmap);
+
+    /* Get a handle to the pixmap privates */
+    pPixmapPriv = winGetPixmapPriv(pPixmap);
+
+    /* Nothing to do if we don't own the DIB */
+    if (!pPixmapPriv->owned)
+        return TRUE;
+
+    /* Free GDI bitmap */
+    if (pPixmapPriv->hBitmap)
+        DeleteObject(pPixmapPriv->hBitmap);
+
+    /* Free the bitmap info header memory */
+    free(pPixmapPriv->pbmih);
+    pPixmapPriv->pbmih = NULL;
+
+    /* Free the pixmap memory */
+    free(pPixmap);
+    pPixmap = NULL;
+
+    return TRUE;
+}
+
+/*
+ * ModifyPixmapHeader - See Porting Layer Definition
+ */
+Bool
+winModifyPixmapHeaderMultiwindow(PixmapPtr pPixmap,
+                                 int width,
+                                 int height,
+                                 int depth,
+                                 int bitsPerPixel, int devKind, void *pPixData)
+{
+    int i;
+    winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap);
+    Bool fResult;
+
+    /* reinitialize everything */
+    pPixmap->drawable.depth = depth;
+    pPixmap->drawable.bitsPerPixel = bitsPerPixel;
+    pPixmap->drawable.id = 0;
+    pPixmap->drawable.x = 0;
+    pPixmap->drawable.y = 0;
+    pPixmap->drawable.width = width;
+    pPixmap->drawable.height = height;
+    pPixmap->devKind = devKind;
+    pPixmap->refcnt = 1;
+    pPixmap->devPrivate.ptr = pPixData;
+    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+
+    /*
+      This can be used for some out-of-order initialization on the screen
+      pixmap, which is the only case we can properly support.
+    */
+
+    /* Look for which screen this pixmap corresponds to */
+    for (i = 0; i < screenInfo.numScreens; i++) {
+        ScreenPtr pScreen = screenInfo.screens[i];
+        winScreenPriv(pScreen);
+        winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo;
+
+        if (pScreenInfo->pfb == pPixData)
+            {
+                /* and initialize pixmap privates from screen privates */
+                pPixmapPriv->hBitmap = pScreenPriv->hbmpShadow;
+                pPixmapPriv->pbBits = pScreenInfo->pfb;
+                pPixmapPriv->pbmih = pScreenPriv->pbmih;
+
+                /* mark these not to get released by DestroyPixmap */
+                pPixmapPriv->owned = FALSE;
+
+                return TRUE;
+            }
+    }
+
+    /* Otherwise, since creating a DIBSection from arbitrary memory is not
+     * possible, fallback to normal.  If needed, we can create a DIBSection with
+     * a copy of the bits later (see comment about a potential slow-path in
+     * winBltExposedWindowRegionShadowGDI()). */
+    pPixmapPriv->hBitmap = 0;
+    pPixmapPriv->pbBits = 0;
+    pPixmapPriv->pbmih = 0;
+    pPixmapPriv->owned = FALSE;
+
+    winDebug("winModifyPixmapHeaderMultiwindow: falling back\n");
+
+    {
+        ScreenPtr pScreen = pPixmap->drawable.pScreen;
+        winScreenPriv(pScreen);
+        WIN_UNWRAP(ModifyPixmapHeader);
+        fResult = (*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData);
+        WIN_WRAP(ModifyPixmapHeader, winModifyPixmapHeaderMultiwindow);
+    }
+
+    return fResult;
+}
diff --git a/hw/xwin/winscrinit.c b/hw/xwin/winscrinit.c
index fdaa1d6b3..9c0473019 100644
--- a/hw/xwin/winscrinit.c
+++ b/hw/xwin/winscrinit.c
@@ -258,6 +258,11 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv)
         return FALSE;
     }
 
+    if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) {
+        ErrorF("-compositewm disabled due to 8bpp depth\n");
+        pScreenInfo->fCompositeWM = FALSE;
+    }
+
     /* Apparently we need this for the render extension */
     miSetPixmapDepths();
 
@@ -417,6 +422,7 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv)
         WRAP(MoveWindow);
         WRAP(CopyWindow);
         WRAP(SetShape);
+        WRAP(ModifyPixmapHeader);
 
         /* Assign multi-window window procedures to be top level procedures */
         pScreen->CreateWindow = winCreateWindowMultiWindow;
@@ -432,6 +438,12 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv)
         pScreen->CopyWindow = winCopyWindowMultiWindow;
         pScreen->SetShape = winSetShapeMultiWindow;
 
+        if (pScreenInfo->fCompositeWM) {
+            pScreen->CreatePixmap = winCreatePixmapMultiwindow;
+            pScreen->DestroyPixmap = winDestroyPixmapMultiwindow;
+            pScreen->ModifyPixmapHeader = winModifyPixmapHeaderMultiwindow;
+        }
+
         /* Undefine the WRAP macro, as it is not needed elsewhere */
 #undef WRAP
     }
@@ -461,11 +473,6 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv)
 
 
     if (pScreenInfo->fMultiWindow) {
-        if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) {
-            ErrorF("-compositewm disabled due to 8bpp depth\n");
-            pScreenInfo->fCompositeWM = FALSE;
-        }
-
 #if CYGDEBUG || YES
         winDebug("winFinishScreenInitFB - Calling winInitWM.\n");
 #endif
diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c
index 24fff71f3..65678962b 100644
--- a/hw/xwin/winshadgdi.c
+++ b/hw/xwin/winshadgdi.c
@@ -831,41 +831,22 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin)
         HBITMAP hBitmap;
         HDC hdcPixmap;
         PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
+        winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap);
 
-        /*
-          This is kind of clunky, and possibly not very efficient.
-
-          Would it be more efficient to only create the DIB bitmap when the
-          composite bitmap is realloced and store it in a window private?
-
-          But we still end up copying and converting all the bits from the
-          window pixmap into a DDB for every update.
-
-          Perhaps better still would be to wrap the screen CreatePixmap routine
-          so it uses CreateDIBSection()?
-         */
-
-        BITMAPV4HEADER bmih;
-        memset(&bmih, 0, sizeof(bmih));
-        bmih.bV4Size = sizeof(BITMAPV4HEADER);
-        bmih.bV4Width = pPixmap->drawable.width;
-        bmih.bV4Height = -pPixmap->drawable.height; /* top-down bitmap */
-        bmih.bV4Planes = 1;
-        bmih.bV4BitCount = pPixmap->drawable.bitsPerPixel;
-        bmih.bV4SizeImage = 0;
         /* window pixmap format is the same as the screen pixmap */
         assert(pPixmap->drawable.bitsPerPixel > 8);
-        bmih.bV4V4Compression = BI_BITFIELDS;
-        bmih.bV4RedMask = pScreenPriv->dwRedMask;
-        bmih.bV4GreenMask = pScreenPriv->dwGreenMask;
-        bmih.bV4BlueMask = pScreenPriv->dwBlueMask;
-        bmih.bV4AlphaMask = 0;
-
-        /* Create the window bitmap from the pixmap */
-        hBitmap = CreateDIBitmap(pScreenPriv->hdcScreen,
-                                 (BITMAPINFOHEADER *)&bmih, CBM_INIT,
-                                 pPixmap->devPrivate.ptr, (BITMAPINFO *)&bmih,
-                                 DIB_RGB_COLORS);
+
+        /* Get the window bitmap from the pixmap */
+        hBitmap = pPixmapPriv->hBitmap;
+
+        /* XXX: There may be a need for a slow-path here: If hBitmap is NULL
+           (because we couldn't back the pixmap with a Windows DIB), we should
+           fall-back to creating a Windows DIB from the pixmap, then deleting it
+           after the BitBlt (as this this code did before the fast-path was
+           added). */
+        if (!hBitmap) {
+            ErrorF("winBltExposedWindowRegionShadowGDI - slow path unimplemented\n");
+        }
 
         /* Select the window bitmap into a screen-compatible DC */
         hdcPixmap = CreateCompatibleDC(pScreenPriv->hdcScreen);
@@ -883,9 +864,8 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin)
             ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: 0x%08x\n",
                    GetLastError());
 
-        /* Release */
+        /* Release DC */
         DeleteDC(hdcPixmap);
-        DeleteObject(hBitmap);
     }
     else
 #endif
commit 6865fe71477206d989f982235fc32be4ff164ccd
Author: Jon Turney <jon.turney at dronecode.org.uk>
Date:   Mon Aug 10 20:16:16 2015 +0100

    hw/xwin: Avoid artefacts when resizing a window
    
    Fill the area outside the current window size with black, rather than
    leaking framebuffer contents or leaving it undrawn.

diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c
index 0235d1b2c..24fff71f3 100644
--- a/hw/xwin/winshadgdi.c
+++ b/hw/xwin/winshadgdi.c
@@ -916,6 +916,30 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin)
     }
     }
 
+    /* If part of the invalidated region is outside the window (which can happen
+       if the native window is being re-sized), fill that area with black */
+    if (ps.rcPaint.right > ps.rcPaint.left + pWin->drawable.width) {
+        BitBlt(hdcUpdate,
+               ps.rcPaint.left + pWin->drawable.width,
+               ps.rcPaint.top,
+               ps.rcPaint.right - (ps.rcPaint.left + pWin->drawable.width),
+               ps.rcPaint.bottom - ps.rcPaint.top,
+               NULL,
+               0, 0,
+               BLACKNESS);
+    }
+
+    if (ps.rcPaint.bottom > ps.rcPaint.top + pWin->drawable.height) {
+        BitBlt(hdcUpdate,
+               ps.rcPaint.left,
+               ps.rcPaint.top + pWin->drawable.height,
+               ps.rcPaint.right - ps.rcPaint.left,
+               ps.rcPaint.bottom - (ps.rcPaint.top + pWin->drawable.height),
+               NULL,
+               0, 0,
+               BLACKNESS);
+    }
+
     /* EndPaint frees the DC */
     EndPaint(hWnd, &ps);
 
commit ebcea16e71cd9c037351f2dc4527ca696346c8a6
Author: Jon Turney <jon.turney at dronecode.org.uk>
Date:   Mon Aug 3 16:47:38 2015 +0100

    hw/xwin: A simpleminded attempt at composition
    
    Rather than drawing the window contents from the shadow framebuffer, use
    Composite extension redirection to cause the server to maintain a bitmap
    image of each top-level X window, and draw the window contents from
    that, so that window contents which are occluded in the framebuffer show
    correctly in the task bar and task switcher previews.
    
    v2:
    Fix incorrect use of memset() found by gcc5
    
    hw/xwin/winshadgdi.c: In function ‘winBltExposedWindowRegionShadowGDI’:
    hw/xwin/winshadgdi.c:861:9: warning: ‘memset’ used with constant zero length parameter; this could be due to transposed parameters [-Wmemset-transposed-args]
    
    v3:
    Turn on -compositewm by default
    
    v4:
    Ignore -swcursor if -compositewm
    
    -swcursor is not compatible with -compositewm (because the window
    contents are drawn from an off-screen pixmap, not from the screen
    pixmap, where the software cursor will be drawn).
    
    v5:
    Update meson.build also
    Add -compositewm option to help output
    Update CI to install prerequisites

diff --git a/.appveyor.yml b/.appveyor.yml
index dd244b8db..50072acd4 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -50,6 +50,7 @@ libXmu-devel,\
 libXpm-devel,\
 libXrender-devel,\
 libXtst-devel,\
+libxcb-composite-devel,\
 libxcb-ewmh-devel,\
 libxcb-icccm-devel,\
 libxcb-image-devel,\
diff --git a/configure.ac b/configure.ac
index 23c0ac285..55bb6942a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2081,7 +2081,7 @@ if test "x$XWIN" = xyes; then
 	AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support])
 	AC_CHECK_TOOL(WINDRES, windres)
 
-	PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau xfixes x11-xcb xcb-aux xcb-image xcb-ewmh xcb-icccm])
+	PKG_CHECK_MODULES([XWINMODULES],[x11 xau xdmcp xfixes x11-xcb xcb-aux xcb-composite xcb-image xcb-ewmh xcb-icccm])
 
 	if test "x$WINDOWSDRI" = xauto; then
 		PKG_CHECK_EXISTS([windowsdriproto], [WINDOWSDRI=yes], [WINDOWSDRI=no])
diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c
index ddbf04253..00053beb0 100644
--- a/hw/xwin/InitOutput.c
+++ b/hw/xwin/InitOutput.c
@@ -716,6 +716,11 @@ winUseMsg(void)
            "\tthe updated region when num_boxes, or more, are in the\n"
            "\tupdated region.\n");
 
+    ErrorF("-[no]compositewm\n"
+           "\tUse the Composite extension to keep a bitmap image of each top-level\n"
+           "\tX window, so window contents which are occluded show correctly in\n"
+           "\ttask bar and task switcher previews.\n");
+
 #ifdef XWIN_XF86CONFIG
     ErrorF("-config\n" "\tSpecify a configuration file.\n");
 
diff --git a/hw/xwin/man/XWin.man b/hw/xwin/man/XWin.man
index 2401f9f09..e61589e8e 100644
--- a/hw/xwin/man/XWin.man
+++ b/hw/xwin/man/XWin.man
@@ -170,6 +170,12 @@ on its own is equivalent to \fB\-resize=randr\fP
 Add the host name to the window title for X applications which are running
 on remote hosts, when that information is available and it's useful to do so.
 The default is enabled.
+.TP 8
+.B \-[no]compositewm
+Use Composite extension redirection to maintain a bitmap image of each top-level
+X window, so window contents which are occluded show correctly in task bar and
+task switcher previews.
+The default is enabled.
 
 .SH OPTIONS CONTROLLING WINDOWS INTEGRATION
 .TP 8
@@ -206,6 +212,7 @@ The default is enabled.
 .TP 8
 .B \-swcursor
 Disable the usage of the \fIWindows\fP cursor and use the X11 software cursor instead.
+This option is ignored if \fB-compositewm\fP is also enabled.
 .TP 8
 .B \-[no]trayicon
 Do not create a tray icon.  Default is to create one
diff --git a/hw/xwin/meson.build b/hw/xwin/meson.build
index 3ec809fef..3462c396d 100644
--- a/hw/xwin/meson.build
+++ b/hw/xwin/meson.build
@@ -137,6 +137,7 @@ xwin_dep = [
     dependency('xcb-image'),
     dependency('xcb-ewmh'),
     dependency('xcb-icccm'),
+    dependency('xcb-composite'),
 ]
 
 executable(
diff --git a/hw/xwin/win.h b/hw/xwin/win.h
index 18f918d29..b667ceb66 100644
--- a/hw/xwin/win.h
+++ b/hw/xwin/win.h
@@ -391,6 +391,7 @@ typedef struct {
     Bool fDecoration;
     Bool fRootless;
     Bool fMultiWindow;
+    Bool fCompositeWM;
     Bool fMultiMonitorOverride;
     Bool fMultipleMonitors;
     Bool fLessPointer;
diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c
index 32bc722e2..0734006fc 100644
--- a/hw/xwin/winmultiwindowwm.c
+++ b/hw/xwin/winmultiwindowwm.c
@@ -49,6 +49,7 @@
 #include <xcb/xcb_icccm.h>
 #include <xcb/xcb_ewmh.h>
 #include <xcb/xcb_aux.h>
+#include <xcb/composite.h>
 
 #include <X11/Xwindows.h>
 
@@ -116,6 +117,7 @@ typedef struct _WMInfo {
     xcb_atom_t atmUtf8String;
     xcb_atom_t atmNetWmName;
     xcb_ewmh_connection_t ewmh;
+    Bool fCompositeWM;
 } WMInfoRec, *WMInfoPtr;
 
 typedef struct _WMProcArgRec {
@@ -1038,6 +1040,8 @@ winMultiWindowXMsgProc(void *pArg)
     xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints;
     int iReturn;
     xcb_auth_info_t *auth_info;
+    xcb_screen_t *root_screen;
+    xcb_window_t root_window_id;
 
     winDebug("winMultiWindowXMsgProc - Hello\n");
 
@@ -1110,11 +1114,11 @@ winMultiWindowXMsgProc(void *pArg)
         pthread_exit(NULL);
     }
 
-    {
-        /* Get root window id */
-        xcb_screen_t *root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen);
-        xcb_window_t root_window_id = root_screen->root;
+    /* Get root window id */
+    root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen);
+    root_window_id = root_screen->root;
 
+    {
         /* Set WM_ICON_SIZE property indicating desired icon sizes */
         typedef struct {
             uint32_t min_width, min_height;
@@ -1152,6 +1156,41 @@ winMultiWindowXMsgProc(void *pArg)
      */
     intern_atom(pProcArg->conn, "WM_STATE");
 
+    /*
+      Enable Composite extension and redirect subwindows of the root window
+     */
+    if (pProcArg->pWMInfo->fCompositeWM) {
+        const char *extension_name = "Composite";
+        xcb_query_extension_cookie_t cookie;
+        xcb_query_extension_reply_t *reply;
+
+        cookie = xcb_query_extension(pProcArg->conn, strlen(extension_name), extension_name);
+        reply = xcb_query_extension_reply(pProcArg->conn, cookie, NULL);
+
+        if (reply && (reply->present)) {
+            xcb_composite_redirect_subwindows(pProcArg->conn,
+                                              root_window_id,
+                                              XCB_COMPOSITE_REDIRECT_AUTOMATIC);
+
+            /*
+              We use automatic updating of the root window for two
+              reasons:
+
+              1) redirected window contents are mirrored to the root
+              window so that the root window draws correctly when shown.
+
+              2) updating the root window causes damage against the
+              shadow framebuffer, which ultimately causes WM_PAINT to be
+              sent to the affected window(s) to cause the damage regions
+              to be redrawn.
+            */
+
+            ErrorF("Using Composite redirection\n");
+
+            free(reply);
+        }
+    }
+
     /* Loop until we explicitly break out */
     while (1) {
         xcb_generic_event_t *event;
@@ -1351,7 +1390,7 @@ winInitWM(void **ppWMInfo,
           pthread_t * ptWMProc,
           pthread_t * ptXMsgProc,
           pthread_mutex_t * ppmServerStarted,
-          int dwScreen, HWND hwndScreen)
+          int dwScreen, HWND hwndScreen, Bool compositeWM)
 {
     WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec));
     WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec));
@@ -1373,6 +1412,7 @@ winInitWM(void **ppWMInfo,
 
     /* Set a return pointer to the Window Manager info structure */
     *ppWMInfo = pWMInfo;
+    pWMInfo->fCompositeWM = compositeWM;
 
     /* Setup the argument structure for the thread function */
     pArg->dwScreen = dwScreen;
diff --git a/hw/xwin/winprocarg.c b/hw/xwin/winprocarg.c
index 5dd878c30..e849cbc97 100644
--- a/hw/xwin/winprocarg.c
+++ b/hw/xwin/winprocarg.c
@@ -128,6 +128,7 @@ winInitializeScreenDefaults(void)
     defaultScreenInfo.fDecoration = TRUE;
     defaultScreenInfo.fRootless = FALSE;
     defaultScreenInfo.fMultiWindow = FALSE;
+    defaultScreenInfo.fCompositeWM = TRUE;
     defaultScreenInfo.fMultiMonitorOverride = FALSE;
     defaultScreenInfo.fMultipleMonitors = FALSE;
     defaultScreenInfo.fLessPointer = FALSE;
@@ -572,6 +573,25 @@ ddxProcessArgument(int argc, char *argv[], int i)
     }
 
     /*
+     * Look for the '-compositewm' argument
+     */
+    if (IS_OPTION("-compositewm")) {
+        screenInfoPtr->fCompositeWM = TRUE;
+
+        /* Indicate that we have processed this argument */
+        return 1;
+    }
+    /*
+     * Look for the '-nocompositewm' argument
+     */
+    if (IS_OPTION("-nocompositewm")) {
+        screenInfoPtr->fCompositeWM = FALSE;
+
+        /* Indicate that we have processed this argument */
+        return 1;
+    }
+
+    /*
      * Look for the '-multiplemonitors' argument
      */
     if (IS_OPTION("-multiplemonitors")
diff --git a/hw/xwin/winscrinit.c b/hw/xwin/winscrinit.c
index d6a1fedc7..fdaa1d6b3 100644
--- a/hw/xwin/winscrinit.c
+++ b/hw/xwin/winscrinit.c
@@ -461,6 +461,11 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv)
 
 
     if (pScreenInfo->fMultiWindow) {
+        if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) {
+            ErrorF("-compositewm disabled due to 8bpp depth\n");
+            pScreenInfo->fCompositeWM = FALSE;
+        }
+
 #if CYGDEBUG || YES
         winDebug("winFinishScreenInitFB - Calling winInitWM.\n");
 #endif
@@ -471,7 +476,8 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv)
                        &pScreenPriv->ptXMsgProc,
                        &pScreenPriv->pmServerStarted,
                        pScreenInfo->dwScreen,
-                       (HWND) &pScreenPriv->hwndScreen)) {
+                       (HWND) &pScreenPriv->hwndScreen,
+                       pScreenInfo->fCompositeWM)) {
             ErrorF("winFinishScreenInitFB - winInitWM () failed.\n");
             return FALSE;
         }
diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c
index 7c3e880dc..0235d1b2c 100644
--- a/hw/xwin/winshadgdi.c
+++ b/hw/xwin/winshadgdi.c
@@ -826,6 +826,70 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin)
         return 0;
     }
 
+#ifdef COMPOSITE
+    if (pWin->redirectDraw != RedirectDrawNone) {
+        HBITMAP hBitmap;
+        HDC hdcPixmap;
+        PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
+
+        /*
+          This is kind of clunky, and possibly not very efficient.
+
+          Would it be more efficient to only create the DIB bitmap when the
+          composite bitmap is realloced and store it in a window private?
+
+          But we still end up copying and converting all the bits from the
+          window pixmap into a DDB for every update.
+
+          Perhaps better still would be to wrap the screen CreatePixmap routine
+          so it uses CreateDIBSection()?
+         */
+
+        BITMAPV4HEADER bmih;
+        memset(&bmih, 0, sizeof(bmih));
+        bmih.bV4Size = sizeof(BITMAPV4HEADER);
+        bmih.bV4Width = pPixmap->drawable.width;
+        bmih.bV4Height = -pPixmap->drawable.height; /* top-down bitmap */
+        bmih.bV4Planes = 1;
+        bmih.bV4BitCount = pPixmap->drawable.bitsPerPixel;
+        bmih.bV4SizeImage = 0;
+        /* window pixmap format is the same as the screen pixmap */
+        assert(pPixmap->drawable.bitsPerPixel > 8);
+        bmih.bV4V4Compression = BI_BITFIELDS;
+        bmih.bV4RedMask = pScreenPriv->dwRedMask;
+        bmih.bV4GreenMask = pScreenPriv->dwGreenMask;
+        bmih.bV4BlueMask = pScreenPriv->dwBlueMask;
+        bmih.bV4AlphaMask = 0;
+
+        /* Create the window bitmap from the pixmap */
+        hBitmap = CreateDIBitmap(pScreenPriv->hdcScreen,
+                                 (BITMAPINFOHEADER *)&bmih, CBM_INIT,
+                                 pPixmap->devPrivate.ptr, (BITMAPINFO *)&bmih,
+                                 DIB_RGB_COLORS);
+
+        /* Select the window bitmap into a screen-compatible DC */
+        hdcPixmap = CreateCompatibleDC(pScreenPriv->hdcScreen);
+        SelectObject(hdcPixmap, hBitmap);
+
+        /* Blt from the window bitmap to the invalidated region */
+        if (!BitBlt(hdcUpdate,
+                    ps.rcPaint.left, ps.rcPaint.top,
+                    ps.rcPaint.right - ps.rcPaint.left,
+                    ps.rcPaint.bottom - ps.rcPaint.top,
+                    hdcPixmap,
+                    ps.rcPaint.left + pWin->borderWidth,
+                    ps.rcPaint.top + pWin->borderWidth,
+                    SRCCOPY))
+            ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: 0x%08x\n",
+                   GetLastError());
+
+        /* Release */
+        DeleteDC(hdcPixmap);
+        DeleteObject(hBitmap);
+    }
+    else
+#endif
+    {
     /* Try to copy from the shadow buffer to the invalidated region */
     if (!BitBlt(hdcUpdate,
                 ps.rcPaint.left, ps.rcPaint.top,
@@ -850,6 +914,7 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin)
                (LPSTR) lpMsgBuf);
         LocalFree(lpMsgBuf);
     }
+    }
 
     /* EndPaint frees the DC */
     EndPaint(hWnd, &ps);
diff --git a/hw/xwin/winvalargs.c b/hw/xwin/winvalargs.c
index 585544eab..008c111a6 100644
--- a/hw/xwin/winvalargs.c
+++ b/hw/xwin/winvalargs.c
@@ -155,6 +155,14 @@ winValidateArgs(void)
                    "-scrollbars, -resize, -nodecoration, or -lesspointer.\n");
             return FALSE;
         }
+
+        /* Ignore -swcursor if -multiwindow -compositewm is requested */
+        if (g_ScreenInfo[i].fMultiWindow && g_ScreenInfo[i].fCompositeWM) {
+            if (g_fSoftwareCursor) {
+                g_fSoftwareCursor = FALSE;
+                winMsg(X_WARNING, "Ignoring -swcursor due to -compositewm\n");
+            }
+        }
     }
 
     winDebug("winValidateArgs - Returning.\n");
diff --git a/hw/xwin/winwindow.h b/hw/xwin/winwindow.h
index 959ce152a..402b9e63c 100644
--- a/hw/xwin/winwindow.h
+++ b/hw/xwin/winwindow.h
@@ -144,7 +144,7 @@ winInitWM(void **ppWMInfo,
           pthread_t * ptWMProc,
           pthread_t * ptXMsgProc,
           pthread_mutex_t * ppmServerStarted,
-          int dwScreen, HWND hwndScreen);
+          int dwScreen, HWND hwndScreen, Bool compositeWM);
 
 void
  winDeinitMultiWindowWM(void);
commit adebc376b9fbda53d234a27f11eea9a0b945b50e
Author: Jon Turney <jon.turney at dronecode.org.uk>
Date:   Mon Aug 3 15:59:40 2015 +0100

    hw/xwin: Push multiwindow wndproc WM_PAINT down into drawing engine
    
    Push the multiwindow wndproc WM_PAINT handling down into the drawing
    engine.  Only the GDI engine is supported in multiwindow mode currently,
    so we only need to do this in the GDI engine.

diff --git a/hw/xwin/win.h b/hw/xwin/win.h
index 27505caad..18f918d29 100644
--- a/hw/xwin/win.h
+++ b/hw/xwin/win.h
@@ -268,6 +268,8 @@ typedef Bool (*winFinishScreenInitProcPtr) (int, ScreenPtr, int, char **);
 
 typedef Bool (*winBltExposedRegionsProcPtr) (ScreenPtr);
 
+typedef Bool (*winBltExposedWindowRegionProcPtr) (ScreenPtr, WindowPtr);
+
 typedef Bool (*winActivateAppProcPtr) (ScreenPtr);
 
 typedef Bool (*winRedrawScreenProcPtr) (ScreenPtr pScreen);
@@ -479,6 +481,7 @@ typedef struct _winPrivScreenRec {
     winCreateBoundingWindowProcPtr pwinCreateBoundingWindow;
     winFinishScreenInitProcPtr pwinFinishScreenInit;
     winBltExposedRegionsProcPtr pwinBltExposedRegions;
+    winBltExposedWindowRegionProcPtr pwinBltExposedWindowRegion;
     winActivateAppProcPtr pwinActivateApp;
     winRedrawScreenProcPtr pwinRedrawScreen;
     winRealizeInstalledPaletteProcPtr pwinRealizeInstalledPalette;
diff --git a/hw/xwin/winmultiwindowwndproc.c b/hw/xwin/winmultiwindowwndproc.c
index 3f47fec65..1cac4a9f4 100644
--- a/hw/xwin/winmultiwindowwndproc.c
+++ b/hw/xwin/winmultiwindowwndproc.c
@@ -302,7 +302,6 @@ LRESULT CALLBACK
 winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     POINT ptMouse;
-    HDC hdcUpdate;
     PAINTSTRUCT ps;
     WindowPtr pWin = NULL;
     winPrivWinPtr pWinPriv = NULL;
@@ -457,18 +456,9 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 
     case WM_PAINT:
         /* Only paint if our window handle is valid */
-        if (hwndScreen == NULL)
+        if (hwnd == NULL)
             break;
 
-        /* BeginPaint gives us an hdc that clips to the invalidated region */
-        hdcUpdate = BeginPaint(hwnd, &ps);
-        /* Avoid the BitBlt's if the PAINTSTRUCT is bogus */
-        if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 &&
-            ps.rcPaint.left == 0 && ps.rcPaint.top == 0) {
-            EndPaint(hwnd, &ps);
-            return 0;
-        }
-
 #ifdef XWIN_GLX_WINDOWS
         if (pWinPriv->fWglUsed) {
             /*
@@ -478,36 +468,16 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
                XXX: For now, just leave it alone, but ideally we want to send an expose event to
                the window so it really redraws the affected region...
              */
+            BeginPaint(hwnd, &ps);
             ValidateRect(hwnd, &(ps.rcPaint));
+            EndPaint(hwnd, &ps);
         }
         else
 #endif
-            /* Try to copy from the shadow buffer */
-        if (!BitBlt(hdcUpdate,
-                        ps.rcPaint.left, ps.rcPaint.top,
-                        ps.rcPaint.right - ps.rcPaint.left,
-                        ps.rcPaint.bottom - ps.rcPaint.top,
-                        s_pScreenPriv->hdcShadow,
-                        ps.rcPaint.left + pWin->drawable.x,
-                        ps.rcPaint.top + pWin->drawable.y, SRCCOPY)) {
-            LPVOID lpMsgBuf;
-
-            /* Display a fancy error message */
-            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                          FORMAT_MESSAGE_FROM_SYSTEM |
-                          FORMAT_MESSAGE_IGNORE_INSERTS,
-                          NULL,
-                          GetLastError(),
-                          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                          (LPTSTR) &lpMsgBuf, 0, NULL);
-
-            ErrorF("winTopLevelWindowProc - BitBlt failed: %s\n",
-                   (LPSTR) lpMsgBuf);
-            LocalFree(lpMsgBuf);
-        }
+            /* Call the engine dependent repainter */
+            if (*s_pScreenPriv->pwinBltExposedWindowRegion)
+                (*s_pScreenPriv->pwinBltExposedWindowRegion) (s_pScreen, pWin);
 
-        /* EndPaint frees the DC */
-        EndPaint(hwnd, &ps);
         return 0;
 
     case WM_MOUSEMOVE:
diff --git a/hw/xwin/winshadddnl.c b/hw/xwin/winshadddnl.c
index 4e1fbd15c..290176920 100644
--- a/hw/xwin/winshadddnl.c
+++ b/hw/xwin/winshadddnl.c
@@ -1201,6 +1201,7 @@ winSetEngineFunctionsShadowDDNL(ScreenPtr pScreen)
         pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed;
     pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB;
     pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowDDNL;
+    pScreenPriv->pwinBltExposedWindowRegion = NULL;
     pScreenPriv->pwinActivateApp = winActivateAppShadowDDNL;
     pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowDDNL;
     pScreenPriv->pwinRealizeInstalledPalette
diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c
index 53a4700a4..7c3e880dc 100644
--- a/hw/xwin/winshadgdi.c
+++ b/hw/xwin/winshadgdi.c
@@ -60,6 +60,9 @@ static Bool
  winBltExposedRegionsShadowGDI(ScreenPtr pScreen);
 
 static Bool
+ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin);
+
+static Bool
  winActivateAppShadowGDI(ScreenPtr pScreen);
 
 static Bool
@@ -802,6 +805,59 @@ winBltExposedRegionsShadowGDI(ScreenPtr pScreen)
 }
 
 /*
+ * Blt exposed region to the given HWND
+ */
+
+static Bool
+winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin)
+{
+    winScreenPriv(pScreen);
+    winPrivWinPtr pWinPriv = winGetWindowPriv(pWin);
+
+    HWND hWnd = pWinPriv->hWnd;
+    HDC hdcUpdate;
+    PAINTSTRUCT ps;
+
+    hdcUpdate = BeginPaint(hWnd, &ps);
+    /* Avoid the BitBlt if the PAINTSTRUCT region is bogus */
+    if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 &&
+        ps.rcPaint.left == 0 && ps.rcPaint.top == 0) {
+        EndPaint(hWnd, &ps);
+        return 0;
+    }
+
+    /* Try to copy from the shadow buffer to the invalidated region */
+    if (!BitBlt(hdcUpdate,
+                ps.rcPaint.left, ps.rcPaint.top,
+                ps.rcPaint.right - ps.rcPaint.left,
+                ps.rcPaint.bottom - ps.rcPaint.top,
+                pScreenPriv->hdcShadow,
+                ps.rcPaint.left + pWin->drawable.x,
+                ps.rcPaint.top + pWin->drawable.y,
+                SRCCOPY)) {
+        LPVOID lpMsgBuf;
+
+        /* Display an error message */
+        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                      FORMAT_MESSAGE_FROM_SYSTEM |
+                      FORMAT_MESSAGE_IGNORE_INSERTS,
+                      NULL,
+                      GetLastError(),
+                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                      (LPTSTR) &lpMsgBuf, 0, NULL);
+
+        ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: %s\n",
+               (LPSTR) lpMsgBuf);
+        LocalFree(lpMsgBuf);
+    }
+
+    /* EndPaint frees the DC */
+    EndPaint(hWnd, &ps);
+
+    return TRUE;
+}
+
+/*
  * Do any engine-specific appliation-activation processing
  */
 
@@ -1144,6 +1200,7 @@ winSetEngineFunctionsShadowGDI(ScreenPtr pScreen)
         pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed;
     pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB;
     pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowGDI;
+    pScreenPriv->pwinBltExposedWindowRegion = winBltExposedWindowRegionShadowGDI;
     pScreenPriv->pwinActivateApp = winActivateAppShadowGDI;
     pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowGDI;
     pScreenPriv->pwinRealizeInstalledPalette =
commit 065f73353bfa5667e0fb4f42e338978b40e86652
Author: Jon Turney <jon.turney at dronecode.org.uk>
Date:   Mon Aug 3 11:39:36 2015 +0100

    hw/xwin: Align winBltExposedRegionsShadowGDI with winTopLevelWindowProc's WM_PAINT
    
    Make winBltExposedRegionsShadowGDI() do the same stuff that
    winTopLevelWindowProc()'s WM_PAINT handler does.
    
    Note that winBltExposedRegionsShadowGDI() is currently used 1) in
    windowed mode when the GDI engine is selected, and 2) in multiwindow
    mode when "Hide Root Window" is off.

diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c
index 6d7ebce07..53a4700a4 100644
--- a/hw/xwin/winshadgdi.c
+++ b/hw/xwin/winshadgdi.c
@@ -750,6 +750,12 @@ winBltExposedRegionsShadowGDI(ScreenPtr pScreen)
 
     /* BeginPaint gives us an hdc that clips to the invalidated region */
     hdcUpdate = BeginPaint(pScreenPriv->hwndScreen, &ps);
+    /* Avoid the BitBlt if the PAINTSTRUCT region is bogus */
+    if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 &&
+        ps.rcPaint.left == 0 && ps.rcPaint.top == 0) {
+        EndPaint(pScreenPriv->hwndScreen, &ps);
+        return 0;
+    }
 
     /* Realize the palette, if we have one */
     if (pScreenPriv->pcmapInstalled != NULL) {
@@ -759,11 +765,30 @@ winBltExposedRegionsShadowGDI(ScreenPtr pScreen)
         RealizePalette(hdcUpdate);
     }
 
-    /* Our BitBlt will be clipped to the invalidated region */
-    BitBlt(hdcUpdate,
-           0, 0,
-           pScreenInfo->dwWidth, pScreenInfo->dwHeight,
-           pScreenPriv->hdcShadow, 0, 0, SRCCOPY);
+    /* Try to copy from the shadow buffer to the invalidated region */
+    if (!BitBlt(hdcUpdate,
+                ps.rcPaint.left, ps.rcPaint.top,
+                ps.rcPaint.right - ps.rcPaint.left,
+                ps.rcPaint.bottom - ps.rcPaint.top,
+                pScreenPriv->hdcShadow,
+                ps.rcPaint.left,
+                ps.rcPaint.top,
+                SRCCOPY)) {
+        LPVOID lpMsgBuf;
+
+        /* Display an error message */
+        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                      FORMAT_MESSAGE_FROM_SYSTEM |
+                      FORMAT_MESSAGE_IGNORE_INSERTS,
+                      NULL,
+                      GetLastError(),
+                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                      (LPTSTR) &lpMsgBuf, 0, NULL);
+
+        ErrorF("winBltExposedRegionsShadowGDI - BitBlt failed: %s\n",
+               (LPSTR) lpMsgBuf);
+        LocalFree(lpMsgBuf);
+    }
 
     /* EndPaint frees the DC */
     EndPaint(pScreenPriv->hwndScreen, &ps);


More information about the xorg-commit mailing list