From 131a8e946898f0d3ea4bf28f4495685ab5a14731 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 10 Dec 2017 15:45:45 +0000 Subject: [PATCH] Ability to copy to multiple clipboards at once. --- putty.h | 4 +-- terminal.c | 75 +++++++++++++++++++++++++++++++----------------- terminal.h | 3 +- unix/gtkwin.c | 6 ++-- windows/window.c | 8 ++++-- 5 files changed, 63 insertions(+), 33 deletions(-) diff --git a/putty.h b/putty.h index efde2d44..e768cf7f 100644 --- a/putty.h +++ b/putty.h @@ -1088,9 +1088,9 @@ void term_blink(Terminal *, int set_cursor); void term_do_paste(Terminal *, const wchar_t *, int); void term_nopaste(Terminal *); int term_ldisc(Terminal *, int option); -void term_copyall(Terminal *, int clipboard); +void term_copyall(Terminal *, const int *, int); void term_reconfig(Terminal *, Conf *); -void term_request_copy(Terminal *, int clipboard); +void term_request_copy(Terminal *, const int *clipboards, int n_clipboards); void term_request_paste(Terminal *, int clipboard); void term_seen_key_event(Terminal *); int term_data(Terminal *, int is_stderr, const char *data, int len); diff --git a/terminal.c b/terminal.c index 32fb6576..06f41e44 100644 --- a/terminal.c +++ b/terminal.c @@ -1707,9 +1707,10 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, term->last_selected_attr = NULL; term->last_selected_tc = NULL; term->last_selected_len = 0; - /* frontends will typically overwrite these with clipboard ids they + /* frontends will typically extend these with clipboard ids they * know about */ - term->mouse_select_clipboard = CLIP_NULL; + term->mouse_select_clipboards[0] = CLIP_LOCAL; + term->n_mouse_select_clipboards = 1; term->mouse_paste_clipboard = CLIP_NULL; return term; @@ -5648,7 +5649,7 @@ static void clip_addchar(clip_workbuf *b, wchar_t chr, int attr, truecolour tc) } static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, - int clipboard) + const int *clipboards, int n_clipboards) { clip_workbuf buf; int old_top_x; @@ -5808,19 +5809,36 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, #if SELECTION_NUL_TERMINATED clip_addchar(&buf, 0, 0, term->basic_erase_char.truecolour); #endif - /* Finally, transfer all that to the clipboard. */ - sfree(term->last_selected_text); - sfree(term->last_selected_attr); - sfree(term->last_selected_tc); - term->last_selected_text = buf.textbuf; - term->last_selected_attr = buf.attrbuf; - term->last_selected_tc = buf.tcbuf; - term->last_selected_len = buf.bufpos; - write_clip(term->frontend, clipboard, - buf.textbuf, buf.attrbuf, buf.tcbuf, buf.bufpos, desel); + /* Finally, transfer all that to the clipboard(s). */ + { + int i; + int clip_local = FALSE; + for (i = 0; i < n_clipboards; i++) { + if (clipboards[i] == CLIP_LOCAL) { + clip_local = TRUE; + } else if (clipboards[i] != CLIP_NULL) { + write_clip(term->frontend, clipboards[i], + buf.textbuf, buf.attrbuf, buf.tcbuf, buf.bufpos, + desel); + } + } + if (clip_local) { + sfree(term->last_selected_text); + sfree(term->last_selected_attr); + sfree(term->last_selected_tc); + term->last_selected_text = buf.textbuf; + term->last_selected_attr = buf.attrbuf; + term->last_selected_tc = buf.tcbuf; + term->last_selected_len = buf.bufpos; + } else { + sfree(buf.textbuf); + sfree(buf.attrbuf); + sfree(buf.tcbuf); + } + } } -void term_copyall(Terminal *term, int clipboard) +void term_copyall(Terminal *term, const int *clipboards, int n_clipboards) { pos top; pos bottom; @@ -5829,7 +5847,7 @@ void term_copyall(Terminal *term, int clipboard) top.x = 0; bottom.y = find_last_nonempty_line(term, screen); bottom.x = term->cols; - clipme(term, top, bottom, 0, TRUE, clipboard); + clipme(term, top, bottom, 0, TRUE, clipboards, n_clipboards); } static void paste_from_clip_local(void *vterm) @@ -5838,16 +5856,19 @@ static void paste_from_clip_local(void *vterm) term_do_paste(term, term->last_selected_text, term->last_selected_len); } -void term_request_copy(Terminal *term, int clipboard) +void term_request_copy(Terminal *term, const int *clipboards, int n_clipboards) { - assert(clipboard != CLIP_LOCAL); - if (clipboard != CLIP_NULL) { - write_clip(term->frontend, clipboard, - term->last_selected_text, - term->last_selected_attr, - term->last_selected_tc, - term->last_selected_len, - FALSE); + int i; + for (i = 0; i < n_clipboards; i++) { + assert(clipboards[i] != CLIP_LOCAL); + if (clipboards[i] != CLIP_NULL) { + write_clip(term->frontend, clipboards[i], + term->last_selected_text, + term->last_selected_attr, + term->last_selected_tc, + term->last_selected_len, + FALSE); + } } } @@ -6447,7 +6468,8 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, */ clipme(term, term->selstart, term->selend, (term->seltype == RECTANGULAR), FALSE, - term->mouse_select_clipboard); + term->mouse_select_clipboards, + term->n_mouse_select_clipboards); term->selstate = SELECTED; } else term->selstate = NO_SELECTION; @@ -6523,7 +6545,8 @@ static void deselect(Terminal *term) void term_lost_clipboard_ownership(Terminal *term, int clipboard) { - if (clipboard != term->mouse_select_clipboard) + if (!(term->n_mouse_select_clipboards > 1 && + clipboard == term->mouse_select_clipboards[1])) return; deselect(term); diff --git a/terminal.h b/terminal.h index c46bf5e1..0057e34f 100644 --- a/terminal.h +++ b/terminal.h @@ -332,7 +332,8 @@ struct terminal_tag { int *last_selected_attr; truecolour *last_selected_tc; size_t last_selected_len; - int mouse_select_clipboard; + int mouse_select_clipboards[N_CLIPBOARDS]; + int n_mouse_select_clipboards; int mouse_paste_clipboard; }; diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 01bf6f29..cdd1d49b 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -4130,7 +4130,8 @@ void reset_terminal_menuitem(GtkMenuItem *item, gpointer data) void copy_all_menuitem(GtkMenuItem *item, gpointer data) { struct gui_data *inst = (struct gui_data *)data; - term_copyall(inst->term, CLIP_SYSTEM); + static const int clips[] = { CLIP_PRIMARY, CLIP_CLIPBOARD }; + term_copyall(inst->term, clips, lenof(clips)); } void special_menuitem(GtkMenuItem *item, gpointer data) @@ -5004,7 +5005,8 @@ void new_session_window(Conf *conf, const char *geometry_string) inst->eventlogstuff = eventlogstuff_new(); inst->term = term_init(inst->conf, &inst->ucsdata, inst); - inst->term->mouse_select_clipboard = MOUSE_SELECT_CLIPBOARD; + inst->term->mouse_select_clipboards[ + inst->term->n_mouse_select_clipboards++] = MOUSE_SELECT_CLIPBOARD; inst->term->mouse_paste_clipboard = MOUSE_PASTE_CLIPBOARD; inst->logctx = log_init(inst, inst->conf); term_provide_logctx(inst->term, inst->logctx); diff --git a/windows/window.c b/windows/window.c index b8452757..84799f48 100644 --- a/windows/window.c +++ b/windows/window.c @@ -637,7 +637,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) * timer_change_notify() which will expect hwnd to exist.) */ term = term_init(conf, &ucsdata, NULL); - term->mouse_select_clipboard = CLIP_SYSTEM; + term->mouse_select_clipboards[ + term->n_mouse_select_clipboards++] = CLIP_SYSTEM; term->mouse_paste_clipboard = CLIP_SYSTEM; logctx = log_init(NULL, conf); term_provide_logctx(term, logctx); @@ -2330,7 +2331,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; case IDM_COPYALL: - term_copyall(term, CLIP_SYSTEM); + { + static const int clips[] = { CLIP_SYSTEM }; + term_copyall(term, clips, lenof(clips)); + } break; case IDM_PASTE: term_request_paste(term, CLIP_SYSTEM);