diff --git a/src/protocols/ssh/client.c b/src/protocols/ssh/client.c index 43985b3f..3183e22e 100644 --- a/src/protocols/ssh/client.c +++ b/src/protocols/ssh/client.c @@ -56,6 +56,7 @@ const char* GUAC_CLIENT_ARGS[] = { #ifdef ENABLE_SSH_AGENT "enable-agent", #endif + "color-scheme", NULL }; @@ -113,6 +114,14 @@ enum __SSH_ARGS_IDX { IDX_ENABLE_AGENT, #endif + /** + * The name of the color scheme to use. Currently valid color schemes are: + * "black-white", "white-black", "gray-black", and "green-black", each + * following the "foreground-background" pattern. By default, this will be + * "gray-black". + */ + IDX_COLOR_SCHEME, + SSH_ARGS_COUNT }; @@ -173,7 +182,8 @@ int guac_client_init(guac_client* client, int argc, char** argv) { client_data->term = guac_terminal_create(client, client_data->font_name, client_data->font_size, client->info.optimal_resolution, - client->info.optimal_width, client->info.optimal_height); + client->info.optimal_width, client->info.optimal_height, + argv[IDX_COLOR_SCHEME]); /* Fail if terminal init failed */ if (client_data->term == NULL) { diff --git a/src/protocols/telnet/client.c b/src/protocols/telnet/client.c index a083df39..dab2bdab 100644 --- a/src/protocols/telnet/client.c +++ b/src/protocols/telnet/client.c @@ -53,6 +53,7 @@ const char* GUAC_CLIENT_ARGS[] = { "password-regex", "font-name", "font-size", + "color-scheme", NULL }; @@ -100,6 +101,14 @@ enum __TELNET_ARGS_IDX { */ IDX_FONT_SIZE, + /** + * The name of the color scheme to use. Currently valid color schemes are: + * "black-white", "white-black", "gray-black", and "green-black", each + * following the "foreground-background" pattern. By default, this will be + * "gray-black". + */ + IDX_COLOR_SCHEME, + TELNET_ARGS_COUNT }; @@ -200,7 +209,8 @@ int guac_client_init(guac_client* client, int argc, char** argv) { client_data->term = guac_terminal_create(client, client_data->font_name, client_data->font_size, client->info.optimal_resolution, - client->info.optimal_width, client->info.optimal_height); + client->info.optimal_width, client->info.optimal_height, + argv[IDX_COLOR_SCHEME]); /* Fail if terminal init failed */ if (client_data->term == NULL) { diff --git a/src/terminal/display.c b/src/terminal/display.c index b54e27e4..c90c2882 100644 --- a/src/terminal/display.c +++ b/src/terminal/display.c @@ -306,8 +306,8 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client, return NULL; } - display->glyph_foreground = foreground; - display->glyph_background = background; + display->default_foreground = display->glyph_foreground = foreground; + display->default_background = display->glyph_background = background; /* Calculate character dimensions */ display->char_width = @@ -475,12 +475,12 @@ void guac_terminal_display_resize(guac_terminal_display* display, int width, int guac_terminal_operation* current; int x, y; - /* Fill with background color (index 0) */ + /* Fill with background color */ guac_terminal_char fill = { .value = 0, .attributes = { - .foreground = 0, - .background = 0 + .foreground = display->default_background, + .background = display->default_background }, .width = 1 }; diff --git a/src/terminal/display.h b/src/terminal/display.h index 084ece81..d42d99bd 100644 --- a/src/terminal/display.h +++ b/src/terminal/display.h @@ -40,6 +40,87 @@ */ #define GUAC_TERMINAL_MAX_CHAR_WIDTH 2 +/** + * The index of black within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_BLACK 0 + +/** + * The index of low-intensity red within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_DARK_RED 1 + +/** + * The index of low-intensity green within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_DARK_GREEN 2 + +/** + * The index of brown within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_BROWN 3 + +/** + * The index of low-intensity blue within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_DARK_BLUE 4 + +/** + * The index of low-intensity magenta (purple) within the terminal color + * palette. + */ +#define GUAC_TERMINAL_COLOR_PURPLE 5 + +/** + * The index of low-intensity cyan (teal) within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_TEAL 6 + +/** + * The index of low-intensity white (gray) within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_GRAY 7 + +/** + * The index of bright black (dark gray) within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_DARK_GRAY 8 + +/** + * The index of bright red within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_RED 9 + +/** + * The index of bright green within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_GREEN 10 + +/** + * The index of bright brown (yellow) within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_YELLOW 11 + +/** + * The index of bright blue within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_BLUE 12 + +/** + * The index of bright magenta within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_MAGENTA 13 + +/** + * The index of bright cyan within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_CYAN 14 + +/** + * The index of bright white within the terminal color palette. + */ +#define GUAC_TERMINAL_COLOR_WHITE 15 + /** * The available color palette. All integer colors within structures * here are indices into this palette. @@ -139,6 +220,16 @@ typedef struct guac_terminal_display { */ int char_height; + /** + * Default foreground color for all glyphs. + */ + int default_foreground; + + /** + * Default background color for all glyphs and the terminal itself. + */ + int default_background; + /** * Color of glyphs in copy buffer */ diff --git a/src/terminal/scrollbar.c b/src/terminal/scrollbar.c index 9727c389..785e909a 100644 --- a/src/terminal/scrollbar.c +++ b/src/terminal/scrollbar.c @@ -243,7 +243,7 @@ void guac_terminal_scrollbar_flush(guac_terminal_scrollbar* scrollbar) { new_state.container_height); guac_protocol_send_cfill(socket, GUAC_COMP_SRC, scrollbar->container, - 0x40, 0x40, 0x40, 0xFF); + 0x80, 0x80, 0x80, 0x40); } @@ -274,11 +274,7 @@ void guac_terminal_scrollbar_flush(guac_terminal_scrollbar* scrollbar) { 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); + 0xA0, 0xA0, 0xA0, 0x8F); } diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 5c688d61..cf7d84fe 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -190,20 +190,92 @@ void guac_terminal_reset(guac_terminal* term) { } -guac_terminal* guac_terminal_create(guac_client* client, - const char* font_name, int font_size, int dpi, +/** + * Paints or repaints the background of the terminal display. This painting + * occurs beneath the actual terminal and scrollbar layers, and thus will not + * overwrite any text or other content currently on the screen. This is only + * necessary to paint over parts of the terminal background which may otherwise + * be transparent (the default layer background). + * + * @param terminal + * The terminal whose background should be painted or repainted. + * + * @param width + * The width of the background to draw, in pixels. + * + * @param height + * The height of the background to draw, in pixels. + */ +static void guac_terminal_paint_background(guac_terminal* terminal, int width, int height) { + guac_terminal_display* display = terminal->display; + guac_client* client = display->client; + guac_socket* socket = client->socket; + + /* Get background color */ + const guac_terminal_color* color = + &guac_terminal_palette[display->default_background]; + + /* Paint background color */ + guac_protocol_send_rect(socket, GUAC_DEFAULT_LAYER, 0, 0, width, height); + guac_protocol_send_cfill(socket, GUAC_COMP_OVER, GUAC_DEFAULT_LAYER, + color->red, color->green, color->blue, 0xFF); + +} + +guac_terminal* guac_terminal_create(guac_client* client, + const char* font_name, int font_size, int dpi, + int width, int height, const char* color_scheme) { + + int default_foreground; + int default_background; + + /* Default to "gray-black" color scheme if no scheme provided */ + if (color_scheme == NULL || color_scheme[0] == '\0') { + default_foreground = GUAC_TERMINAL_COLOR_GRAY; + default_background = GUAC_TERMINAL_COLOR_BLACK; + } + + /* Otherwise, parse color scheme */ + else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_GRAY_BLACK) == 0) { + default_foreground = GUAC_TERMINAL_COLOR_GRAY; + default_background = GUAC_TERMINAL_COLOR_BLACK; + } + else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_BLACK_WHITE) == 0) { + default_foreground = GUAC_TERMINAL_COLOR_BLACK; + default_background = GUAC_TERMINAL_COLOR_WHITE; + } + else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_GREEN_BLACK) == 0) { + default_foreground = GUAC_TERMINAL_COLOR_DARK_GREEN; + default_background = GUAC_TERMINAL_COLOR_BLACK; + } + else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_WHITE_BLACK) == 0) { + default_foreground = GUAC_TERMINAL_COLOR_WHITE; + default_background = GUAC_TERMINAL_COLOR_BLACK; + } + + /* If invalid, default to "gray-black" */ + else { + guac_client_log(client, GUAC_LOG_WARNING, + "Invalid color scheme: \"%s\". Defaulting to \"gray-black\".", + color_scheme); + default_foreground = GUAC_TERMINAL_COLOR_GRAY; + default_background = GUAC_TERMINAL_COLOR_BLACK; + } + + /* Build default character using default colors */ guac_terminal_char default_char = { .value = 0, .attributes = { - .foreground = 7, - .background = 0, + .foreground = default_foreground, + .background = default_background, .bold = false, .reverse = false, .underscore = false }, - .width = 1}; + .width = 1 + }; /* Calculate available display area */ int available_width = width - GUAC_TERMINAL_SCROLLBAR_WIDTH; @@ -260,6 +332,7 @@ guac_terminal* guac_terminal_create(guac_client* client, /* Size display */ guac_protocol_send_size(term->display->client->socket, GUAC_DEFAULT_LAYER, width, height); + guac_terminal_paint_background(term, width, height); guac_terminal_display_resize(term->display, term->term_width, term->term_height); @@ -1234,6 +1307,7 @@ 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); + guac_terminal_paint_background(terminal, width, height); /* Notify scrollbar of resize */ guac_terminal_scrollbar_parent_resized(terminal->scrollbar, width, height, rows); diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h index 7c6b7507..488692d6 100644 --- a/src/terminal/terminal.h +++ b/src/terminal/terminal.h @@ -65,6 +65,26 @@ */ #define GUAC_TERMINAL_CLIPBOARD_MAX_LENGTH 262144 +/** + * The name of the color scheme having black foreground and white background. + */ +#define GUAC_TERMINAL_SCHEME_BLACK_WHITE "black-white" + +/** + * The name of the color scheme having gray foreground and black background. + */ +#define GUAC_TERMINAL_SCHEME_GRAY_BLACK "gray-black" + +/** + * The name of the color scheme having green foreground and black background. + */ +#define GUAC_TERMINAL_SCHEME_GREEN_BLACK "green-black" + +/** + * The name of the color scheme having white foreground and black background. + */ +#define GUAC_TERMINAL_SCHEME_WHITE_BLACK "white-black" + typedef struct guac_terminal guac_terminal; /** @@ -348,10 +368,40 @@ struct guac_terminal { /** * Creates a new guac_terminal, having the given width and height, and * rendering to the given client. + * + * @param client + * The client to which the terminal will be rendered. + * + * @param font_name + * The name of the font to use when rendering glyphs. + * + * @param font_size + * The size of each glyph, in points. + * + * @param dpi + * The DPI of the display. The given font size will be adjusted to produce + * glyphs at the given DPI. + * + * @param width + * The width of the terminal, in pixels. + * + * @param height + * The height of the terminal, in pixels. + * + * @param color_scheme + * The name of the color scheme to use. This string must be one of the + * names defined by the GUAC_TERMINAL_SCHEME_* constants. If blank or NULL, + * the default scheme of GUAC_TERMINAL_SCHEME_GRAY_BLACK will be used. If + * invalid, a warning will be logged, and the terminal will fall back on + * GUAC_TERMINAL_SCHEME_GRAY_BLACK. + * + * @return + * A new guac_terminal having the given font, dimensions, and attributes + * which renders all text to the given client. */ guac_terminal* guac_terminal_create(guac_client* client, const char* font_name, int font_size, int dpi, - int width, int height); + int width, int height, const char* color_scheme); /** * Frees all resources associated with the given terminal.