From 6ea36b5a27d529f4751d1a511bbe9d05f1b4d291 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 26 Nov 2014 15:23:26 -0800 Subject: [PATCH] GUAC-936: Use initial resolution for all future resizing of display. Suggest reasonable resolution only if resolution of display is not provided/forced. --- src/protocols/rdp/Makefile.am | 2 + src/protocols/rdp/client.c | 81 ++++++++----------------------- src/protocols/rdp/guac_handlers.c | 7 +++ src/protocols/rdp/rdp_settings.h | 6 +++ src/protocols/rdp/resolution.c | 60 +++++++++++++++++++++++ src/protocols/rdp/resolution.h | 49 +++++++++++++++++++ 6 files changed, 144 insertions(+), 61 deletions(-) create mode 100644 src/protocols/rdp/resolution.c create mode 100644 src/protocols/rdp/resolution.h diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am index 88bda718..8c65c421 100644 --- a/src/protocols/rdp/Makefile.am +++ b/src/protocols/rdp/Makefile.am @@ -43,6 +43,7 @@ libguac_client_rdp_la_SOURCES = \ rdp_settings.c \ rdp_stream.c \ rdp_svc.c \ + resolution.c \ unicode.c guacsvc_sources = \ @@ -95,6 +96,7 @@ noinst_HEADERS = \ rdp_status.h \ rdp_stream.h \ rdp_svc.h \ + resolution.h \ unicode.h # Add compatibility layer for WinPR if not available diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c index e97ea1df..e35c6436 100644 --- a/src/protocols/rdp/client.c +++ b/src/protocols/rdp/client.c @@ -33,6 +33,7 @@ #include "rdp_pointer.h" #include "rdp_stream.h" #include "rdp_svc.h" +#include "resolution.h" #ifdef HAVE_FREERDP_DISPLAY_UPDATE_SUPPORT #include "rdp_disp.h" @@ -509,56 +510,6 @@ void __guac_rdp_client_load_keymap(guac_client* client, } -/** - * Reduces the resolution of the client to the given resolution in DPI if - * doing so is reasonable. This function returns non-zero if the resolution - * was successfully reduced to the given DPI, and zero if reduction failed. - */ -static int __guac_rdp_reduce_resolution(guac_client* client, int resolution) { - - int width = client->info.optimal_width * resolution / client->info.optimal_resolution; - int height = client->info.optimal_height * resolution / client->info.optimal_resolution; - - /* Reduced resolution if result is reasonably sized */ - if (width*height >= GUAC_RDP_REASONABLE_AREA) { - client->info.optimal_width = width; - client->info.optimal_height = height; - client->info.optimal_resolution = resolution; - guac_client_log(client, GUAC_LOG_INFO, - "Reducing resolution to %i DPI (%ix%i)", resolution, width, height); - return 1; - } - - /* No reduction performed */ - return 0; - -} - -/** - * Forces the client resolution to the given value, without checking whether - * the resulting width and height are reasonable. - */ -static void __guac_rdp_force_resolution(guac_client* client, int resolution) { - - int width = client->info.optimal_width * resolution / client->info.optimal_resolution; - int height = client->info.optimal_height * resolution / client->info.optimal_resolution; - - /* Do not force DPI to zero */ - if (resolution == 0) { - guac_client_log(client, GUAC_LOG_WARNING, - "Cowardly refusing to force resolution to %i DPI", resolution); - return; - } - - /* Reduced resolution if result is reasonably sized */ - client->info.optimal_width = width; - client->info.optimal_height = height; - client->info.optimal_resolution = resolution; - guac_client_log(client, GUAC_LOG_INFO, - "Resolution forced to %i DPI (%ix%i)", resolution, width, height); - -} - int guac_client_init(guac_client* client, int argc, char** argv) { rdp_guac_client_data* guac_client_data; @@ -648,23 +599,22 @@ int guac_client_init(guac_client* client, int argc, char** argv) { if (argv[IDX_PORT][0] != '\0') settings->port = atoi(argv[IDX_PORT]); - guac_client_log(client, GUAC_LOG_INFO, "Client resolution is %ix%i at %i DPI", + guac_client_log(client, GUAC_LOG_DEBUG, + "Client resolution is %ix%i at %i DPI", client->info.optimal_width, client->info.optimal_height, client->info.optimal_resolution); - /* Use optimal resolution unless overridden */ + /* Use suggested resolution unless overridden */ + settings->resolution = guac_rdp_suggest_resolution(client); if (argv[IDX_DPI][0] != '\0') - __guac_rdp_force_resolution(client, atoi(argv[IDX_DPI])); - - /* If resolution not forced, attempt to reduce resolution for high DPI */ - else if (client->info.optimal_resolution > GUAC_RDP_NATIVE_RESOLUTION - && !__guac_rdp_reduce_resolution(client, GUAC_RDP_NATIVE_RESOLUTION) - && !__guac_rdp_reduce_resolution(client, GUAC_RDP_HIGH_RESOLUTION)) - guac_client_log(client, GUAC_LOG_INFO, "No reasonable lower resolution"); + settings->resolution = atoi(argv[IDX_DPI]); /* Use optimal width unless overridden */ - settings->width = client->info.optimal_width; + settings->width = client->info.optimal_width + * settings->resolution + / client->info.optimal_resolution; + if (argv[IDX_WIDTH][0] != '\0') settings->width = atoi(argv[IDX_WIDTH]); @@ -680,7 +630,10 @@ int guac_client_init(guac_client* client, int argc, char** argv) { settings->width = settings->width & ~0x3; /* Use optimal height unless overridden */ - settings->height = client->info.optimal_height; + settings->height = client->info.optimal_height + * settings->resolution + / client->info.optimal_resolution; + if (argv[IDX_HEIGHT][0] != '\0') settings->height = atoi(argv[IDX_HEIGHT]); @@ -692,6 +645,12 @@ int guac_client_init(guac_client* client, int argc, char** argv) { argv[IDX_WIDTH], settings->height); } + guac_client_log(client, GUAC_LOG_DEBUG, + "Using resolution of %ix%i at %i DPI", + settings->width, + settings->height, + settings->resolution); + /* Domain */ settings->domain = NULL; if (argv[IDX_DOMAIN][0] != '\0') diff --git a/src/protocols/rdp/guac_handlers.c b/src/protocols/rdp/guac_handlers.c index 621b0a00..8bdd7f4e 100644 --- a/src/protocols/rdp/guac_handlers.c +++ b/src/protocols/rdp/guac_handlers.c @@ -480,6 +480,13 @@ int rdp_guac_client_size_handler(guac_client* client, int width, int height) { freerdp* rdp_inst = guac_client_data->rdp_inst; + /* Convert client pixels to remote pixels */ + width = width * guac_client_data->settings.resolution + / client->info.optimal_resolution; + + height = height * guac_client_data->settings.resolution + / client->info.optimal_resolution; + /* Send display update */ pthread_mutex_lock(&(guac_client_data->rdp_lock)); guac_rdp_disp_set_size(guac_client_data->disp, rdp_inst->context, diff --git a/src/protocols/rdp/rdp_settings.h b/src/protocols/rdp/rdp_settings.h index e6e152d0..191243a2 100644 --- a/src/protocols/rdp/rdp_settings.h +++ b/src/protocols/rdp/rdp_settings.h @@ -122,6 +122,12 @@ typedef struct guac_rdp_settings { */ int height; + /** + * The DPI of the remote display to assume when converting between + * client pixels and remote pixels. + */ + int resolution; + /** * Whether audio is enabled. */ diff --git a/src/protocols/rdp/resolution.c b/src/protocols/rdp/resolution.c new file mode 100644 index 00000000..1d36a4ff --- /dev/null +++ b/src/protocols/rdp/resolution.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "client.h" +#include "resolution.h" + +#include + +int guac_rdp_resolution_reasonable(guac_client* client, int resolution) { + + int width = client->info.optimal_width; + int height = client->info.optimal_height; + + /* Convert client pixels to remote pixels */ + width = width * resolution / client->info.optimal_resolution; + height = height * resolution / client->info.optimal_resolution; + + /* + * Resolution is reasonable if the same as the client optimal resolution + * OR if the resulting display area is reasonable + */ + return client->info.optimal_resolution == resolution + || width*height >= GUAC_RDP_REASONABLE_AREA; + +} + +int guac_rdp_suggest_resolution(guac_client* client) { + + /* Prefer RDP's native resolution */ + if (guac_rdp_resolution_reasonable(client, GUAC_RDP_NATIVE_RESOLUTION)) + return GUAC_RDP_NATIVE_RESOLUTION; + + /* If native resolution is too tiny, try higher resolution */ + if (guac_rdp_resolution_reasonable(client, GUAC_RDP_HIGH_RESOLUTION)) + return GUAC_RDP_HIGH_RESOLUTION; + + /* Fallback to client-suggested resolution */ + return client->info.optimal_resolution; + +} + diff --git a/src/protocols/rdp/resolution.h b/src/protocols/rdp/resolution.h new file mode 100644 index 00000000..7f637d02 --- /dev/null +++ b/src/protocols/rdp/resolution.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef GUAC_RDP_RESOLUTION_H +#define GUAC_RDP_RESOLUTION_H + +#include + +/** + * Returns whether the given resolution is reasonable for the given client, + * based on arbitrary criteria for reasonability. + * + * @param client The guac_client to test the given resolution against. + * @param resolution The resolution to test, in DPI. + * @return Non-zero if the resolution is reasonable, zero otherwise. + */ +int guac_rdp_resolution_reasonable(guac_client* client, int resolution); + +/** + * Returns a reasonable resolution for the remote display, given the size and + * resolution of a guac_client. + * + * @param client The guac_client whose size and resolution shall be used to + * determine an appropriate remote display resolution. + * @return A reasonable resolution for the remote display, in DPI. + */ +int guac_rdp_suggest_resolution(guac_client* client); + +#endif +