From 0996a6a186f53773088dba03d4a7ee7ab0a4e5ca Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 26 Jan 2015 12:52:30 -0800 Subject: [PATCH 1/7] GUAC-803: Stub out terminal scrollbar API. --- src/terminal/Makefile.am | 2 + src/terminal/scrollbar.c | 55 +++++++++++ src/terminal/scrollbar.h | 193 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 src/terminal/scrollbar.c create mode 100644 src/terminal/scrollbar.h diff --git a/src/terminal/Makefile.am b/src/terminal/Makefile.am index 412e75a5..9e2781eb 100644 --- a/src/terminal/Makefile.am +++ b/src/terminal/Makefile.am @@ -34,6 +34,7 @@ noinst_HEADERS = \ cursor.h \ display.h \ ibar.h \ + scrollbar.h \ terminal.h \ terminal_handlers.h \ types.h @@ -46,6 +47,7 @@ libguac_terminal_la_SOURCES = \ cursor.c \ display.c \ ibar.c \ + scrollbar.c \ terminal.c \ terminal_handlers.c diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c new file mode 100644 index 00000000..18cf9958 --- /dev/null +++ b/src/terminal/scrollbar.c @@ -0,0 +1,55 @@ +/* + * 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 "scrollbar.h" + +#include +#include + +#include + +guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, + guac_layer* parent, int parent_width, int parent_height) { + /* STUB */ + return NULL; +} + +void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) { + /* STUB */ +} + +void guac_terminal_scrollbar_set_bounds(guac_terminal_scrollbar* scrollbar, + int min, int max) { + /* STUB */ +} + +void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, + int value) { + /* STUB */ +} + +void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, + int parent_width, int parent_height) { + /* STUB */ +} + diff --git a/src/terminal/scrollbar.h b/src/terminal/scrollbar.h new file mode 100644 index 00000000..f649a908 --- /dev/null +++ b/src/terminal/scrollbar.h @@ -0,0 +1,193 @@ +/* + * 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_SCROLLBAR_H +#define GUAC_TERMINAL_SCROLLBAR_H + +#include "config.h" + +#include +#include + +/** + * The width of the scrollbar, in pixels. + */ +#define GUAC_TERMINAL_SCROLLBAR_WIDTH 16 + +/** + * The number of pixels between the inner box of the scrollbar and the outer + * box. + */ +#define GUAC_TERMINAL_SCROLLBAR_PADDING 2 + +/** + * The minimum height of the inner box of the scrollbar, in pixels. + */ +#define GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT 64 + +/** + * A scrollbar, made up of an outer and inner box, which represents its value + * graphically by the relative position and size of the inner box. + */ +typedef struct guac_terminal_scrollbar { + + /** + * The client associated with this scrollbar. + */ + guac_client* client; + + /** + * The layer containing the scrollbar. + */ + const guac_layer* parent; + + /** + * The width of the parent layer, in pixels. + */ + int parent_width; + + /** + * The height of the parent layer, in pixels. + */ + int parent_height; + + /** + * The scrollbar itself. + */ + guac_layer* container; + + /** + * The movable box within the scrollbar, representing the current scroll + * value. + */ + guac_layer* layer; + + /** + * The minimum scroll value. + */ + int min; + + /** + * The maximum scroll value. + */ + int max; + + /** + * The current scroll value. + */ + int value; + +} guac_terminal_scrollbar; + +/** + * Allocates a new scrollbar, associating that scrollbar with the given client + * and parent layer. The dimensions of the parent layer dictate the initial + * position of the scrollbar. Currently, the scrollbar is always anchored to + * the right edge of the parent layer. + * + * This will cause instructions to be written to the client's socket, but the + * client's socket will not be automatically flushed. + * + * @param client + * The client to associate with the new scrollbar. + * + * @param parent + * The layer which will contain the newly-allocated scrollbar. + * + * @param parent_width + * The width of the parent layer, in pixels. + * + * @param parent_height + * The height of the parent layer, in pixels. + * + * @return + * A newly allocated scrollbar. + */ +guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, + guac_layer* parent, int parent_width, int parent_height); + +/** + * Frees the given scrollbar. + * + * @param scrollbar + * The scrollbar to free. + */ +void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar); + +/** + * Sets the minimum and maximum allowed scroll values of the given scrollbar + * to the given values. If necessary, the current value of the scrollbar will + * be adjusted to fit within the new bounds. + * + * This may cause instructions to be written to the client's socket, but the + * client's socket will not be automatically flushed. + * + * @param scrollbar + * The scrollbar whose bounds are changing. + * + * @param min + * The new minimum value of the scrollbar. + * + * @param max + * The new maximum value of the scrollbar. + */ +void guac_terminal_scrollbar_set_bounds(guac_terminal_scrollbar* scrollbar, + int min, int max); + +/** + * Sets the current value of the given scrollbar. If the value specified does + * not fall within the scrollbar's defined minimum and maximum values, the + * value will be adjusted to fit. + * + * This may cause instructions to be written to the client's socket, but the + * client's socket will not be automatically flushed. + * + * @param scrollbar + * The scrollbar whose value is changing. + * + * @param value + * The value to assign to the scrollbar. If the value if out of bounds, it + * will be automatically adjusted to fit. + */ +void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, + int value); + +/** + * Notifies the scrollbar that the parent layer has been resized, and that the + * scrollbar may need to be repositioned or resized accordingly. + * + * This may cause instructions to be written to the client's socket, but the + * client's socket will not be automatically flushed. + * + * @param scrollbar + * The scrollbar whose parent layer has been resized. + * + * @param parent_width + * The new width of the parent layer, in pixels. + * + * @param parent_height + * The new height of the parent layer, in pixels. + */ +void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, + int parent_width, int parent_height); + +#endif From 3529bd7664fe20a9f455c000cf650f18a31c42ab Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 26 Jan 2015 13:37:07 -0800 Subject: [PATCH 2/7] GUAC-803: Allocate/free and draw scrollbar. Reposition scrollbar when terminal is resized. --- src/terminal/scrollbar.c | 85 +++++++++++++++++++++++++++++++++++++--- src/terminal/scrollbar.h | 4 +- src/terminal/terminal.c | 13 +++++- src/terminal/terminal.h | 6 +++ 4 files changed, 100 insertions(+), 8 deletions(-) diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index 18cf9958..f75f9d43 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -25,17 +25,52 @@ #include #include +#include +#include #include guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, - guac_layer* parent, int parent_width, int parent_height) { - /* STUB */ - return NULL; + const guac_layer* parent, int parent_width, int parent_height) { + + /* Allocate scrollbar */ + guac_terminal_scrollbar* scrollbar = + malloc(sizeof(guac_terminal_scrollbar)); + + /* Associate client */ + scrollbar->client = client; + + /* Init default min/max and value */ + scrollbar->min = 0; + scrollbar->max = 0; + scrollbar->value = 0; + + /* Init parent data */ + scrollbar->parent = parent; + scrollbar->parent_width = 0; + scrollbar->parent_height = 0; + + /* Allocate and init layers */ + scrollbar->container = guac_client_alloc_layer(client); + scrollbar->box = guac_client_alloc_layer(client); + + /* Reposition and resize to fit parent */ + guac_terminal_scrollbar_parent_resized(scrollbar, + parent_width, parent_height); + + return scrollbar; + } void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) { - /* STUB */ + + /* Free layers */ + guac_client_free_layer(scrollbar->client, scrollbar->box); + guac_client_free_layer(scrollbar->client, scrollbar->container); + + /* Free scrollbar */ + free(scrollbar); + } void guac_terminal_scrollbar_set_bounds(guac_terminal_scrollbar* scrollbar, @@ -50,6 +85,46 @@ 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) { - /* STUB */ + + guac_socket* socket = scrollbar->client->socket; + + /* Calculate container position and dimensions */ + int container_x = parent_width - GUAC_TERMINAL_SCROLLBAR_WIDTH; + int container_y = 0; + int container_width = GUAC_TERMINAL_SCROLLBAR_WIDTH; + int container_height = parent_height; + + /* Calculate box position and dimensions */ + int box_x = GUAC_TERMINAL_SCROLLBAR_PADDING; + int box_y = GUAC_TERMINAL_SCROLLBAR_PADDING; + int box_width = GUAC_TERMINAL_SCROLLBAR_WIDTH - GUAC_TERMINAL_SCROLLBAR_PADDING*2; + int box_height = 64; /* STUB */ + + /* Reposition container relative to parent dimensions */ + guac_protocol_send_move(socket, + scrollbar->container, scrollbar->parent, + container_x, container_y, 0); + + /* Resize to fit within parent */ + guac_protocol_send_size(socket, scrollbar->container, + container_width, container_height); + + /* Reposition box relative to container and current value */ + guac_protocol_send_move(socket, + scrollbar->box, scrollbar->container, + box_x, box_y, 0); + + /* Resize box relative to scrollable area */ + guac_protocol_send_size(socket, scrollbar->box, + box_width, box_height); + + /* Fill box with solid color */ + guac_protocol_send_rect(socket, scrollbar->box, 0, 0, box_width, box_height); + guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->box, 0xFF, 0xFF, 0xFF, 0x80); + + /* Assign new dimensions */ + scrollbar->parent_width = parent_width; + scrollbar->parent_height = parent_height; + } diff --git a/src/terminal/scrollbar.h b/src/terminal/scrollbar.h index f649a908..614a93be 100644 --- a/src/terminal/scrollbar.h +++ b/src/terminal/scrollbar.h @@ -79,7 +79,7 @@ typedef struct guac_terminal_scrollbar { * The movable box within the scrollbar, representing the current scroll * value. */ - guac_layer* layer; + guac_layer* box; /** * The minimum scroll value. @@ -123,7 +123,7 @@ typedef struct guac_terminal_scrollbar { * A newly allocated scrollbar. */ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, - guac_layer* parent, int parent_width, int parent_height); + const guac_layer* parent, int parent_width, int parent_height); /** * Frees the given scrollbar. diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 0fbeca79..a1a9ebfd 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 "scrollbar.h" #include "terminal.h" #include "terminal_handlers.h" #include "types.h" @@ -159,7 +160,7 @@ void guac_terminal_reset(guac_terminal* term) { term->cursor_row = term->visible_cursor_row = term->saved_cursor_row = 0; term->cursor_col = term->visible_cursor_col = term->saved_cursor_col = 0; - /* Clear scrollback, buffer, and scoll region */ + /* Clear scrollback, buffer, and scroll region */ term->buffer->top = 0; term->buffer->length = 0; term->scroll_start = 0; @@ -268,6 +269,10 @@ guac_terminal* guac_terminal_create(guac_client* client, /* Allocate clipboard */ term->clipboard = guac_common_clipboard_alloc(GUAC_TERMINAL_CLIPBOARD_MAX_LENGTH); + /* Allocate scrollbar */ + term->scrollbar = guac_terminal_scrollbar_alloc(term->client, + GUAC_DEFAULT_LAYER, width, height); + return term; } @@ -291,6 +296,9 @@ void guac_terminal_free(guac_terminal* term) { /* Free clipboard */ guac_common_clipboard_free(term->clipboard); + /* Free scrollbar */ + guac_terminal_scrollbar_free(term->scrollbar); + /* Free cursors */ guac_terminal_cursor_free(term->client, term->ibar_cursor); guac_terminal_cursor_free(term->client, term->blank_cursor); @@ -1130,6 +1138,9 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) { /* Resize default layer to given pixel dimensions */ guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, width, height); + /* Notify scrollbar of resize */ + guac_terminal_scrollbar_parent_resized(terminal->scrollbar, width, height); + /* Resize terminal if row/column dimensions have changed */ if (columns != terminal->term_width || rows != terminal->term_height) { diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h index 0c530988..5f6e7ec2 100644 --- a/src/terminal/terminal.h +++ b/src/terminal/terminal.h @@ -30,6 +30,7 @@ #include "cursor.h" #include "display.h" #include "guac_clipboard.h" +#include "scrollbar.h" #include "types.h" #include @@ -117,6 +118,11 @@ struct guac_terminal { */ int stdin_pipe_fd[2]; + /** + * Graphical representation of the current scroll state. + */ + guac_terminal_scrollbar* scrollbar; + /** * The relative offset of the display. A positive value indicates that * many rows have been scrolled into view, zero indicates that no From 4018f2c40fe8d616c6595a44879d7b19bbe94f90 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 26 Jan 2015 15:51:50 -0800 Subject: [PATCH 3/7] GUAC-803: Update rendering of scrollbar as terminal display is scrolled or resized. Position and scale inner box of scrollbar appropriately. --- src/terminal/scrollbar.c | 128 ++++++++++++++++++++++++++++----------- src/terminal/scrollbar.h | 20 +++++- src/terminal/terminal.c | 22 +++++-- 3 files changed, 128 insertions(+), 42 deletions(-) diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index f75f9d43..7779602a 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -31,7 +31,7 @@ #include guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, - const guac_layer* parent, int parent_width, int parent_height) { + const guac_layer* parent, int parent_width, int parent_height, int visible_area) { /* Allocate scrollbar */ guac_terminal_scrollbar* scrollbar = @@ -49,6 +49,7 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, scrollbar->parent = parent; scrollbar->parent_width = 0; scrollbar->parent_height = 0; + scrollbar->visible_area = 0; /* Allocate and init layers */ scrollbar->container = guac_client_alloc_layer(client); @@ -56,7 +57,7 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, /* Reposition and resize to fit parent */ guac_terminal_scrollbar_parent_resized(scrollbar, - parent_width, parent_height); + parent_width, parent_height, visible_area); return scrollbar; @@ -73,41 +74,37 @@ void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) { } -void guac_terminal_scrollbar_set_bounds(guac_terminal_scrollbar* scrollbar, - int min, int max) { - /* STUB */ -} - -void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, - int value) { - /* STUB */ -} - -void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, - int parent_width, int parent_height) { +/** + * Updates the position and size of the scrollbar inner box relative to the + * current scrollbar value, bounds, and parent layer dimensions. + * + * @param scrollbar + * The scrollbar whose inner box should be updated. + */ +static void __update_box(guac_terminal_scrollbar* scrollbar) { guac_socket* socket = scrollbar->client->socket; - /* Calculate container position and dimensions */ - int container_x = parent_width - GUAC_TERMINAL_SCROLLBAR_WIDTH; - int container_y = 0; - int container_width = GUAC_TERMINAL_SCROLLBAR_WIDTH; - int container_height = parent_height; + /* Skip if no scrolling region at all */ + if (scrollbar->min >= scrollbar->max) + return; + + int region_size = scrollbar->max - scrollbar->min; + + /* Calculate box dimensions */ + int box_width = GUAC_TERMINAL_SCROLLBAR_WIDTH - GUAC_TERMINAL_SCROLLBAR_PADDING*2; + int box_height = GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT; + + /* Size box relative to visible area */ + int padded_container_height = (scrollbar->parent_height - GUAC_TERMINAL_SCROLLBAR_PADDING*2); + int proportional_height = padded_container_height * scrollbar->visible_area / (region_size + scrollbar->visible_area); + if (proportional_height > box_height) + box_height = proportional_height; /* Calculate box position and dimensions */ - int box_x = GUAC_TERMINAL_SCROLLBAR_PADDING; - int box_y = GUAC_TERMINAL_SCROLLBAR_PADDING; - int box_width = GUAC_TERMINAL_SCROLLBAR_WIDTH - GUAC_TERMINAL_SCROLLBAR_PADDING*2; - int box_height = 64; /* STUB */ - - /* Reposition container relative to parent dimensions */ - guac_protocol_send_move(socket, - scrollbar->container, scrollbar->parent, - container_x, container_y, 0); - - /* Resize to fit within parent */ - guac_protocol_send_size(socket, scrollbar->container, - container_width, container_height); + int box_x = GUAC_TERMINAL_SCROLLBAR_PADDING; + int box_y = GUAC_TERMINAL_SCROLLBAR_PADDING + + (padded_container_height - box_height) * (scrollbar->value - scrollbar->min) / region_size; /* Reposition box relative to container and current value */ guac_protocol_send_move(socket, @@ -122,9 +119,70 @@ void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, guac_protocol_send_rect(socket, scrollbar->box, 0, 0, box_width, box_height); guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->box, 0xFF, 0xFF, 0xFF, 0x80); - /* Assign new dimensions */ - scrollbar->parent_width = parent_width; - scrollbar->parent_height = parent_height; +} + +void guac_terminal_scrollbar_set_bounds(guac_terminal_scrollbar* scrollbar, + int min, int max) { + + /* Fit value within bounds */ + if (scrollbar->value > max) + scrollbar->value = max; + else if (scrollbar->value < min) + scrollbar->value = min; + + /* Update bounds */ + scrollbar->min = min; + scrollbar->max = max; + + /* Update box position and size */ + __update_box(scrollbar); + +} + +void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, + int value) { + + /* Fit value within bounds */ + if (value > scrollbar->max) + value = scrollbar->max; + else if (value < scrollbar->min) + value = scrollbar->min; + + /* Update value */ + scrollbar->value = value; + + /* Update box position and size */ + __update_box(scrollbar); + +} + +void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, + int parent_width, int parent_height, int visible_area) { + + guac_socket* socket = scrollbar->client->socket; + + /* Calculate container position and dimensions */ + int container_x = parent_width - GUAC_TERMINAL_SCROLLBAR_WIDTH; + int container_y = 0; + int container_width = GUAC_TERMINAL_SCROLLBAR_WIDTH; + int container_height = parent_height; + + /* Reposition container relative to parent dimensions */ + guac_protocol_send_move(socket, + scrollbar->container, scrollbar->parent, + container_x, container_y, 0); + + /* Resize to fit within parent */ + guac_protocol_send_size(socket, scrollbar->container, + container_width, container_height); + + /* Assign new dimensions */ + scrollbar->parent_width = parent_width; + scrollbar->parent_height = parent_height; + scrollbar->visible_area = visible_area; + + /* Update box position and size */ + __update_box(scrollbar); } diff --git a/src/terminal/scrollbar.h b/src/terminal/scrollbar.h index 614a93be..2fc1cce0 100644 --- a/src/terminal/scrollbar.h +++ b/src/terminal/scrollbar.h @@ -91,6 +91,11 @@ typedef struct guac_terminal_scrollbar { */ int max; + /** + * The size of the visible area, in the same units as min and max. + */ + int visible_area; + /** * The current scroll value. */ @@ -119,11 +124,17 @@ typedef struct guac_terminal_scrollbar { * @param parent_height * The height of the parent layer, in pixels. * + * @param visible_area + * The amount of scrollable data that can be shown within the parent layer + * at any given time. This value uses the same units as min, max, and the + * current scroll value. + * * @return * A newly allocated scrollbar. */ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, - const guac_layer* parent, int parent_width, int parent_height); + const guac_layer* parent, int parent_width, int parent_height, + int visible_area); /** * Frees the given scrollbar. @@ -186,8 +197,13 @@ void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, * * @param parent_height * The new height of the parent layer, in pixels. + * + * @param visible_area + * The amount of scrollable data that can be shown within the parent layer + * at any given time. This value uses the same units as min, max, and the + * current scroll value. */ void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, - int parent_width, int parent_height); + int parent_width, int parent_height, int visible_area); #endif diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index a1a9ebfd..0f62cfad 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -167,6 +167,10 @@ void guac_terminal_reset(guac_terminal* term) { term->scroll_end = term->term_height - 1; term->scroll_offset = 0; + /* Reset scrollbar bounds */ + guac_terminal_scrollbar_set_bounds(term->scrollbar, term->term_height - term->buffer->length, 0); + guac_terminal_scrollbar_set_value(term->scrollbar, -term->scroll_offset); + /* Reset flags */ term->text_selected = false; term->application_cursor_keys = false; @@ -251,6 +255,10 @@ guac_terminal* guac_terminal_create(guac_client* client, guac_terminal_display_resize(term->display, term->term_width, term->term_height); + /* Allocate scrollbar */ + term->scrollbar = guac_terminal_scrollbar_alloc(term->client, + GUAC_DEFAULT_LAYER, width, height, term->term_height); + /* Init terminal */ guac_terminal_reset(term); @@ -269,10 +277,6 @@ guac_terminal* guac_terminal_create(guac_client* client, /* Allocate clipboard */ term->clipboard = guac_common_clipboard_alloc(GUAC_TERMINAL_CLIPBOARD_MAX_LENGTH); - /* Allocate scrollbar */ - term->scrollbar = guac_terminal_scrollbar_alloc(term->client, - GUAC_DEFAULT_LAYER, width, height); - return term; } @@ -524,6 +528,9 @@ int guac_terminal_scroll_up(guac_terminal* term, if (term->buffer->length > term->buffer->available) term->buffer->length = term->buffer->available; + /* Reset scrollbar bounds */ + guac_terminal_scrollbar_set_bounds(term->scrollbar, term->term_height - term->buffer->length, 0); + /* Update cursor location if within region */ if (term->visible_cursor_row >= start_row && term->visible_cursor_row <= end_row) @@ -639,6 +646,7 @@ void guac_terminal_scroll_display_down(guac_terminal* terminal, /* Advance by scroll amount */ terminal->scroll_offset -= scroll_amount; + guac_terminal_scrollbar_set_value(terminal->scrollbar, -terminal->scroll_offset); /* Get row range */ end_row = terminal->term_height - terminal->scroll_offset - 1; @@ -703,6 +711,7 @@ void guac_terminal_scroll_display_up(guac_terminal* terminal, /* Advance by scroll amount */ terminal->scroll_offset += scroll_amount; + guac_terminal_scrollbar_set_value(terminal->scrollbar, -terminal->scroll_offset); /* Get row range */ start_row = -terminal->scroll_offset; @@ -1080,6 +1089,7 @@ static void __guac_terminal_resize(guac_terminal* term, int width, int height) { if (term->scroll_offset >= shift_amount) { term->scroll_offset -= shift_amount; + guac_terminal_scrollbar_set_value(term->scrollbar, -term->scroll_offset); /* Draw characters from scroll at bottom */ __guac_terminal_redraw_rect(term, term->term_height, 0, term->term_height + shift_amount - 1, width-1); @@ -1095,6 +1105,7 @@ static void __guac_terminal_resize(guac_terminal* term, int width, int height) { /* Update shift_amount and scroll based on new rows */ shift_amount -= term->scroll_offset; term->scroll_offset = 0; + guac_terminal_scrollbar_set_value(term->scrollbar, -term->scroll_offset); /* If anything remains, move screen as necessary */ if (shift_amount > 0) { @@ -1139,7 +1150,8 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) { guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, width, height); /* Notify scrollbar of resize */ - guac_terminal_scrollbar_parent_resized(terminal->scrollbar, width, height); + guac_terminal_scrollbar_parent_resized(terminal->scrollbar, width, height, rows); + guac_terminal_scrollbar_set_bounds(terminal->scrollbar, rows - terminal->buffer->length, 0); /* Resize terminal if row/column dimensions have changed */ if (columns != terminal->term_width || rows != terminal->term_height) { From 65e0265fa06ca8559e149a7a687b54b8f857a160 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 27 Jan 2015 16:18:03 -0800 Subject: [PATCH 4/7] GUAC-803: Improve style of scrollbar. --- src/terminal/scrollbar.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index 7779602a..8f905adc 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -117,7 +117,11 @@ static void __update_box(guac_terminal_scrollbar* scrollbar) { /* Fill box with solid color */ guac_protocol_send_rect(socket, scrollbar->box, 0, 0, box_width, box_height); - guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->box, 0xFF, 0xFF, 0xFF, 0x80); + guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->box, + 0x80, 0x80, 0x80, 0xFF); + guac_protocol_send_cstroke(socket, GUAC_COMP_OVER, scrollbar->box, + GUAC_LINE_CAP_SQUARE, GUAC_LINE_JOIN_MITER, 2, + 0xA0, 0xA0, 0xA0, 0xFF); } @@ -176,6 +180,12 @@ void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, guac_protocol_send_size(socket, scrollbar->container, container_width, container_height); + /* Fill container with solid color */ + guac_protocol_send_rect(socket, scrollbar->container, 0, 0, + container_width, container_height); + guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->container, + 0x40, 0x40, 0x40, 0xFF); + /* Assign new dimensions */ scrollbar->parent_width = parent_width; scrollbar->parent_height = parent_height; From 1218a18bf48c6c47c4045b11e505365a28ec92d0 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 28 Jan 2015 15:41:12 -0800 Subject: [PATCH 5/7] GUAC-803: It's a handle, not a box. Well, OK, it is a technically also a box... but that's not the point. --- src/terminal/scrollbar.c | 62 ++++++++++++++++++++-------------------- src/terminal/scrollbar.h | 17 +++++------ 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index 8f905adc..36160958 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -53,7 +53,7 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, /* Allocate and init layers */ scrollbar->container = guac_client_alloc_layer(client); - scrollbar->box = guac_client_alloc_layer(client); + scrollbar->handle = guac_client_alloc_layer(client); /* Reposition and resize to fit parent */ guac_terminal_scrollbar_parent_resized(scrollbar, @@ -66,7 +66,7 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) { /* Free layers */ - guac_client_free_layer(scrollbar->client, scrollbar->box); + guac_client_free_layer(scrollbar->client, scrollbar->handle); guac_client_free_layer(scrollbar->client, scrollbar->container); /* Free scrollbar */ @@ -75,13 +75,13 @@ void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) { } /** - * Updates the position and size of the scrollbar inner box relative to the + * Updates the position and size of the scrollbar handle relative to the * current scrollbar value, bounds, and parent layer dimensions. * * @param scrollbar - * The scrollbar whose inner box should be updated. + * The scrollbar whose handle should be updated. */ -static void __update_box(guac_terminal_scrollbar* scrollbar) { +static void __update_handle(guac_terminal_scrollbar* scrollbar) { guac_socket* socket = scrollbar->client->socket; @@ -91,35 +91,35 @@ static void __update_box(guac_terminal_scrollbar* scrollbar) { int region_size = scrollbar->max - scrollbar->min; - /* Calculate box dimensions */ - int box_width = GUAC_TERMINAL_SCROLLBAR_WIDTH - GUAC_TERMINAL_SCROLLBAR_PADDING*2; - int box_height = GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT; + /* Calculate handle dimensions */ + int handle_width = GUAC_TERMINAL_SCROLLBAR_WIDTH - GUAC_TERMINAL_SCROLLBAR_PADDING*2; + int handle_height = GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT; - /* Size box relative to visible area */ + /* Size handle relative to visible area */ int padded_container_height = (scrollbar->parent_height - GUAC_TERMINAL_SCROLLBAR_PADDING*2); int proportional_height = padded_container_height * scrollbar->visible_area / (region_size + scrollbar->visible_area); - if (proportional_height > box_height) - box_height = proportional_height; + if (proportional_height > handle_height) + handle_height = proportional_height; - /* Calculate box position and dimensions */ - int box_x = GUAC_TERMINAL_SCROLLBAR_PADDING; - int box_y = GUAC_TERMINAL_SCROLLBAR_PADDING - + (padded_container_height - box_height) * (scrollbar->value - scrollbar->min) / region_size; + /* Calculate handle position and dimensions */ + int handle_x = GUAC_TERMINAL_SCROLLBAR_PADDING; + int handle_y = GUAC_TERMINAL_SCROLLBAR_PADDING + + (padded_container_height - handle_height) * (scrollbar->value - scrollbar->min) / region_size; - /* Reposition box relative to container and current value */ + /* Reposition handle relative to container and current value */ guac_protocol_send_move(socket, - scrollbar->box, scrollbar->container, - box_x, box_y, 0); + scrollbar->handle, scrollbar->container, + handle_x, handle_y, 0); - /* Resize box relative to scrollable area */ - guac_protocol_send_size(socket, scrollbar->box, - box_width, box_height); + /* Resize handle relative to scrollable area */ + guac_protocol_send_size(socket, scrollbar->handle, + handle_width, handle_height); - /* Fill box with solid color */ - guac_protocol_send_rect(socket, scrollbar->box, 0, 0, box_width, box_height); - guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->box, + /* Fill handle with solid color */ + guac_protocol_send_rect(socket, scrollbar->handle, 0, 0, handle_width, handle_height); + guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->handle, 0x80, 0x80, 0x80, 0xFF); - guac_protocol_send_cstroke(socket, GUAC_COMP_OVER, scrollbar->box, + guac_protocol_send_cstroke(socket, GUAC_COMP_OVER, scrollbar->handle, GUAC_LINE_CAP_SQUARE, GUAC_LINE_JOIN_MITER, 2, 0xA0, 0xA0, 0xA0, 0xFF); @@ -138,8 +138,8 @@ void guac_terminal_scrollbar_set_bounds(guac_terminal_scrollbar* scrollbar, scrollbar->min = min; scrollbar->max = max; - /* Update box position and size */ - __update_box(scrollbar); + /* Update handle position and size */ + __update_handle(scrollbar); } @@ -155,8 +155,8 @@ void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, /* Update value */ scrollbar->value = value; - /* Update box position and size */ - __update_box(scrollbar); + /* Update handle position and size */ + __update_handle(scrollbar); } @@ -191,8 +191,8 @@ void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, scrollbar->parent_height = parent_height; scrollbar->visible_area = visible_area; - /* Update box position and size */ - __update_box(scrollbar); + /* Update handle position and size */ + __update_handle(scrollbar); } diff --git a/src/terminal/scrollbar.h b/src/terminal/scrollbar.h index 2fc1cce0..0190055b 100644 --- a/src/terminal/scrollbar.h +++ b/src/terminal/scrollbar.h @@ -34,19 +34,20 @@ #define GUAC_TERMINAL_SCROLLBAR_WIDTH 16 /** - * The number of pixels between the inner box of the scrollbar and the outer - * box. + * The number of pixels between the draggable handle of the scrollbar and the + * boundary of the containing layer. */ #define GUAC_TERMINAL_SCROLLBAR_PADDING 2 /** - * The minimum height of the inner box of the scrollbar, in pixels. + * The minimum height of the draggable handle of the scrollbar, in pixels. */ #define GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT 64 /** - * A scrollbar, made up of an outer and inner box, which represents its value - * graphically by the relative position and size of the inner box. + * 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 { @@ -76,10 +77,10 @@ typedef struct guac_terminal_scrollbar { guac_layer* container; /** - * The movable box within the scrollbar, representing the current scroll - * value. + * The draggable handle within the scrollbar, representing the current + * scroll value. */ - guac_layer* box; + guac_layer* handle; /** * The minimum scroll value. From 0f4e45e39d1467e7202b4df76a8db1751953b98a Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 28 Jan 2015 16:43:03 -0800 Subject: [PATCH 6/7] GUAC-803: Separate scrollbar graphical update from state update. --- src/terminal/scrollbar.c | 214 +++++++++++++++++++++++++++------------ src/terminal/scrollbar.h | 69 +++++++++++++ src/terminal/terminal.c | 6 ++ 3 files changed, 223 insertions(+), 66 deletions(-) diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index 36160958..c1a5bc9a 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -51,6 +51,18 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, scrollbar->parent_height = 0; scrollbar->visible_area = 0; + /* Init handle render state */ + scrollbar->render_state.handle_x = 0; + scrollbar->render_state.handle_y = 0; + scrollbar->render_state.handle_width = 0; + scrollbar->render_state.handle_height = 0; + + /* Init container render state */ + scrollbar->render_state.container_x = 0; + scrollbar->render_state.container_y = 0; + scrollbar->render_state.container_width = 0; + scrollbar->render_state.container_height = 0; + /* Allocate and init layers */ scrollbar->container = guac_client_alloc_layer(client); scrollbar->handle = guac_client_alloc_layer(client); @@ -75,53 +87,155 @@ void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) { } /** - * Updates the position and size of the scrollbar handle relative to the - * current scrollbar value, bounds, and parent layer dimensions. + * 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. * * @param scrollbar - * The scrollbar whose handle should be updated. + * The scrollbar whose render 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. */ -static void __update_handle(guac_terminal_scrollbar* scrollbar) { +static void calculate_render_state(guac_terminal_scrollbar* scrollbar, + guac_terminal_scrollbar_render_state* render_state) { + + /* Calculate container dimensions */ + render_state->container_width = GUAC_TERMINAL_SCROLLBAR_WIDTH; + render_state->container_height = scrollbar->parent_height; + + /* Calculate container position */ + render_state->container_x = scrollbar->parent_width + - render_state->container_width; + + render_state->container_y = 0; + + /* Calculate handle dimensions */ + render_state->handle_width = render_state->container_width + - GUAC_TERMINAL_SCROLLBAR_PADDING*2; + + /* Handle can be no bigger than the scrollbar itself */ + int max_handle_height = render_state->container_height + - GUAC_TERMINAL_SCROLLBAR_PADDING*2; + + /* Calculate legal delta between scroll values */ + int scroll_delta; + if (scrollbar->max > scrollbar->min) + scroll_delta = scrollbar->max - scrollbar->min; + else + scroll_delta = 0; + + /* Scale handle relative to visible area vs. scrolling region size */ + int proportional_height = max_handle_height + * scrollbar->visible_area + / (scroll_delta + scrollbar->visible_area); + + /* Ensure handle is no smaller than minimum height */ + if (proportional_height > GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT) + render_state->handle_height = proportional_height; + else + render_state->handle_height = GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT; + + /* Ensure handle is no larger than maximum height */ + if (render_state->handle_height > max_handle_height) + render_state->handle_height = max_handle_height; + + /* Calculate handle position */ + render_state->handle_x = GUAC_TERMINAL_SCROLLBAR_PADDING; + + /* 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; + + /* ... unless there is only one possible scroll value */ + else + render_state->handle_y = GUAC_TERMINAL_SCROLLBAR_PADDING; + +} + +void guac_terminal_scrollbar_flush(guac_terminal_scrollbar* scrollbar) { guac_socket* socket = scrollbar->client->socket; - /* Skip if no scrolling region at all */ - if (scrollbar->min >= scrollbar->max) - return; + /* Get old render state */ + guac_terminal_scrollbar_render_state* old_state = &scrollbar->render_state; - int region_size = scrollbar->max - scrollbar->min; + /* Calculate new render state */ + guac_terminal_scrollbar_render_state new_state; + calculate_render_state(scrollbar, &new_state); - /* Calculate handle dimensions */ - int handle_width = GUAC_TERMINAL_SCROLLBAR_WIDTH - GUAC_TERMINAL_SCROLLBAR_PADDING*2; - int handle_height = GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT; + /* Reposition container if moved */ + if (old_state->container_x != new_state.container_x + || old_state->container_y != new_state.container_y) { - /* Size handle relative to visible area */ - int padded_container_height = (scrollbar->parent_height - GUAC_TERMINAL_SCROLLBAR_PADDING*2); - int proportional_height = padded_container_height * scrollbar->visible_area / (region_size + scrollbar->visible_area); - if (proportional_height > handle_height) - handle_height = proportional_height; + guac_protocol_send_move(socket, + scrollbar->container, scrollbar->parent, + new_state.container_x, + new_state.container_y, + 0); - /* Calculate handle position and dimensions */ - int handle_x = GUAC_TERMINAL_SCROLLBAR_PADDING; - int handle_y = GUAC_TERMINAL_SCROLLBAR_PADDING - + (padded_container_height - handle_height) * (scrollbar->value - scrollbar->min) / region_size; + } - /* Reposition handle relative to container and current value */ - guac_protocol_send_move(socket, - scrollbar->handle, scrollbar->container, - handle_x, handle_y, 0); + /* Resize and redraw container if size changed */ + if (old_state->container_width != new_state.container_width + || old_state->container_height != new_state.container_height) { - /* Resize handle relative to scrollable area */ - guac_protocol_send_size(socket, scrollbar->handle, - handle_width, handle_height); + /* Set new size */ + guac_protocol_send_size(socket, scrollbar->container, + new_state.container_width, + new_state.container_height); - /* Fill handle with solid color */ - guac_protocol_send_rect(socket, scrollbar->handle, 0, 0, handle_width, handle_height); - guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->handle, - 0x80, 0x80, 0x80, 0xFF); - guac_protocol_send_cstroke(socket, GUAC_COMP_OVER, scrollbar->handle, - GUAC_LINE_CAP_SQUARE, GUAC_LINE_JOIN_MITER, 2, - 0xA0, 0xA0, 0xA0, 0xFF); + /* Fill container with solid color */ + guac_protocol_send_rect(socket, scrollbar->container, 0, 0, + new_state.container_width, + new_state.container_height); + + guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->container, + 0x40, 0x40, 0x40, 0xFF); + + } + + /* Reposition handle if moved */ + if (old_state->handle_x != new_state.handle_x + || old_state->handle_y != new_state.handle_y) { + + guac_protocol_send_move(socket, + scrollbar->handle, scrollbar->container, + new_state.handle_x, + new_state.handle_y, + 0); + + } + + /* Resize and redraw handle if size changed */ + if (old_state->handle_width != new_state.handle_width + || old_state->handle_height != new_state.handle_height) { + + /* Send new size */ + guac_protocol_send_size(socket, scrollbar->handle, + new_state.handle_width, + new_state.handle_height); + + /* Fill and stroke handle with solid color */ + guac_protocol_send_rect(socket, scrollbar->handle, 0, 0, + new_state.handle_width, + new_state.handle_height); + + guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->handle, + 0x80, 0x80, 0x80, 0xFF); + + guac_protocol_send_cstroke(socket, GUAC_COMP_OVER, scrollbar->handle, + GUAC_LINE_CAP_SQUARE, GUAC_LINE_JOIN_MITER, 2, + 0xA0, 0xA0, 0xA0, 0xFF); + + } + + /* Store current render state */ + scrollbar->render_state = new_state; } @@ -138,9 +252,6 @@ void guac_terminal_scrollbar_set_bounds(guac_terminal_scrollbar* scrollbar, scrollbar->min = min; scrollbar->max = max; - /* Update handle position and size */ - __update_handle(scrollbar); - } void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, @@ -155,44 +266,15 @@ void guac_terminal_scrollbar_set_value(guac_terminal_scrollbar* scrollbar, /* Update value */ scrollbar->value = value; - /* Update handle position and size */ - __update_handle(scrollbar); - } void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar, int parent_width, int parent_height, int visible_area) { - guac_socket* socket = scrollbar->client->socket; - - /* Calculate container position and dimensions */ - int container_x = parent_width - GUAC_TERMINAL_SCROLLBAR_WIDTH; - int container_y = 0; - int container_width = GUAC_TERMINAL_SCROLLBAR_WIDTH; - int container_height = parent_height; - - /* Reposition container relative to parent dimensions */ - guac_protocol_send_move(socket, - scrollbar->container, scrollbar->parent, - container_x, container_y, 0); - - /* Resize to fit within parent */ - guac_protocol_send_size(socket, scrollbar->container, - container_width, container_height); - - /* Fill container with solid color */ - guac_protocol_send_rect(socket, scrollbar->container, 0, 0, - container_width, container_height); - guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->container, - 0x40, 0x40, 0x40, 0xFF); - /* Assign new dimensions */ scrollbar->parent_width = parent_width; scrollbar->parent_height = parent_height; scrollbar->visible_area = visible_area; - /* Update handle position and size */ - __update_handle(scrollbar); - } diff --git a/src/terminal/scrollbar.h b/src/terminal/scrollbar.h index 0190055b..e1bee7ff 100644 --- a/src/terminal/scrollbar.h +++ b/src/terminal/scrollbar.h @@ -44,6 +44,58 @@ */ #define GUAC_TERMINAL_SCROLLBAR_MIN_HEIGHT 64 +/** + * The state of all scrollbar components, describing all variable aspects of + * the scrollbar's appearance. + */ +typedef struct guac_terminal_scrollbar_render_state { + + /** + * The current X-coordinate of the upper-left corner of the scrollbar's + * handle. This value will be relative to the scrollbar's containing layer. + */ + int handle_x; + + /** + * The current Y-coordinate of the upper-left corner of the scrollbar's + * handle. This value will be relative to the scrollbar's containing layer. + */ + int handle_y; + + /** + * The width of the scrollbar's handle. + */ + int handle_width; + + /** + * The height of the scrollbar's handle. + */ + int handle_height; + + /** + * The current X-coordinate of the upper-left corner of the scrollbar's + * containing layer. + */ + int container_x; + + /** + * The current Y-coordinate of the upper-left corner of the scrollbar's + * containing layer. + */ + int container_y; + + /** + * The width of the scrollbar's containing layer. + */ + int container_width; + + /** + * The height of the scrollbar's containing layer. + */ + int container_height; + +} guac_terminal_scrollbar_render_state; + /** * 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 @@ -102,6 +154,11 @@ typedef struct guac_terminal_scrollbar { */ int value; + /** + * The current state of all variable, visible parts of the scrollbar. + */ + guac_terminal_scrollbar_render_state render_state; + } guac_terminal_scrollbar; /** @@ -145,6 +202,18 @@ guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client, */ void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar); +/** + * Flushes the render state of the given scrollbar, updating the remote display + * accordingly. + * + * This may cause instructions to be written to the client's socket, but the + * client's socket will not be automatically flushed. + * + * @param scrollbar + * The scrollbar whose render state is to be flushed. + */ +void guac_terminal_scrollbar_flush(guac_terminal_scrollbar* scrollbar); + /** * Sets the minimum and maximum allowed scroll values of the given scrollbar * to the given values. If necessary, the current value of the scrollbar will diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 0f62cfad..111df247 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -682,6 +682,8 @@ void guac_terminal_scroll_display_down(guac_terminal* terminal, } guac_terminal_display_flush(terminal->display); + guac_terminal_scrollbar_flush(terminal->scrollbar); + guac_protocol_send_sync(terminal->client->socket, terminal->client->last_sent_timestamp); guac_socket_flush(terminal->client->socket); @@ -747,6 +749,8 @@ void guac_terminal_scroll_display_up(guac_terminal* terminal, } guac_terminal_display_flush(terminal->display); + guac_terminal_scrollbar_flush(terminal->scrollbar); + guac_protocol_send_sync(terminal->client->socket, terminal->client->last_sent_timestamp); guac_socket_flush(terminal->client->socket); @@ -1170,6 +1174,7 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) { /* If terminal size hasn't changed, still need to flush */ else { + guac_terminal_scrollbar_flush(terminal->scrollbar); guac_protocol_send_sync(socket, client->last_sent_timestamp); guac_socket_flush(socket); } @@ -1181,6 +1186,7 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) { void guac_terminal_flush(guac_terminal* terminal) { guac_terminal_commit_cursor(terminal); guac_terminal_display_flush(terminal->display); + guac_terminal_scrollbar_flush(terminal->scrollbar); } void guac_terminal_lock(guac_terminal* terminal) { From d5b7baab75f48a8bae3e746bbb6e9f4d5ed0707c Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 28 Jan 2015 17:06:18 -0800 Subject: [PATCH 7/7] GUAC-803: Restrict display area to left of scrollbar. --- src/terminal/terminal.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 111df247..7a1a9160 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -202,6 +202,11 @@ guac_terminal* guac_terminal_create(guac_client* client, }, .width = 1}; + /* Calculate available display area */ + int available_width = width - GUAC_TERMINAL_SCROLLBAR_WIDTH; + if (available_width < 0) + available_width = 0; + guac_terminal* term = malloc(sizeof(guac_terminal)); term->client = client; term->upload_path_handler = NULL; @@ -227,7 +232,7 @@ guac_terminal* guac_terminal_create(guac_client* client, term->current_attributes = default_char.attributes; term->default_char = default_char; - term->term_width = width / term->display->char_width; + term->term_width = available_width / term->display->char_width; term->term_height = height / term->display->char_height; /* Open STDOUT pipe */ @@ -1146,9 +1151,14 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) { guac_client* client = display->client; guac_socket* socket = client->socket; + /* Calculate available display area */ + int available_width = width - GUAC_TERMINAL_SCROLLBAR_WIDTH; + if (available_width < 0) + available_width = 0; + /* Calculate dimensions */ int rows = height / display->char_height; - int columns = width / display->char_width; + int columns = available_width / display->char_width; /* Resize default layer to given pixel dimensions */ guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, width, height);