diff --git a/protocols/ssh/include/ssh_terminal.h b/protocols/ssh/include/ssh_terminal.h index bf0d020f..7c9b7f4a 100644 --- a/protocols/ssh/include/ssh_terminal.h +++ b/protocols/ssh/include/ssh_terminal.h @@ -79,5 +79,18 @@ void ssh_guac_terminal_free(ssh_guac_terminal* term); int ssh_guac_terminal_write(ssh_guac_terminal* term, const char* c, int size); int ssh_guac_terminal_send_glyph(ssh_guac_terminal* term, int row, int col, char c); +int ssh_guac_terminal_copy(ssh_guac_terminal* term, + int src_row, int src_col, int rows, int cols, + int dst_row, int dst_col); +int ssh_guac_terminal_clear(ssh_guac_terminal* term, + int row, int col, int rows, int cols); + +int ssh_guac_terminal_scroll_up(ssh_guac_terminal* term, + int start_row, int end_row, int amount); + +int ssh_guac_terminal_clear_range(ssh_guac_terminal* term, + int start_row, int start_col, + int end_row, int end_col); + #endif diff --git a/protocols/ssh/src/ssh_terminal.c b/protocols/ssh/src/ssh_terminal.c index 99aa273c..6ed440ec 100644 --- a/protocols/ssh/src/ssh_terminal.c +++ b/protocols/ssh/src/ssh_terminal.c @@ -173,3 +173,102 @@ int ssh_guac_terminal_write(ssh_guac_terminal* term, const char* c, int size) { } +int ssh_guac_terminal_copy(ssh_guac_terminal* term, + int src_row, int src_col, int rows, int cols, + int dst_row, int dst_col) { + + GUACIO* io = term->client->io; + + /* Send copy instruction */ + return guac_send_copy(io, + + GUAC_DEFAULT_LAYER, + src_col * term->char_width, src_row * term->char_height, + cols * term->char_width, rows * term->char_height, + + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + dst_col * term->char_width, dst_row * term->char_height); + +} + + +int ssh_guac_terminal_clear(ssh_guac_terminal* term, + int row, int col, int rows, int cols) { + + GUACIO* io = term->client->io; + + /* Fill with background */ + return guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + + col * term->char_width, row * term->char_height, + cols * term->char_width, rows * term->char_height, + + /* Background */ + 0, 0, 0, 255); + +} + +int ssh_guac_terminal_scroll_up(ssh_guac_terminal* term, + int start_row, int end_row, int amount) { + + /* Calculate height of scroll region */ + int height = end_row - start_row + 1; + + return + + /* Move rows within scroll region up by the given amount */ + ssh_guac_terminal_copy(term, + start_row + amount, 0, + height - amount, term->term_width, + start_row, 0) + + /* Fill new rows with background */ + || ssh_guac_terminal_clear(term, + end_row - amount + 1, 0, amount, term->term_width); + +} + + +int ssh_guac_terminal_clear_range(ssh_guac_terminal* term, + int start_row, int start_col, + int end_row, int end_col) { + + /* If not at far left, must clear sub-region to far right */ + if (start_col > 0) { + + /* Clear from start_col to far right */ + if (ssh_guac_terminal_clear(term, + start_row, start_col, 1, term->term_width - start_col)) + return 1; + + /* One less row to clear */ + start_row++; + } + + /* If not at far right, must clear sub-region to far left */ + if (end_col < term->term_width - 1) { + + /* Clear from far left to end_col */ + if (ssh_guac_terminal_clear(term, + end_row, 0, 1, end_col + 1)) + return 1; + + /* One less row to clear */ + end_row--; + + } + + /* Remaining region now guaranteed rectangular. Clear, if possible */ + if (start_row <= end_row) { + + if (ssh_guac_terminal_clear(term, + start_row, 0, end_row - start_row + 1, term->term_width)) + return 1; + + } + + return 0; + +} + diff --git a/protocols/ssh/src/ssh_terminal_handlers.c b/protocols/ssh/src/ssh_terminal_handlers.c index b86f85d1..532d51d7 100644 --- a/protocols/ssh/src/ssh_terminal_handlers.c +++ b/protocols/ssh/src/ssh_terminal_handlers.c @@ -42,17 +42,12 @@ #include #include -#include -#include -#include #include "ssh_terminal.h" #include "ssh_terminal_handlers.h" int ssh_guac_terminal_echo(ssh_guac_terminal* term, char c) { - GUACIO* io = term->client->io; - /* Wrap if necessary */ if (term->cursor_col >= term->term_width) { term->cursor_col = 0; @@ -62,21 +57,9 @@ int ssh_guac_terminal_echo(ssh_guac_terminal* term, char c) { /* Scroll up if necessary */ if (term->cursor_row >= term->term_height) { term->cursor_row = term->term_height - 1; - - /* Copy screen up by one row */ - guac_send_copy(io, - GUAC_DEFAULT_LAYER, 0, term->char_height, - term->char_width * term->term_width, - term->char_height * (term->term_height - 1), - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, 0, 0); - /* Fill bottom row with background */ - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, term->char_height * (term->term_height - 1), - term->char_width * term->term_width, - term->char_height * term->term_height, - 0, 0, 0, 255); + /* Scroll up by one row */ + ssh_guac_terminal_scroll_up(term, 0, term->term_height - 1, 1); } @@ -155,8 +138,6 @@ int ssh_guac_terminal_charset(ssh_guac_terminal* term, char c) { int ssh_guac_terminal_csi(ssh_guac_terminal* term, char c) { - GUACIO* io = term->client->io; - /* CSI function arguments */ static int argc = 0; static int argv[16]; @@ -204,67 +185,23 @@ int ssh_guac_terminal_csi(ssh_guac_terminal* term, char c) { /* J: Erase display */ case 'J': - + /* Erase from cursor to end of display */ - if (argv[0] == 0) { - - /* Until end of line */ - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - term->cursor_col * term->char_width, - term->cursor_row * term->char_height, - (term->term_width - term->cursor_col) * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - - /* Until end of display */ - if (term->cursor_row < term->term_height - 1) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - (term->cursor_row+1) * term->char_height, - term->term_width * term->char_width, - term->term_height * term->char_height, - 0, 0, 0, 255); /* Background color */ - } - - } + if (argv[0] == 0) + ssh_guac_terminal_clear_range(term, + term->cursor_row, term->cursor_col, + term->term_height-1, term->term_width-1); /* Erase from start to cursor */ - else if (argv[0] == 1) { - - /* Until start of line */ - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - term->cursor_row * term->char_height, - term->cursor_col * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - - /* From start */ - if (term->cursor_row >= 1) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - 0, - term->term_width * term->char_width, - (term->cursor_row-1) * term->char_height, - 0, 0, 0, 255); /* Background color */ - } - - } + else if (argv[0] == 1) + ssh_guac_terminal_clear_range(term, + 0, 0, + term->cursor_row, term->cursor_col); /* Entire screen */ - else if (argv[0] == 2) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - 0, - term->term_width * term->char_width, - term->term_height * term->char_height, - 0, 0, 0, 255); /* Background color */ - } + else if (argv[0] == 2) + ssh_guac_terminal_clear(term, + 0, 0, term->term_height, term->term_width); break; @@ -272,37 +209,22 @@ int ssh_guac_terminal_csi(ssh_guac_terminal* term, char c) { case 'K': /* Erase from cursor to end of line */ - if (argv[0] == 0) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - term->cursor_col * term->char_width, - term->cursor_row * term->char_height, - (term->term_width - term->cursor_col) * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - } + if (argv[0] == 0) + ssh_guac_terminal_clear(term, + term->cursor_row, term->cursor_col, + 1, term->term_width - term->cursor_col); /* Erase from start to cursor */ - else if (argv[0] == 1) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - term->cursor_row * term->char_height, - term->cursor_col * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - } + else if (argv[0] == 1) + ssh_guac_terminal_clear(term, + term->cursor_row, 0, + 1, term->cursor_col + 1); /* Erase line */ - else if (argv[0] == 2) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - term->cursor_row * term->char_height, - term->term_width * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - } + else if (argv[0] == 2) + ssh_guac_terminal_clear(term, + term->cursor_row, 0, + 1, term->term_width); break;