Skip to content

Commit

Permalink
Merge changes from patch branch back to main.
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-jumper committed Aug 6, 2024
2 parents a5a9100 + 2a9554b commit ac8191d
Show file tree
Hide file tree
Showing 14 changed files with 301 additions and 65 deletions.
31 changes: 31 additions & 0 deletions src/common/common/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@

#include <pthread.h>

/**
* The minimum display size (height or width) in pixels.
*/
#define GUAC_COMMON_DISPLAY_MIN_SIZE 200

/**
* The maximum display size (height or width) in pixels.
*/
#define GUAC_COMMON_DISPLAY_MAX_SIZE 8192

/**
* The minimum amount of time that must elapse between display size updates,
* in milliseconds.
*/
#define GUAC_COMMON_DISPLAY_UPDATE_INTERVAL 500

/**
* A list element representing a pairing of a Guacamole layer with a
* corresponding guac_common_surface which wraps that layer. Adjacent layers
Expand Down Expand Up @@ -135,6 +151,19 @@ typedef struct guac_common_display {
guac_common_display* guac_common_display_alloc(guac_client* client,
int width, int height);

/**
* Fits a given dimension within the allowed bounds for display sizing,
* adjusting the other dimension such that aspect ratio is maintained.
*
* @param a
* The dimension to fit within allowed bounds.
*
* @param b
* The other dimension to adjust if and only if necessary to preserve
* aspect ratio.
*/
void guac_common_display_fit(int* a, int* b);

/**
* Frees the given display, and any associated resources, including any
* allocated buffers/layers.
Expand Down Expand Up @@ -258,5 +287,7 @@ void guac_common_display_free_buffer(guac_common_display* display,
void guac_common_display_set_lossless(guac_common_display* display,
int lossless);



#endif

31 changes: 31 additions & 0 deletions src/common/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,37 @@ void guac_common_display_dup(

}

void guac_common_display_fit(int* a, int* b) {

int a_value = *a;
int b_value = *b;

/* Ensure first dimension is within allowed range */
if (a_value < GUAC_COMMON_DISPLAY_MIN_SIZE) {

/* Adjust other dimension to maintain aspect ratio */
int adjusted_b = b_value * GUAC_COMMON_DISPLAY_MIN_SIZE / a_value;
if (adjusted_b > GUAC_COMMON_DISPLAY_MAX_SIZE)
adjusted_b = GUAC_COMMON_DISPLAY_MAX_SIZE;

*a = GUAC_COMMON_DISPLAY_MIN_SIZE;
*b = adjusted_b;

}
else if (a_value > GUAC_COMMON_DISPLAY_MAX_SIZE) {

/* Adjust other dimension to maintain aspect ratio */
int adjusted_b = b_value * GUAC_COMMON_DISPLAY_MAX_SIZE / a_value;
if (adjusted_b < GUAC_COMMON_DISPLAY_MIN_SIZE)
adjusted_b = GUAC_COMMON_DISPLAY_MIN_SIZE;

*a = GUAC_COMMON_DISPLAY_MAX_SIZE;
*b = adjusted_b;

}

}

void guac_common_display_set_lossless(guac_common_display* display,
int lossless) {

Expand Down
49 changes: 4 additions & 45 deletions src/protocols/rdp/channels/disp.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

#include "channels/disp.h"
#include "common/display.h"
#include "plugins/channels.h"
#include "fs.h"
#include "rdp.h"
Expand Down Expand Up @@ -149,56 +150,14 @@ void guac_rdp_disp_load_plugin(rdpContext* context) {

}

/**
* Fits a given dimension within the allowed bounds for Display Update
* messages, adjusting the other dimension such that aspect ratio is
* maintained.
*
* @param a The dimension to fit within allowed bounds.
*
* @param b
* The other dimension to adjust if and only if necessary to preserve
* aspect ratio.
*/
static void guac_rdp_disp_fit(int* a, int* b) {

int a_value = *a;
int b_value = *b;

/* Ensure first dimension is within allowed range */
if (a_value < GUAC_RDP_DISP_MIN_SIZE) {

/* Adjust other dimension to maintain aspect ratio */
int adjusted_b = b_value * GUAC_RDP_DISP_MIN_SIZE / a_value;
if (adjusted_b > GUAC_RDP_DISP_MAX_SIZE)
adjusted_b = GUAC_RDP_DISP_MAX_SIZE;

*a = GUAC_RDP_DISP_MIN_SIZE;
*b = adjusted_b;

}
else if (a_value > GUAC_RDP_DISP_MAX_SIZE) {

/* Adjust other dimension to maintain aspect ratio */
int adjusted_b = b_value * GUAC_RDP_DISP_MAX_SIZE / a_value;
if (adjusted_b < GUAC_RDP_DISP_MIN_SIZE)
adjusted_b = GUAC_RDP_DISP_MIN_SIZE;

*a = GUAC_RDP_DISP_MAX_SIZE;
*b = adjusted_b;

}

}

void guac_rdp_disp_set_size(guac_rdp_disp* disp, guac_rdp_settings* settings,
freerdp* rdp_inst, int width, int height) {

/* Fit width within bounds, adjusting height to maintain aspect ratio */
guac_rdp_disp_fit(&width, &height);
guac_common_display_fit(&width, &height);

/* Fit height within bounds, adjusting width to maintain aspect ratio */
guac_rdp_disp_fit(&height, &width);
guac_common_display_fit(&height, &width);

/* Width must be even */
if (width % 2 == 1)
Expand Down Expand Up @@ -226,7 +185,7 @@ void guac_rdp_disp_update_size(guac_rdp_disp* disp,
guac_timestamp now = guac_timestamp_current();

/* Limit display update frequency */
if (now - disp->last_request <= GUAC_RDP_DISP_UPDATE_INTERVAL)
if (now - disp->last_request <= GUAC_COMMON_DISPLAY_UPDATE_INTERVAL)
return;

/* Do NOT send requests unless the size will change */
Expand Down
16 changes: 0 additions & 16 deletions src/protocols/rdp/channels/disp.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,6 @@
#include <guacamole/client.h>
#include <guacamole/timestamp.h>

/**
* The minimum value for width or height, in pixels.
*/
#define GUAC_RDP_DISP_MIN_SIZE 200

/**
* The maximum value for width or height, in pixels.
*/
#define GUAC_RDP_DISP_MAX_SIZE 8192

/**
* The minimum amount of time that must elapse between display size updates,
* in milliseconds.
*/
#define GUAC_RDP_DISP_UPDATE_INTERVAL 500

/**
* Display size update module.
*/
Expand Down
6 changes: 6 additions & 0 deletions src/protocols/vnc/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ int guac_client_init(guac_client* client) {
pthread_mutex_init(&vnc_client->tls_lock, NULL);
#endif

/* Initialize the message lock. */
pthread_mutex_init(&(vnc_client->message_lock), NULL);

/* Init clipboard */
vnc_client->clipboard = guac_common_clipboard_alloc();

Expand Down Expand Up @@ -209,6 +212,9 @@ int guac_vnc_client_free_handler(guac_client* client) {
pthread_mutex_destroy(&(vnc_client->tls_lock));
#endif

/* Clean up the message lock. */
pthread_mutex_destroy(&(vnc_client->message_lock));

/* Free generic data struct */
guac_mem_free(client->data);

Expand Down
137 changes: 136 additions & 1 deletion src/protocols/vnc/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "config.h"

#include "client.h"
#include "display.h"
#include "common/iconv.h"
#include "common/surface.h"
#include "vnc.h"
Expand All @@ -30,6 +31,7 @@
#include <guacamole/mem.h>
#include <guacamole/protocol.h>
#include <guacamole/socket.h>
#include <guacamole/timestamp.h>
#include <rfb/rfbclient.h>
#include <rfb/rfbproto.h>

Expand Down Expand Up @@ -153,6 +155,140 @@ void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, in

}

/**
* This function does the actual work of sending the message to the RFB/VNC
* server to request the resize, and then makes sure that the client frame
* buffer is updated, as well.
*
* @param client
* The remote frame buffer client that is triggering the resize
* request.
*
* @param width
* The updated width of the screen.
*
* @param height
* The updated height of the screen.
*
* @return
* TRUE if the screen update was sent to the server, otherwise false. Note
* that a successful send of the resize message to the server does NOT mean
* that the server has any obligation to resize the display - it only
* indicates that the VNC library has successfully sent the request.
*/
static rfbBool guac_vnc_send_desktop_size(rfbClient* client, int width, int height) {

/* Get the Guacamole client data */
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);

/* Don't send an update if the sreen appears to be uninitialized. */
if (client->screen.width == 0 || client->screen.height == 0) {
guac_client_log(gc, GUAC_LOG_ERROR, "Screen has not been initialized, cannot send resize.");
return FALSE;
}

/* Don't send an update if the requested dimensions are identical to current dimensions. */
if (client->screen.width == rfbClientSwap16IfLE(width) && client->screen.height == rfbClientSwap16IfLE(height)) {
guac_client_log(gc, GUAC_LOG_WARNING, "Screen size has not changed, not sending update.");
return FALSE;
}

/**
* Note: The RFB protocol requires two message types to be sent during a
* resize request - the first for the desktop size (total size of all
* monitors), and then a message for each screen that is attached to the
* remote server. Both libvncclient and Guacamole only support a single
* screen, so we send the desktop resize and screen resize with (nearly)
* identical data, but if one or both of these components is updated in the
* future to support multiple screens, this will need to be re-worked.
*/

/* Set up the messages. */
rfbSetDesktopSizeMsg size_msg;
rfbExtDesktopScreen new_screen;

/* Configure the desktop size update message. */
size_msg.type = rfbSetDesktopSize;
size_msg.width = rfbClientSwap16IfLE(width);
size_msg.height = rfbClientSwap16IfLE(height);
size_msg.numberOfScreens = 1;

/* Configure the screen update message. */
new_screen.id = client->screen.id;
new_screen.x = client->screen.x;
new_screen.y = client->screen.y;
new_screen.flags = client->screen.flags;
new_screen.width = rfbClientSwap16IfLE(width);
new_screen.height = rfbClientSwap16IfLE(height);

/* Stop updates while the resize is in progress. */
client->requestedResize = TRUE;

/* Send the resize messages to the remote server. */
if (!WriteToRFBServer(client, (char *)&size_msg, sz_rfbSetDesktopSizeMsg)
|| !WriteToRFBServer(client, (char *)&new_screen, sz_rfbExtDesktopScreen)) {

guac_client_log(gc, GUAC_LOG_ERROR, "Failed to send new desktop and screen size to the VNC server.");
return FALSE;

}

/* Update the client frame buffer with the requested size. */
client->screen.width = rfbClientSwap16IfLE(width);
client->screen.height = rfbClientSwap16IfLE(height);

/* Request a full screen update. */
client->requestedResize = FALSE;
if (!SendFramebufferUpdateRequest(client, 0, 0, width, height, FALSE)) {
guac_client_log(gc, GUAC_LOG_WARNING, "Failed to request a full screen update.");
}

/* Update should be successful. */
return TRUE;
}

void* guac_vnc_display_set_owner_size(guac_user* owner, void* data) {

/* Pull RFB clients from provided data. */
rfbClient* rfb_client = (rfbClient*) data;

guac_user_log(owner, GUAC_LOG_DEBUG, "Sending VNC display size for owner's display.");

/* Set the display size. */
guac_vnc_display_set_size(rfb_client, owner->info.optimal_width, owner->info.optimal_height);

/* Always return NULL. */
return NULL;

}

void guac_vnc_display_set_size(rfbClient* client, int width, int height) {

/* Get the VNC client */
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
guac_vnc_client* vnc_client = (guac_vnc_client*) gc->data;

/* Fit width within bounds, adjusting height to maintain aspect ratio */
guac_common_display_fit(&width, &height);

/* Fit height within bounds, adjusting width to maintain aspect ratio */
guac_common_display_fit(&height, &width);

/* Acquire the lock for sending messages to server. */
pthread_mutex_lock(&(vnc_client->message_lock));

/* Send the display size update. */
guac_client_log(gc, GUAC_LOG_TRACE, "Setting VNC display size.");
if (guac_vnc_send_desktop_size(client, width, height))
guac_client_log(gc, GUAC_LOG_TRACE, "Successfully sent desktop size message.");
else
guac_client_log(gc, GUAC_LOG_TRACE, "Failed to send desktop size message.");

/* Release the lock. */
pthread_mutex_unlock(&(vnc_client->message_lock));

}

void guac_vnc_set_pixel_format(rfbClient* client, int color_depth) {
client->format.trueColour = 1;
switch(color_depth) {
Expand Down Expand Up @@ -205,4 +341,3 @@ rfbBool guac_vnc_malloc_framebuffer(rfbClient* rfb_client) {
/* Use original, wrapped proc */
return vnc_client->rfb_MallocFrameBuffer(rfb_client);
}

Loading

0 comments on commit ac8191d

Please sign in to comment.