Merge pull request #21 from glyptodon/terminal-scrollbar
GUAC-803: Add scrollbar to right of terminal display.
This commit is contained in:
commit
04a11f1343
@ -34,6 +34,7 @@ noinst_HEADERS = \
|
|||||||
cursor.h \
|
cursor.h \
|
||||||
display.h \
|
display.h \
|
||||||
ibar.h \
|
ibar.h \
|
||||||
|
scrollbar.h \
|
||||||
terminal.h \
|
terminal.h \
|
||||||
terminal_handlers.h \
|
terminal_handlers.h \
|
||||||
types.h
|
types.h
|
||||||
@ -46,6 +47,7 @@ libguac_terminal_la_SOURCES = \
|
|||||||
cursor.c \
|
cursor.c \
|
||||||
display.c \
|
display.c \
|
||||||
ibar.c \
|
ibar.c \
|
||||||
|
scrollbar.c \
|
||||||
terminal.c \
|
terminal.c \
|
||||||
terminal_handlers.c
|
terminal_handlers.c
|
||||||
|
|
||||||
|
280
src/terminal/scrollbar.c
Normal file
280
src/terminal/scrollbar.c
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
* 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 <guacamole/client.h>
|
||||||
|
#include <guacamole/layer.h>
|
||||||
|
#include <guacamole/socket.h>
|
||||||
|
#include <guacamole/protocol.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
guac_terminal_scrollbar* guac_terminal_scrollbar_alloc(guac_client* client,
|
||||||
|
const guac_layer* parent, int parent_width, int parent_height, int visible_area) {
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Reposition and resize to fit parent */
|
||||||
|
guac_terminal_scrollbar_parent_resized(scrollbar,
|
||||||
|
parent_width, parent_height, visible_area);
|
||||||
|
|
||||||
|
return scrollbar;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_terminal_scrollbar_free(guac_terminal_scrollbar* scrollbar) {
|
||||||
|
|
||||||
|
/* Free layers */
|
||||||
|
guac_client_free_layer(scrollbar->client, scrollbar->handle);
|
||||||
|
guac_client_free_layer(scrollbar->client, scrollbar->container);
|
||||||
|
|
||||||
|
/* Free scrollbar */
|
||||||
|
free(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.
|
||||||
|
*
|
||||||
|
* @param scrollbar
|
||||||
|
* 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 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;
|
||||||
|
|
||||||
|
/* Get old render state */
|
||||||
|
guac_terminal_scrollbar_render_state* old_state = &scrollbar->render_state;
|
||||||
|
|
||||||
|
/* Calculate new render state */
|
||||||
|
guac_terminal_scrollbar_render_state new_state;
|
||||||
|
calculate_render_state(scrollbar, &new_state);
|
||||||
|
|
||||||
|
/* Reposition container if moved */
|
||||||
|
if (old_state->container_x != new_state.container_x
|
||||||
|
|| old_state->container_y != new_state.container_y) {
|
||||||
|
|
||||||
|
guac_protocol_send_move(socket,
|
||||||
|
scrollbar->container, scrollbar->parent,
|
||||||
|
new_state.container_x,
|
||||||
|
new_state.container_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) {
|
||||||
|
|
||||||
|
/* Set new size */
|
||||||
|
guac_protocol_send_size(socket, scrollbar->container,
|
||||||
|
new_state.container_width,
|
||||||
|
new_state.container_height);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_terminal_scrollbar_parent_resized(guac_terminal_scrollbar* scrollbar,
|
||||||
|
int parent_width, int parent_height, int visible_area) {
|
||||||
|
|
||||||
|
/* Assign new dimensions */
|
||||||
|
scrollbar->parent_width = parent_width;
|
||||||
|
scrollbar->parent_height = parent_height;
|
||||||
|
scrollbar->visible_area = visible_area;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
279
src/terminal/scrollbar.h
Normal file
279
src/terminal/scrollbar.h
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
/*
|
||||||
|
* 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 <guacamole/client.h>
|
||||||
|
#include <guacamole/layer.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width of the scrollbar, in pixels.
|
||||||
|
*/
|
||||||
|
#define GUAC_TERMINAL_SCROLLBAR_WIDTH 16
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 draggable handle of the scrollbar, in pixels.
|
||||||
|
*/
|
||||||
|
#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
|
||||||
|
* scrollbar.
|
||||||
|
*/
|
||||||
|
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 draggable handle within the scrollbar, representing the current
|
||||||
|
* scroll value.
|
||||||
|
*/
|
||||||
|
guac_layer* handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum scroll value.
|
||||||
|
*/
|
||||||
|
int min;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum scroll value.
|
||||||
|
*/
|
||||||
|
int max;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the visible area, in the same units as min and max.
|
||||||
|
*/
|
||||||
|
int visible_area;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current scroll value.
|
||||||
|
*/
|
||||||
|
int value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current state of all variable, visible parts of the scrollbar.
|
||||||
|
*/
|
||||||
|
guac_terminal_scrollbar_render_state render_state;
|
||||||
|
|
||||||
|
} 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.
|
||||||
|
*
|
||||||
|
* @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,
|
||||||
|
int visible_area);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the given scrollbar.
|
||||||
|
*
|
||||||
|
* @param scrollbar
|
||||||
|
* The scrollbar to free.
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @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 visible_area);
|
||||||
|
|
||||||
|
#endif
|
@ -29,6 +29,7 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "ibar.h"
|
#include "ibar.h"
|
||||||
#include "guac_clipboard.h"
|
#include "guac_clipboard.h"
|
||||||
|
#include "scrollbar.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "terminal_handlers.h"
|
#include "terminal_handlers.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@ -159,13 +160,17 @@ void guac_terminal_reset(guac_terminal* term) {
|
|||||||
term->cursor_row = term->visible_cursor_row = term->saved_cursor_row = 0;
|
term->cursor_row = term->visible_cursor_row = term->saved_cursor_row = 0;
|
||||||
term->cursor_col = term->visible_cursor_col = term->saved_cursor_col = 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->top = 0;
|
||||||
term->buffer->length = 0;
|
term->buffer->length = 0;
|
||||||
term->scroll_start = 0;
|
term->scroll_start = 0;
|
||||||
term->scroll_end = term->term_height - 1;
|
term->scroll_end = term->term_height - 1;
|
||||||
term->scroll_offset = 0;
|
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 */
|
/* Reset flags */
|
||||||
term->text_selected = false;
|
term->text_selected = false;
|
||||||
term->application_cursor_keys = false;
|
term->application_cursor_keys = false;
|
||||||
@ -197,6 +202,11 @@ guac_terminal* guac_terminal_create(guac_client* client,
|
|||||||
},
|
},
|
||||||
.width = 1};
|
.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));
|
guac_terminal* term = malloc(sizeof(guac_terminal));
|
||||||
term->client = client;
|
term->client = client;
|
||||||
term->upload_path_handler = NULL;
|
term->upload_path_handler = NULL;
|
||||||
@ -222,7 +232,7 @@ guac_terminal* guac_terminal_create(guac_client* client,
|
|||||||
term->current_attributes = default_char.attributes;
|
term->current_attributes = default_char.attributes;
|
||||||
term->default_char = default_char;
|
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;
|
term->term_height = height / term->display->char_height;
|
||||||
|
|
||||||
/* Open STDOUT pipe */
|
/* Open STDOUT pipe */
|
||||||
@ -250,6 +260,10 @@ guac_terminal* guac_terminal_create(guac_client* client,
|
|||||||
guac_terminal_display_resize(term->display,
|
guac_terminal_display_resize(term->display,
|
||||||
term->term_width, term->term_height);
|
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 */
|
/* Init terminal */
|
||||||
guac_terminal_reset(term);
|
guac_terminal_reset(term);
|
||||||
|
|
||||||
@ -291,6 +305,9 @@ void guac_terminal_free(guac_terminal* term) {
|
|||||||
/* Free clipboard */
|
/* Free clipboard */
|
||||||
guac_common_clipboard_free(term->clipboard);
|
guac_common_clipboard_free(term->clipboard);
|
||||||
|
|
||||||
|
/* Free scrollbar */
|
||||||
|
guac_terminal_scrollbar_free(term->scrollbar);
|
||||||
|
|
||||||
/* Free cursors */
|
/* Free cursors */
|
||||||
guac_terminal_cursor_free(term->client, term->ibar_cursor);
|
guac_terminal_cursor_free(term->client, term->ibar_cursor);
|
||||||
guac_terminal_cursor_free(term->client, term->blank_cursor);
|
guac_terminal_cursor_free(term->client, term->blank_cursor);
|
||||||
@ -516,6 +533,9 @@ int guac_terminal_scroll_up(guac_terminal* term,
|
|||||||
if (term->buffer->length > term->buffer->available)
|
if (term->buffer->length > term->buffer->available)
|
||||||
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 */
|
/* Update cursor location if within region */
|
||||||
if (term->visible_cursor_row >= start_row &&
|
if (term->visible_cursor_row >= start_row &&
|
||||||
term->visible_cursor_row <= end_row)
|
term->visible_cursor_row <= end_row)
|
||||||
@ -631,6 +651,7 @@ void guac_terminal_scroll_display_down(guac_terminal* terminal,
|
|||||||
|
|
||||||
/* Advance by scroll amount */
|
/* Advance by scroll amount */
|
||||||
terminal->scroll_offset -= scroll_amount;
|
terminal->scroll_offset -= scroll_amount;
|
||||||
|
guac_terminal_scrollbar_set_value(terminal->scrollbar, -terminal->scroll_offset);
|
||||||
|
|
||||||
/* Get row range */
|
/* Get row range */
|
||||||
end_row = terminal->term_height - terminal->scroll_offset - 1;
|
end_row = terminal->term_height - terminal->scroll_offset - 1;
|
||||||
@ -666,6 +687,8 @@ void guac_terminal_scroll_display_down(guac_terminal* terminal,
|
|||||||
}
|
}
|
||||||
|
|
||||||
guac_terminal_display_flush(terminal->display);
|
guac_terminal_display_flush(terminal->display);
|
||||||
|
guac_terminal_scrollbar_flush(terminal->scrollbar);
|
||||||
|
|
||||||
guac_protocol_send_sync(terminal->client->socket,
|
guac_protocol_send_sync(terminal->client->socket,
|
||||||
terminal->client->last_sent_timestamp);
|
terminal->client->last_sent_timestamp);
|
||||||
guac_socket_flush(terminal->client->socket);
|
guac_socket_flush(terminal->client->socket);
|
||||||
@ -695,6 +718,7 @@ void guac_terminal_scroll_display_up(guac_terminal* terminal,
|
|||||||
|
|
||||||
/* Advance by scroll amount */
|
/* Advance by scroll amount */
|
||||||
terminal->scroll_offset += scroll_amount;
|
terminal->scroll_offset += scroll_amount;
|
||||||
|
guac_terminal_scrollbar_set_value(terminal->scrollbar, -terminal->scroll_offset);
|
||||||
|
|
||||||
/* Get row range */
|
/* Get row range */
|
||||||
start_row = -terminal->scroll_offset;
|
start_row = -terminal->scroll_offset;
|
||||||
@ -730,6 +754,8 @@ void guac_terminal_scroll_display_up(guac_terminal* terminal,
|
|||||||
}
|
}
|
||||||
|
|
||||||
guac_terminal_display_flush(terminal->display);
|
guac_terminal_display_flush(terminal->display);
|
||||||
|
guac_terminal_scrollbar_flush(terminal->scrollbar);
|
||||||
|
|
||||||
guac_protocol_send_sync(terminal->client->socket,
|
guac_protocol_send_sync(terminal->client->socket,
|
||||||
terminal->client->last_sent_timestamp);
|
terminal->client->last_sent_timestamp);
|
||||||
guac_socket_flush(terminal->client->socket);
|
guac_socket_flush(terminal->client->socket);
|
||||||
@ -1072,6 +1098,7 @@ static void __guac_terminal_resize(guac_terminal* term, int width, int height) {
|
|||||||
if (term->scroll_offset >= shift_amount) {
|
if (term->scroll_offset >= shift_amount) {
|
||||||
|
|
||||||
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 */
|
/* Draw characters from scroll at bottom */
|
||||||
__guac_terminal_redraw_rect(term, term->term_height, 0, term->term_height + shift_amount - 1, width-1);
|
__guac_terminal_redraw_rect(term, term->term_height, 0, term->term_height + shift_amount - 1, width-1);
|
||||||
@ -1087,6 +1114,7 @@ static void __guac_terminal_resize(guac_terminal* term, int width, int height) {
|
|||||||
/* Update shift_amount and scroll based on new rows */
|
/* Update shift_amount and scroll based on new rows */
|
||||||
shift_amount -= term->scroll_offset;
|
shift_amount -= term->scroll_offset;
|
||||||
term->scroll_offset = 0;
|
term->scroll_offset = 0;
|
||||||
|
guac_terminal_scrollbar_set_value(term->scrollbar, -term->scroll_offset);
|
||||||
|
|
||||||
/* If anything remains, move screen as necessary */
|
/* If anything remains, move screen as necessary */
|
||||||
if (shift_amount > 0) {
|
if (shift_amount > 0) {
|
||||||
@ -1123,13 +1151,22 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) {
|
|||||||
guac_client* client = display->client;
|
guac_client* client = display->client;
|
||||||
guac_socket* socket = client->socket;
|
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 */
|
/* Calculate dimensions */
|
||||||
int rows = height / display->char_height;
|
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 */
|
/* Resize default layer to given pixel dimensions */
|
||||||
guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, width, height);
|
guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, width, height);
|
||||||
|
|
||||||
|
/* Notify scrollbar of resize */
|
||||||
|
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 */
|
/* Resize terminal if row/column dimensions have changed */
|
||||||
if (columns != terminal->term_width || rows != terminal->term_height) {
|
if (columns != terminal->term_width || rows != terminal->term_height) {
|
||||||
|
|
||||||
@ -1147,6 +1184,7 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) {
|
|||||||
|
|
||||||
/* If terminal size hasn't changed, still need to flush */
|
/* If terminal size hasn't changed, still need to flush */
|
||||||
else {
|
else {
|
||||||
|
guac_terminal_scrollbar_flush(terminal->scrollbar);
|
||||||
guac_protocol_send_sync(socket, client->last_sent_timestamp);
|
guac_protocol_send_sync(socket, client->last_sent_timestamp);
|
||||||
guac_socket_flush(socket);
|
guac_socket_flush(socket);
|
||||||
}
|
}
|
||||||
@ -1158,6 +1196,7 @@ int guac_terminal_resize(guac_terminal* terminal, int width, int height) {
|
|||||||
void guac_terminal_flush(guac_terminal* terminal) {
|
void guac_terminal_flush(guac_terminal* terminal) {
|
||||||
guac_terminal_commit_cursor(terminal);
|
guac_terminal_commit_cursor(terminal);
|
||||||
guac_terminal_display_flush(terminal->display);
|
guac_terminal_display_flush(terminal->display);
|
||||||
|
guac_terminal_scrollbar_flush(terminal->scrollbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_terminal_lock(guac_terminal* terminal) {
|
void guac_terminal_lock(guac_terminal* terminal) {
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "guac_clipboard.h"
|
#include "guac_clipboard.h"
|
||||||
|
#include "scrollbar.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@ -117,6 +118,11 @@ struct guac_terminal {
|
|||||||
*/
|
*/
|
||||||
int stdin_pipe_fd[2];
|
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
|
* The relative offset of the display. A positive value indicates that
|
||||||
* many rows have been scrolled into view, zero indicates that no
|
* many rows have been scrolled into view, zero indicates that no
|
||||||
|
Loading…
Reference in New Issue
Block a user