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
This commit is contained in:
parent
adebc376b9
commit
ebcea16e71
|
@ -50,6 +50,7 @@ libXmu-devel,\
|
||||||
libXpm-devel,\
|
libXpm-devel,\
|
||||||
libXrender-devel,\
|
libXrender-devel,\
|
||||||
libXtst-devel,\
|
libXtst-devel,\
|
||||||
|
libxcb-composite-devel,\
|
||||||
libxcb-ewmh-devel,\
|
libxcb-ewmh-devel,\
|
||||||
libxcb-icccm-devel,\
|
libxcb-icccm-devel,\
|
||||||
libxcb-image-devel,\
|
libxcb-image-devel,\
|
||||||
|
|
|
@ -2081,7 +2081,7 @@ if test "x$XWIN" = xyes; then
|
||||||
AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support])
|
AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support])
|
||||||
AC_CHECK_TOOL(WINDRES, windres)
|
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
|
if test "x$WINDOWSDRI" = xauto; then
|
||||||
PKG_CHECK_EXISTS([windowsdriproto], [WINDOWSDRI=yes], [WINDOWSDRI=no])
|
PKG_CHECK_EXISTS([windowsdriproto], [WINDOWSDRI=yes], [WINDOWSDRI=no])
|
||||||
|
|
|
@ -716,6 +716,11 @@ winUseMsg(void)
|
||||||
"\tthe updated region when num_boxes, or more, are in the\n"
|
"\tthe updated region when num_boxes, or more, are in the\n"
|
||||||
"\tupdated region.\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
|
#ifdef XWIN_XF86CONFIG
|
||||||
ErrorF("-config\n" "\tSpecify a configuration file.\n");
|
ErrorF("-config\n" "\tSpecify a configuration file.\n");
|
||||||
|
|
||||||
|
|
|
@ -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
|
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.
|
on remote hosts, when that information is available and it's useful to do so.
|
||||||
The default is enabled.
|
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
|
.SH OPTIONS CONTROLLING WINDOWS INTEGRATION
|
||||||
.TP 8
|
.TP 8
|
||||||
|
@ -206,6 +212,7 @@ The default is enabled.
|
||||||
.TP 8
|
.TP 8
|
||||||
.B \-swcursor
|
.B \-swcursor
|
||||||
Disable the usage of the \fIWindows\fP cursor and use the X11 software cursor instead.
|
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
|
.TP 8
|
||||||
.B \-[no]trayicon
|
.B \-[no]trayicon
|
||||||
Do not create a tray icon. Default is to create one
|
Do not create a tray icon. Default is to create one
|
||||||
|
|
|
@ -137,6 +137,7 @@ xwin_dep = [
|
||||||
dependency('xcb-image'),
|
dependency('xcb-image'),
|
||||||
dependency('xcb-ewmh'),
|
dependency('xcb-ewmh'),
|
||||||
dependency('xcb-icccm'),
|
dependency('xcb-icccm'),
|
||||||
|
dependency('xcb-composite'),
|
||||||
]
|
]
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
|
|
|
@ -391,6 +391,7 @@ typedef struct {
|
||||||
Bool fDecoration;
|
Bool fDecoration;
|
||||||
Bool fRootless;
|
Bool fRootless;
|
||||||
Bool fMultiWindow;
|
Bool fMultiWindow;
|
||||||
|
Bool fCompositeWM;
|
||||||
Bool fMultiMonitorOverride;
|
Bool fMultiMonitorOverride;
|
||||||
Bool fMultipleMonitors;
|
Bool fMultipleMonitors;
|
||||||
Bool fLessPointer;
|
Bool fLessPointer;
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
#include <xcb/xcb_ewmh.h>
|
#include <xcb/xcb_ewmh.h>
|
||||||
#include <xcb/xcb_aux.h>
|
#include <xcb/xcb_aux.h>
|
||||||
|
#include <xcb/composite.h>
|
||||||
|
|
||||||
#include <X11/Xwindows.h>
|
#include <X11/Xwindows.h>
|
||||||
|
|
||||||
|
@ -116,6 +117,7 @@ typedef struct _WMInfo {
|
||||||
xcb_atom_t atmUtf8String;
|
xcb_atom_t atmUtf8String;
|
||||||
xcb_atom_t atmNetWmName;
|
xcb_atom_t atmNetWmName;
|
||||||
xcb_ewmh_connection_t ewmh;
|
xcb_ewmh_connection_t ewmh;
|
||||||
|
Bool fCompositeWM;
|
||||||
} WMInfoRec, *WMInfoPtr;
|
} WMInfoRec, *WMInfoPtr;
|
||||||
|
|
||||||
typedef struct _WMProcArgRec {
|
typedef struct _WMProcArgRec {
|
||||||
|
@ -1038,6 +1040,8 @@ winMultiWindowXMsgProc(void *pArg)
|
||||||
xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints;
|
xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints;
|
||||||
int iReturn;
|
int iReturn;
|
||||||
xcb_auth_info_t *auth_info;
|
xcb_auth_info_t *auth_info;
|
||||||
|
xcb_screen_t *root_screen;
|
||||||
|
xcb_window_t root_window_id;
|
||||||
|
|
||||||
winDebug("winMultiWindowXMsgProc - Hello\n");
|
winDebug("winMultiWindowXMsgProc - Hello\n");
|
||||||
|
|
||||||
|
@ -1110,11 +1114,11 @@ winMultiWindowXMsgProc(void *pArg)
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
/* Get root window id */
|
||||||
/* Get root window id */
|
root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen);
|
||||||
xcb_screen_t *root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen);
|
root_window_id = root_screen->root;
|
||||||
xcb_window_t root_window_id = root_screen->root;
|
|
||||||
|
|
||||||
|
{
|
||||||
/* Set WM_ICON_SIZE property indicating desired icon sizes */
|
/* Set WM_ICON_SIZE property indicating desired icon sizes */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t min_width, min_height;
|
uint32_t min_width, min_height;
|
||||||
|
@ -1152,6 +1156,41 @@ winMultiWindowXMsgProc(void *pArg)
|
||||||
*/
|
*/
|
||||||
intern_atom(pProcArg->conn, "WM_STATE");
|
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 */
|
/* Loop until we explicitly break out */
|
||||||
while (1) {
|
while (1) {
|
||||||
xcb_generic_event_t *event;
|
xcb_generic_event_t *event;
|
||||||
|
@ -1351,7 +1390,7 @@ winInitWM(void **ppWMInfo,
|
||||||
pthread_t * ptWMProc,
|
pthread_t * ptWMProc,
|
||||||
pthread_t * ptXMsgProc,
|
pthread_t * ptXMsgProc,
|
||||||
pthread_mutex_t * ppmServerStarted,
|
pthread_mutex_t * ppmServerStarted,
|
||||||
int dwScreen, HWND hwndScreen)
|
int dwScreen, HWND hwndScreen, Bool compositeWM)
|
||||||
{
|
{
|
||||||
WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec));
|
WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec));
|
||||||
WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec));
|
WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec));
|
||||||
|
@ -1373,6 +1412,7 @@ winInitWM(void **ppWMInfo,
|
||||||
|
|
||||||
/* Set a return pointer to the Window Manager info structure */
|
/* Set a return pointer to the Window Manager info structure */
|
||||||
*ppWMInfo = pWMInfo;
|
*ppWMInfo = pWMInfo;
|
||||||
|
pWMInfo->fCompositeWM = compositeWM;
|
||||||
|
|
||||||
/* Setup the argument structure for the thread function */
|
/* Setup the argument structure for the thread function */
|
||||||
pArg->dwScreen = dwScreen;
|
pArg->dwScreen = dwScreen;
|
||||||
|
|
|
@ -128,6 +128,7 @@ winInitializeScreenDefaults(void)
|
||||||
defaultScreenInfo.fDecoration = TRUE;
|
defaultScreenInfo.fDecoration = TRUE;
|
||||||
defaultScreenInfo.fRootless = FALSE;
|
defaultScreenInfo.fRootless = FALSE;
|
||||||
defaultScreenInfo.fMultiWindow = FALSE;
|
defaultScreenInfo.fMultiWindow = FALSE;
|
||||||
|
defaultScreenInfo.fCompositeWM = TRUE;
|
||||||
defaultScreenInfo.fMultiMonitorOverride = FALSE;
|
defaultScreenInfo.fMultiMonitorOverride = FALSE;
|
||||||
defaultScreenInfo.fMultipleMonitors = FALSE;
|
defaultScreenInfo.fMultipleMonitors = FALSE;
|
||||||
defaultScreenInfo.fLessPointer = FALSE;
|
defaultScreenInfo.fLessPointer = FALSE;
|
||||||
|
@ -571,6 +572,25 @@ ddxProcessArgument(int argc, char *argv[], int i)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* Look for the '-multiplemonitors' argument
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -461,6 +461,11 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv)
|
||||||
|
|
||||||
|
|
||||||
if (pScreenInfo->fMultiWindow) {
|
if (pScreenInfo->fMultiWindow) {
|
||||||
|
if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) {
|
||||||
|
ErrorF("-compositewm disabled due to 8bpp depth\n");
|
||||||
|
pScreenInfo->fCompositeWM = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
#if CYGDEBUG || YES
|
#if CYGDEBUG || YES
|
||||||
winDebug("winFinishScreenInitFB - Calling winInitWM.\n");
|
winDebug("winFinishScreenInitFB - Calling winInitWM.\n");
|
||||||
#endif
|
#endif
|
||||||
|
@ -471,7 +476,8 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv)
|
||||||
&pScreenPriv->ptXMsgProc,
|
&pScreenPriv->ptXMsgProc,
|
||||||
&pScreenPriv->pmServerStarted,
|
&pScreenPriv->pmServerStarted,
|
||||||
pScreenInfo->dwScreen,
|
pScreenInfo->dwScreen,
|
||||||
(HWND) &pScreenPriv->hwndScreen)) {
|
(HWND) &pScreenPriv->hwndScreen,
|
||||||
|
pScreenInfo->fCompositeWM)) {
|
||||||
ErrorF("winFinishScreenInitFB - winInitWM () failed.\n");
|
ErrorF("winFinishScreenInitFB - winInitWM () failed.\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -826,6 +826,70 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin)
|
||||||
return 0;
|
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 */
|
/* Try to copy from the shadow buffer to the invalidated region */
|
||||||
if (!BitBlt(hdcUpdate,
|
if (!BitBlt(hdcUpdate,
|
||||||
ps.rcPaint.left, ps.rcPaint.top,
|
ps.rcPaint.left, ps.rcPaint.top,
|
||||||
|
@ -850,6 +914,7 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin)
|
||||||
(LPSTR) lpMsgBuf);
|
(LPSTR) lpMsgBuf);
|
||||||
LocalFree(lpMsgBuf);
|
LocalFree(lpMsgBuf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* EndPaint frees the DC */
|
/* EndPaint frees the DC */
|
||||||
EndPaint(hWnd, &ps);
|
EndPaint(hWnd, &ps);
|
||||||
|
|
|
@ -155,6 +155,14 @@ winValidateArgs(void)
|
||||||
"-scrollbars, -resize, -nodecoration, or -lesspointer.\n");
|
"-scrollbars, -resize, -nodecoration, or -lesspointer.\n");
|
||||||
return FALSE;
|
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");
|
winDebug("winValidateArgs - Returning.\n");
|
||||||
|
|
|
@ -144,7 +144,7 @@ winInitWM(void **ppWMInfo,
|
||||||
pthread_t * ptWMProc,
|
pthread_t * ptWMProc,
|
||||||
pthread_t * ptXMsgProc,
|
pthread_t * ptXMsgProc,
|
||||||
pthread_mutex_t * ppmServerStarted,
|
pthread_mutex_t * ppmServerStarted,
|
||||||
int dwScreen, HWND hwndScreen);
|
int dwScreen, HWND hwndScreen, Bool compositeWM);
|
||||||
|
|
||||||
void
|
void
|
||||||
winDeinitMultiWindowWM(void);
|
winDeinitMultiWindowWM(void);
|
||||||
|
|
Loading…
Reference in New Issue