GUACAMOLE-573: Allow text selection to be expanded using Shift (fixes 
GUACAMOLE-191).


Project: http://git-wip-us.apache.org/repos/asf/guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-server/commit/6f08ef2a
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-server/tree/6f08ef2a
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-server/diff/6f08ef2a

Branch: refs/heads/master
Commit: 6f08ef2a07b8f908cc0ce8a9f82f846f3b73a7cd
Parents: c0d3238
Author: Michael Jumper <mjum...@apache.org>
Authored: Sat Jun 16 22:50:20 2018 -0700
Committer: Michael Jumper <mjum...@apache.org>
Committed: Sun Jun 17 00:01:47 2018 -0700

----------------------------------------------------------------------
 src/terminal/display.c           | 102 ++++----------
 src/terminal/select.c            | 255 +++++++++++++++++++++++++++++-----
 src/terminal/terminal.c          |  49 ++++---
 src/terminal/terminal/display.h  |  18 +--
 src/terminal/terminal/select.h   |  97 +++++++++++++
 src/terminal/terminal/terminal.h |  10 +-
 6 files changed, 391 insertions(+), 140 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/6f08ef2a/src/terminal/display.c
----------------------------------------------------------------------
diff --git a/src/terminal/display.c b/src/terminal/display.c
index 9391ec1..c4c7471 100644
--- a/src/terminal/display.c
+++ b/src/terminal/display.c
@@ -37,54 +37,6 @@
 #include <guacamole/socket.h>
 #include <pango/pangocairo.h>
 
-/**
- * Clears the currently-selected region, removing the highlight.
- */
-static void __guac_terminal_display_clear_select(guac_terminal_display* 
display) {
-
-    guac_socket* socket = display->client->socket;
-    guac_layer* select_layer = display->select_layer;
-
-    guac_protocol_send_rect(socket, select_layer, 0, 0, 1, 1);
-    guac_protocol_send_cfill(socket, GUAC_COMP_SRC, select_layer,
-            0x00, 0x00, 0x00, 0x00);
-
-    guac_client_end_frame(display->client);
-    guac_socket_flush(socket);
-
-    /* Text is no longer selected */
-    display->text_selected =
-    display->selection_committed = false;
-
-}
-
-/**
- * Returns whether at least one character within the given range is selected.
- */
-static bool __guac_terminal_display_selected_contains(guac_terminal_display* 
display,
-        int start_row, int start_column, int end_row, int end_column) {
-
-    /* If test range starts after highlight ends, does not intersect */
-    if (start_row > display->selection_end_row)
-        return false;
-
-    if (start_row == display->selection_end_row
-            && start_column > display->selection_end_column)
-        return false;
-
-    /* If test range ends before highlight starts, does not intersect */
-    if (end_row < display->selection_start_row)
-        return false;
-
-    if (end_row == display->selection_start_row
-            && end_column < display->selection_start_column)
-        return false;
-
-    /* Otherwise, does intersect */
-    return true;
-
-}
-
 /* Maps any codepoint onto a number between 0 and 511 inclusive */
 int __guac_terminal_hash_codepoint(int codepoint) {
 
@@ -310,8 +262,7 @@ guac_terminal_display* 
guac_terminal_display_alloc(guac_client* client,
     display->operations = NULL;
 
     /* Initially nothing selected */
-    display->text_selected =
-    display->selection_committed = false;
+    display->text_selected = false;
 
     return display;
 
@@ -413,11 +364,6 @@ void 
guac_terminal_display_copy_columns(guac_terminal_display* display, int row,
 
     }
 
-    /* If selection visible and committed, clear if update touches selection */
-    if (display->text_selected && display->selection_committed &&
-        __guac_terminal_display_selected_contains(display, row, start_column, 
row, end_column))
-            __guac_terminal_display_clear_select(display);
-
 }
 
 void guac_terminal_display_copy_rows(guac_terminal_display* display,
@@ -463,11 +409,6 @@ void 
guac_terminal_display_copy_rows(guac_terminal_display* display,
 
     }
 
-    /* If selection visible and committed, clear if update touches selection */
-    if (display->text_selected && display->selection_committed &&
-        __guac_terminal_display_selected_contains(display, start_row, 0, 
end_row, display->width - 1))
-            __guac_terminal_display_clear_select(display);
-
 }
 
 void guac_terminal_display_set_columns(guac_terminal_display* display, int row,
@@ -502,11 +443,6 @@ void 
guac_terminal_display_set_columns(guac_terminal_display* display, int row,
 
     }
 
-    /* If selection visible and committed, clear if update touches selection */
-    if (display->text_selected && display->selection_committed &&
-        __guac_terminal_display_selected_contains(display, row, start_column, 
row, end_column))
-            __guac_terminal_display_clear_select(display);
-
 }
 
 void guac_terminal_display_resize(guac_terminal_display* display, int width, 
int height) {
@@ -570,10 +506,6 @@ void guac_terminal_display_resize(guac_terminal_display* 
display, int width, int
             display->char_width  * width,
             display->char_height * height);
 
-    /* If selection visible and committed, clear */
-    if (display->text_selected && display->selection_committed)
-        __guac_terminal_display_clear_select(display);
-
 }
 
 void __guac_terminal_display_flush_copy(guac_terminal_display* display) {
@@ -899,16 +831,20 @@ void guac_terminal_display_dup(guac_terminal_display* 
display, guac_user* user,
 
 }
 
-void guac_terminal_display_commit_select(guac_terminal_display* display) {
-    display->selection_committed = true;
-}
-
 void guac_terminal_display_select(guac_terminal_display* display,
         int start_row, int start_col, int end_row, int end_col) {
 
     guac_socket* socket = display->client->socket;
     guac_layer* select_layer = display->select_layer;
 
+    /* Do nothing if selection is unchanged */
+    if (display->text_selected
+            && display->selection_start_row    == start_row
+            && display->selection_start_column == start_col
+            && display->selection_end_row      == end_row
+            && display->selection_end_column   == end_col)
+        return;
+
     /* Text is now selected */
     display->text_selected = true;
 
@@ -989,8 +925,24 @@ void guac_terminal_display_select(guac_terminal_display* 
display,
     guac_protocol_send_cfill(socket, GUAC_COMP_SRC, select_layer,
             0x00, 0x80, 0xFF, 0x60);
 
-    guac_client_end_frame(display->client);
-    guac_socket_flush(socket);
+}
+
+void guac_terminal_display_clear_select(guac_terminal_display* display) {
+
+    /* Do nothing if nothing is selected */
+    if (!display->text_selected)
+        return;
+
+    guac_socket* socket = display->client->socket;
+    guac_layer* select_layer = display->select_layer;
+
+    guac_protocol_send_rect(socket, select_layer, 0, 0, 1, 1);
+    guac_protocol_send_cfill(socket, GUAC_COMP_SRC, select_layer,
+            0x00, 0x00, 0x00, 0x00);
+
+    /* Text is no longer selected */
+    display->text_selected = false;
 
 }
 
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/6f08ef2a/src/terminal/select.c
----------------------------------------------------------------------
diff --git a/src/terminal/select.c b/src/terminal/select.c
index ad7f5ac..69bb0bc 100644
--- a/src/terminal/select.c
+++ b/src/terminal/select.c
@@ -30,21 +30,93 @@
 #include <guacamole/socket.h>
 #include <guacamole/unicode.h>
 
+#include <stdbool.h>
+
+/**
+ * Returns the coordinates for the currently-selected range of text within the
+ * given terminal, normalized such that the start coordinate is before the end
+ * coordinate and the end coordinate takes into account character width. If no
+ * text is currently selected, the behavior of this function is undefined.
+ *
+ * @param terminal
+ *     The guac_terminal instance whose selected text coordinates should be
+ *     retrieved in normalized form.
+ *
+ * @param start_row
+ *     A pointer to an int which should receive the row number of the first
+ *     character of text selected within the terminal, where the first
+ *     (top-most) row in the terminal is row 0. Rows within the scrollback
+ *     buffer (above the top-most row of the terminal) will be negative.
+ *
+ * @param start_col
+ *     A pointer to an int which should receive the column number of the first
+ *     character of text selected within terminal, where 0 is the first
+ *     (left-most) column within the row.
+ *
+ * @param end_row
+ *     A pointer to an int which should receive the row number of the last
+ *     character of text selected within the terminal, where the first
+ *     (top-most) row in the terminal is row 0. Rows within the scrollback
+ *     buffer (above the top-most row of the terminal) will be negative.
+ *
+ * @param end_col
+ *     A pointer to an int which should receive the column number of the first
+ *     character of text selected within terminal, taking into account the
+ *     width of that character, where 0 is the first (left-most) column within
+ *     the row.
+ */
+static void guac_terminal_select_normalized_range(guac_terminal* terminal,
+        int* start_row, int* start_col, int* end_row, int* end_col) {
+
+    /* Pass through start/end coordinates if they are already in the expected
+     * order, adjusting only for final character width */
+    if (terminal->selection_start_row < terminal->selection_end_row
+        || (terminal->selection_start_row == terminal->selection_end_row
+            && terminal->selection_start_column < 
terminal->selection_end_column)) {
+
+        *start_row = terminal->selection_start_row;
+        *start_col = terminal->selection_start_column;
+        *end_row   = terminal->selection_end_row;
+        *end_col   = terminal->selection_end_column + 
terminal->selection_end_width - 1;
+
+    }
+
+    /* Coordinates must otherwise be swapped in addition to adjusting for
+     * final character width */
+    else {
+        *end_row   = terminal->selection_start_row;
+        *end_col   = terminal->selection_start_column + 
terminal->selection_start_width - 1;
+        *start_row = terminal->selection_end_row;
+        *start_col = terminal->selection_end_column;
+    }
+
+}
+
 void guac_terminal_select_redraw(guac_terminal* terminal) {
 
-    int start_row = terminal->selection_start_row + terminal->scroll_offset;
-    int start_column = terminal->selection_start_column;
+    /* Update the selected region of the display if text is currently
+     * selected */
+    if (terminal->text_selected) {
 
-    int end_row = terminal->selection_end_row + terminal->scroll_offset;
-    int end_column = terminal->selection_end_column;
+        int start_row = terminal->selection_start_row + 
terminal->scroll_offset;
+        int start_column = terminal->selection_start_column;
 
-    /* Update start/end columns to include character width */
-    if (start_row > end_row || (start_row == end_row && start_column > 
end_column))
-        start_column += terminal->selection_start_width - 1;
-    else
-        end_column += terminal->selection_end_width - 1;
+        int end_row = terminal->selection_end_row + terminal->scroll_offset;
+        int end_column = terminal->selection_end_column;
+
+        /* Update start/end columns to include character width */
+        if (start_row > end_row || (start_row == end_row && start_column > 
end_column))
+            start_column += terminal->selection_start_width - 1;
+        else
+            end_column += terminal->selection_end_width - 1;
 
-    guac_terminal_display_select(terminal->display, start_row, start_column, 
end_row, end_column);
+        guac_terminal_display_select(terminal->display, start_row, 
start_column, end_row, end_column);
+
+    }
+
+    /* Clear the display selection if no text is currently selected */
+    else
+        guac_terminal_display_clear_select(terminal->display);
 
 }
 
@@ -52,8 +124,28 @@ void guac_terminal_select_redraw(guac_terminal* terminal) {
  * Locates the beginning of the character at the given row and column, updating
  * the column to the starting column of that character. The width, if 
available,
  * is returned. If the character has no defined width, 1 is returned.
+ *
+ * @param terminal
+ *     The guac_terminal in which the character should be located.
+ *
+ * @param row
+ *     The row number of the desired character, where the first (top-most) row
+ *     in the terminal is row 0. Rows within the scrollback buffer (above the
+ *     top-most row of the terminal) will be negative.
+ *
+ * @param column
+ *     A pointer to an int containing the column number of the desired
+ *     character, where 0 is the first (left-most) column within the row. If
+ *     the character is a multi-column character, the value of this int will be
+ *     adjusted as necessary such that it contains the column number of the
+ *     first column containing the character.
+ *
+ * @return
+ *     The width of the specified character, in columns, or 1 if the character
+ *     has no defined width.
  */
-static int __guac_terminal_find_char(guac_terminal* terminal, int row, int* 
column) {
+static int guac_terminal_find_char(guac_terminal* terminal,
+        int row, int* column) {
 
     int start_column = *column;
 
@@ -82,7 +174,7 @@ static int __guac_terminal_find_char(guac_terminal* 
terminal, int row, int* colu
 
 void guac_terminal_select_start(guac_terminal* terminal, int row, int column) {
 
-    int width = __guac_terminal_find_char(terminal, row, &column);
+    int width = guac_terminal_find_char(terminal, row, &column);
 
     terminal->selection_start_row =
     terminal->selection_end_row   = row;
@@ -93,9 +185,9 @@ void guac_terminal_select_start(guac_terminal* terminal, int 
row, int column) {
     terminal->selection_start_width =
     terminal->selection_end_width   = width;
 
-    terminal->text_selected = true;
-
-    guac_terminal_select_redraw(terminal);
+    terminal->text_selected = false;
+    terminal->selection_committed = false;
+    guac_terminal_notify(terminal);
 
 }
 
@@ -106,17 +198,59 @@ void guac_terminal_select_update(guac_terminal* terminal, 
int row, int column) {
         || column <  terminal->selection_end_column
         || column >= terminal->selection_end_column + 
terminal->selection_end_width) {
 
-        int width = __guac_terminal_find_char(terminal, row, &column);
+        int width = guac_terminal_find_char(terminal, row, &column);
 
         terminal->selection_end_row = row;
         terminal->selection_end_column = column;
         terminal->selection_end_width = width;
+        terminal->text_selected = true;
+
+        guac_terminal_notify(terminal);
 
-        guac_terminal_select_redraw(terminal);
     }
 
 }
 
+void guac_terminal_select_resume(guac_terminal* terminal, int row, int column) 
{
+
+    int selection_start_row;
+    int selection_start_column;
+    int selection_end_row;
+    int selection_end_column;
+
+    /* No need to test coordinates if no text is selected at all */
+    if (!terminal->text_selected)
+        return;
+
+    /* Use normalized coordinates for sake of simple comparison */
+    guac_terminal_select_normalized_range(terminal,
+            &selection_start_row, &selection_start_column,
+            &selection_end_row, &selection_end_column);
+
+    /* Prefer to expand from start, such that attempting to resume a selection
+     * within the existing selection preserves the top-most portion of the
+     * selection */
+    if (row > selection_start_row ||
+            (row == selection_start_row && column > selection_start_column)) {
+        terminal->selection_start_row = selection_start_row;
+        terminal->selection_start_column = selection_start_column;
+    }
+
+    /* Expand from bottom-most portion of selection if doing otherwise would
+     * reduce the size of the selection */
+    else {
+        terminal->selection_start_row = selection_end_row;
+        terminal->selection_start_column = selection_end_column;
+    }
+
+    /* Selection is again in-progress */
+    terminal->selection_committed = false;
+
+    /* Update selection to contain given character */
+    guac_terminal_select_update(terminal, row, column);
+
+}
+
 /**
  * Appends the text within the given subsection of a terminal row to the
  * clipboard. The provided coordinates are considered inclusiveley (the
@@ -200,33 +334,22 @@ void guac_terminal_select_end(guac_terminal* terminal) {
     guac_client* client = terminal->client;
     guac_socket* socket = client->socket;
 
+    /* If no text is selected, nothing to do */
+    if (!terminal->text_selected)
+        return;
+
+    /* Selection is now committed */
+    terminal->selection_committed = true;
+
     /* Reset current clipboard contents */
     guac_common_clipboard_reset(terminal->clipboard, "text/plain");
 
-    /* Deselect */
-    terminal->text_selected = false;
-    guac_terminal_display_commit_select(terminal->display);
-
     int start_row, start_col;
     int end_row, end_col;
 
     /* Ensure proper ordering of start and end coords */
-    if (terminal->selection_start_row < terminal->selection_end_row
-        || (terminal->selection_start_row == terminal->selection_end_row
-            && terminal->selection_start_column < 
terminal->selection_end_column)) {
-
-        start_row = terminal->selection_start_row;
-        start_col = terminal->selection_start_column;
-        end_row   = terminal->selection_end_row;
-        end_col   = terminal->selection_end_column + 
terminal->selection_end_width - 1;
-
-    }
-    else {
-        end_row   = terminal->selection_start_row;
-        end_col   = terminal->selection_start_column + 
terminal->selection_start_width - 1;
-        start_row = terminal->selection_end_row;
-        start_col = terminal->selection_end_column;
-    }
+    guac_terminal_select_normalized_range(terminal,
+            &start_row, &start_col, &end_row, &end_col);
 
     /* If only one row, simply copy */
     if (end_row == start_row)
@@ -254,5 +377,63 @@ void guac_terminal_select_end(guac_terminal* terminal) {
     guac_common_clipboard_send(terminal->clipboard, client);
     guac_socket_flush(socket);
 
+    guac_terminal_notify(terminal);
+
+}
+
+bool guac_terminal_select_contains(guac_terminal* terminal,
+        int start_row, int start_column, int end_row, int end_column) {
+
+    int selection_start_row;
+    int selection_start_column;
+    int selection_end_row;
+    int selection_end_column;
+
+    /* No need to test coordinates if no text is selected at all */
+    if (!terminal->text_selected)
+        return false;
+
+    /* Use normalized coordinates for sake of simple comparison */
+    guac_terminal_select_normalized_range(terminal,
+            &selection_start_row, &selection_start_column,
+            &selection_end_row, &selection_end_column);
+
+    /* If test range starts after highlight ends, does not intersect */
+    if (start_row > selection_end_row)
+        return false;
+
+    if (start_row == selection_end_row && start_column > selection_end_column)
+        return false;
+
+    /* If test range ends before highlight starts, does not intersect */
+    if (end_row < selection_start_row)
+        return false;
+
+    if (end_row == selection_start_row && end_column < selection_start_column)
+        return false;
+
+    /* Otherwise, does intersect */
+    return true;
+
+}
+
+void guac_terminal_select_touch(guac_terminal* terminal,
+        int start_row, int start_column, int end_row, int end_column) {
+
+    /* Only clear selection if selection is committed */
+    if (!terminal->selection_committed)
+        return;
+
+    /* Clear selection if it contains any characters within the given region */
+    if (guac_terminal_select_contains(terminal, start_row, start_column,
+                end_row, end_column)) {
+
+        /* Text is no longer selected */
+        terminal->text_selected = false;
+        terminal->selection_committed = false;
+        guac_terminal_notify(terminal);
+
+    }
+
 }
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/6f08ef2a/src/terminal/terminal.c
----------------------------------------------------------------------
diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c
index 8f3e918..40c9099 100644
--- a/src/terminal/terminal.c
+++ b/src/terminal/terminal.c
@@ -61,6 +61,9 @@ static void __guac_terminal_set_columns(guac_terminal* 
terminal, int row,
     guac_terminal_buffer_set_columns(terminal->buffer, row,
             start_column, end_column, character);
 
+    /* Clear selection if region is modified */
+    guac_terminal_select_touch(terminal, row, start_column, row, end_column);
+
 }
 
 /**
@@ -173,6 +176,7 @@ void guac_terminal_reset(guac_terminal* term) {
 
     /* Reset flags */
     term->text_selected = false;
+    term->selection_committed = false;
     term->application_cursor_keys = false;
     term->automatic_carriage_return = false;
     term->insert_mode = false;
@@ -1279,6 +1283,9 @@ void guac_terminal_copy_columns(guac_terminal* terminal, 
int row,
     guac_terminal_buffer_copy_columns(terminal->buffer, row,
             start_column, end_column, offset);
 
+    /* Clear selection if region is modified */
+    guac_terminal_select_touch(terminal, row, start_column, row, end_column);
+
     /* Update cursor location if within region */
     if (row == terminal->visible_cursor_row &&
             terminal->visible_cursor_col >= start_column &&
@@ -1300,6 +1307,10 @@ void guac_terminal_copy_rows(guac_terminal* terminal,
     guac_terminal_buffer_copy_rows(terminal->buffer,
             start_row, end_row, offset);
 
+    /* Clear selection if region is modified */
+    guac_terminal_select_touch(terminal, start_row, 0, end_row,
+            terminal->term_width);
+
     /* Update cursor location if within region */
     if (terminal->visible_cursor_row >= start_row &&
         terminal->visible_cursor_row <= end_row)
@@ -1532,6 +1543,7 @@ void guac_terminal_flush(guac_terminal* terminal) {
         guac_terminal_typescript_flush(terminal->typescript);
 
     /* Flush display state */
+    guac_terminal_select_redraw(terminal);
     guac_terminal_commit_cursor(terminal);
     guac_terminal_display_flush(terminal->display);
     guac_terminal_scrollbar_flush(terminal->scrollbar);
@@ -1764,28 +1776,33 @@ static int __guac_terminal_send_mouse(guac_terminal* 
term, guac_user* user,
     if ((released_mask & GUAC_CLIENT_MOUSE_RIGHT) || (released_mask & 
GUAC_CLIENT_MOUSE_MIDDLE))
         return guac_terminal_send_data(term, term->clipboard->buffer, 
term->clipboard->length);
 
-    /* If text selected, change state based on left mouse mouse button */
-    if (term->text_selected) {
+    /* If left mouse button was just released, stop selection */
+    if (released_mask & GUAC_CLIENT_MOUSE_LEFT)
+        guac_terminal_select_end(term);
+
+    /* Update selection state contextually while the left mouse button is
+     * pressed */
+    else if (mask & GUAC_CLIENT_MOUSE_LEFT) {
 
-        /* If mouse button released, stop selection */
-        if (released_mask & GUAC_CLIENT_MOUSE_LEFT)
-            guac_terminal_select_end(term);
+        int row = y / term->display->char_height - term->scroll_offset;
+        int col = x / term->display->char_width;
 
-        /* Otherwise, just update */
+        /* If mouse button was already just pressed, start a new selection or
+         * resume the existing selection depending on whether shift is held */
+        if (pressed_mask & GUAC_CLIENT_MOUSE_LEFT) {
+            if (term->mod_shift)
+                guac_terminal_select_resume(term, row, col);
+            else
+                guac_terminal_select_start(term, row, col);
+        }
+
+        /* In all other cases, simply update the existing selection as long as
+         * the mouse button is pressed */
         else
-            guac_terminal_select_update(term,
-                    y / term->display->char_height - term->scroll_offset,
-                    x / term->display->char_width);
+            guac_terminal_select_update(term, row, col);
 
     }
 
-    /* Otherwise, if mouse button pressed AND moved, start selection */
-    else if (!(pressed_mask & GUAC_CLIENT_MOUSE_LEFT) &&
-               mask         & GUAC_CLIENT_MOUSE_LEFT)
-        guac_terminal_select_start(term,
-                y / term->display->char_height - term->scroll_offset,
-                x / term->display->char_width);
-
     /* Scroll up if wheel moved up */
     if (released_mask & GUAC_CLIENT_MOUSE_SCROLL_UP)
         guac_terminal_scroll_display_up(term, 
GUAC_TERMINAL_WHEEL_SCROLL_AMOUNT);

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/6f08ef2a/src/terminal/terminal/display.h
----------------------------------------------------------------------
diff --git a/src/terminal/terminal/display.h b/src/terminal/terminal/display.h
index 98337fd..e54003b 100644
--- a/src/terminal/terminal/display.h
+++ b/src/terminal/terminal/display.h
@@ -182,18 +182,11 @@ typedef struct guac_terminal_display {
     guac_layer* select_layer;
 
     /**
-     * Whether text is being selected.
+     * Whether text is currently selected.
      */
     bool text_selected;
 
     /**
-     * Whether the selection is finished, and will no longer be modified. A
-     * committed selection remains highlighted for reference, but the
-     * highlight will be removed when the display changes.
-     */
-    bool selection_committed;
-
-    /**
      * The row that the selection starts at.
      */
     int selection_start_row;
@@ -333,10 +326,13 @@ void guac_terminal_display_select(guac_terminal_display* 
display,
         int start_row, int start_col, int end_row, int end_col);
 
 /**
- * Commits the select rectangle, allowing the display to clear it when
- * necessary.
+ * Clears the currently-selected region, removing the highlight.
+ *
+ * @param display
+ *     The guac_terminal_display whose currently-selected region should be
+ *     cleared.
  */
-void guac_terminal_display_commit_select(guac_terminal_display* display);
+void guac_terminal_display_clear_select(guac_terminal_display* display);
 
 #endif
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/6f08ef2a/src/terminal/terminal/select.h
----------------------------------------------------------------------
diff --git a/src/terminal/terminal/select.h b/src/terminal/terminal/select.h
index b6e7009..1ae7d3d 100644
--- a/src/terminal/terminal/select.h
+++ b/src/terminal/terminal/select.h
@@ -24,6 +24,20 @@
 #include "config.h"
 #include "terminal.h"
 
+#include <stdbool.h>
+
+/**
+ * Forwards the visible portion of the text selection rectangle to the
+ * underlying terminal display, requesting that it be redrawn. If no
+ * visible change would result from redrawing the selection rectangle,
+ * this function may have no effect.
+ *
+ * @param terminal
+ *     The guac_terminal whose text selection rectangle should be
+ *     redrawn.
+ */
+void guac_terminal_select_redraw(guac_terminal* terminal);
+
 /**
  * Marks the start of text selection at the given row and column. Any existing
  * selection is cleared. This function should only be invoked while the
@@ -66,6 +80,27 @@ void guac_terminal_select_start(guac_terminal* terminal, int 
row, int column);
 void guac_terminal_select_update(guac_terminal* terminal, int row, int column);
 
 /**
+ * Resumes selecting text, expanding the existing selected region from the
+ * closest end to additionally contain the given character. This function
+ * should only be invoked while the guac_terminal is locked through a call to
+ * guac_terminal_lock().
+ *
+ * @param terminal
+ *     The guac_terminal instance associated with the text being selected.
+ *
+ * @param row
+ *     The row number of the character to include within the text selection,
+ *     where the first (top-most) row in the terminal is row 0. Rows within the
+ *     scrollback buffer (above the top-most row of the terminal) will be
+ *     negative.
+ *
+ * @param column
+ *     The column number of the character to include within the text selection,
+ *     where the first (left-most) column in the terminal is column 0.
+ */
+void guac_terminal_select_resume(guac_terminal* terminal, int row, int column);
+
+/**
  * Ends text selection, removing any highlight and storing the selected
  * character data within the clipboard associated with the given terminal. If
  * more text is selected than can fit within the clipboard, text at the end of
@@ -78,5 +113,67 @@ void guac_terminal_select_update(guac_terminal* terminal, 
int row, int column);
  */
 void guac_terminal_select_end(guac_terminal* terminal);
 
+/**
+ * Returns whether at least one character within the given range is currently
+ * selected.
+ *
+ * @param terminal
+ *     The guac_terminal instance associated with the text being selected.
+ *
+ * @param start_row
+ *     The first row of the region to test, inclusive, where the first
+ *     (top-most) row in the terminal is row 0. Rows within the scrollback
+ *     buffer (above the top-most row of the terminal) will be negative.
+ *
+ * @param start_column
+ *     The first column of the region to test, inclusive, where the first
+ *     (left-most) column in the terminal is column 0.
+ *
+ * @param end_row
+ *     The last row of the region to test, inclusive, where the first
+ *     (top-most) row in the terminal is row 0. Rows within the scrollback
+ *     buffer (above the top-most row of the terminal) will be negative.
+ *
+ * @param end_column
+ *     The last column of the region to test, inclusive, where the first
+ *     (left-most) column in the terminal is column 0.
+ *
+ * @return
+ *     true if at least one character within the given range is currently
+ *     selected, false otherwise.
+ */
+bool guac_terminal_select_contains(guac_terminal* terminal,
+        int start_row, int start_column, int end_row, int end_column);
+
+/**
+ * Clears the current selection if it contains at least one character within
+ * the given region. If no text is currently selected, the selection has not
+ * yet been committed, or the region does not contain at least one selected
+ * character, this function has no effect.
+ *
+ * @param terminal
+ *     The guac_terminal instance associated with the text being selected.
+ *
+ * @param start_row
+ *     The first row of the region, inclusive, where the first (top-most) row
+ *     in the terminal is row 0. Rows within the scrollback buffer (above the
+ *     top-most row of the terminal) will be negative.
+ *
+ * @param start_column
+ *     The first column of the region, inclusive, where the first (left-most)
+ *     column in the terminal is column 0.
+ *
+ * @param end_row
+ *     The last row of the region, inclusive, where the first (top-most) row in
+ *     the terminal is row 0. Rows within the scrollback buffer (above the
+ *     top-most row of the terminal) will be negative.
+ *
+ * @param end_column
+ *     The last column of the region, inclusive, where the first (left-most)
+ *     column in the terminal is column 0.
+ */
+void guac_terminal_select_touch(guac_terminal* terminal,
+        int start_row, int start_column, int end_row, int end_column);
+
 #endif
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/6f08ef2a/src/terminal/terminal/terminal.h
----------------------------------------------------------------------
diff --git a/src/terminal/terminal/terminal.h b/src/terminal/terminal/terminal.h
index 67b5b3e..8d6b48f 100644
--- a/src/terminal/terminal/terminal.h
+++ b/src/terminal/terminal/terminal.h
@@ -367,11 +367,19 @@ struct guac_terminal {
     int active_char_set;
 
     /**
-     * Whether text is being selected.
+     * Whether text is currently selected.
      */
     bool text_selected;
 
     /**
+     * Whether the selection is finished, and will no longer be modified. A
+     * committed selection remains highlighted for reference, but the
+     * highlight will be removed if characters within the selected region are
+     * modified.
+     */
+    bool selection_committed;
+
+    /**
      * The row that the selection starts at.
      */
     int selection_start_row;

Reply via email to