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..f956f6aa 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,18 +91,19 @@ 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); @@ -111,28 +111,24 @@ void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user, } /** - * 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. + * 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 structure describing the cursor to - * be shown. + * 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_show(guac_user* user, void* data) { +static void* guac_common_cursor_broadcast_position(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); + /* 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); } @@ -143,39 +139,16 @@ static void* guac_common_cursor_show(guac_user* user, void* data) { 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); - - 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); } @@ -217,65 +190,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 +209,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, 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) { diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index ecab9b17..758b72d7 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; }