From 697e020abd1bb4bd0e40eedbef6cf18bd5bddbf9 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 8 Nov 2022 09:33:02 +0100 Subject: [PATCH] [rail] Added window update from surface --- client/X11/xf_event.c | 2 + client/X11/xf_gfx.c | 4 +- client/X11/xf_rail.c | 12 ++-- client/X11/xf_window.c | 126 +++++++++++++++++++++++++++++++++++++++-- client/X11/xf_window.h | 11 +++- 5 files changed, 141 insertions(+), 14 deletions(-) diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 02fed3851..98a87c0b9 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -807,6 +807,8 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, const XConfigureEvent* even appWindow->width = event->width; appWindow->height = event->height; + xf_AppWindowResize(xfc, appWindow); + /* * Additional checks for not in a local move and not ignoring configure to send * position update to server, also should the window not be focused then do not diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 7a7fc6878..8e7ece77d 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -431,8 +431,8 @@ static UINT xf_UpdateWindowFromSurface(RdpgfxClientContext* context, gdiGfxSurfa xfContext* xfc = (xfContext*)gdi->context; WINPR_ASSERT(gdi->context); -// if (freerdp_settings_get_bool(gdi->context->settings, FreeRDP_RemoteApplicationMode)) -// return xf_AppUpdateWindowFromSurface(xfc, surface); + if (freerdp_settings_get_bool(gdi->context->settings, FreeRDP_RemoteApplicationMode)) + return xf_AppUpdateWindowFromSurface(xfc, surface); WLog_WARN(TAG, "[%s] function not implemented", __func__); return CHANNEL_RC_OK; diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index 07de55d56..ce5c6b19c 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -1131,13 +1131,15 @@ xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, UINT32 x, UINT32 y, U appWindow->y = y; appWindow->width = width; appWindow->height = height; - xf_AppWindowCreate(xfc, appWindow); + + if (!xf_AppWindowCreate(xfc, appWindow)) + goto fail; if (!HashTable_Insert(xfc->railWindows, &appWindow->windowId, (void*)appWindow)) - { - rail_window_free(appWindow); - return NULL; - } + goto fail; return appWindow; +fail: + rail_window_free(appWindow); + return NULL; } BOOL xf_rail_del_window(xfContext* xfc, UINT64 id) diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index c3c16d75e..02c7a4cad 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -51,6 +51,7 @@ #include "xf_input.h" #endif +#include "xf_gfx.h" #include "xf_rail.h" #include "xf_input.h" #include "xf_keyboard.h" @@ -783,7 +784,7 @@ int xf_AppWindowInit(xfContext* xfc, xfAppWindow* appWindow) return 1; } -int xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow) +BOOL xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow) { XGCValues gcv = { 0 }; int input_mask; @@ -815,9 +816,13 @@ int xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow) xfc->depth, InputOutput, xfc->visual, 0, &xfc->attribs); if (!appWindow->handle) - return -1; + return FALSE; appWindow->gc = XCreateGC(xfc->display, appWindow->handle, GCGraphicsExposures, &gcv); + + if (!xf_AppWindowResize(xfc, appWindow)) + return FALSE; + class_hints = XAllocClassHint(); if (class_hints) @@ -859,7 +864,7 @@ int xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow) if (xfc->_XWAYLAND_MAY_GRAB_KEYBOARD) xf_SendClientEvent(xfc, appWindow->handle, xfc->_XWAYLAND_MAY_GRAB_KEYBOARD, 1, 1); - return 1; + return TRUE; } void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth, int maxHeight, @@ -1111,16 +1116,27 @@ void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, i if (settings->SoftwareGdi) { - XPutImage(xfc->display, xfc->primary, appWindow->gc, xfc->image, ax, ay, ax, ay, width, + XPutImage(xfc->display, appWindow->pixmap, appWindow->gc, xfc->image, ax, ay, x, y, width, height); } - XCopyArea(xfc->display, xfc->primary, appWindow->handle, appWindow->gc, ax, ay, width, height, - x, y); + XCopyArea(xfc->display, appWindow->pixmap, appWindow->handle, appWindow->gc, x, y, width, + height, x, y); XFlush(xfc->display); xf_unlock_x11(xfc); } +static void xf_AppWindowDestroyImage(xfAppWindow* appWindow) +{ + WINPR_ASSERT(appWindow); + if (appWindow->image) + { + appWindow->image->data = NULL; + XDestroyImage(appWindow->image); + appWindow->image = NULL; + } +} + void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow) { if (!appWindow) @@ -1132,6 +1148,11 @@ void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow) if (appWindow->gc) XFreeGC(xfc->display, appWindow->gc); + if (appWindow->pixmap) + XFreePixmap(xfc->display, appWindow->pixmap); + + xf_AppWindowDestroyImage(appWindow); + if (appWindow->handle) { XUnmapWindow(xfc->display, appWindow->handle); @@ -1185,3 +1206,96 @@ xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd) free(pKeys); return NULL; } + +UINT xf_AppUpdateWindowFromSurface(xfContext* xfc, gdiGfxSurface* surface) +{ + XImage* image = NULL; + UINT rc = ERROR_INTERNAL_ERROR; + + WINPR_ASSERT(xfc); + WINPR_ASSERT(surface); + + xfAppWindow* appWindow = xf_rail_get_window(xfc, surface->windowId); + if (!appWindow) + { + WLog_VRB(TAG, "[%s] Failed to find a window for id=0x%08" PRIx64, __func__, + surface->windowId); + return CHANNEL_RC_OK; + } + + const BOOL swGdi = freerdp_settings_get_bool(xfc->common.context.settings, FreeRDP_SoftwareGdi); + UINT32 nrects = 0; + const RECTANGLE_16* rects = region16_rects(&surface->invalidRegion, &nrects); + + xf_lock_x11(xfc); + if (swGdi) + { + if (appWindow->surfaceId != surface->surfaceId) + { + xf_AppWindowDestroyImage(appWindow); + appWindow->surfaceId = surface->surfaceId; + } + if (appWindow->width != (INT64)surface->width) + xf_AppWindowDestroyImage(appWindow); + if (appWindow->height != (INT64)surface->height) + xf_AppWindowDestroyImage(appWindow); + + if (!appWindow->image) + { + appWindow->image = + XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, surface->data, + surface->width, surface->height, xfc->scanline_pad, surface->scanline); + if (!appWindow->image) + { + WLog_WARN(TAG, + "[%s] Failed create a XImage[%" PRIu32 "x%" PRIu32 ", scanline=%" PRIu32 + ", bpp=%" PRIu32 "] for window id=0x%08" PRIx64, + __func__, surface->width, surface->height, surface->scanline, xfc->depth, + surface->windowId); + goto fail; + } + appWindow->image->byte_order = LSBFirst; + appWindow->image->bitmap_bit_order = LSBFirst; + } + + image = appWindow->image; + } + else + { + xfGfxSurface* xfSurface = (xfGfxSurface*)surface; + image = xfSurface->image; + } + + for (UINT32 x = 0; x < nrects; x++) + { + const RECTANGLE_16* rect = &rects[x]; + const UINT32 width = rect->right - rect->left; + const UINT32 height = rect->bottom - rect->top; + + XPutImage(xfc->display, appWindow->pixmap, appWindow->gc, image, rect->left, rect->top, + rect->left, rect->top, width, height); + + XCopyArea(xfc->display, appWindow->pixmap, appWindow->handle, appWindow->gc, rect->left, + rect->top, width, height, rect->left, rect->top); + } + + rc = CHANNEL_RC_OK; +fail: + XFlush(xfc->display); + xf_unlock_x11(xfc); + return rc; +} + +BOOL xf_AppWindowResize(xfContext* xfc, xfAppWindow* appWindow) +{ + WINPR_ASSERT(xfc); + WINPR_ASSERT(appWindow); + + if (appWindow->pixmap != 0) + XFreePixmap(xfc->display, appWindow->pixmap); + appWindow->pixmap = + XCreatePixmap(xfc->display, xfc->drawable, appWindow->width, appWindow->height, xfc->depth); + xf_AppWindowDestroyImage(appWindow); + + return appWindow->pixmap != 0; +} diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index b3fd86166..ca3837789 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -23,6 +23,7 @@ #include #include +#include typedef struct xf_app_window xfAppWindow; @@ -155,6 +156,9 @@ struct xf_app_window BOOL maxHorz; BOOL minimized; BOOL rail_ignore_configure; + + Pixmap pixmap; + XImage* image; }; void xf_ewmhints_init(xfContext* xfc); @@ -178,8 +182,11 @@ BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int leng unsigned long* nitems, unsigned long* bytes, BYTE** prop); void xf_SendClientEvent(xfContext* xfc, Window window, Atom atom, unsigned int numArgs, ...); -int xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow); +BOOL xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow); int xf_AppWindowInit(xfContext* xfc, xfAppWindow* appWindow); + +BOOL xf_AppWindowResize(xfContext* xfc, xfAppWindow* appWindow); + void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, const char* name); void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height); void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state); @@ -190,6 +197,8 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UINT32 ex_style); void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height); +UINT xf_AppUpdateWindowFromSurface(xfContext* xfc, gdiGfxSurface* surface); + void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow); void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth, int maxHeight, int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight,