Skip to content

Commit f277130

Browse files
committed
GUACAMOLE-1196: Implement our own function for sending size updates to server.
The current state of the libvncclient implementation of the SendExtDesktopSize function is broken and does not work reliably with VNC servers. In order to still support this functionality until an updated libvncclient version is release, I went ahead and implemented an internal version of that function.
1 parent 7c726bb commit f277130

2 files changed

Lines changed: 100 additions & 2 deletions

File tree

‎src/protocols/vnc/display.c‎

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,98 @@ void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, in
157157

158158
#ifdef ENABLE_VNC_DESKTOP_SIZE
159159

160+
/**
161+
* This function does the actual work of sending the message to the RFB/VNC
162+
* server to request the resize, and then makes sure that the client frame
163+
* buffer is updated, as well.
164+
*
165+
* @param client
166+
* The remote frame buffer client that is triggering the resize
167+
* request.
168+
*
169+
* @param width
170+
* The updated width of the screen.
171+
*
172+
* @param height
173+
* The updated height of the screen.
174+
*
175+
* @return
176+
* TRUE if the screen update was sent to the server, otherwise false. Note
177+
* that a successful send of the resize message to the server does NOT mean
178+
* that the server has any obligation to resize the display - it only
179+
* indicates that the VNC library has successfully sent the request.
180+
*/
181+
static rfbBool guac_vnc_send_desktop_size(rfbClient* client, int width, int height) {
182+
183+
/* Get the Guacamole client data */
184+
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
185+
186+
/* Don't send an update if the sreen appears to be uninitialized. */
187+
if (client->screen.width == 0 || client->screen.height == 0) {
188+
guac_client_log(gc, GUAC_LOG_ERROR, "Screen has not been initialized, cannot send resize.");
189+
return FALSE;
190+
}
191+
192+
/* Don't send an update if the requested dimensions are identical to current dimensions. */
193+
if (client->screen.width == rfbClientSwap16IfLE(width) && client->screen.height == rfbClientSwap16IfLE(height)) {
194+
guac_client_log(gc, GUAC_LOG_WARNING, "Screen size has not changed, not sending update.");
195+
return FALSE;
196+
}
197+
198+
/**
199+
* Note: The RFB protocol requires two message types to be sent during a
200+
* resize request - the first for the desktop size (total size of all
201+
* monitors), and then a message for each screen that is attached to the
202+
* remote server. Both libvncclient and Guacamole only support a single
203+
* screen, so we send the desktop resize and screen resize with (nearly)
204+
* identical data, but if one or both of these components is updated in the
205+
* future to support multiple screens, this will need to be re-worked.
206+
*/
207+
208+
/* Set up the messages. */
209+
rfbSetDesktopSizeMsg size_msg;
210+
rfbExtDesktopScreen new_screen;
211+
212+
/* Configure the desktop size update message. */
213+
size_msg.type = rfbSetDesktopSize;
214+
size_msg.width = rfbClientSwap16IfLE(width);
215+
size_msg.height = rfbClientSwap16IfLE(height);
216+
size_msg.numberOfScreens = 1;
217+
218+
/* Configure the screen update message. */
219+
new_screen.id = client->screen.id;
220+
new_screen.x = client->screen.x;
221+
new_screen.y = client->screen.y;
222+
new_screen.flags = client->screen.flags;
223+
new_screen.width = rfbClientSwap16IfLE(width);
224+
new_screen.height = rfbClientSwap16IfLE(height);
225+
226+
/* Stop updates while the resize is in progress. */
227+
client->requestedResize = TRUE;
228+
229+
/* Send the resize messages to the remote server. */
230+
if (!WriteToRFBServer(client, (char *)&size_msg, sz_rfbSetDesktopSizeMsg)
231+
|| !WriteToRFBServer(client, (char *)&new_screen, sz_rfbExtDesktopScreen)) {
232+
233+
guac_client_log(gc, GUAC_LOG_ERROR, "Failed to send new desktop and screen size to the VNC server.");
234+
return FALSE;
235+
236+
}
237+
238+
/* Update the client frame buffer with the requested size. */
239+
client->screen.width = rfbClientSwap16IfLE(width);
240+
client->screen.height = rfbClientSwap16IfLE(height);
241+
242+
/* Request a full screen update. */
243+
client->requestedResize = FALSE;
244+
if (!SendFramebufferUpdateRequest(client, 0, 0, width, height, FALSE)) {
245+
guac_client_log(gc, GUAC_LOG_WARNING, "Failed to request a full screen update.");
246+
}
247+
248+
/* Update should be successful. */
249+
return TRUE;
250+
}
251+
160252
void guac_vnc_display_set_size(rfbClient* client, int width, int height) {
161253

162254
/* Get the VNC client */
@@ -171,7 +263,11 @@ void guac_vnc_display_set_size(rfbClient* client, int width, int height) {
171263

172264
/* Send the display size update. */
173265
pthread_mutex_lock(&(vnc_client->message_lock));
174-
SendExtDesktopSize(client, width, height);
266+
guac_client_log(gc, GUAC_LOG_TRACE, "Setting VNC display size.");
267+
if (guac_vnc_send_desktop_size(client, width, height))
268+
guac_client_log(gc, GUAC_LOG_TRACE, "Successfully sent desktop size message.");
269+
else
270+
guac_client_log(gc, GUAC_LOG_TRACE, "Failed to send desktop size message.");
175271
pthread_mutex_unlock(&(vnc_client->message_lock));
176272

177273
}

‎src/protocols/vnc/input.c‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ int guac_vnc_user_key_handler(guac_user* user, int keysym, int pressed) {
6969

7070
int guac_vnc_user_size_handler(guac_user* user, int width, int height) {
7171

72+
guac_user_log(user, GUAC_LOG_TRACE, "Running user size handler.");
73+
7274
/* Get the Guacamole VNC client */
7375
guac_vnc_client* vnc_client = (guac_vnc_client*) user->client->data;
7476

@@ -79,4 +81,4 @@ int guac_vnc_user_size_handler(guac_user* user, int width, int height) {
7981

8082
}
8183

82-
#endif // ENABLE_VNC_DESKTOP_SIZE
84+
#endif // ENABLE_VNC_DESKTOP_SIZE

0 commit comments

Comments
 (0)