diff --git a/src/protocols/vnc/client.h b/src/protocols/vnc/client.h index dd0ec7413..86fe264ad 100644 --- a/src/protocols/vnc/client.h +++ b/src/protocols/vnc/client.h @@ -23,29 +23,14 @@ #include /** - * The maximum duration of a frame in milliseconds. This ensures we at least - * meet a reasonable minimum framerate in the case that the VNC server provides - * no frame boundaries and streams data continuously enough that frame - * boundaries are not discernable through timing. + * The amount of time to wait for new messages from the VNC server before + * moving on to internal matters, in milliseconds. This value must be kept + * reasonably small such that a slow VNC server will not prevent external + * events from being handled (such as the stop signal from guac_client_stop()), + * but large enough that the message handling loop does not eat up CPU + * spinning. */ -#define GUAC_VNC_MAX_FRAME_DURATION 33 - -/** - * The minimum duration of a frame in milliseconds. This ensures we don't start - * flushing a ton of tiny frames if an VNC server provides no frame boundaries - * and streams data inconsistently enough that timing would suggest frame - * boundaries in the middle of a frame. - */ -#define GUAC_VNC_MIN_FRAME_DURATION 10 - -/** - * The amount of time to wait for a new message from the VNC server when - * beginning a new frame, in milliseconds. This value must be kept reasonably - * small such that a slow VNC server will not prevent external events from - * being handled (such as the stop signal from guac_client_stop()), but large - * enough that the message handling loop does not eat up CPU spinning. - */ -#define GUAC_VNC_FRAME_START_TIMEOUT 1000 +#define GUAC_VNC_MESSAGE_CHECK_INTERVAL 1000 /** * The number of milliseconds to wait between connection attempts. diff --git a/src/protocols/vnc/cursor.c b/src/protocols/vnc/cursor.c index 7a1bc1518..079ddd36f 100644 --- a/src/protocols/vnc/cursor.c +++ b/src/protocols/vnc/cursor.c @@ -114,6 +114,7 @@ void guac_vnc_cursor(rfbClient* client, int x, int y, int w, int h, int vnc_bpp) /* Draw operation is now complete */ guac_display_layer_close_raw(cursor_layer, context); + guac_display_render_thread_notify_modified(vnc_client->render_thread); /* libvncclient does not free rcMask as it does rcSource */ if (client->rcMask != NULL) { diff --git a/src/protocols/vnc/display.c b/src/protocols/vnc/display.c index 70b03be8a..8b09f8b6e 100644 --- a/src/protocols/vnc/display.c +++ b/src/protocols/vnc/display.c @@ -129,6 +129,8 @@ void guac_vnc_update(rfbClient* client, int x, int y, int w, int h) { vnc_client->copy_rect_used = 0; } + guac_display_render_thread_notify_modified(vnc_client->render_thread); + } void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) { diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index cdd21bd63..f72ad7a96 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -596,44 +596,22 @@ void* guac_vnc_client_thread(void* data) { guac_display_end_frame(vnc_client->display); + vnc_client->render_thread = guac_display_render_thread_create(vnc_client->display); + /* Handle messages from VNC server while client is running */ while (client->state == GUAC_CLIENT_RUNNING) { /* Wait for data and construct a reasonable frame */ - int wait_result = guac_vnc_wait_for_messages(rfb_client, GUAC_VNC_FRAME_START_TIMEOUT); + int wait_result = guac_vnc_wait_for_messages(rfb_client, GUAC_VNC_MESSAGE_CHECK_INTERVAL); if (wait_result > 0) { - /* Read server messages until frame is built */ - guac_timestamp frame_start = guac_timestamp_current(); - do { - - /* Handle any message received */ - if (!guac_vnc_handle_messages(vnc_client)) { - guac_client_abort(client, - GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, - "Error handling message from VNC server."); - break; - } - - int frame_duration = guac_timestamp_current() - frame_start; - - /* Continue processing messages for up to a reasonable minimum - * framerate without an explicit frame boundary indicating that - * the frame is not yet complete */ - if (frame_duration > GUAC_VNC_MAX_FRAME_DURATION) - break; - - /* Do not exceed a reasonable maximum framerate without an - * explicit frame boundary terminating the frame early */ - int allowed_wait = GUAC_VNC_MIN_FRAME_DURATION - frame_duration; - if (allowed_wait < 0) - allowed_wait = 0; - - wait_result = guac_vnc_wait_for_messages(rfb_client, allowed_wait); - - } while (wait_result > 0); - - guac_display_end_frame(vnc_client->display); + /* Handle any message received */ + if (!guac_vnc_handle_messages(vnc_client)) { + guac_client_abort(client, + GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, + "Error handling message from VNC server."); + break; + } } @@ -643,6 +621,10 @@ void* guac_vnc_client_thread(void* data) { } + /* Stop render loop */ + guac_display_render_thread_destroy(vnc_client->render_thread); + vnc_client->render_thread = NULL; + /* Kill client and finish connection */ guac_client_stop(client); guac_client_log(client, GUAC_LOG_INFO, "Internal VNC client disconnected"); diff --git a/src/protocols/vnc/vnc.h b/src/protocols/vnc/vnc.h index 7e5676af8..6b83d41d0 100644 --- a/src/protocols/vnc/vnc.h +++ b/src/protocols/vnc/vnc.h @@ -113,6 +113,12 @@ typedef struct guac_vnc_client { */ guac_display_layer_raw_context* current_context; + /** + * The current instance of the guac_display render thread. If the thread + * has not yet been started, this will be NULL. + */ + guac_display_render_thread* render_thread; + /** * Internal clipboard. */