GUACAMOLE-871: Merge support for DECTECM private mode sequence (show/hide cursor).

diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c
index b76a6ea..1430b05 100644
--- a/src/terminal/terminal.c
+++ b/src/terminal/terminal.c
@@ -202,6 +202,7 @@
     /* Reset cursor location */
     term->cursor_row = term->visible_cursor_row = term->saved_cursor_row = 0;
     term->cursor_col = term->visible_cursor_col = term->saved_cursor_col = 0;
+    term->cursor_visible = true;
 
     /* Clear scrollback, buffer, and scroll region */
     term->buffer->top = 0;
@@ -777,31 +778,42 @@
 
     guac_terminal_char* guac_char;
 
-    guac_terminal_buffer_row* old_row;
-    guac_terminal_buffer_row* new_row;
+    guac_terminal_buffer_row* row;
 
     /* If no change, done */
-    if (term->visible_cursor_row == term->cursor_row && term->visible_cursor_col == term->cursor_col)
+    if (term->cursor_visible && term->visible_cursor_row == term->cursor_row && term->visible_cursor_col == term->cursor_col)
         return;
 
-    /* Get old and new rows with cursor */
-    new_row = guac_terminal_buffer_get_row(term->buffer, term->cursor_row, term->cursor_col+1);
-    old_row = guac_terminal_buffer_get_row(term->buffer, term->visible_cursor_row, term->visible_cursor_col+1);
+    /* Clear cursor if it was visible */
+    if (term->visible_cursor_row != -1 && term->visible_cursor_col != -1) {
+        /* Get old row with cursor */
+        row = guac_terminal_buffer_get_row(term->buffer, term->visible_cursor_row, term->visible_cursor_col+1);
 
-    /* Clear cursor */
-    guac_char = &(old_row->characters[term->visible_cursor_col]);
-    guac_char->attributes.cursor = false;
-    guac_terminal_display_set_columns(term->display, term->visible_cursor_row + term->scroll_offset,
-            term->visible_cursor_col, term->visible_cursor_col, guac_char);
+        guac_char = &(row->characters[term->visible_cursor_col]);
+        guac_char->attributes.cursor = false;
+        guac_terminal_display_set_columns(term->display, term->visible_cursor_row + term->scroll_offset,
+                term->visible_cursor_col, term->visible_cursor_col, guac_char);
+    }
 
-    /* Set cursor */
-    guac_char = &(new_row->characters[term->cursor_col]);
-    guac_char->attributes.cursor = true;
-    guac_terminal_display_set_columns(term->display, term->cursor_row + term->scroll_offset,
-            term->cursor_col, term->cursor_col, guac_char);
+    /* Set cursor if should be visible */
+    if (term->cursor_visible) {
+        /* Get new row with cursor */
+        row = guac_terminal_buffer_get_row(term->buffer, term->cursor_row, term->cursor_col+1);
 
-    term->visible_cursor_row = term->cursor_row;
-    term->visible_cursor_col = term->cursor_col;
+        guac_char = &(row->characters[term->cursor_col]);
+        guac_char->attributes.cursor = true;
+        guac_terminal_display_set_columns(term->display, term->cursor_row + term->scroll_offset,
+                term->cursor_col, term->cursor_col, guac_char);
+
+        term->visible_cursor_row = term->cursor_row;
+        term->visible_cursor_col = term->cursor_col;
+    }
+
+    /* Otherwise set visible position to a sentinel value */
+    else {
+        term->visible_cursor_row = -1;
+        term->visible_cursor_col = -1;
+    }
 
     return;
 
@@ -1240,7 +1252,8 @@
             /* Update buffer top and cursor row based on shift */
             term->buffer->top += shift_amount;
             term->cursor_row  -= shift_amount;
-            term->visible_cursor_row  -= shift_amount;
+            if (term->visible_cursor_row != -1)
+                term->visible_cursor_row -= shift_amount;
 
             /* Redraw characters within old region */
             __guac_terminal_redraw_rect(term, height - shift_amount, 0, height-1, width-1);
@@ -1274,7 +1287,8 @@
             /* Update buffer top and cursor row based on shift */
             term->buffer->top -= shift_amount;
             term->cursor_row  += shift_amount;
-            term->visible_cursor_row  += shift_amount;
+            if (term->visible_cursor_row != -1)
+                term->visible_cursor_row += shift_amount;
 
             /* If scrolled enough, use scroll to fulfill entire resize */
             if (term->scroll_offset >= shift_amount) {
diff --git a/src/terminal/terminal/terminal.h b/src/terminal/terminal/terminal.h
index 4185837..2d61959 100644
--- a/src/terminal/terminal/terminal.h
+++ b/src/terminal/terminal/terminal.h
@@ -338,12 +338,19 @@
     int cursor_col;
 
     /**
+     * The desired visibility state of the cursor.
+     */
+    bool cursor_visible;
+
+    /**
      * The row of the rendered cursor.
+     * Will be set to -1 if the cursor is not visible.
      */
     int visible_cursor_row;
 
     /**
      * The column of the rendered cursor.
+     * Will be set to -1 if the cursor is not visible.
      */
     int visible_cursor_col;
 
diff --git a/src/terminal/terminal_handlers.c b/src/terminal/terminal_handlers.c
index ec258ff..d406c48 100644
--- a/src/terminal/terminal_handlers.c
+++ b/src/terminal/terminal_handlers.c
@@ -432,6 +432,7 @@
     if (private_mode == '?') {
         switch (num) {
             case 1:  return &(term->application_cursor_keys); /* DECCKM */
+            case 25: return &(term->cursor_visible); /* DECTECM */
         }
     }