GUACAMOLE-573: Copy terminal data directly into clipboard. Do not assume 
selected region will be strictly visible.


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

Branch: refs/heads/master
Commit: c0d323828e1db5c3068c5d9e7730690dcad80460
Parents: f87af06
Author: Michael Jumper <mjum...@apache.org>
Authored: Sat Jun 16 19:43:26 2018 -0700
Committer: Michael Jumper <mjum...@apache.org>
Committed: Sat Jun 16 23:58:38 2018 -0700

----------------------------------------------------------------------
 src/terminal/select.c          | 148 ++++++++++++++++++++++--------------
 src/terminal/terminal.c        |  26 +------
 src/terminal/terminal/select.h |  13 ++--
 3 files changed, 96 insertions(+), 91 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/c0d32382/src/terminal/select.c
----------------------------------------------------------------------
diff --git a/src/terminal/select.c b/src/terminal/select.c
index b9e8474..ad7f5ac 100644
--- a/src/terminal/select.c
+++ b/src/terminal/select.c
@@ -20,33 +20,15 @@
 #include "config.h"
 
 #include "common/clipboard.h"
-#include "common/cursor.h"
 #include "terminal/buffer.h"
-#include "terminal/common.h"
 #include "terminal/display.h"
-#include "terminal/palette.h"
+#include "terminal/select.h"
 #include "terminal/terminal.h"
-#include "terminal/terminal_handlers.h"
 #include "terminal/types.h"
-#include "terminal/typescript.h"
-#include "terminal/xparsecolor.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <wchar.h>
 
 #include <guacamole/client.h>
-#include <guacamole/error.h>
-#include <guacamole/protocol.h>
 #include <guacamole/socket.h>
-#include <guacamole/timestamp.h>
+#include <guacamole/unicode.h>
 
 void guac_terminal_select_redraw(guac_terminal* terminal) {
 
@@ -135,37 +117,96 @@ void guac_terminal_select_update(guac_terminal* terminal, 
int row, int column) {
 
 }
 
-int __guac_terminal_buffer_string(guac_terminal_buffer_row* row, int start, 
int end, char* string) {
+/**
+ * Appends the text within the given subsection of a terminal row to the
+ * clipboard. The provided coordinates are considered inclusiveley (the
+ * characters at the start and end column are included in the copied
+ * text). Any out-of-bounds coordinates will be automatically clipped within
+ * the bounds of the given row.
+ *
+ * @param terminal
+ *     The guac_terminal instance associated with the buffer containing the
+ *     text being copied and the clipboard receiving the copied text.
+ *
+ * @param row
+ *     The row number of the text within the terminal to be copied into the
+ *     clipboard, 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
+ *     The first column of the text to be copied from the given row into the
+ *     clipboard associated with the given terminal, where 0 is the first
+ *     (left-most) column within the row.
+ *
+ * @param end
+ *     The last column of the text to be copied from the given row into the
+ *     clipboard associated with the given terminal, where 0 is the first
+ *     (left-most) column within the row.
+ */
+static void guac_terminal_clipboard_append_row(guac_terminal* terminal,
+        int row, int start, int end) {
+
+    char buffer[1024];
+    int i = start;
+
+    guac_terminal_buffer_row* buffer_row =
+        guac_terminal_buffer_get_row(terminal->buffer, row, 0);
+
+    /* If selection is entirely outside the bounds of the row, then there is
+     * nothing to append */
+    if (start > buffer_row->length - 1)
+        return;
+
+    /* Clip given range to actual bounds of row */
+    if (end == -1 || end > buffer_row->length - 1)
+        end = buffer_row->length - 1;
+
+    /* Repeatedly convert chunks of terminal buffer rows until entire specified
+     * region has been appended to clipboard */
+    while (i <= end) {
+
+        int remaining = sizeof(buffer);
+        char* current = buffer;
+
+        /* Convert as many codepoints within the given range as possible */
+        for (i = start; i <= end; i++) {
 
-    int length = 0;
-    int i;
-    for (i=start; i<=end; i++) {
+            int codepoint = buffer_row->characters[i].value;
 
-        int codepoint = row->characters[i].value;
+            /* Ignore null (blank) characters */
+            if (codepoint == 0 || codepoint == GUAC_CHAR_CONTINUATION)
+                continue;
+
+            /* Encode current codepoint as UTF-8 */
+            int bytes = guac_utf8_write(codepoint, current, remaining);
+            if (bytes == 0)
+                break;
+
+            current += bytes;
+            remaining -= bytes;
 
-        /* If not null (blank), add to string */
-        if (codepoint != 0 && codepoint != GUAC_CHAR_CONTINUATION) {
-            int bytes = guac_terminal_encode_utf8(codepoint, string);
-            string += bytes;
-            length += bytes;
         }
 
-    }
+        /* Append converted buffer to clipboard */
+        guac_common_clipboard_append(terminal->clipboard, buffer, current - 
buffer);
 
-    return length;
+    }
 
 }
 
-void guac_terminal_select_end(guac_terminal* terminal, char* string) {
+void guac_terminal_select_end(guac_terminal* terminal) {
+
+    guac_client* client = terminal->client;
+    guac_socket* socket = client->socket;
+
+    /* Reset current clipboard contents */
+    guac_common_clipboard_reset(terminal->clipboard, "text/plain");
 
     /* Deselect */
     terminal->text_selected = false;
     guac_terminal_display_commit_select(terminal->display);
 
-    guac_terminal_buffer_row* buffer_row;
-
-    int row;
-
     int start_row, start_col;
     int end_row, end_col;
 
@@ -188,41 +229,30 @@ void guac_terminal_select_end(guac_terminal* terminal, 
char* string) {
     }
 
     /* If only one row, simply copy */
-    buffer_row = guac_terminal_buffer_get_row(terminal->buffer, start_row, 0);
-    if (end_row == start_row) {
-        if (buffer_row->length - 1 < end_col)
-            end_col = buffer_row->length - 1;
-        string += __guac_terminal_buffer_string(buffer_row, start_col, 
end_col, string);
-    }
+    if (end_row == start_row)
+        guac_terminal_clipboard_append_row(terminal, start_row, start_col, 
end_col);
 
     /* Otherwise, copy multiple rows */
     else {
 
         /* Store first row */
-        string += __guac_terminal_buffer_string(buffer_row, start_col, 
buffer_row->length - 1, string);
+        guac_terminal_clipboard_append_row(terminal, start_row, start_col, -1);
 
         /* Store all middle rows */
-        for (row=start_row+1; row<end_row; row++) {
-
-            buffer_row = guac_terminal_buffer_get_row(terminal->buffer, row, 
0);
-
-            *(string++) = '\n';
-            string += __guac_terminal_buffer_string(buffer_row, 0, 
buffer_row->length - 1, string);
-
+        for (int row = start_row + 1; row < end_row; row++) {
+            guac_common_clipboard_append(terminal->clipboard, "\n", 1);
+            guac_terminal_clipboard_append_row(terminal, row, 0, -1);
         }
 
         /* Store last row */
-        buffer_row = guac_terminal_buffer_get_row(terminal->buffer, end_row, 
0);
-        if (buffer_row->length - 1 < end_col)
-            end_col = buffer_row->length - 1;
-
-        *(string++) = '\n';
-        string += __guac_terminal_buffer_string(buffer_row, 0, end_col, 
string);
+        guac_common_clipboard_append(terminal->clipboard, "\n", 1);
+        guac_terminal_clipboard_append_row(terminal, end_row, 0, end_col);
 
     }
 
-    /* Null terminator */
-    *string = 0;
+    /* Send data */
+    guac_common_clipboard_send(terminal->clipboard, client);
+    guac_socket_flush(socket);
 
 }
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/c0d32382/src/terminal/terminal.c
----------------------------------------------------------------------
diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c
index e6c99d4..8f3e918 100644
--- a/src/terminal/terminal.c
+++ b/src/terminal/terminal.c
@@ -1729,9 +1729,6 @@ int guac_terminal_send_key(guac_terminal* term, int 
keysym, int pressed) {
 static int __guac_terminal_send_mouse(guac_terminal* term, guac_user* user,
         int x, int y, int mask) {
 
-    guac_client* client = term->client;
-    guac_socket* socket = client->socket;
-
     /* Determine which buttons were just released and pressed */
     int released_mask =  term->mouse_mask & ~mask;
     int pressed_mask  = ~term->mouse_mask &  mask;
@@ -1771,27 +1768,8 @@ static int __guac_terminal_send_mouse(guac_terminal* 
term, guac_user* user,
     if (term->text_selected) {
 
         /* If mouse button released, stop selection */
-        if (released_mask & GUAC_CLIENT_MOUSE_LEFT) {
-
-            int selected_length;
-
-            /* End selection and get selected text */
-            int selectable_size = term->term_width * term->term_height * 
sizeof(char);
-            char* string = malloc(selectable_size);
-            guac_terminal_select_end(term, string);
-
-            selected_length = strnlen(string, selectable_size);
-
-            /* Store new data */
-            guac_common_clipboard_reset(term->clipboard, "text/plain");
-            guac_common_clipboard_append(term->clipboard, string, 
selected_length);
-            free(string);
-
-            /* Send data */
-            guac_common_clipboard_send(term->clipboard, client);
-            guac_socket_flush(socket);
-
-        }
+        if (released_mask & GUAC_CLIENT_MOUSE_LEFT)
+            guac_terminal_select_end(term);
 
         /* Otherwise, just update */
         else

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/c0d32382/src/terminal/terminal/select.h
----------------------------------------------------------------------
diff --git a/src/terminal/terminal/select.h b/src/terminal/terminal/select.h
index 936ae7a..b6e7009 100644
--- a/src/terminal/terminal/select.h
+++ b/src/terminal/terminal/select.h
@@ -67,19 +67,16 @@ void guac_terminal_select_update(guac_terminal* terminal, 
int row, int column);
 
 /**
  * Ends text selection, removing any highlight and storing the selected
- * character data within the provided string buffer. This function should only
- * be invoked while the guac_terminal is locked through a call to
+ * 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
+ * the selected area will be dropped as necessary. 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 string
- *     The buffer which should receive the characters within the selected
- *     area. This buffer must already have been allocated with sufficient
- *     space to store the selected text.
  */
-void guac_terminal_select_end(guac_terminal* terminal, char* string);
+void guac_terminal_select_end(guac_terminal* terminal);
 
 #endif
 

Reply via email to