From f26c9443dc21771ea92aa84ee3c4e58655d1f1a4 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 3 Feb 2015 23:51:04 -0800 Subject: [PATCH 1/4] GUAC-803: Handle mouse events within scrollbar. --- src/terminal/scrollbar.c | 88 +++++++++++++++++++++++++++++++++++++--- src/terminal/scrollbar.h | 43 ++++++++++++++++++++ src/terminal/terminal.c | 19 +++++++-- 3 files changed, 140 insertions(+), 10 deletions(-) diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index c1a5bc9a..e0643976 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -67,6 +67,9 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, scrollbar->container = guac_client_alloc_layer(client); scrollbar->handle = guac_client_alloc_layer(client); + /* Init mouse event state tracking */ + scrollbar->dragging_handle = 0; + /* Reposition and resize to fit parent */ guac_terminal_scrollbar_parent_resized(scrollbar, parent_width, parent_height, visible_area); @@ -141,15 +144,36 @@ static void calculate_render_state(guac_terminal_scrollbar* scrollbar, if (render_state->handle_height > max_handle_height) render_state->handle_height = max_handle_height; - /* Calculate handle position */ + /* Calculate handle X position */ render_state->handle_x = GUAC_TERMINAL_SCROLLBAR_PADDING; + /* Calculate handle Y range */ + int min_handle_y = GUAC_TERMINAL_SCROLLBAR_PADDING; + int max_handle_y = min_handle_y + max_handle_height + - render_state->handle_height; + + /* Position handle relative to mouse if being dragged */ + if (scrollbar->dragging_handle) { + + int dragged_handle_y = scrollbar->drag_current_y + - scrollbar->drag_offset_y; + + /* Keep handle within bounds */ + if (dragged_handle_y < min_handle_y) + dragged_handle_y = min_handle_y; + else if (dragged_handle_y > max_handle_y) + dragged_handle_y = max_handle_y; + + render_state->handle_y = dragged_handle_y; + + } + /* Handle Y position is relative to current scroll value */ - if (scroll_delta > 0) - render_state->handle_y = GUAC_TERMINAL_SCROLLBAR_PADDING - + (max_handle_height - render_state->handle_height) - * (scrollbar->value - scrollbar->min) - / scroll_delta; + else if (scroll_delta > 0) + render_state->handle_y = min_handle_y + + (max_handle_y - min_handle_y) + * (scrollbar->value - scrollbar->min) + / scroll_delta; /* ... unless there is only one possible scroll value */ else @@ -278,3 +302,55 @@ void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, } +int guac_terminal_scrollbar_handle_mouse(guac_terminal_scrollbar* scrollbar, + int x, int y, int mask) { + + /* Get container rectangle bounds */ + int parent_left = scrollbar->render_state.container_x; + int parent_top = scrollbar->render_state.container_y; + int parent_right = parent_left + scrollbar->render_state.container_width; + int parent_bottom = parent_top + scrollbar->render_state.container_height; + + /* Calculate handle rectangle bounds */ + int handle_left = parent_left + scrollbar->render_state.handle_x; + int handle_top = parent_top + scrollbar->render_state.handle_y; + int handle_right = handle_left + scrollbar->render_state.handle_width; + int handle_bottom = handle_top + scrollbar->render_state.handle_height; + + /* Handle click on handle */ + if (scrollbar->dragging_handle) { + + /* Update drag while mouse button is held */ + if (mask & GUAC_CLIENT_MOUSE_LEFT) { + scrollbar->drag_current_y = y; + /* TODO: Update scrollbar value */ + } + + /* Stop drag if mouse button is released */ + else + scrollbar->dragging_handle = 0; + + /* Mouse event was handled by scrollbar */ + return 1; + + } + else if (mask == GUAC_CLIENT_MOUSE_LEFT + && x >= handle_left && x < handle_right + && y >= handle_top && y < handle_bottom) { + + /* Start drag */ + scrollbar->dragging_handle = 1; + scrollbar->drag_offset_y = y - handle_top; + scrollbar->drag_current_y = y; + + /* Mouse event was handled by scrollbar */ + return 1; + + } + + /* Eat any events that occur within the scrollbar */ + return x >= parent_left && x < parent_right + && y >= parent_top && y < parent_bottom; + +} + diff --git a/src/terminal/scrollbar.h b/src/terminal/scrollbar.h index e1bee7ff..f46a42a8 100644 --- a/src/terminal/scrollbar.h +++ b/src/terminal/scrollbar.h @@ -159,6 +159,24 @@ typedef struct guac_terminal_scrollbar { */ guac_terminal_scrollbar_render_state render_state; + /** + * Whether the scrollbar handle is currently being dragged. + */ + int dragging_handle; + + /** + * The offset of the Y location of the mouse pointer when the dragging + * began, relative to the top of the scrollbar handle. If dragging is not + * in progress, this value is undefined. + */ + int drag_offset_y; + + /** + * The current Y location of the mouse pointer if dragging is in progress. + * If dragging is not in progress, this value is undefined. + */ + int drag_current_y; + } guac_terminal_scrollbar; /** @@ -276,4 +294,29 @@ void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, int parent_width, int parent_height, int visible_area); +/** + * Notifies the scrollbar of the current mouse state, allowing it to update + * itself with respect to button state and dragging. + * + * @param scrollbar + * The scrollbar to notify of the current mouse state. + * + * @param x + * The X coordinate of the mouse pointer. + * + * @param y + * The Y coordinate of the mouse pointer. + * + * @param mask + * The button mask, where the Nth bit of the button mask represents the + * pressed state of the Nth mouse button, where button 0 is the left + * mouse button, button 1 is the middle button, etc. + * + * @return + * Zero if the mouse event was not handled by the scrollbar, non-zero + * otherwise. + */ +int guac_terminal_scrollbar_handle_mouse(guac_terminal_scrollbar* scrollbar, + int x, int y, int mask); + #endif diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 7a1a9160..3c2f7f92 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -1379,17 +1379,28 @@ int guac_terminal_send_key(guac_terminal* term, int keysym, int pressed) { static int __guac_terminal_send_mouse(guac_terminal* term, int x, int y, int mask) { + guac_client* client = term->client; + guac_socket* socket = client->socket; + /* Determine which buttons were just released and pressed */ int released_mask = term->mouse_mask & ~mask; int pressed_mask = ~term->mouse_mask & mask; + /* Notify scrollbar, do not handle anything handled by scrollbar */ + if (guac_terminal_scrollbar_handle_mouse(term->scrollbar, x, y, mask)) { + guac_terminal_scrollbar_flush(term->scrollbar); + guac_protocol_send_sync(socket, client->last_sent_timestamp); + guac_socket_flush(socket); + return 0; + } + term->mouse_mask = mask; /* Show mouse cursor if not already shown */ if (term->current_cursor != term->ibar_cursor) { term->current_cursor = term->ibar_cursor; - guac_terminal_set_cursor(term->client, term->ibar_cursor); - guac_socket_flush(term->client->socket); + guac_terminal_set_cursor(client, term->ibar_cursor); + guac_socket_flush(socket); } /* Paste contents of clipboard on right or middle mouse button up */ @@ -1417,8 +1428,8 @@ static int __guac_terminal_send_mouse(guac_terminal* term, int x, int y, int mas free(string); /* Send data */ - guac_common_clipboard_send(term->clipboard, term->client); - guac_socket_flush(term->client->socket); + guac_common_clipboard_send(term->clipboard, client); + guac_socket_flush(socket); } From 0a7f13ab5c9a2efacc1c6b58491ae82b7cbd8b1f Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 4 Feb 2015 00:21:19 -0800 Subject: [PATCH 2/4] GUAC-803: Calculate new scrollbar value based on mouse position. --- src/terminal/scrollbar.c | 52 ++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index e0643976..45eb37f6 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -90,19 +90,29 @@ void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) { } /** - * Calculates the render state of the scroll bar, given its minimum, maximum, - * and current values. This render state will not be reflected graphically - * unless the scrollbar is flushed. + * Calculates the state of the scroll bar, given its minimum, maximum, current + * values, and the state of any dragging operation. The resulting render state + * will not be reflected graphically unless the scrollbar is flushed, and any + * resulting value will not be assigned to the scrollbar unless explicitly set + * with guac_terminal_scrollbar_set_value(). * * @param scrollbar - * The scrollbar whose render state should be calculated. + * The scrollbar whose state should be calculated. * * @param render_state * A pointer to an existing guac_terminal_scrollbar_render_state that will * be populated with the calculated result. + * + * @param value + * A pointer to an existing int that will be populated with the updated + * scrollbar value. */ -static void calculate_render_state(guac_terminal_scrollbar* scrollbar, - guac_terminal_scrollbar_render_state* render_state) { +static void calculate_state(guac_terminal_scrollbar* scrollbar, + guac_terminal_scrollbar_render_state* render_state, + int* value) { + + /* Use unchanged current value by default */ + *value = scrollbar->value; /* Calculate container dimensions */ render_state->container_width = GUAC_TERMINAL_SCROLLBAR_WIDTH; @@ -166,6 +176,14 @@ static void calculate_render_state(guac_terminal_scrollbar* scrollbar, render_state->handle_y = dragged_handle_y; + /* Calculate scrollbar value */ + if (max_handle_y > min_handle_y) { + *value = scrollbar->min + + (dragged_handle_y - min_handle_y) + * scroll_delta + / (max_handle_y - min_handle_y); + } + } /* Handle Y position is relative to current scroll value */ @@ -185,12 +203,24 @@ void guac_terminal_scrollbar_flush(guac_terminal_scrollbar* scrollbar) { guac_socket* socket = scrollbar->client->socket; - /* Get old render state */ + /* Get old state */ + int old_value = scrollbar->value; guac_terminal_scrollbar_render_state* old_state = &scrollbar->render_state; - /* Calculate new render state */ + /* Calculate new state */ + int new_value; guac_terminal_scrollbar_render_state new_state; - calculate_render_state(scrollbar, &new_state); + calculate_state(scrollbar, &new_state, &new_value); + + /* Notify of scroll if value is changing */ + if (new_value != old_value) { + + /* TODO: Call scroll value handler */ + guac_client_log(scrollbar->client, GUAC_LOG_DEBUG, + "SCROLL: min=%i max=%i value=%i", + scrollbar->min, scrollbar->max, new_value); + + } /* Reposition container if moved */ if (old_state->container_x != new_state.container_x @@ -321,10 +351,8 @@ int guac_terminal_scrollbar_handle_mouse(guac_terminal_scrollbar* scrollbar, if (scrollbar->dragging_handle) { /* Update drag while mouse button is held */ - if (mask & GUAC_CLIENT_MOUSE_LEFT) { + if (mask & GUAC_CLIENT_MOUSE_LEFT) scrollbar->drag_current_y = y; - /* TODO: Update scrollbar value */ - } /* Stop drag if mouse button is released */ else From fc476fd99e63fae06aea48191cc90d530c9879f0 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 4 Feb 2015 00:41:45 -0800 Subject: [PATCH 3/4] GUAC-803: Actually scroll when the scrollbar handle is dragged. --- src/terminal/scrollbar.c | 10 ++-------- src/terminal/scrollbar.h | 24 ++++++++++++++++++++++-- src/terminal/terminal.c | 22 ++++++++++++++++++++++ src/terminal/terminal.h | 13 +++++++++++++ 4 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index 45eb37f6..9727c389 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -213,14 +213,8 @@ void guac_terminal_scrollbar_flush(guac_terminal_scrollbar* scrollbar) { calculate_state(scrollbar, &new_state, &new_value); /* Notify of scroll if value is changing */ - if (new_value != old_value) { - - /* TODO: Call scroll value handler */ - guac_client_log(scrollbar->client, GUAC_LOG_DEBUG, - "SCROLL: min=%i max=%i value=%i", - scrollbar->min, scrollbar->max, new_value); - - } + if (new_value != old_value && scrollbar->scroll_handler) + scrollbar->scroll_handler(scrollbar, new_value); /* Reposition container if moved */ if (old_state->container_x != new_state.container_x diff --git a/src/terminal/scrollbar.h b/src/terminal/scrollbar.h index f46a42a8..13c66b12 100644 --- a/src/terminal/scrollbar.h +++ b/src/terminal/scrollbar.h @@ -96,12 +96,21 @@ typedef struct guac_terminal_scrollbar_render_state { } guac_terminal_scrollbar_render_state; +typedef struct guac_terminal_scrollbar guac_terminal_scrollbar; + +/** + * Handler which is called whenever the scrollbar value changes outside a call + * to guac_terminal_scrollbar_set_value(). + */ +typedef void guac_terminal_scrollbar_scroll_handler( + guac_terminal_scrollbar* scrollbar, int value); + /** * A scrollbar, made up of a containing layer and inner draggable handle. The * position of the handle within the layer represents the value of the * scrollbar. */ -typedef struct guac_terminal_scrollbar { +struct guac_terminal_scrollbar { /** * The client associated with this scrollbar. @@ -177,7 +186,18 @@ typedef struct guac_terminal_scrollbar { */ int drag_current_y; -} guac_terminal_scrollbar; + /** + * The function to call when the scrollbar handle is being dragged, and + * the new scrollbar value needs to be handled and assigned. + */ + guac_terminal_scrollbar_scroll_handler* scroll_handler; + + /** + * Arbitrary reference to data related to this scrollbar. + */ + void* data; + +}; /** * Allocates a new scrollbar, associating that scrollbar with the given client diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 3c2f7f92..48d9842b 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -264,6 +264,10 @@ guac_terminal* guac_terminal_create(guac_client* client, term->scrollbar = guac_terminal_scrollbar_alloc(term->client, GUAC_DEFAULT_LAYER, width, height, term->term_height); + /* Associate scrollbar with this terminal */ + term->scrollbar->data = term; + term->scrollbar->scroll_handler = guac_terminal_scroll_handler; + /* Init terminal */ guac_terminal_reset(term); @@ -1472,6 +1476,24 @@ int guac_terminal_send_mouse(guac_terminal* term, int x, int y, int mask) { } +void guac_terminal_scroll_handler(guac_terminal_scrollbar* scrollbar, int value) { + + guac_terminal* terminal = (guac_terminal*) scrollbar->data; + + /* Calculate change in scroll offset */ + int delta = -value - terminal->scroll_offset; + + /* Update terminal based on change in scroll offset */ + if (delta < 0) + guac_terminal_scroll_display_down(terminal, -delta); + else if (delta > 0) + guac_terminal_scroll_display_up(terminal, delta); + + /* Update scrollbar value */ + guac_terminal_scrollbar_set_value(scrollbar, value); + +} + void guac_terminal_clipboard_reset(guac_terminal* term, const char* mimetype) { guac_common_clipboard_reset(term->clipboard, mimetype); } diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h index 5f6e7ec2..3619ae15 100644 --- a/src/terminal/terminal.h +++ b/src/terminal/terminal.h @@ -388,6 +388,19 @@ int guac_terminal_send_key(guac_terminal* term, int keysym, int pressed); */ int guac_terminal_send_mouse(guac_terminal* term, int x, int y, int mask); +/** + * Handles a scroll event received from the scrollbar associated with a + * terminal. + * + * @param scrollbar + * The scrollbar that has been scrolled. + * + * @param value + * The new value that should be stored within the scrollbar, and + * represented within the terminal display. + */ +void guac_terminal_scroll_handler(guac_terminal_scrollbar* scrollbar, int value); + /** * Clears the current clipboard contents and sets the mimetype for future * contents. From 207d97bec01d02253a71c21b2ddcdf50dc8f05c3 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 4 Feb 2015 01:01:39 -0800 Subject: [PATCH 4/4] GUAC-803: Use normal pointer when mouse is over scrollbar. --- src/terminal/Makefile.am | 2 + src/terminal/pointer.c | 94 ++++++++++++++++++++++++++++++++++++++++ src/terminal/pointer.h | 68 +++++++++++++++++++++++++++++ src/terminal/terminal.c | 18 +++++++- src/terminal/terminal.h | 5 +++ 5 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 src/terminal/pointer.c create mode 100644 src/terminal/pointer.h diff --git a/src/terminal/Makefile.am b/src/terminal/Makefile.am index 9e2781eb..0fb19264 100644 --- a/src/terminal/Makefile.am +++ b/src/terminal/Makefile.am @@ -34,6 +34,7 @@ noinst_HEADERS = \ cursor.h \ display.h \ ibar.h \ + pointer.h \ scrollbar.h \ terminal.h \ terminal_handlers.h \ @@ -47,6 +48,7 @@ libguac_terminal_la_SOURCES = \ cursor.c \ display.c \ ibar.c \ + pointer.c \ scrollbar.c \ terminal.c \ terminal_handlers.c diff --git a/src/terminal/pointer.c b/src/terminal/pointer.c new file mode 100644 index 00000000..1b7ea272 --- /dev/null +++ b/src/terminal/pointer.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "config.h" + +#include "cursor.h" + +#include +#include +#include +#include + +/* Macros for prettying up the embedded image. */ +#define X 0x00,0x00,0x00,0xFF +#define U 0x80,0x80,0x80,0xFF +#define O 0xFF,0xFF,0xFF,0xFF +#define _ 0x00,0x00,0x00,0x00 + +/* Dimensions */ +const int guac_terminal_pointer_width = 11; +const int guac_terminal_pointer_height = 16; + +/* Format */ +const cairo_format_t guac_terminal_pointer_format = CAIRO_FORMAT_ARGB32; +const int guac_terminal_pointer_stride = 44; + +/* Embedded pointer graphic */ +unsigned char guac_terminal_pointer[] = { + + O,_,_,_,_,_,_,_,_,_,_, + O,O,_,_,_,_,_,_,_,_,_, + O,X,O,_,_,_,_,_,_,_,_, + O,X,X,O,_,_,_,_,_,_,_, + O,X,X,X,O,_,_,_,_,_,_, + O,X,X,X,X,O,_,_,_,_,_, + O,X,X,X,X,X,O,_,_,_,_, + O,X,X,X,X,X,X,O,_,_,_, + O,X,X,X,X,X,X,X,O,_,_, + O,X,X,X,X,X,X,X,X,O,_, + O,X,X,X,X,X,O,O,O,O,O, + O,X,X,O,X,X,O,_,_,_,_, + O,X,O,_,O,X,X,O,_,_,_, + O,O,_,_,O,X,X,O,_,_,_, + O,_,_,_,_,O,X,X,O,_,_, + _,_,_,_,_,O,O,O,O,_,_ + +}; + +guac_terminal_cursor* guac_terminal_create_pointer(guac_client* client) { + + guac_socket* socket = client->socket; + guac_terminal_cursor* cursor = guac_terminal_cursor_alloc(client); + + /* Draw to buffer */ + cairo_surface_t* graphic = cairo_image_surface_create_for_data( + guac_terminal_pointer, + guac_terminal_pointer_format, + guac_terminal_pointer_width, + guac_terminal_pointer_height, + guac_terminal_pointer_stride); + + guac_protocol_send_png(socket, GUAC_COMP_SRC, cursor->buffer, + 0, 0, graphic); + cairo_surface_destroy(graphic); + + /* Initialize cursor properties */ + cursor->width = guac_terminal_pointer_width; + cursor->height = guac_terminal_pointer_height; + cursor->hotspot_x = 0; + cursor->hotspot_y = 0; + + return cursor; + +} + diff --git a/src/terminal/pointer.h b/src/terminal/pointer.h new file mode 100644 index 00000000..aae2f3d2 --- /dev/null +++ b/src/terminal/pointer.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#ifndef GUAC_TERMINAL_POINTER_H +#define GUAC_TERMINAL_POINTER_H + +#include "config.h" + +#include +#include + +/** + * Width of the embedded mouse cursor graphic. + */ +extern const int guac_terminal_pointer_width; + +/** + * Height of the embedded mouse cursor graphic. + */ +extern const int guac_terminal_pointer_height; + +/** + * Number of bytes in each row of the embedded mouse cursor graphic. + */ +extern const int guac_terminal_pointer_stride; + +/** + * The Cairo grapic format of the mouse cursor graphic. + */ +extern const cairo_format_t guac_terminal_pointer_format; + +/** + * Embedded mouse cursor graphic. + */ +extern unsigned char guac_terminal_pointer[]; + +/** + * Creates a new pointer cursor, returning the corresponding cursor object. + * + * @param client + * The guac_client to send the cursor to. + * + * @return + * A new cursor which must be free'd via guac_terminal_cursor_free(). + */ +guac_terminal_cursor* guac_terminal_create_pointer(guac_client* client); + +#endif diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 48d9842b..4f24ec5a 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -29,6 +29,7 @@ #include "display.h" #include "ibar.h" #include "guac_clipboard.h" +#include "pointer.h" #include "scrollbar.h" #include "terminal.h" #include "terminal_handlers.h" @@ -276,8 +277,9 @@ guac_terminal* guac_terminal_create(guac_client* client, term->mod_shift = 0; /* Set up mouse cursors */ - term->ibar_cursor = guac_terminal_create_ibar(client); - term->blank_cursor = guac_terminal_create_blank(client); + term->pointer_cursor = guac_terminal_create_pointer(client); + term->ibar_cursor = guac_terminal_create_ibar(client); + term->blank_cursor = guac_terminal_create_blank(client); /* Initialize mouse cursor */ term->current_cursor = term->blank_cursor; @@ -313,6 +315,7 @@ void guac_terminal_free(guac_terminal* term) { guac_terminal_scrollbar_free(term->scrollbar); /* Free cursors */ + guac_terminal_cursor_free(term->client, term->pointer_cursor); guac_terminal_cursor_free(term->client, term->ibar_cursor); guac_terminal_cursor_free(term->client, term->blank_cursor); @@ -1392,10 +1395,20 @@ static int __guac_terminal_send_mouse(guac_terminal* term, int x, int y, int mas /* Notify scrollbar, do not handle anything handled by scrollbar */ if (guac_terminal_scrollbar_handle_mouse(term->scrollbar, x, y, mask)) { + + /* Set pointer cursor if mouse is over scrollbar */ + if (term->current_cursor != term->pointer_cursor) { + term->current_cursor = term->pointer_cursor; + guac_terminal_set_cursor(client, term->pointer_cursor); + } + + /* Flush scrollbar */ guac_terminal_scrollbar_flush(term->scrollbar); guac_protocol_send_sync(socket, client->last_sent_timestamp); guac_socket_flush(socket); + return 0; + } term->mouse_mask = mask; @@ -1404,6 +1417,7 @@ static int __guac_terminal_send_mouse(guac_terminal* term, int x, int y, int mas if (term->current_cursor != term->ibar_cursor) { term->current_cursor = term->ibar_cursor; guac_terminal_set_cursor(client, term->ibar_cursor); + guac_protocol_send_sync(socket, client->last_sent_timestamp); guac_socket_flush(socket); } diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h index 3619ae15..60d959d3 100644 --- a/src/terminal/terminal.h +++ b/src/terminal/terminal.h @@ -307,6 +307,11 @@ struct guac_terminal { */ int mouse_mask; + /** + * The cached pointer cursor. + */ + guac_terminal_cursor* pointer_cursor; + /** * The cached I-bar cursor. */