diff --git a/src/terminal/Makefile.am b/src/terminal/Makefile.am index 53bc74d1..b3474605 100644 --- a/src/terminal/Makefile.am +++ b/src/terminal/Makefile.am @@ -27,6 +27,7 @@ noinst_HEADERS = \ terminal/char_mappings.h \ terminal/common.h \ terminal/display.h \ + terminal/palette.h \ terminal/scrollbar.h \ terminal/terminal.h \ terminal/terminal_handlers.h \ @@ -38,6 +39,7 @@ libguac_terminal_la_SOURCES = \ char_mappings.c \ common.c \ display.c \ + palette.c \ scrollbar.c \ terminal.c \ terminal_handlers.c \ diff --git a/src/terminal/display.c b/src/terminal/display.c index 1a0aeb52..cd9f6a6d 100644 --- a/src/terminal/display.c +++ b/src/terminal/display.c @@ -22,6 +22,7 @@ #include "common/surface.h" #include "terminal/common.h" #include "terminal/display.h" +#include "terminal/palette.h" #include "terminal/types.h" #include @@ -36,30 +37,6 @@ #include #include -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. */ @@ -127,24 +104,29 @@ int __guac_terminal_hash_codepoint(int codepoint) { int __guac_terminal_set_colors(guac_terminal_display* display, guac_terminal_attributes* attributes) { - int background, foreground; + const guac_terminal_color* background; + const guac_terminal_color* foreground; /* Handle reverse video */ if (attributes->reverse != attributes->cursor) { - background = attributes->foreground; - foreground = attributes->background; + background = &attributes->foreground; + foreground = &attributes->background; } else { - foreground = attributes->foreground; - background = attributes->background; + foreground = &attributes->foreground; + background = &attributes->background; } /* Handle bold */ - if (attributes->bold && foreground <= 7) - foreground += 8; + if (attributes->bold + && 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_background = background; + display->glyph_foreground = *foreground; + display->glyph_background = *background; return 0; @@ -163,12 +145,10 @@ int __guac_terminal_set(guac_terminal_display* display, int row, int col, int co char utf8[4]; /* Use foreground color */ - const guac_terminal_color* color = - &guac_terminal_palette[display->glyph_foreground]; + const guac_terminal_color* color = &display->glyph_foreground; /* Use background color */ - const guac_terminal_color* background = - &guac_terminal_palette[display->glyph_background]; + const guac_terminal_color* background = &display->glyph_background; cairo_surface_t* surface; 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, const char* font_name, int font_size, int dpi, - int foreground, int background) { + guac_terminal_color* foreground, guac_terminal_color* background) { PangoFontMap* font_map; PangoFont* font; @@ -303,8 +283,8 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client, return NULL; } - display->default_foreground = display->glyph_foreground = foreground; - display->default_background = display->glyph_background = background; + display->default_foreground = display->glyph_foreground = *foreground; + display->default_background = display->glyph_background = *background; /* Calculate character dimensions */ display->char_width = @@ -688,14 +668,11 @@ void __guac_terminal_display_flush_clear(guac_terminal_display* display) { int rect_width, rect_height; /* Color of the rectangle to draw */ - int color; + const guac_terminal_color* color; if (current->character.attributes.reverse != current->character.attributes.cursor) - color = current->character.attributes.foreground; + color = ¤t->character.attributes.foreground; else - color = current->character.attributes.background; - - const guac_terminal_color* guac_color = - &guac_terminal_palette[color]; + color = ¤t->character.attributes.background; /* Current row within a subrect */ guac_terminal_operation* rect_current_row; @@ -709,16 +686,16 @@ void __guac_terminal_display_flush_clear(guac_terminal_display* display) { /* Find width */ for (rect_col=col; rect_colwidth; rect_col++) { - int joining_color; + const guac_terminal_color* joining_color; 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 - joining_color = rect_current->character.attributes.background; + joining_color = &rect_current->character.attributes.background; /* If not identical operation, stop */ if (rect_current->type != GUAC_CHAR_SET || guac_terminal_has_glyph(rect_current->character.value) - || joining_color != color) + || guac_terminal_colorcmp(joining_color, color) != 0) break; /* Next column */ @@ -754,16 +731,16 @@ void __guac_terminal_display_flush_clear(guac_terminal_display* display) { for (rect_col=0; rect_colcharacter.attributes.reverse != rect_current->character.attributes.cursor) - joining_color = rect_current->character.attributes.foreground; + joining_color = &rect_current->character.attributes.foreground; else - joining_color = rect_current->character.attributes.background; + joining_color = &rect_current->character.attributes.background; /* Mark clear operations as NOP */ if (rect_current->type == GUAC_CHAR_SET && !guac_terminal_has_glyph(rect_current->character.value) - && joining_color == color) + && guac_terminal_colorcmp(joining_color, color) == 0) rect_current->type = GUAC_CHAR_NOP; /* Next column */ @@ -783,7 +760,7 @@ void __guac_terminal_display_flush_clear(guac_terminal_display* display) { row * display->char_height, rect_width * display->char_width, rect_height * display->char_height, - guac_color->red, guac_color->green, guac_color->blue, + color->red, color->green, color->blue, 0xFF); } /* end if clear operation */ diff --git a/src/terminal/palette.c b/src/terminal/palette.c new file mode 100644 index 00000000..5c9c3b40 --- /dev/null +++ b/src/terminal/palette.c @@ -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; + +} + diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 758b72d7..711a0fa8 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -24,6 +24,7 @@ #include "terminal/buffer.h" #include "terminal/common.h" #include "terminal/display.h" +#include "terminal/palette.h" #include "terminal/terminal.h" #include "terminal/terminal_handlers.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; /* Get background color */ - const guac_terminal_color* color = - &guac_terminal_palette[display->default_background]; + const guac_terminal_color* color = &display->default_background; /* Reset size */ 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 = { .value = 0, .attributes = { - .foreground = default_foreground, - .background = default_background, + .foreground = guac_terminal_palette[default_foreground], + .background = guac_terminal_palette[default_background], .bold = false, .reverse = false, .underscore = false @@ -326,8 +326,8 @@ guac_terminal* guac_terminal_create(guac_client* client, /* Init display */ term->display = guac_terminal_display_alloc(client, font_name, font_size, dpi, - default_char.attributes.foreground, - default_char.attributes.background); + &default_char.attributes.foreground, + &default_char.attributes.background); /* Fail if display init failed */ if (term->display == NULL) { @@ -875,17 +875,18 @@ static bool guac_terminal_is_visible(guac_terminal* term, if (guac_terminal_has_glyph(c->value)) return true; - int background; + const guac_terminal_color* background; /* Determine actual background color of character */ if (c->attributes.reverse != c->attributes.cursor) - background = c->attributes.foreground; + background = &c->attributes.foreground; else - background = c->attributes.background; + background = &c->attributes.background; /* Blank characters are visible if their background color differs from that * of the terminal */ - return background != term->default_char.attributes.background; + return guac_terminal_colorcmp(background, + &term->default_char.attributes.background) != 0; } diff --git a/src/terminal/terminal/common.h b/src/terminal/terminal/common.h index f7eda619..ad059a87 100644 --- a/src/terminal/terminal/common.h +++ b/src/terminal/terminal/common.h @@ -22,6 +22,7 @@ #define _GUAC_TERMINAL_COMMON_H #include "config.h" +#include "types.h" #include diff --git a/src/terminal/terminal/display.h b/src/terminal/terminal/display.h index 655d1aa0..6397fe53 100644 --- a/src/terminal/terminal/display.h +++ b/src/terminal/terminal/display.h @@ -24,6 +24,7 @@ #include "config.h" #include "common/surface.h" +#include "palette.h" #include "types.h" #include @@ -37,93 +38,6 @@ */ #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. */ @@ -220,22 +134,24 @@ typedef struct guac_terminal_display { /** * Default foreground color for all glyphs. */ - int default_foreground; + guac_terminal_color default_foreground; /** * 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. @@ -292,7 +208,7 @@ typedef struct guac_terminal_display { */ guac_terminal_display* guac_terminal_display_alloc(guac_client* client, 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. diff --git a/src/terminal/terminal/palette.h b/src/terminal/terminal/palette.h new file mode 100644 index 00000000..b18038fb --- /dev/null +++ b/src/terminal/terminal/palette.h @@ -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 + +/** + * 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 + diff --git a/src/terminal/terminal/terminal_handlers.h b/src/terminal/terminal/terminal_handlers.h index cc976862..0a8fdcef 100644 --- a/src/terminal/terminal/terminal_handlers.h +++ b/src/terminal/terminal/terminal_handlers.h @@ -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); +/** + * 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, * typically initiated with "ESC ]". diff --git a/src/terminal/terminal/types.h b/src/terminal/terminal/types.h index ccb862ff..7d3cd537 100644 --- a/src/terminal/terminal/types.h +++ b/src/terminal/terminal/types.h @@ -22,8 +22,10 @@ #define _GUAC_TERMINAL_TYPES_H #include "config.h" +#include "palette.h" #include +#include /** * A character which is not truly a character, but rather part of an @@ -34,28 +36,6 @@ */ #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. */ @@ -83,14 +63,14 @@ typedef struct guac_terminal_attributes { 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; diff --git a/src/terminal/terminal_handlers.c b/src/terminal/terminal_handlers.c index 328400cc..8e83fb11 100644 --- a/src/terminal/terminal_handlers.c +++ b/src/terminal/terminal_handlers.c @@ -20,6 +20,7 @@ #include "config.h" #include "terminal/char_mappings.h" +#include "terminal/palette.h" #include "terminal/terminal.h" #include "terminal/terminal_handlers.h" #include "terminal/types.h" @@ -366,7 +367,8 @@ int guac_terminal_escape(guac_terminal* term, unsigned char c) { break; 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; } @@ -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) { /* CSI function arguments */ @@ -779,13 +919,30 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) { /* Foreground */ 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->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 */ @@ -797,7 +954,13 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) { /* Background */ 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 */ else if (value == 49) @@ -860,11 +1023,11 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) { default: if (c != ';') { - guac_client_log(term->client, GUAC_LOG_INFO, + guac_client_log(term->client, GUAC_LOG_DEBUG, "Unhandled CSI sequence: %c", c); for (i=0; iclient, GUAC_LOG_INFO, + guac_client_log(term->client, GUAC_LOG_DEBUG, " -> 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) { static int operation = 0; @@ -1020,6 +1196,10 @@ int guac_terminal_osc(guac_terminal* term, unsigned char c) { else if (operation == 482203) 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 */ operation = 0; @@ -1031,7 +1211,8 @@ int guac_terminal_osc(guac_terminal* term, unsigned char c) { /* Stop on unrecognized character */ 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; }