You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by mj...@apache.org on 2018/05/27 15:50:31 UTC
[4/6] guacamole-server git commit: GUACAMOLE-470: Support
configurable colors in color-scheme parameter.
GUACAMOLE-470: Support configurable colors in color-scheme parameter.
Add support for configuring individual colors in the color-scheme
parameter, by parsing the parameter content into name-value pairs.
Backward compatibility is preserved by translating previously supported
values into corresponding new values.
Project: http://git-wip-us.apache.org/repos/asf/guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-server/commit/1bd537c3
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-server/tree/1bd537c3
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-server/diff/1bd537c3
Branch: refs/heads/master
Commit: 1bd537c350303b0de41f666bc795561dc04beb6c
Parents: f8b3507
Author: Jim Chen <nc...@mozilla.com>
Authored: Wed May 16 00:23:15 2018 -0400
Committer: Jim Chen <nc...@mozilla.com>
Committed: Sat May 26 23:18:27 2018 -0400
----------------------------------------------------------------------
src/protocols/ssh/settings.c | 10 +-
src/protocols/telnet/settings.c | 10 +-
src/terminal/terminal.c | 299 ++++++++++++++++++++++++++++++----
src/terminal/terminal/terminal.h | 15 ++
4 files changed, 292 insertions(+), 42 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/1bd537c3/src/protocols/ssh/settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c
index 983f7f0..923c9e1 100644
--- a/src/protocols/ssh/settings.c
+++ b/src/protocols/ssh/settings.c
@@ -121,10 +121,12 @@ enum SSH_ARGS_IDX {
#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".
+ * The color scheme to use, as a series of semicolon-separated color-value
+ * pairs: "background: <color>", "foreground: <color>", or
+ * "color<n>: <color>", where <n> is a number from 0 to 255, and <color> is
+ * "color<n>" or an X11 color code (e.g. "aqua" or "rgb:12/34/56").
+ * The color scheme can also be one of the special values: "black-white",
+ * "white-black", "gray-black", or "green-black".
*/
IDX_COLOR_SCHEME,
http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/1bd537c3/src/protocols/telnet/settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c
index 8f80291..45d6290 100644
--- a/src/protocols/telnet/settings.c
+++ b/src/protocols/telnet/settings.c
@@ -99,10 +99,12 @@ 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".
+ * The color scheme to use, as a series of semicolon-separated color-value
+ * pairs: "background: <color>", "foreground: <color>", or
+ * "color<n>: <color>", where <n> is a number from 0 to 255, and <color> is
+ * "color<n>" or an X11 color code (e.g. "aqua" or "rgb:12/34/56").
+ * The color scheme can also be one of the special values: "black-white",
+ * "white-black", "gray-black", or "green-black".
*/
IDX_COLOR_SCHEME,
http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/1bd537c3/src/terminal/terminal.c
----------------------------------------------------------------------
diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c
index a9f5ae5..50d24be 100644
--- a/src/terminal/terminal.c
+++ b/src/terminal/terminal.c
@@ -29,7 +29,9 @@
#include "terminal/terminal_handlers.h"
#include "terminal/types.h"
#include "terminal/typescript.h"
+#include "terminal/xparsecolor.h"
+#include <ctype.h>
#include <errno.h>
#include <pthread.h>
#include <stdarg.h>
@@ -255,53 +257,255 @@ void* guac_terminal_thread(void* data) {
}
-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,
- const int backspace) {
+/**
+ * Compare a non-null-terminated string to a null-terminated literal, in the
+ * same manner as strcmp().
+ *
+ * @param str_start
+ * Start of the non-null-terminated string.
+ *
+ * @param str_end
+ * End of the non-null-terminated string, after the last character.
+ *
+ * @param literal
+ * The null-terminated literal to compare against.
+ *
+ * @return
+ * Zero if the two strings are equal and non-zero otherwise.
+ */
+static int guac_terminal_color_scheme_compare_token(const char* str_start,
+ const char* str_end, const char* literal) {
- int default_foreground;
- int default_background;
+ const int result = strncmp(literal, str_start, str_end - str_start);
+ if (result != 0)
+ return result;
- /* 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;
- }
+ /* At this point, literal is same length or longer than
+ * | str_end - str_start |, so if the two are equal, literal should
+ * have its null-terminator at | str_end - str_start |. */
+ return (int) (unsigned char) literal[str_end - str_start];
+}
- /* 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;
+/**
+ * Strip the leading and trailing spaces of a bounded string.
+ *
+ * @param[in,out] str_start
+ * Address of a pointer to the start of the string. On return, the pointer
+ * is advanced to after any leading spaces.
+ *
+ * @param[in,out] str_end
+ * Address of a pointer to the end of the string, after the last character.
+ * On return, the pointer is moved back to before any trailing spaces.
+ */
+static void guac_terminal_color_scheme_strip_spaces(const char** str_start,
+ const char** str_end) {
+
+ /* Strip leading spaces. */
+ while (*str_start < *str_end && isspace(**str_start))
+ (*str_start)++;
+
+ /* Strip trailing spaces. */
+ while (*str_end > *str_start && isspace(*(*str_end - 1)))
+ (*str_end)--;
+}
+
+/**
+ * Parse the name part of the name-value pair within the color-scheme
+ * configuration.
+ *
+ * @param client
+ * The client that the terminal is connected to.
+ *
+ * @param name_start
+ * Start of the name string.
+ *
+ * @param name_end
+ * End of the name string, after the last character.
+ *
+ * @param foreground
+ * Pointer to the foreground color.
+ *
+ * @param background
+ * Pointer to the background color.
+ *
+ * @param palette
+ * Pointer to the palette array.
+ *
+ * @param[out] target
+ * On return, pointer to the color struct that corresponds to the name.
+ *
+ * @return
+ * Zero if successful or non-zero otherwise.
+ */
+static int guac_terminal_parse_color_scheme_name(guac_client* client,
+ const char* name_start, const char* name_end,
+ guac_terminal_color* foreground, guac_terminal_color* background,
+ guac_terminal_color (*palette)[256],
+ guac_terminal_color** target) {
+
+ guac_terminal_color_scheme_strip_spaces(&name_start, &name_end);
+
+ if (!guac_terminal_color_scheme_compare_token(
+ name_start, name_end, GUAC_TERMINAL_SCHEME_FOREGROUND)) {
+ *target = foreground;
+ return 0;
}
- else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_BLACK_WHITE) == 0) {
- default_foreground = GUAC_TERMINAL_COLOR_BLACK;
- default_background = GUAC_TERMINAL_COLOR_WHITE;
+
+ if (!guac_terminal_color_scheme_compare_token(
+ name_start, name_end, GUAC_TERMINAL_SCHEME_BACKGROUND)) {
+ *target = background;
+ return 0;
}
- else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_GREEN_BLACK) == 0) {
- default_foreground = GUAC_TERMINAL_COLOR_DARK_GREEN;
- default_background = GUAC_TERMINAL_COLOR_BLACK;
+
+ /* Parse color<n> value. */
+ int index = -1;
+ if (sscanf(name_start, GUAC_TERMINAL_SCHEME_NUMBERED "%d", &index) &&
+ index >= 0 && index <= 255) {
+ *target = &(*palette)[index];
+ return 0;
}
- else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_WHITE_BLACK) == 0) {
- default_foreground = GUAC_TERMINAL_COLOR_WHITE;
- default_background = GUAC_TERMINAL_COLOR_BLACK;
+
+ guac_client_log(client, GUAC_LOG_WARNING,
+ "Unknown color name: \"%.*s\".",
+ name_end - name_start, name_start);
+ return 1;
+}
+
+/**
+ * Parse the value part of the name-value pair within the color-scheme
+ * configuration.
+ *
+ * @param client
+ * The client that the terminal is connected to.
+ *
+ * @param value_start
+ * Start of the value string.
+ *
+ * @param value_end
+ * End of the value string, after the last character.
+ *
+ * @param palette
+ * The current color palette.
+ *
+ * @param[out] target
+ * On return, the parsed color.
+ *
+ * @return
+ * Zero if successful or non-zero otherwise.
+ */
+static int guac_terminal_parse_color_scheme_value(guac_client* client,
+ const char* value_start, const char* value_end,
+ const guac_terminal_color (*palette)[256],
+ guac_terminal_color* target) {
+
+ guac_terminal_color_scheme_strip_spaces(&value_start, &value_end);
+
+ /* Parse color<n> value. */
+ int index = -1;
+ if (sscanf(value_start, GUAC_TERMINAL_SCHEME_NUMBERED "%d", &index) &&
+ index >= 0 && index <= 255) {
+ *target = (*palette)[index];
+ return 0;
}
- /* 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;
+ /* Parse X11 value. */
+ if (!guac_terminal_xparsecolor(value_start, target))
+ return 0;
+
+ guac_client_log(client, GUAC_LOG_WARNING,
+ "Invalid color value: \"%.*s\".",
+ value_end - value_start, value_start);
+ return 1;
+}
+
+/**
+ * Parse a color-scheme configuration string, and return specified
+ * foreground/background colors and color palette.
+ *
+ * @param client
+ * The client that the terminal is connected to.
+ *
+ * @param color_scheme
+ * A semicolon-separated list of name-value pairs, i.e.
+ * "<name>: <value> [; <name>: <value> [; ...]]".
+ * For example, "color2: rgb:cc/33/22; background: color5".
+ *
+ * @param[out] foreground
+ * Parsed foreground color.
+ *
+ * @param[out] background
+ * Parsed background color.
+ *
+ * @param[in,out] palette
+ * Parsed color palette. The caller is responsible for allocating a mutable
+ * array on entry. On return, the array contains the parsed palette.
+ */
+static void guac_terminal_parse_color_scheme(guac_client* client,
+ const char* color_scheme, guac_terminal_color* foreground,
+ guac_terminal_color* background,
+ guac_terminal_color (*palette)[256]) {
+
+ /* Set default gray-black color scheme and initial palette. */
+ *foreground = GUAC_TERMINAL_INITIAL_PALETTE[GUAC_TERMINAL_COLOR_GRAY];
+ *background = GUAC_TERMINAL_INITIAL_PALETTE[GUAC_TERMINAL_COLOR_BLACK];
+ memcpy(palette, GUAC_TERMINAL_INITIAL_PALETTE,
+ sizeof(GUAC_TERMINAL_INITIAL_PALETTE));
+
+ /* Current char being parsed, or NULL if at end of parsing. */
+ const char* cursor = color_scheme;
+
+ while (cursor) {
+ /* Start of the current "name: value" pair. */
+ const char* pair_start = cursor;
+
+ /* End of the current name-value pair. */
+ const char* pair_end = strchr(pair_start, ';');
+ if (pair_end) {
+ cursor = pair_end + 1;
+ }
+ else {
+ pair_end = pair_start + strlen(pair_start);
+ cursor = NULL;
+ }
+
+ guac_terminal_color_scheme_strip_spaces(&pair_start, &pair_end);
+ if (pair_start >= pair_end)
+ /* Allow empty pairs, which happens, e.g., when the configuration
+ * string ends in a semi-colon. */
+ continue;
+
+ /* End of the name part of the pair. */
+ const char* name_end = memchr(pair_start, ':', pair_end - pair_start);
+ if (name_end == NULL) {
+ guac_client_log(client, GUAC_LOG_WARNING,
+ "Expecting colon: \"%.*s\".",
+ pair_end - pair_start, pair_start);
+ return;
+ }
+
+ /* The color that the name corresponds to. */
+ guac_terminal_color* color_target = NULL;
+
+ if (guac_terminal_parse_color_scheme_name(
+ client, pair_start, name_end, foreground, background,
+ palette, &color_target))
+ return; /* Parsing failed. */
+
+ if (guac_terminal_parse_color_scheme_value(
+ client, name_end + 1, pair_end, palette, color_target))
+ return; /* Parsing failed. */
}
+}
+
+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,
+ const int backspace) {
/* Build default character using default colors */
guac_terminal_char default_char = {
.value = 0,
.attributes = {
- .foreground = GUAC_TERMINAL_INITIAL_PALETTE[default_foreground],
- .background = GUAC_TERMINAL_INITIAL_PALETTE[default_background],
.bold = false,
.half_bright = false,
.reverse = false,
@@ -310,6 +514,32 @@ guac_terminal* guac_terminal_create(guac_client* client,
.width = 1
};
+ /* Initialized by guac_terminal_parse_color_scheme. */
+ guac_terminal_color (*default_palette)[256] = (guac_terminal_color(*)[256])
+ malloc(sizeof(guac_terminal_color[256]));
+
+ /* Special cases. */
+ if (color_scheme == NULL || color_scheme[0] == '\0') {
+ /* guac_terminal_parse_color_scheme defaults to gray-black */
+ }
+ else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_GRAY_BLACK) == 0) {
+ color_scheme = "foreground:color7;background:color0";
+ }
+ else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_BLACK_WHITE) == 0) {
+ color_scheme = "foreground:color0;background:color15";
+ }
+ else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_GREEN_BLACK) == 0) {
+ color_scheme = "foreground:color2;background:color0";
+ }
+ else if (strcmp(color_scheme, GUAC_TERMINAL_SCHEME_WHITE_BLACK) == 0) {
+ color_scheme = "foreground:color15;background:color0";
+ }
+
+ guac_terminal_parse_color_scheme(client, color_scheme,
+ &default_char.attributes.foreground,
+ &default_char.attributes.background,
+ default_palette);
+
/* Calculate available display area */
int available_width = width - GUAC_TERMINAL_SCROLLBAR_WIDTH;
if (available_width < 0)
@@ -332,7 +562,8 @@ guac_terminal* guac_terminal_create(guac_client* client,
term->display = guac_terminal_display_alloc(client,
font_name, font_size, dpi,
&default_char.attributes.foreground,
- &default_char.attributes.background, NULL);
+ &default_char.attributes.background,
+ default_palette);
/* Fail if display init failed */
if (term->display == NULL) {
http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/1bd537c3/src/terminal/terminal/terminal.h
----------------------------------------------------------------------
diff --git a/src/terminal/terminal/terminal.h b/src/terminal/terminal/terminal.h
index c071b40..6094c39 100644
--- a/src/terminal/terminal/terminal.h
+++ b/src/terminal/terminal/terminal.h
@@ -83,6 +83,21 @@
*/
#define GUAC_TERMINAL_SCHEME_WHITE_BLACK "white-black"
+/**
+ * Color name representing the foreground color.
+ */
+#define GUAC_TERMINAL_SCHEME_FOREGROUND "foreground"
+
+/**
+ * Color name representing the background color.
+ */
+#define GUAC_TERMINAL_SCHEME_BACKGROUND "background"
+
+/**
+ * Color name representing a numbered color.
+ */
+#define GUAC_TERMINAL_SCHEME_NUMBERED "color"
+
typedef struct guac_terminal guac_terminal;
/**