GUACAMOLE-278: Merge 256-color support for terminal.

This commit is contained in:
James Muehlner 2017-04-26 21:13:51 -07:00
commit d88b5d1011
10 changed files with 767 additions and 196 deletions

View File

@ -27,6 +27,7 @@ noinst_HEADERS = \
terminal/char_mappings.h \ terminal/char_mappings.h \
terminal/common.h \ terminal/common.h \
terminal/display.h \ terminal/display.h \
terminal/palette.h \
terminal/scrollbar.h \ terminal/scrollbar.h \
terminal/terminal.h \ terminal/terminal.h \
terminal/terminal_handlers.h \ terminal/terminal_handlers.h \
@ -38,6 +39,7 @@ libguac_terminal_la_SOURCES = \
char_mappings.c \ char_mappings.c \
common.c \ common.c \
display.c \ display.c \
palette.c \
scrollbar.c \ scrollbar.c \
terminal.c \ terminal.c \
terminal_handlers.c \ terminal_handlers.c \

View File

@ -22,6 +22,7 @@
#include "common/surface.h" #include "common/surface.h"
#include "terminal/common.h" #include "terminal/common.h"
#include "terminal/display.h" #include "terminal/display.h"
#include "terminal/palette.h"
#include "terminal/types.h" #include "terminal/types.h"
#include <math.h> #include <math.h>
@ -36,30 +37,6 @@
#include <guacamole/socket.h> #include <guacamole/socket.h>
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
const guac_terminal_color guac_terminal_palette[16] = {
/* Normal colors */
{0x00, 0x00, 0x00}, /* Black */
{0x99, 0x3E, 0x3E}, /* Red */
{0x3E, 0x99, 0x3E}, /* Green */
{0x99, 0x99, 0x3E}, /* Brown */
{0x3E, 0x3E, 0x99}, /* Blue */
{0x99, 0x3E, 0x99}, /* Magenta */
{0x3E, 0x99, 0x99}, /* Cyan */
{0x99, 0x99, 0x99}, /* White */
/* Intense colors */
{0x3E, 0x3E, 0x3E}, /* Black */
{0xFF, 0x67, 0x67}, /* Red */
{0x67, 0xFF, 0x67}, /* Green */
{0xFF, 0xFF, 0x67}, /* Brown */
{0x67, 0x67, 0xFF}, /* Blue */
{0xFF, 0x67, 0xFF}, /* Magenta */
{0x67, 0xFF, 0xFF}, /* Cyan */
{0xFF, 0xFF, 0xFF}, /* White */
};
/** /**
* Clears the currently-selected region, removing the highlight. * Clears the currently-selected region, removing the highlight.
*/ */
@ -127,24 +104,29 @@ int __guac_terminal_hash_codepoint(int codepoint) {
int __guac_terminal_set_colors(guac_terminal_display* display, int __guac_terminal_set_colors(guac_terminal_display* display,
guac_terminal_attributes* attributes) { guac_terminal_attributes* attributes) {
int background, foreground; const guac_terminal_color* background;
const guac_terminal_color* foreground;
/* Handle reverse video */ /* Handle reverse video */
if (attributes->reverse != attributes->cursor) { if (attributes->reverse != attributes->cursor) {
background = attributes->foreground; background = &attributes->foreground;
foreground = attributes->background; foreground = &attributes->background;
} }
else { else {
foreground = attributes->foreground; foreground = &attributes->foreground;
background = attributes->background; background = &attributes->background;
} }
/* Handle bold */ /* Handle bold */
if (attributes->bold && foreground <= 7) if (attributes->bold
foreground += 8; && foreground->palette_index >= GUAC_TERMINAL_FIRST_DARK
&& foreground->palette_index <= GUAC_TERMINAL_LAST_DARK) {
foreground = &guac_terminal_palette[foreground->palette_index
+ GUAC_TERMINAL_INTENSE_OFFSET];
}
display->glyph_foreground = foreground; display->glyph_foreground = *foreground;
display->glyph_background = background; display->glyph_background = *background;
return 0; return 0;
@ -163,12 +145,10 @@ int __guac_terminal_set(guac_terminal_display* display, int row, int col, int co
char utf8[4]; char utf8[4];
/* Use foreground color */ /* Use foreground color */
const guac_terminal_color* color = const guac_terminal_color* color = &display->glyph_foreground;
&guac_terminal_palette[display->glyph_foreground];
/* Use background color */ /* Use background color */
const guac_terminal_color* background = const guac_terminal_color* background = &display->glyph_background;
&guac_terminal_palette[display->glyph_background];
cairo_surface_t* surface; cairo_surface_t* surface;
cairo_t* cairo; cairo_t* cairo;
@ -259,7 +239,7 @@ int __guac_terminal_set(guac_terminal_display* display, int row, int col, int co
guac_terminal_display* guac_terminal_display_alloc(guac_client* client, guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
const char* font_name, int font_size, int dpi, const char* font_name, int font_size, int dpi,
int foreground, int background) { guac_terminal_color* foreground, guac_terminal_color* background) {
PangoFontMap* font_map; PangoFontMap* font_map;
PangoFont* font; PangoFont* font;
@ -303,8 +283,8 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
return NULL; return NULL;
} }
display->default_foreground = display->glyph_foreground = foreground; display->default_foreground = display->glyph_foreground = *foreground;
display->default_background = display->glyph_background = background; display->default_background = display->glyph_background = *background;
/* Calculate character dimensions */ /* Calculate character dimensions */
display->char_width = display->char_width =
@ -688,14 +668,11 @@ void __guac_terminal_display_flush_clear(guac_terminal_display* display) {
int rect_width, rect_height; int rect_width, rect_height;
/* Color of the rectangle to draw */ /* Color of the rectangle to draw */
int color; const guac_terminal_color* color;
if (current->character.attributes.reverse != current->character.attributes.cursor) if (current->character.attributes.reverse != current->character.attributes.cursor)
color = current->character.attributes.foreground; color = &current->character.attributes.foreground;
else else
color = current->character.attributes.background; color = &current->character.attributes.background;
const guac_terminal_color* guac_color =
&guac_terminal_palette[color];
/* Current row within a subrect */ /* Current row within a subrect */
guac_terminal_operation* rect_current_row; guac_terminal_operation* rect_current_row;
@ -709,16 +686,16 @@ void __guac_terminal_display_flush_clear(guac_terminal_display* display) {
/* Find width */ /* Find width */
for (rect_col=col; rect_col<display->width; rect_col++) { for (rect_col=col; rect_col<display->width; rect_col++) {
int joining_color; const guac_terminal_color* joining_color;
if (rect_current->character.attributes.reverse != rect_current->character.attributes.cursor) if (rect_current->character.attributes.reverse != rect_current->character.attributes.cursor)
joining_color = rect_current->character.attributes.foreground; joining_color = &rect_current->character.attributes.foreground;
else else
joining_color = rect_current->character.attributes.background; joining_color = &rect_current->character.attributes.background;
/* If not identical operation, stop */ /* If not identical operation, stop */
if (rect_current->type != GUAC_CHAR_SET if (rect_current->type != GUAC_CHAR_SET
|| guac_terminal_has_glyph(rect_current->character.value) || guac_terminal_has_glyph(rect_current->character.value)
|| joining_color != color) || guac_terminal_colorcmp(joining_color, color) != 0)
break; break;
/* Next column */ /* Next column */
@ -754,16 +731,16 @@ void __guac_terminal_display_flush_clear(guac_terminal_display* display) {
for (rect_col=0; rect_col<rect_width; rect_col++) { for (rect_col=0; rect_col<rect_width; rect_col++) {
int joining_color; const guac_terminal_color* joining_color;
if (rect_current->character.attributes.reverse != rect_current->character.attributes.cursor) if (rect_current->character.attributes.reverse != rect_current->character.attributes.cursor)
joining_color = rect_current->character.attributes.foreground; joining_color = &rect_current->character.attributes.foreground;
else else
joining_color = rect_current->character.attributes.background; joining_color = &rect_current->character.attributes.background;
/* Mark clear operations as NOP */ /* Mark clear operations as NOP */
if (rect_current->type == GUAC_CHAR_SET if (rect_current->type == GUAC_CHAR_SET
&& !guac_terminal_has_glyph(rect_current->character.value) && !guac_terminal_has_glyph(rect_current->character.value)
&& joining_color == color) && guac_terminal_colorcmp(joining_color, color) == 0)
rect_current->type = GUAC_CHAR_NOP; rect_current->type = GUAC_CHAR_NOP;
/* Next column */ /* Next column */
@ -783,7 +760,7 @@ void __guac_terminal_display_flush_clear(guac_terminal_display* display) {
row * display->char_height, row * display->char_height,
rect_width * display->char_width, rect_width * display->char_width,
rect_height * display->char_height, rect_height * display->char_height,
guac_color->red, guac_color->green, guac_color->blue, color->red, color->green, color->blue,
0xFF); 0xFF);
} /* end if clear operation */ } /* end if clear operation */

308
src/terminal/palette.c Normal file
View File

@ -0,0 +1,308 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "terminal/palette.h"
const guac_terminal_color guac_terminal_palette[256] = {
/* Normal colors */
{0, 0x00, 0x00, 0x00}, /* Black */
{1, 0x99, 0x3E, 0x3E}, /* Red */
{2, 0x3E, 0x99, 0x3E}, /* Green */
{3, 0x99, 0x99, 0x3E}, /* Brown */
{4, 0x3E, 0x3E, 0x99}, /* Blue */
{5, 0x99, 0x3E, 0x99}, /* Magenta */
{6, 0x3E, 0x99, 0x99}, /* Cyan */
{7, 0x99, 0x99, 0x99}, /* White */
/* Intense colors */
{8, 0x3E, 0x3E, 0x3E}, /* Black */
{9, 0xFF, 0x67, 0x67}, /* Red */
{10, 0x67, 0xFF, 0x67}, /* Green */
{11, 0xFF, 0xFF, 0x67}, /* Brown */
{12, 0x67, 0x67, 0xFF}, /* Blue */
{13, 0xFF, 0x67, 0xFF}, /* Magenta */
{14, 0x67, 0xFF, 0xFF}, /* Cyan */
{15, 0xFF, 0xFF, 0xFF}, /* White */
/* Remainder of xterm's 256-color palette */
{16, 0x00, 0x00, 0x00},
{17, 0x00, 0x00, 0x5F},
{18, 0x00, 0x00, 0x87},
{19, 0x00, 0x00, 0xAF},
{20, 0x00, 0x00, 0xD7},
{21, 0x00, 0x00, 0xFF},
{22, 0x00, 0x5F, 0x00},
{23, 0x00, 0x5F, 0x5F},
{24, 0x00, 0x5F, 0x87},
{25, 0x00, 0x5F, 0xAF},
{26, 0x00, 0x5F, 0xD7},
{27, 0x00, 0x5F, 0xFF},
{28, 0x00, 0x87, 0x00},
{29, 0x00, 0x87, 0x5F},
{30, 0x00, 0x87, 0x87},
{31, 0x00, 0x87, 0xAF},
{32, 0x00, 0x87, 0xD7},
{33, 0x00, 0x87, 0xFF},
{34, 0x00, 0xAF, 0x00},
{35, 0x00, 0xAF, 0x5F},
{36, 0x00, 0xAF, 0x87},
{37, 0x00, 0xAF, 0xAF},
{38, 0x00, 0xAF, 0xD7},
{39, 0x00, 0xAF, 0xFF},
{40, 0x00, 0xD7, 0x00},
{41, 0x00, 0xD7, 0x5F},
{42, 0x00, 0xD7, 0x87},
{43, 0x00, 0xD7, 0xAF},
{44, 0x00, 0xD7, 0xD7},
{45, 0x00, 0xD7, 0xFF},
{46, 0x00, 0xFF, 0x00},
{47, 0x00, 0xFF, 0x5F},
{48, 0x00, 0xFF, 0x87},
{49, 0x00, 0xFF, 0xAF},
{50, 0x00, 0xFF, 0xD7},
{51, 0x00, 0xFF, 0xFF},
{52, 0x5F, 0x00, 0x00},
{53, 0x5F, 0x00, 0x5F},
{54, 0x5F, 0x00, 0x87},
{55, 0x5F, 0x00, 0xAF},
{56, 0x5F, 0x00, 0xD7},
{57, 0x5F, 0x00, 0xFF},
{58, 0x5F, 0x5F, 0x00},
{59, 0x5F, 0x5F, 0x5F},
{60, 0x5F, 0x5F, 0x87},
{61, 0x5F, 0x5F, 0xAF},
{62, 0x5F, 0x5F, 0xD7},
{63, 0x5F, 0x5F, 0xFF},
{64, 0x5F, 0x87, 0x00},
{65, 0x5F, 0x87, 0x5F},
{66, 0x5F, 0x87, 0x87},
{67, 0x5F, 0x87, 0xAF},
{68, 0x5F, 0x87, 0xD7},
{69, 0x5F, 0x87, 0xFF},
{70, 0x5F, 0xAF, 0x00},
{71, 0x5F, 0xAF, 0x5F},
{72, 0x5F, 0xAF, 0x87},
{73, 0x5F, 0xAF, 0xAF},
{74, 0x5F, 0xAF, 0xD7},
{75, 0x5F, 0xAF, 0xFF},
{76, 0x5F, 0xD7, 0x00},
{77, 0x5F, 0xD7, 0x5F},
{78, 0x5F, 0xD7, 0x87},
{79, 0x5F, 0xD7, 0xAF},
{80, 0x5F, 0xD7, 0xD7},
{81, 0x5F, 0xD7, 0xFF},
{82, 0x5F, 0xFF, 0x00},
{83, 0x5F, 0xFF, 0x5F},
{84, 0x5F, 0xFF, 0x87},
{85, 0x5F, 0xFF, 0xAF},
{86, 0x5F, 0xFF, 0xD7},
{87, 0x5F, 0xFF, 0xFF},
{88, 0x87, 0x00, 0x00},
{89, 0x87, 0x00, 0x5F},
{90, 0x87, 0x00, 0x87},
{91, 0x87, 0x00, 0xAF},
{92, 0x87, 0x00, 0xD7},
{93, 0x87, 0x00, 0xFF},
{94, 0x87, 0x5F, 0x00},
{95, 0x87, 0x5F, 0x5F},
{96, 0x87, 0x5F, 0x87},
{97, 0x87, 0x5F, 0xAF},
{98, 0x87, 0x5F, 0xD7},
{99, 0x87, 0x5F, 0xFF},
{100, 0x87, 0x87, 0x00},
{101, 0x87, 0x87, 0x5F},
{102, 0x87, 0x87, 0x87},
{103, 0x87, 0x87, 0xAF},
{104, 0x87, 0x87, 0xD7},
{105, 0x87, 0x87, 0xFF},
{106, 0x87, 0xAF, 0x00},
{107, 0x87, 0xAF, 0x5F},
{108, 0x87, 0xAF, 0x87},
{109, 0x87, 0xAF, 0xAF},
{110, 0x87, 0xAF, 0xD7},
{111, 0x87, 0xAF, 0xFF},
{112, 0x87, 0xD7, 0x00},
{113, 0x87, 0xD7, 0x5F},
{114, 0x87, 0xD7, 0x87},
{115, 0x87, 0xD7, 0xAF},
{116, 0x87, 0xD7, 0xD7},
{117, 0x87, 0xD7, 0xFF},
{118, 0x87, 0xFF, 0x00},
{119, 0x87, 0xFF, 0x5F},
{120, 0x87, 0xFF, 0x87},
{121, 0x87, 0xFF, 0xAF},
{122, 0x87, 0xFF, 0xD7},
{123, 0x87, 0xFF, 0xFF},
{124, 0xAF, 0x00, 0x00},
{125, 0xAF, 0x00, 0x5F},
{126, 0xAF, 0x00, 0x87},
{127, 0xAF, 0x00, 0xAF},
{128, 0xAF, 0x00, 0xD7},
{129, 0xAF, 0x00, 0xFF},
{130, 0xAF, 0x5F, 0x00},
{131, 0xAF, 0x5F, 0x5F},
{132, 0xAF, 0x5F, 0x87},
{133, 0xAF, 0x5F, 0xAF},
{134, 0xAF, 0x5F, 0xD7},
{135, 0xAF, 0x5F, 0xFF},
{136, 0xAF, 0x87, 0x00},
{137, 0xAF, 0x87, 0x5F},
{138, 0xAF, 0x87, 0x87},
{139, 0xAF, 0x87, 0xAF},
{140, 0xAF, 0x87, 0xD7},
{141, 0xAF, 0x87, 0xFF},
{142, 0xAF, 0xAF, 0x00},
{143, 0xAF, 0xAF, 0x5F},
{144, 0xAF, 0xAF, 0x87},
{145, 0xAF, 0xAF, 0xAF},
{146, 0xAF, 0xAF, 0xD7},
{147, 0xAF, 0xAF, 0xFF},
{148, 0xAF, 0xD7, 0x00},
{149, 0xAF, 0xD7, 0x5F},
{150, 0xAF, 0xD7, 0x87},
{151, 0xAF, 0xD7, 0xAF},
{152, 0xAF, 0xD7, 0xD7},
{153, 0xAF, 0xD7, 0xFF},
{154, 0xAF, 0xFF, 0x00},
{155, 0xAF, 0xFF, 0x5F},
{156, 0xAF, 0xFF, 0x87},
{157, 0xAF, 0xFF, 0xAF},
{158, 0xAF, 0xFF, 0xD7},
{159, 0xAF, 0xFF, 0xFF},
{160, 0xD7, 0x00, 0x00},
{161, 0xD7, 0x00, 0x5F},
{162, 0xD7, 0x00, 0x87},
{163, 0xD7, 0x00, 0xAF},
{164, 0xD7, 0x00, 0xD7},
{165, 0xD7, 0x00, 0xFF},
{166, 0xD7, 0x5F, 0x00},
{167, 0xD7, 0x5F, 0x5F},
{168, 0xD7, 0x5F, 0x87},
{169, 0xD7, 0x5F, 0xAF},
{170, 0xD7, 0x5F, 0xD7},
{171, 0xD7, 0x5F, 0xFF},
{172, 0xD7, 0x87, 0x00},
{173, 0xD7, 0x87, 0x5F},
{174, 0xD7, 0x87, 0x87},
{175, 0xD7, 0x87, 0xAF},
{176, 0xD7, 0x87, 0xD7},
{177, 0xD7, 0x87, 0xFF},
{178, 0xD7, 0xAF, 0x00},
{179, 0xD7, 0xAF, 0x5F},
{180, 0xD7, 0xAF, 0x87},
{181, 0xD7, 0xAF, 0xAF},
{182, 0xD7, 0xAF, 0xD7},
{183, 0xD7, 0xAF, 0xFF},
{184, 0xD7, 0xD7, 0x00},
{185, 0xD7, 0xD7, 0x5F},
{186, 0xD7, 0xD7, 0x87},
{187, 0xD7, 0xD7, 0xAF},
{188, 0xD7, 0xD7, 0xD7},
{189, 0xD7, 0xD7, 0xFF},
{190, 0xD7, 0xFF, 0x00},
{191, 0xD7, 0xFF, 0x5F},
{192, 0xD7, 0xFF, 0x87},
{193, 0xD7, 0xFF, 0xAF},
{194, 0xD7, 0xFF, 0xD7},
{195, 0xD7, 0xFF, 0xFF},
{196, 0xFF, 0x00, 0x00},
{197, 0xFF, 0x00, 0x5F},
{198, 0xFF, 0x00, 0x87},
{199, 0xFF, 0x00, 0xAF},
{200, 0xFF, 0x00, 0xD7},
{201, 0xFF, 0x00, 0xFF},
{202, 0xFF, 0x5F, 0x00},
{203, 0xFF, 0x5F, 0x5F},
{204, 0xFF, 0x5F, 0x87},
{205, 0xFF, 0x5F, 0xAF},
{206, 0xFF, 0x5F, 0xD7},
{207, 0xFF, 0x5F, 0xFF},
{208, 0xFF, 0x87, 0x00},
{209, 0xFF, 0x87, 0x5F},
{210, 0xFF, 0x87, 0x87},
{211, 0xFF, 0x87, 0xAF},
{212, 0xFF, 0x87, 0xD7},
{213, 0xFF, 0x87, 0xFF},
{214, 0xFF, 0xAF, 0x00},
{215, 0xFF, 0xAF, 0x5F},
{216, 0xFF, 0xAF, 0x87},
{217, 0xFF, 0xAF, 0xAF},
{218, 0xFF, 0xAF, 0xD7},
{219, 0xFF, 0xAF, 0xFF},
{220, 0xFF, 0xD7, 0x00},
{221, 0xFF, 0xD7, 0x5F},
{222, 0xFF, 0xD7, 0x87},
{223, 0xFF, 0xD7, 0xAF},
{224, 0xFF, 0xD7, 0xD7},
{225, 0xFF, 0xD7, 0xFF},
{226, 0xFF, 0xFF, 0x00},
{227, 0xFF, 0xFF, 0x5F},
{228, 0xFF, 0xFF, 0x87},
{229, 0xFF, 0xFF, 0xAF},
{230, 0xFF, 0xFF, 0xD7},
{231, 0xFF, 0xFF, 0xFF},
{232, 0x08, 0x08, 0x08},
{233, 0x12, 0x12, 0x12},
{234, 0x1C, 0x1C, 0x1C},
{235, 0x26, 0x26, 0x26},
{236, 0x30, 0x30, 0x30},
{237, 0x3A, 0x3A, 0x3A},
{238, 0x44, 0x44, 0x44},
{239, 0x4E, 0x4E, 0x4E},
{240, 0x58, 0x58, 0x58},
{241, 0x62, 0x62, 0x62},
{242, 0x6C, 0x6C, 0x6C},
{243, 0x76, 0x76, 0x76},
{244, 0x80, 0x80, 0x80},
{245, 0x8A, 0x8A, 0x8A},
{246, 0x94, 0x94, 0x94},
{247, 0x9E, 0x9E, 0x9E},
{248, 0xA8, 0xA8, 0xA8},
{249, 0xB2, 0xB2, 0xB2},
{250, 0xBC, 0xBC, 0xBC},
{251, 0xC6, 0xC6, 0xC6},
{252, 0xD0, 0xD0, 0xD0},
{253, 0xDA, 0xDA, 0xDA},
{254, 0xE4, 0xE4, 0xE4},
{255, 0xEE, 0xEE, 0xEE}
};
int guac_terminal_colorcmp(const guac_terminal_color* a,
const guac_terminal_color* b) {
/* Consider red component highest order ... */
if (a->red != b->red)
return a->red - b->red;
/* ... followed by green ... */
if (a->green != b->green)
return a->green - b->green;
/* ... followed by blue */
if (a->blue != b->blue)
return a->blue - b->blue;
/* If all components match, colors are equal */
return 0;
}

View File

@ -24,6 +24,7 @@
#include "terminal/buffer.h" #include "terminal/buffer.h"
#include "terminal/common.h" #include "terminal/common.h"
#include "terminal/display.h" #include "terminal/display.h"
#include "terminal/palette.h"
#include "terminal/terminal.h" #include "terminal/terminal.h"
#include "terminal/terminal_handlers.h" #include "terminal/terminal_handlers.h"
#include "terminal/types.h" #include "terminal/types.h"
@ -205,8 +206,7 @@ static void guac_terminal_repaint_default_layer(guac_terminal* terminal,
guac_terminal_display* display = terminal->display; guac_terminal_display* display = terminal->display;
/* Get background color */ /* Get background color */
const guac_terminal_color* color = const guac_terminal_color* color = &display->default_background;
&guac_terminal_palette[display->default_background];
/* Reset size */ /* Reset size */
guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, width, height); guac_protocol_send_size(socket, GUAC_DEFAULT_LAYER, width, height);
@ -296,8 +296,8 @@ guac_terminal* guac_terminal_create(guac_client* client,
guac_terminal_char default_char = { guac_terminal_char default_char = {
.value = 0, .value = 0,
.attributes = { .attributes = {
.foreground = default_foreground, .foreground = guac_terminal_palette[default_foreground],
.background = default_background, .background = guac_terminal_palette[default_background],
.bold = false, .bold = false,
.reverse = false, .reverse = false,
.underscore = false .underscore = false
@ -326,8 +326,8 @@ guac_terminal* guac_terminal_create(guac_client* client,
/* Init display */ /* Init display */
term->display = guac_terminal_display_alloc(client, term->display = guac_terminal_display_alloc(client,
font_name, font_size, dpi, font_name, font_size, dpi,
default_char.attributes.foreground, &default_char.attributes.foreground,
default_char.attributes.background); &default_char.attributes.background);
/* Fail if display init failed */ /* Fail if display init failed */
if (term->display == NULL) { if (term->display == NULL) {
@ -875,17 +875,18 @@ static bool guac_terminal_is_visible(guac_terminal* term,
if (guac_terminal_has_glyph(c->value)) if (guac_terminal_has_glyph(c->value))
return true; return true;
int background; const guac_terminal_color* background;
/* Determine actual background color of character */ /* Determine actual background color of character */
if (c->attributes.reverse != c->attributes.cursor) if (c->attributes.reverse != c->attributes.cursor)
background = c->attributes.foreground; background = &c->attributes.foreground;
else else
background = c->attributes.background; background = &c->attributes.background;
/* Blank characters are visible if their background color differs from that /* Blank characters are visible if their background color differs from that
* of the terminal */ * of the terminal */
return background != term->default_char.attributes.background; return guac_terminal_colorcmp(background,
&term->default_char.attributes.background) != 0;
} }

View File

@ -22,6 +22,7 @@
#define _GUAC_TERMINAL_COMMON_H #define _GUAC_TERMINAL_COMMON_H
#include "config.h" #include "config.h"
#include "types.h"
#include <stdbool.h> #include <stdbool.h>

View File

@ -24,6 +24,7 @@
#include "config.h" #include "config.h"
#include "common/surface.h" #include "common/surface.h"
#include "palette.h"
#include "types.h" #include "types.h"
#include <guacamole/client.h> #include <guacamole/client.h>
@ -37,93 +38,6 @@
*/ */
#define GUAC_TERMINAL_MAX_CHAR_WIDTH 2 #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.
*/
extern const guac_terminal_color guac_terminal_palette[16];
/** /**
* All available terminal operations which affect character cells. * All available terminal operations which affect character cells.
*/ */
@ -220,22 +134,24 @@ typedef struct guac_terminal_display {
/** /**
* Default foreground color for all glyphs. * Default foreground color for all glyphs.
*/ */
int default_foreground; guac_terminal_color default_foreground;
/** /**
* Default background color for all glyphs and the terminal itself. * Default background color for all glyphs and the terminal itself.
*/ */
int default_background; guac_terminal_color default_background;
/** /**
* Color of glyphs in copy buffer * The foreground color to be used for the next glyph rendered to the
* terminal.
*/ */
int glyph_foreground; guac_terminal_color glyph_foreground;
/** /**
* Color of glyphs in copy buffer * The background color to be used for the next glyph rendered to the
* terminal.
*/ */
int glyph_background; guac_terminal_color glyph_background;
/** /**
* The surface containing the actual terminal. * The surface containing the actual terminal.
@ -292,7 +208,7 @@ typedef struct guac_terminal_display {
*/ */
guac_terminal_display* guac_terminal_display_alloc(guac_client* client, guac_terminal_display* guac_terminal_display_alloc(guac_client* client,
const char* font_name, int font_size, int dpi, const char* font_name, int font_size, int dpi,
int foreground, int background); guac_terminal_color* foreground, guac_terminal_color* background);
/** /**
* Frees the given display. * Frees the given display.

View File

@ -0,0 +1,193 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUAC_TERMINAL_PALETTE_H
#define GUAC_TERMINAL_PALETTE_H
#include "config.h"
#include <stdint.h>
/**
* 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 index of the first low-intensity color in the 16-color portion of the
* palette.
*/
#define GUAC_TERMINAL_FIRST_DARK 0
/**
* The index of the last low-intensity color in the 16-color portion of the
* palette.
*/
#define GUAC_TERMINAL_LAST_DARK 7
/**
* The index of the first high-intensity color in the 16-color portion of the
* palette.
*/
#define GUAC_TERMINAL_FIRST_INTENSE 8
/**
* The index of the last high-intensity color in the 16-color portion of the
* palette.
*/
#define GUAC_TERMINAL_LAST_INTENSE 15
/**
* The distance between the palette indices of the dark colors (0 through 7)
* and the bright colors (8 - 15) in the 16-color portion of the palette.
*/
#define GUAC_TERMINAL_INTENSE_OFFSET 8
/**
* An RGB color, where each component ranges from 0 to 255.
*/
typedef struct guac_terminal_color {
/**
* The index of this color within the terminal palette, or -1 if the color
* does not exist within the terminal palette.
*/
int palette_index;
/**
* The red component of this color.
*/
uint8_t red;
/**
* The green component of this color.
*/
uint8_t green;
/**
* The blue component of this color.
*/
uint8_t blue;
} guac_terminal_color;
/**
* Compares two colors, returning a negative value if the first color is less
* than the second, a positive value if the first color is greater than the
* second, and zero if the colors are identical. Only the color components are
* compared (not the palette index). The red component is considered the
* highest order component, followed by green, followed by blue.
*
* @param a
* The first color to compare.
*
* @param b
* The second color to compare.
*
* @return
* A negative value if the first color is less than the second, a positive
* value if the first color is greater than the second, and zero if the
* colors are identical.
*/
int guac_terminal_colorcmp(const guac_terminal_color* a,
const guac_terminal_color* b);
/**
* The terminal color palette.
*/
extern const guac_terminal_color guac_terminal_palette[256];
#endif

View File

@ -138,6 +138,18 @@ int guac_terminal_open_pipe_stream(guac_terminal* term, unsigned char c);
*/ */
int guac_terminal_close_pipe_stream(guac_terminal* term, unsigned char c); int guac_terminal_close_pipe_stream(guac_terminal* term, unsigned char c);
/**
* Parses the remainder of xterm's OSC sequence for redefining the terminal
* emulator's palette.
*
* @param term
* The terminal that received the given character of data.
*
* @param c
* The character that was received by the given terminal.
*/
int guac_terminal_xterm_palette(guac_terminal* term, unsigned char c);
/** /**
* Handles the remaining characters of an Operating System Code (OSC) sequence, * Handles the remaining characters of an Operating System Code (OSC) sequence,
* typically initiated with "ESC ]". * typically initiated with "ESC ]".

View File

@ -22,8 +22,10 @@
#define _GUAC_TERMINAL_TYPES_H #define _GUAC_TERMINAL_TYPES_H
#include "config.h" #include "config.h"
#include "palette.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
/** /**
* A character which is not truly a character, but rather part of an * A character which is not truly a character, but rather part of an
@ -34,28 +36,6 @@
*/ */
#define GUAC_CHAR_CONTINUATION -1 #define GUAC_CHAR_CONTINUATION -1
/**
* An RGB color, where each component ranges from 0 to 255.
*/
typedef struct guac_terminal_color {
/**
* The red component of this color.
*/
int red;
/**
* The green component of this color.
*/
int green;
/**
* The blue component of this color.
*/
int blue;
} guac_terminal_color;
/** /**
* Terminal attributes, as can be applied to a single character. * Terminal attributes, as can be applied to a single character.
*/ */
@ -83,14 +63,14 @@ typedef struct guac_terminal_attributes {
bool underscore; bool underscore;
/** /**
* The foreground color of this character, as a palette index. * The foreground color of this character.
*/ */
int foreground; guac_terminal_color foreground;
/** /**
* The background color of this character, as a palette index. * The background color of this character.
*/ */
int background; guac_terminal_color background;
} guac_terminal_attributes; } guac_terminal_attributes;

View File

@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "terminal/char_mappings.h" #include "terminal/char_mappings.h"
#include "terminal/palette.h"
#include "terminal/terminal.h" #include "terminal/terminal.h"
#include "terminal/terminal_handlers.h" #include "terminal/terminal_handlers.h"
#include "terminal/types.h" #include "terminal/types.h"
@ -366,7 +367,8 @@ int guac_terminal_escape(guac_terminal* term, unsigned char c) {
break; break;
default: default:
guac_client_log(term->client, GUAC_LOG_INFO, "Unhandled ESC sequence: %c", c); guac_client_log(term->client, GUAC_LOG_DEBUG,
"Unhandled ESC sequence: %c", c);
term->char_handler = guac_terminal_echo; term->char_handler = guac_terminal_echo;
} }
@ -434,6 +436,144 @@ static bool* __guac_terminal_get_flag(guac_terminal* term, int num, char private
} }
/**
* Parses an xterm SGR sequence specifying the RGB values of a color.
*
* @param argc
* The number of arguments within the argv array.
*
* @param argv
* The SGR arguments to parse, with the first relevant argument the
* red component of the RGB color.
*
* @param color
* The guac_terminal_color structure which should receive the parsed
* color values.
*
* @return
* The number of arguments parsed, or zero if argv does not contain
* enough elements to represent an RGB color.
*/
static int guac_terminal_parse_xterm256_rgb(int argc, const int* argv,
guac_terminal_color* color) {
/* RGB color palette entries require three arguments */
if (argc < 3)
return 0;
/* Read RGB components from arguments */
int red = argv[0];
int green = argv[1];
int blue = argv[2];
/* Ignore if components are out of range */
if ( red < 0 || red > 255
|| green < 0 || green > 255
|| blue < 0 || blue > 255)
return 3;
/* Store RGB components */
color->red = (uint8_t) red;
color->green = (uint8_t) green;
color->blue = (uint8_t) blue;
/* Color is not from the palette */
color->palette_index = -1;
/* Done */
return 3;
}
/**
* Parses an xterm SGR sequence specifying the index of a color within the
* 256-color palette.
*
* @param argc
* The number of arguments within the argv array.
*
* @param argv
* The SGR arguments to parse, with the first relevant argument being
* the index of the color.
*
* @param color
* The guac_terminal_color structure which should receive the parsed
* color values.
*
* @return
* The number of arguments parsed, or zero if the palette index is
* absent.
*/
static int guac_terminal_parse_xterm256_index(int argc, const int* argv,
guac_terminal_color* color) {
/* 256-color palette entries require only one argument */
if (argc < 1)
return 0;
/* Ignore if palette index is out of bounds */
int index = argv[0];
if (index < 0 || index > 255)
return 1;
/* Copy palette entry */
*color = guac_terminal_palette[index];
/* Done */
return 1;
}
/**
* Parses an xterm SGR sequence specifying the index of a color within the
* 256-color palette, or specfying the RGB values of a color. The number of
* arguments required by these sequences varies. If a 256-color sequence is
* recognized, the number of arguments parsed is returned.
*
* @param argc
* The number of arguments within the argv array.
*
* @param argv
* The SGR arguments to parse, with the first relevant argument being
* the first element of the array. In the case of an xterm 256-color
* SGR sequence, the first element here will be either 2, for an
* RGB color, or 5, for a 256-color palette index. All other values
* are invalid and will not be parsed.
*
* @param color
* The guac_terminal_color structure which should receive the parsed
* color values.
*
* @return
* The number of arguments parsed, or zero if argv does not point to
* the first element of an xterm 256-color SGR sequence.
*/
static int guac_terminal_parse_xterm256(int argc, const int* argv,
guac_terminal_color* color) {
/* All 256-color codes must have at least a type */
if (argc < 1)
return 0;
switch (argv[0]) {
/* RGB */
case 2:
return guac_terminal_parse_xterm256_rgb(
argc - 1, &argv[1], color) + 1;
/* Palette index */
case 5:
return guac_terminal_parse_xterm256_index(
argc - 1, &argv[1], color) + 1;
}
/* Invalid type */
return 0;
}
int guac_terminal_csi(guac_terminal* term, unsigned char c) { int guac_terminal_csi(guac_terminal* term, unsigned char c) {
/* CSI function arguments */ /* CSI function arguments */
@ -779,13 +919,30 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
/* Foreground */ /* Foreground */
else if (value >= 30 && value <= 37) else if (value >= 30 && value <= 37)
term->current_attributes.foreground = value - 30;
/* Underscore on, default foreground */
else if (value == 38) {
term->current_attributes.underscore = true;
term->current_attributes.foreground = term->current_attributes.foreground =
term->default_char.attributes.foreground; guac_terminal_palette[value - 30];
/* Underscore on, default foreground OR 256-color
* foreground */
else if (value == 38) {
/* Attempt to set foreground with 256-color entry */
int xterm256_length =
guac_terminal_parse_xterm256(argc - 1, &argv[i + 1],
&term->current_attributes.foreground);
/* If valid 256-color entry, foreground has been set */
if (xterm256_length > 0)
i += xterm256_length;
/* Otherwise interpret as underscore and default
* foreground */
else {
term->current_attributes.underscore = true;
term->current_attributes.foreground =
term->default_char.attributes.foreground;
}
} }
/* Underscore off, default foreground */ /* Underscore off, default foreground */
@ -797,7 +954,13 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
/* Background */ /* Background */
else if (value >= 40 && value <= 47) else if (value >= 40 && value <= 47)
term->current_attributes.background = value - 40; term->current_attributes.background =
guac_terminal_palette[value - 40];
/* 256-color background */
else if (value == 48)
i += guac_terminal_parse_xterm256(argc - 1, &argv[i + 1],
&term->current_attributes.background);
/* Reset background */ /* Reset background */
else if (value == 49) else if (value == 49)
@ -860,11 +1023,11 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
default: default:
if (c != ';') { if (c != ';') {
guac_client_log(term->client, GUAC_LOG_INFO, guac_client_log(term->client, GUAC_LOG_DEBUG,
"Unhandled CSI sequence: %c", c); "Unhandled CSI sequence: %c", c);
for (i=0; i<argc; i++) for (i=0; i<argc; i++)
guac_client_log(term->client, GUAC_LOG_INFO, guac_client_log(term->client, GUAC_LOG_DEBUG,
" -> argv[%i] = %i", i, argv[i]); " -> argv[%i] = %i", i, argv[i]);
} }
@ -993,6 +1156,19 @@ int guac_terminal_close_pipe_stream(guac_terminal* term, unsigned char c) {
} }
int guac_terminal_xterm_palette(guac_terminal* term, unsigned char c) {
/* NOTE: Currently unimplemented. Attempts to set the 256-color palette
* are ignored. */
/* Stop on ECMA-48 ST (String Terminator */
if (c == 0x9C || c == 0x5C || c == 0x07)
term->char_handler = guac_terminal_echo;
return 0;
}
int guac_terminal_osc(guac_terminal* term, unsigned char c) { int guac_terminal_osc(guac_terminal* term, unsigned char c) {
static int operation = 0; static int operation = 0;
@ -1020,6 +1196,10 @@ int guac_terminal_osc(guac_terminal* term, unsigned char c) {
else if (operation == 482203) else if (operation == 482203)
term->char_handler = guac_terminal_close_pipe_stream; term->char_handler = guac_terminal_close_pipe_stream;
/* xterm 256-color palette redefinition */
else if (operation == 4)
term->char_handler = guac_terminal_xterm_palette;
/* Reset parameter for next OSC */ /* Reset parameter for next OSC */
operation = 0; operation = 0;
@ -1031,7 +1211,8 @@ int guac_terminal_osc(guac_terminal* term, unsigned char c) {
/* Stop on unrecognized character */ /* Stop on unrecognized character */
else { else {
guac_client_log(term->client, GUAC_LOG_INFO, "Unexpected character in OSC: 0x%X", c); guac_client_log(term->client, GUAC_LOG_DEBUG,
"Unexpected character in OSC: 0x%X", c);
term->char_handler = guac_terminal_echo; term->char_handler = guac_terminal_echo;
} }