GUACAMOLE-148: Merge terminal scrolling fix.

This commit is contained in:
James Muehlner 2017-01-29 12:12:00 -08:00
commit 6695da4b16
2 changed files with 124 additions and 112 deletions

View File

@ -259,12 +259,18 @@ struct guac_terminal {
int scroll_end; int scroll_end;
/** /**
* The current row location of the cursor. * The current row location of the cursor. Note that while most terminal
* operations will clip the cursor location within the bounds of the
* terminal, this is not guaranteed.
*/ */
int cursor_row; int cursor_row;
/** /**
* The current column location of the cursor. * The current column location of the cursor. Note that while most
* terminal operations will clip the cursor location within the bounds
* of the terminal, this is not guaranteed. There are times when the
* cursor is legitimately outside the terminal bounds (such as when the
* end of a line is reached, but it is not yet necessary to scroll up).
*/ */
int cursor_col; int cursor_col;

View File

@ -47,6 +47,81 @@
*/ */
#define GUAC_TERMINAL_OK "\x1B[0n" #define GUAC_TERMINAL_OK "\x1B[0n"
/**
* Advances the cursor to the next row, scrolling if the cursor would otherwise
* leave the scrolling region. If the cursor is already outside the scrolling
* region, the cursor is prevented from leaving the terminal bounds.
*
* @param term
* The guac_terminal whose cursor should be advanced to the next row.
*/
static void guac_terminal_linefeed(guac_terminal* term) {
/* Scroll up if necessary */
if (term->cursor_row == term->scroll_end)
guac_terminal_scroll_up(term, term->scroll_start,
term->scroll_end, 1);
/* Otherwise, just advance to next row if space remains */
else if (term->cursor_row < term->term_height - 1)
term->cursor_row++;
}
/**
* Moves the cursor backward to the previous row, scrolling if the cursor would
* otherwise leave the scrolling region. If the cursor is already outside the
* scrolling region, the cursor is prevented from leaving the terminal bounds.
*
* @param term
* The guac_terminal whose cursor should be moved backward by one row.
*/
static void guac_terminal_reverse_linefeed(guac_terminal* term) {
/* Scroll down if necessary */
if (term->cursor_row == term->scroll_start)
guac_terminal_scroll_down(term, term->scroll_start,
term->scroll_end, 1);
/* Otherwise, move back one row if space remains */
else if (term->cursor_row > 0)
term->cursor_row--;
}
/**
* Sets the position of the cursor without exceeding terminal bounds. Values
* which are out of bounds will be shifted to the nearest legal boundary.
*
* @param term
* The guac_terminal whose cursor position is being set.
*
* @param row
* The desired new row position.
*
* @param col
* The desired new column position.
*/
static void guac_terminal_move_cursor(guac_terminal* term, int row, int col) {
/* Ensure cursor row is within terminal bounds */
if (row >= term->term_height)
row = term->term_height - 1;
else if (row < 0)
row = 0;
/* Ensure cursor column is within terminal bounds */
if (col >= term->term_width)
col = term->term_width - 1;
else if (col < 0)
col = 0;
/* Update cursor position */
term->cursor_row = row;
term->cursor_col = col;
}
int guac_terminal_echo(guac_terminal* term, unsigned char c) { int guac_terminal_echo(guac_terminal* term, unsigned char c) {
int width; int width;
@ -121,30 +196,23 @@ int guac_terminal_echo(guac_terminal* term, unsigned char c) {
/* Backspace */ /* Backspace */
case 0x08: case 0x08:
if (term->cursor_col >= 1) guac_terminal_move_cursor(term, term->cursor_row,
term->cursor_col--; term->cursor_col - 1);
break; break;
/* Tab */ /* Tab */
case 0x09: case 0x09:
term->cursor_col = guac_terminal_next_tab(term, term->cursor_col); guac_terminal_move_cursor(term, term->cursor_row,
guac_terminal_next_tab(term, term->cursor_col));
break; break;
/* Line feed / VT / FF */ /* Line feed / VT / FF */
case '\n': case '\n':
case 0x0B: /* VT */ case 0x0B: /* VT */
case 0x0C: /* FF */ case 0x0C: /* FF */
term->cursor_row++;
/* Scroll up if necessary */ /* Advance to next row */
if (term->cursor_row > term->scroll_end) { guac_terminal_linefeed(term);
term->cursor_row = term->scroll_end;
/* Scroll up by one row */
guac_terminal_scroll_up(term, term->scroll_start,
term->scroll_end, 1);
}
/* If automatic carriage return, fall through to CR handler */ /* If automatic carriage return, fall through to CR handler */
if (!term->automatic_carriage_return) if (!term->automatic_carriage_return)
@ -152,7 +220,7 @@ int guac_terminal_echo(guac_terminal* term, unsigned char c) {
/* Carriage return */ /* Carriage return */
case '\r': case '\r':
term->cursor_col = 0; guac_terminal_move_cursor(term, term->cursor_row, 0);
break; break;
/* SO (activates character set G1) */ /* SO (activates character set G1) */
@ -193,17 +261,7 @@ int guac_terminal_echo(guac_terminal* term, unsigned char c) {
/* Wrap if necessary */ /* Wrap if necessary */
if (term->cursor_col >= term->term_width) { if (term->cursor_col >= term->term_width) {
term->cursor_col = 0; term->cursor_col = 0;
term->cursor_row++; guac_terminal_linefeed(term);
}
/* Scroll up if necessary */
if (term->cursor_row > term->scroll_end) {
term->cursor_row = term->scroll_end;
/* Scroll up by one row */
guac_terminal_scroll_up(term, term->scroll_start,
term->scroll_end, 1);
} }
/* If insert mode, shift other characters right by 1 */ /* If insert mode, shift other characters right by 1 */
@ -264,50 +322,23 @@ int guac_terminal_escape(guac_terminal* term, unsigned char c) {
/* Restore Cursor (DECRC) */ /* Restore Cursor (DECRC) */
case '8': case '8':
guac_terminal_move_cursor(term,
term->cursor_row = term->saved_cursor_row; term->saved_cursor_row,
if (term->cursor_row >= term->term_height) term->saved_cursor_col);
term->cursor_row = term->term_height - 1;
term->cursor_col = term->saved_cursor_col;
if (term->cursor_col >= term->term_width)
term->cursor_col = term->term_width - 1;
term->char_handler = guac_terminal_echo; term->char_handler = guac_terminal_echo;
break; break;
/* Index (IND) */ /* Index (IND) */
case 'D': case 'D':
term->cursor_row++; guac_terminal_linefeed(term);
/* Scroll up if necessary */
if (term->cursor_row > term->scroll_end) {
term->cursor_row = term->scroll_end;
/* Scroll up by one row */
guac_terminal_scroll_up(term, term->scroll_start,
term->scroll_end, 1);
}
term->char_handler = guac_terminal_echo; term->char_handler = guac_terminal_echo;
break; break;
/* Next Line (NEL) */ /* Next Line (NEL) */
case 'E': case 'E':
term->cursor_col = 0; guac_terminal_move_cursor(term, term->cursor_row, 0);
term->cursor_row++; guac_terminal_linefeed(term);
/* Scroll up if necessary */
if (term->cursor_row > term->scroll_end) {
term->cursor_row = term->scroll_end;
/* Scroll up by one row */
guac_terminal_scroll_up(term, term->scroll_start,
term->scroll_end, 1);
}
term->char_handler = guac_terminal_echo; term->char_handler = guac_terminal_echo;
break; break;
@ -319,19 +350,7 @@ int guac_terminal_escape(guac_terminal* term, unsigned char c) {
/* Reverse Linefeed */ /* Reverse Linefeed */
case 'M': case 'M':
guac_terminal_reverse_linefeed(term);
term->cursor_row--;
/* Scroll down if necessary */
if (term->cursor_row < term->scroll_start) {
term->cursor_row = term->scroll_start;
/* Scroll down by one row */
guac_terminal_scroll_down(term, term->scroll_start,
term->scroll_end, 1);
}
term->char_handler = guac_terminal_echo; term->char_handler = guac_terminal_echo;
break; break;
@ -484,9 +503,9 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
if (amount == 0) amount = 1; if (amount == 0) amount = 1;
/* Move cursor */ /* Move cursor */
term->cursor_row -= amount; guac_terminal_move_cursor(term,
if (term->cursor_row < 0) term->cursor_row - amount,
term->cursor_row = 0; term->cursor_col);
break; break;
@ -499,9 +518,9 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
if (amount == 0) amount = 1; if (amount == 0) amount = 1;
/* Move cursor */ /* Move cursor */
term->cursor_row += amount; guac_terminal_move_cursor(term,
if (term->cursor_row >= term->term_height) term->cursor_row + amount,
term->cursor_row = term->term_height - 1; term->cursor_col);
break; break;
@ -514,9 +533,9 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
if (amount == 0) amount = 1; if (amount == 0) amount = 1;
/* Move cursor */ /* Move cursor */
term->cursor_col += amount; guac_terminal_move_cursor(term,
if (term->cursor_col >= term->term_width) term->cursor_row,
term->cursor_col = term->term_width - 1; term->cursor_col + amount);
break; break;
@ -528,9 +547,9 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
if (amount == 0) amount = 1; if (amount == 0) amount = 1;
/* Move cursor */ /* Move cursor */
term->cursor_col -= amount; guac_terminal_move_cursor(term,
if (term->cursor_col < 0) term->cursor_row,
term->cursor_col = 0; term->cursor_col - amount);
break; break;
@ -541,13 +560,10 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
amount = argv[0]; amount = argv[0];
if (amount == 0) amount = 1; if (amount == 0) amount = 1;
/* Move cursor */ /* Move cursor down, reset to column 1 */
term->cursor_row += amount; guac_terminal_move_cursor(term,
if (term->cursor_row >= term->term_height) term->cursor_row + amount,
term->cursor_row = term->term_height - 1; 0);
/* Reset to column 1 */
term->cursor_col = 0;
break; break;
@ -558,13 +574,10 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
amount = argv[0]; amount = argv[0];
if (amount == 0) amount = 1; if (amount == 0) amount = 1;
/* Move cursor */ /* Move cursor up , reset to column 1 */
term->cursor_row -= amount; guac_terminal_move_cursor(term,
if (term->cursor_row < 0) term->cursor_row - amount,
term->cursor_row = 0; 0);
/* Reset to column 1 */
term->cursor_col = 0;
break; break;
@ -572,7 +585,7 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
case '`': case '`':
case 'G': case 'G':
col = argv[0]; if (col != 0) col--; col = argv[0]; if (col != 0) col--;
term->cursor_col = col; guac_terminal_move_cursor(term, term->cursor_row, col);
break; break;
/* H: Move cursor */ /* H: Move cursor */
@ -582,8 +595,7 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
row = argv[0]; if (row != 0) row--; row = argv[0]; if (row != 0) row--;
col = argv[1]; if (col != 0) col--; col = argv[1]; if (col != 0) col--;
term->cursor_row = row; guac_terminal_move_cursor(term, row, col);
term->cursor_col = col;
break; break;
/* J: Erase display */ /* J: Erase display */
@ -694,7 +706,7 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
/* d: Move cursor, current col */ /* d: Move cursor, current col */
case 'd': case 'd':
row = argv[0]; if (row != 0) row--; row = argv[0]; if (row != 0) row--;
term->cursor_row = row; guac_terminal_move_cursor(term, row, term->cursor_col);
break; break;
/* g: Clear tab */ /* g: Clear tab */
@ -839,15 +851,9 @@ int guac_terminal_csi(guac_terminal* term, unsigned char c) {
/* Restore Cursor */ /* Restore Cursor */
case 'u': case 'u':
guac_terminal_move_cursor(term,
term->cursor_row = term->saved_cursor_row; term->saved_cursor_row,
if (term->cursor_row >= term->term_height) term->saved_cursor_col);
term->cursor_row = term->term_height - 1;
term->cursor_col = term->saved_cursor_col;
if (term->cursor_col >= term->term_width)
term->cursor_col = term->term_width - 1;
break; break;
/* Warn of unhandled codes */ /* Warn of unhandled codes */