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:
Jon Turney 2015-08-03 16:47:38 +01:00
parent adebc376b9
commit ebcea16e71
12 changed files with 162 additions and 8 deletions

View File

@ -50,6 +50,7 @@ libXmu-devel,\
libXpm-devel,\
libXrender-devel,\
libXtst-devel,\
libxcb-composite-devel,\
libxcb-ewmh-devel,\
libxcb-icccm-devel,\
libxcb-image-devel,\

View File

@ -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])

View File

@ -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");

View File

@ -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

View File

@ -137,6 +137,7 @@ xwin_dep = [
dependency('xcb-image'),
dependency('xcb-ewmh'),
dependency('xcb-icccm'),
dependency('xcb-composite'),
]
executable(

View File

@ -391,6 +391,7 @@ typedef struct {
Bool fDecoration;
Bool fRootless;
Bool fMultiWindow;
Bool fCompositeWM;
Bool fMultiMonitorOverride;
Bool fMultipleMonitors;
Bool fLessPointer;

View File

@ -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;

View File

@ -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;
@ -571,6 +572,25 @@ ddxProcessArgument(int argc, char *argv[], int i)
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
*/

View File

@ -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;
}

View File

@ -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);

View File

@ -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");

View File

@ -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);