diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index d061c6485..33cc0a369 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -174,6 +174,7 @@ extern "C" freerdp_listener* listener; size_t maxClientsConnected; + BOOL SupportMultiRectBitmapUpdates; /** @since version 3.13.0 */ }; struct rdp_shadow_surface diff --git a/server/shadow/shadow.c b/server/shadow/shadow.c index 59c3b074f..adfc6ec10 100644 --- a/server/shadow/shadow.c +++ b/server/shadow/shadow.c @@ -95,6 +95,8 @@ int main(int argc, char** argv) "Allow GFX AVC420 codec" }, { "gfx-avc444", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Allow GFX AVC444 codec" }, + { "bitmap-compat", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, + "Limit BitmapUpdate to 1 rectangle (fixes broken windows 11 24H2 clients)" }, { "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" }, { "buildconfig", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_BUILDCONFIG, NULL, NULL, NULL, diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 8dbe08519..e0e36da44 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -50,23 +50,25 @@ typedef struct * * So send all updates only with a single rectangle. */ -#define BitmapUpdateProxy(update, context, bitmap) \ - BitmapUpdateProxyEx((update), (context), (bitmap), __FILE__, __LINE__, __func__) -static BOOL BitmapUpdateProxyEx(rdpUpdate* update, rdpContext* context, const BITMAP_UPDATE* bitmap, +#define BitmapUpdateProxy(client, bitmap) \ + BitmapUpdateProxyEx((client), (bitmap), __FILE__, __LINE__, __func__) +static BOOL BitmapUpdateProxyEx(rdpShadowClient* client, const BITMAP_UPDATE* bitmap, const char* file, size_t line, const char* fkt) { - WINPR_ASSERT(update); - WINPR_ASSERT(context); + WINPR_ASSERT(client); WINPR_ASSERT(bitmap); - for (UINT32 x = 0; x < bitmap->number; x++) + rdpShadowServer* server = client->server; + WINPR_ASSERT(server); + + rdpContext* context = (rdpContext*)client; + + rdpUpdate* update = context->update; + WINPR_ASSERT(update); + + if (server->SupportMultiRectBitmapUpdates) { - BITMAP_UPDATE cur = { 0 }; - BITMAP_DATA* bmp = &bitmap->rectangles[x]; - cur.rectangles = bmp; - cur.number = 1; - cur.skipCompression = bitmap->skipCompression; - const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, &cur); + const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, bitmap); if (!rc) { const DWORD log_level = WLOG_ERROR; @@ -74,11 +76,34 @@ static BOOL BitmapUpdateProxyEx(rdpUpdate* update, rdpContext* context, const BI if (WLog_IsLevelActive(log, log_level)) { WLog_PrintMessage(log, WLOG_MESSAGE_TEXT, log_level, line, file, fkt, - "BitmapUpdate[%" PRIu32 "] failed", x); + "BitmapUpdate[count %" PRIu32 "] failed", bitmap->number); } return FALSE; } } + else + { + for (UINT32 x = 0; x < bitmap->number; x++) + { + BITMAP_UPDATE cur = { 0 }; + BITMAP_DATA* bmp = &bitmap->rectangles[x]; + cur.rectangles = bmp; + cur.number = 1; + cur.skipCompression = bitmap->skipCompression; + const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, &cur); + if (!rc) + { + const DWORD log_level = WLOG_ERROR; + wLog* log = WLog_Get(TAG); + if (WLog_IsLevelActive(log, log_level)) + { + WLog_PrintMessage(log, WLOG_MESSAGE_TEXT, log_level, line, file, fkt, + "BitmapUpdate[count 1, at %" PRIu32 "] failed", x); + } + return FALSE; + } + } + } return TRUE; } @@ -1813,7 +1838,7 @@ static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrc if ((newUpdateSize >= maxUpdateSize) || (i + 1) >= k) { bitmapUpdate.number = j; - ret = BitmapUpdateProxy(update, context, &bitmapUpdate); + ret = BitmapUpdateProxy(client, &bitmapUpdate); if (!ret) break; @@ -1827,7 +1852,7 @@ static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrc } else { - ret = BitmapUpdateProxy(update, context, &bitmapUpdate); + ret = BitmapUpdateProxy(client, &bitmapUpdate); } out: diff --git a/server/shadow/shadow_server.c b/server/shadow/shadow_server.c index 6e7a90dad..a4c6eea3d 100644 --- a/server/shadow/shadow_server.c +++ b/server/shadow/shadow_server.c @@ -236,6 +236,10 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a { server->mayView = arg->Value ? TRUE : FALSE; } + CommandLineSwitchCase(arg, "bitmap-compat") + { + server->SupportMultiRectBitmapUpdates = arg->Value ? FALSE : TRUE; + } CommandLineSwitchCase(arg, "may-interact") { server->mayInteract = arg->Value ? TRUE : FALSE; @@ -1001,6 +1005,7 @@ rdpShadowServer* shadow_server_new(void) if (!server) return NULL; + server->SupportMultiRectBitmapUpdates = TRUE; server->port = 3389; server->mayView = TRUE; server->mayInteract = TRUE;