From 1a96c5b41506b67aad556f885ad4a424812e2930 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 10 Mar 2017 12:27:24 -0800 Subject: [PATCH 1/4] GUACAMOLE-231: Add "mouse" instruction for server reporting of mouse position. --- src/libguac/guacamole/protocol.h | 20 ++++++++++++++++++++ src/libguac/protocol.c | 17 +++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/libguac/guacamole/protocol.h b/src/libguac/guacamole/protocol.h index 638d7b28..88a0a185 100644 --- a/src/libguac/guacamole/protocol.h +++ b/src/libguac/guacamole/protocol.h @@ -144,6 +144,26 @@ int guac_protocol_send_log(guac_socket* socket, const char* format, ...); int vguac_protocol_send_log(guac_socket* socket, const char* format, va_list args); +/** + * Sends a mouse instruction over the given guac_socket connection. + * + * If an error occurs sending the instruction, a non-zero value is + * returned, and guac_error is set appropriately. + * + * @param socket + * The guac_socket connection to use. + * + * @param x + * The X coordinate of the current mouse position. + * + * @param y + * The Y coordinate of the current mouse position. + * + * @return + * Zero on success, non-zero on error. + */ +int guac_protocol_send_mouse(guac_socket* socket, int x, int y); + /** * Sends a nest instruction over the given guac_socket connection. * diff --git a/src/libguac/protocol.c b/src/libguac/protocol.c index 1040fb1d..8da18249 100644 --- a/src/libguac/protocol.c +++ b/src/libguac/protocol.c @@ -684,6 +684,23 @@ int guac_protocol_send_lstroke(guac_socket* socket, } +int guac_protocol_send_mouse(guac_socket* socket, int x, int y) { + + int ret_val; + + guac_socket_instruction_begin(socket); + ret_val = + guac_socket_write_string(socket, "5.mouse,") + || __guac_socket_write_length_int(socket, x) + || guac_socket_write_string(socket, ",") + || __guac_socket_write_length_int(socket, y) + || guac_socket_write_string(socket, ";"); + + guac_socket_instruction_end(socket); + return ret_val; + +} + int guac_protocol_send_move(guac_socket* socket, const guac_layer* layer, const guac_layer* parent, int x, int y, int z) { From ae7e8d3890e6d08271f87551c4d501f8ff605bb3 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 10 Mar 2017 12:28:00 -0800 Subject: [PATCH 2/4] GUACAMOLE-231: Report mouse position using new "mouse" instruction. Rely on client-side cursor layer implementation. --- src/common/common/cursor.h | 5 +- src/common/cursor.c | 168 ++++++------------------------------- 2 files changed, 27 insertions(+), 146 deletions(-) diff --git a/src/common/common/cursor.h b/src/common/common/cursor.h index 86a7f14a..00bc48e7 100644 --- a/src/common/common/cursor.h +++ b/src/common/common/cursor.h @@ -45,10 +45,9 @@ typedef struct guac_common_cursor { guac_client* client; /** - * The cursor layer. This layer will be available to all connected users, - * but will be visible only to those users who are not moving the mouse. + * The buffer containing the current cursor image. */ - guac_layer* layer; + guac_layer* buffer; /** * The width of the cursor image, in pixels. diff --git a/src/common/cursor.c b/src/common/cursor.c index e63ada10..0384ea36 100644 --- a/src/common/cursor.c +++ b/src/common/cursor.c @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -41,9 +40,9 @@ guac_common_cursor* guac_common_cursor_alloc(guac_client* client) { if (cursor == NULL) return NULL; - /* Associate cursor with client and allocate cursor layer */ + /* Associate cursor with client and allocate cursor buffer */ cursor->client = client; - cursor->layer= guac_client_alloc_layer(client); + cursor->buffer = guac_client_alloc_buffer(client); /* Allocate initial image buffer */ cursor->image_buffer_size = GUAC_COMMON_CURSOR_DEFAULT_SIZE; @@ -70,7 +69,7 @@ guac_common_cursor* guac_common_cursor_alloc(guac_client* client) { void guac_common_cursor_free(guac_common_cursor* cursor) { guac_client* client = cursor->client; - guac_layer* layer = cursor->layer; + guac_layer* buffer = cursor->buffer; cairo_surface_t* surface = cursor->surface; /* Free image buffer and surface */ @@ -78,11 +77,11 @@ void guac_common_cursor_free(guac_common_cursor* cursor) { if (surface != NULL) cairo_surface_destroy(surface); - /* Destroy layer within remotely-connected client */ - guac_protocol_send_dispose(client->socket, layer); + /* Destroy buffer within remotely-connected client */ + guac_protocol_send_dispose(client->socket, buffer); - /* Return layer to pool */ - guac_client_free_layer(client, layer); + /* Return buffer to pool */ + guac_client_free_buffer(client, buffer); free(cursor); @@ -92,89 +91,37 @@ void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user, guac_socket* socket) { /* Synchronize location */ - guac_protocol_send_move(socket, cursor->layer, GUAC_DEFAULT_LAYER, - cursor->x - cursor->hotspot_x, - cursor->y - cursor->hotspot_y, - INT_MAX); + guac_protocol_send_mouse(socket, cursor->x, cursor->y); /* Synchronize cursor image */ if (cursor->surface != NULL) { - guac_protocol_send_size(socket, cursor->layer, + guac_protocol_send_size(socket, cursor->buffer, cursor->width, cursor->height); guac_user_stream_png(user, socket, GUAC_COMP_SRC, - cursor->layer, 0, 0, cursor->surface); + cursor->buffer, 0, 0, cursor->surface); + + guac_protocol_send_cursor(socket, + cursor->hotspot_x, cursor->hotspot_y, + cursor->buffer, 0, 0, cursor->width, cursor->height); } guac_socket_flush(socket); } -/** - * Callback for guac_client_for_user() which shows the cursor layer for the - * given user (if they exist). The cursor layer is normally hidden when a user - * is moving the mouse, and will only be shown if a DIFFERENT user is moving - * the mouse. - * - * @param user - * The user to show the cursor to, or NULL if that user does not exist. - * - * @param data - * A pointer to the guac_common_cursor structure describing the cursor to - * be shown. - * - * @return - * Always NULL. - */ -static void* guac_common_cursor_show(guac_user* user, void* data) { - - guac_common_cursor* cursor = (guac_common_cursor*) data; - - /* Make cursor layer visible to given user */ - if (user != NULL) { - guac_protocol_send_shade(user->socket, cursor->layer, 255); - guac_socket_flush(user->socket); - } - - return NULL; - -} - void guac_common_cursor_move(guac_common_cursor* cursor, guac_user* user, int x, int y) { - guac_user* last_user = cursor->user; - /* Update current user of cursor */ - if (last_user != user) { - - cursor->user = user; - - /* Make cursor layer visible to previous user */ - guac_client_for_user(cursor->client, last_user, - guac_common_cursor_show, cursor); - - /* Show hardware cursor */ - guac_protocol_send_cursor(user->socket, - cursor->hotspot_x, cursor->hotspot_y, - cursor->layer, 0, 0, cursor->width, cursor->height); - - /* Hide cursor layer from new user */ - guac_protocol_send_shade(user->socket, cursor->layer, 0); - guac_socket_flush(user->socket); - - } + cursor->user = user; /* Update cursor position */ cursor->x = x; cursor->y = y; - guac_protocol_send_move(cursor->client->socket, cursor->layer, - GUAC_DEFAULT_LAYER, - x - cursor->hotspot_x, - y - cursor->hotspot_y, - INT_MAX); - + /* Notify of change in cursor position */ + guac_protocol_send_mouse(cursor->client->socket, x, y); guac_socket_flush(cursor->client->socket); } @@ -217,65 +164,6 @@ static void guac_common_cursor_resize(guac_common_cursor* cursor, } -/** - * Callback for guac_client_foreach_user() which sends the current cursor image - * as PNG data to each connected client. - * - * @param user - * The user to send the cursor image to. - * - * @param data - * A pointer to the guac_common_cursor structure containing the cursor - * image that should be sent to the given user. - * - * @return - * Always NULL. - */ -static void* __send_user_cursor_image(guac_user* user, void* data) { - - guac_common_cursor* cursor = (guac_common_cursor*) data; - - guac_user_stream_png(user, user->socket, GUAC_COMP_SRC, - cursor->layer, 0, 0, cursor->surface); - - return NULL; - -} - -/** - * Callback for guac_client_for_user() which updates the hardware cursor and - * hotspot for the given user (if they exist). The hardware cursor image is - * normally hidden when a user is not moving the mouse, and will only be shown - * if that user begins moving the mouse. - * - * @param user - * The user whose hardware cursor should be updated, or NULL if that user - * does not exist. - * - * @param data - * A pointer to the guac_common_cursor structure describing the cursor to - * be sent as the hardware cursor. - * - * @return - * Always NULL. - */ -static void* guac_common_cursor_update(guac_user* user, void* data) { - - guac_common_cursor* cursor = (guac_common_cursor*) data; - - /* Update hardware cursor of current user */ - if (user != NULL) { - guac_protocol_send_cursor(user->socket, - cursor->hotspot_x, cursor->hotspot_y, - cursor->layer, 0, 0, cursor->width, cursor->height); - - guac_socket_flush(user->socket); - } - - return NULL; - -} - void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy, unsigned const char* data, int width, int height, int stride) { @@ -295,26 +183,20 @@ void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy, cursor->hotspot_x = hx; cursor->hotspot_y = hy; - /* Update location based on new hotspot */ - guac_protocol_send_move(cursor->client->socket, cursor->layer, - GUAC_DEFAULT_LAYER, - cursor->x - hx, - cursor->y - hy, - INT_MAX); - /* Broadcast new cursor image to all users */ - guac_protocol_send_size(cursor->client->socket, cursor->layer, + guac_protocol_send_size(cursor->client->socket, cursor->buffer, width, height); - guac_client_foreach_user(cursor->client, __send_user_cursor_image, cursor); + guac_client_stream_png(cursor->client, cursor->client->socket, + GUAC_COMP_SRC, cursor->buffer, 0, 0, cursor->surface); + + /* Update cursor image */ + guac_protocol_send_cursor(cursor->client->socket, + cursor->hotspot_x, cursor->hotspot_y, + cursor->buffer, 0, 0, cursor->width, cursor->height); guac_socket_flush(cursor->client->socket); - /* Update hardware cursor of current user (if they are indeed valid) */ - if (cursor->user != NULL) - guac_client_for_user(cursor->client, cursor->user, - guac_common_cursor_update, cursor); - } void guac_common_cursor_set_surface(guac_common_cursor* cursor, int hx, int hy, From 240e18cd921c7a38a5d216dc8a323941c3dd981c Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 11 Mar 2017 14:35:43 -0800 Subject: [PATCH 3/4] GUACAMOLE-231: Broadcast mouse position only to users who are not moving the mouse. --- src/common/cursor.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/common/cursor.c b/src/common/cursor.c index 0384ea36..f956f6aa 100644 --- a/src/common/cursor.c +++ b/src/common/cursor.c @@ -110,6 +110,32 @@ void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user, } +/** + * Callback for guac_client_foreach_user() which sends the current cursor + * position to any given user except the user that moved the cursor last. + * + * @param data + * A pointer to the guac_common_cursor whose position should be broadcast + * to all users except the user that moved the cursor last. + * + * @return + * Always NULL. + */ +static void* guac_common_cursor_broadcast_position(guac_user* user, + void* data) { + + guac_common_cursor* cursor = (guac_common_cursor*) data; + + /* Send cursor position only if the user is not moving the cursor */ + if (user != cursor->user) { + guac_protocol_send_mouse(user->socket, cursor->x, cursor->y); + guac_socket_flush(user->socket); + } + + return NULL; + +} + void guac_common_cursor_move(guac_common_cursor* cursor, guac_user* user, int x, int y) { @@ -120,9 +146,9 @@ void guac_common_cursor_move(guac_common_cursor* cursor, guac_user* user, cursor->x = x; cursor->y = y; - /* Notify of change in cursor position */ - guac_protocol_send_mouse(cursor->client->socket, x, y); - guac_socket_flush(cursor->client->socket); + /* Notify all other users of change in cursor position */ + guac_client_foreach_user(cursor->client, + guac_common_cursor_broadcast_position, cursor); } From fe8771e1816d51762011fd1200ec6ce4a89dde1c Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 11 Mar 2017 14:58:52 -0800 Subject: [PATCH 4/4] GUACAMOLE-231: Notifying terminal for mouse movement is no longer necessary (common cursor sends its own position updates without requiring new frames). --- src/terminal/terminal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index a65f4469..c5df648d 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -1746,7 +1746,6 @@ int guac_terminal_send_mouse(guac_terminal* term, guac_user* user, result = __guac_terminal_send_mouse(term, user, x, y, mask); guac_terminal_unlock(term); - guac_terminal_notify(term); return result; }