diff --git a/fuzzterm.c b/fuzzterm.c index 3ce8b584..667d2eea 100644 --- a/fuzzterm.c +++ b/fuzzterm.c @@ -82,9 +82,10 @@ void free_ctx(Context ctx) { } void palette_set(void *frontend, int a, int b, int c, int d) { } void palette_reset(void *frontend) { } int palette_get(void *frontend, int n, int *r, int *g, int *b) {return FALSE;} -void write_clip(void *frontend, wchar_t *a, int *b, truecolour *c, int d, int e) { } +void write_clip(void *frontend, int clipboard, + wchar_t *a, int *b, truecolour *c, int d, int e) { } void set_raw_mouse_mode(void *frontend, int m) { } -void request_paste(void *frontend) { } +void frontend_request_paste(void *frontend, int clipboard) { } void do_beep(void *frontend, int a) { } void sys_cursor(void *frontend, int x, int y) { } void modalfatalbox(const char *fmt, ...) { exit(0); } diff --git a/putty.h b/putty.h index d53eaca0..eea7fe9c 100644 --- a/putty.h +++ b/putty.h @@ -615,6 +615,25 @@ typedef struct truecolour { optionalrgb_equal((c1).fg, (c2).fg) && \ optionalrgb_equal((c1).bg, (c2).bg)) +/* + * Enumeration of clipboards. CLIP_NULL is the only one provided + * systemwide: it's a non=clipboard, writes to which are ignored and + * reads from which return no data. Each platform front end extends + * this enumeration in its own way. + */ +#define CROSS_PLATFORM_CLIPBOARDS(X) \ + X(CLIP_NULL, "null clipboard") \ + /* end of list */ + +#define ALL_CLIPBOARDS(X) \ + CROSS_PLATFORM_CLIPBOARDS(X) \ + PLATFORM_CLIPBOARDS(X) \ + /* end of list */ + +#define CLIP_ID(id,name) id, +enum { ALL_CLIPBOARDS(CLIP_ID) N_CLIPBOARDS }; +#undef CLIP_ID + /* * Exports from the front end. */ @@ -635,7 +654,8 @@ void free_ctx(Context); void palette_set(void *frontend, int, int, int, int); void palette_reset(void *frontend); int palette_get(void *frontend, int n, int *r, int *g, int *b); -void write_clip(void *frontend, wchar_t *, int *, truecolour *, int, int); +void write_clip(void *frontend, int clipboard, wchar_t *, int *, + truecolour *, int, int); void optimised_move(void *frontend, int, int, int); void set_raw_mouse_mode(void *frontend, int); void connection_fatal(void *frontend, const char *, ...); @@ -647,7 +667,7 @@ void modalfatalbox(const char *, ...); void do_beep(void *frontend, int); void begin_session(void *frontend); void sys_cursor(void *frontend, int x, int y); -void request_paste(void *frontend); +void frontend_request_paste(void *frontend, int clipboard); void frontend_keypress(void *frontend); void frontend_echoedit_update(void *frontend, int echo, int edit); /* It's the backend's responsibility to invoke this at the start of a @@ -1051,15 +1071,16 @@ void term_mouse(Terminal *, Mouse_Button, Mouse_Button, Mouse_Action, int,int,int,int,int); void term_key(Terminal *, Key_Sym, wchar_t *, size_t, unsigned int, unsigned int); -void term_deselect(Terminal *); +void term_lost_clipboard_ownership(Terminal *, int clipboard); void term_update(Terminal *); void term_invalidate(Terminal *); 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 *); +void term_copyall(Terminal *, int clipboard); void term_reconfig(Terminal *, Conf *); +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); int term_data_untrusted(Terminal *, const char *data, int len); diff --git a/terminal.c b/terminal.c index f416e109..dd3c8548 100644 --- a/terminal.c +++ b/terminal.c @@ -1703,6 +1703,11 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, term->basic_erase_char.truecolour.bg = optionalrgb_none; term->erase_char = term->basic_erase_char; + /* frontends will typically overwrite these with clipboard ids they + * know about */ + term->mouse_select_clipboard = CLIP_NULL; + term->mouse_paste_clipboard = CLIP_NULL; + return term; } @@ -5638,7 +5643,8 @@ static void clip_addchar(clip_workbuf *b, wchar_t chr, int attr, truecolour tc) b->bufpos++; } -static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) +static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel, + int clipboard) { clip_workbuf buf; int old_top_x; @@ -5799,13 +5805,14 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) clip_addchar(&buf, 0, 0, term->basic_erase_char.truecolour); #endif /* Finally, transfer all that to the clipboard. */ - write_clip(term->frontend, buf.textbuf, buf.attrbuf, buf.tcbuf, buf.bufpos, desel); + write_clip(term->frontend, clipboard, + buf.textbuf, buf.attrbuf, buf.tcbuf, buf.bufpos, desel); sfree(buf.textbuf); sfree(buf.attrbuf); sfree(buf.tcbuf); } -void term_copyall(Terminal *term) +void term_copyall(Terminal *term, int clipboard) { pos top; pos bottom; @@ -5814,7 +5821,14 @@ void term_copyall(Terminal *term) top.x = 0; bottom.y = find_last_nonempty_line(term, screen); bottom.x = term->cols; - clipme(term, top, bottom, 0, TRUE); + clipme(term, top, bottom, 0, TRUE, clipboard); +} + +void term_request_paste(Terminal *term, int clipboard) +{ + if (clipboard == CLIP_NULL) + return; + frontend_request_paste(term->frontend, clipboard); } /* @@ -6397,7 +6411,8 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, * data to the clipboard. */ clipme(term, term->selstart, term->selend, - (term->seltype == RECTANGULAR), FALSE); + (term->seltype == RECTANGULAR), FALSE, + term->mouse_select_clipboard); term->selstate = SELECTED; } else term->selstate = NO_SELECTION; @@ -6407,7 +6422,7 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, || a == MA_2CLK || a == MA_3CLK #endif )) { - request_paste(term->frontend); + term_request_paste(term, term->mouse_paste_clipboard); } /* @@ -6471,8 +6486,11 @@ static void deselect(Terminal *term) term->selstart.x = term->selstart.y = term->selend.x = term->selend.y = 0; } -void term_deselect(Terminal *term) +void term_lost_clipboard_ownership(Terminal *term, int clipboard) { + if (clipboard != term->mouse_select_clipboard) + return; + deselect(term); term_update(term); diff --git a/terminal.h b/terminal.h index 03659744..8cb56f6f 100644 --- a/terminal.h +++ b/terminal.h @@ -327,6 +327,9 @@ struct terminal_tag { int scroll_on_key; int xterm_256_colour; int true_colour; + + int mouse_select_clipboard; + int mouse_paste_clipboard; }; #define in_utf(term) ((term)->utf || (term)->ucsdata->line_codepage==CP_UTF8) diff --git a/unix/gtkapp.c b/unix/gtkapp.c index d1861b1e..57358dcb 100644 --- a/unix/gtkapp.c +++ b/unix/gtkapp.c @@ -147,7 +147,7 @@ static void paste_cb(GSimpleAction *action, GVariant *parameter, gpointer user_data) { - request_paste(user_data); + paste_menu_action(user_data); } static const GActionEntry win_actions[] = { diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 96421ac5..99144557 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -1022,7 +1022,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #ifdef KEY_EVENT_DIAGNOSTICS debug((" - Shift-Insert paste\n")); #endif - request_paste(inst); + term_request_paste(inst->term, CLIP_SYSTEM); return TRUE; } @@ -2532,15 +2532,16 @@ static void clipboard_clear(GtkClipboard *clipboard, gpointer data) struct gui_data *inst = cdi->inst; if (inst->current_cdi == cdi) { - term_deselect(inst->term); + term_lost_clipboard_ownership(inst->term, CLIP_SYSTEM); inst->current_cdi = NULL; } sfree(cdi->pasteout_data_utf8); sfree(cdi); } -void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour, - int len, int must_deselect) +void write_clip(void *frontend, int clipboard, + char_t *data, int *attr, truecolour *truecolour, int len, + int must_deselect) { struct gui_data *inst = (struct gui_data *)frontend; struct clipboard_data_instance *cdi; @@ -2609,9 +2610,10 @@ static void clipboard_text_received(GtkClipboard *clipboard, sfree(paste); } -void request_paste(void *frontend) +void frontend_request_paste(void *frontend, int clipboard) { struct gui_data *inst = (struct gui_data *)frontend; + assert(clipboard == CLIP_SYSTEM); gtk_clipboard_request_text(inst->clipboard, clipboard_text_received, inst); } @@ -2667,8 +2669,9 @@ static char *retrieve_cutbuffer(int *nbytes) #endif } -void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour, - int len, int must_deselect) +void write_clip(void *frontend, int clipboard, + wchar_t *data, int *attr, truecolour *truecolour, int len, + int must_deselect) { struct gui_data *inst = (struct gui_data *)frontend; if (inst->pasteout_data) @@ -2763,7 +2766,7 @@ void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour } if (must_deselect) - term_deselect(inst->term); + term_lost_clipboard_ownership(inst->term, clipboard); } static void selection_get(GtkWidget *widget, GtkSelectionData *seldata, @@ -2790,7 +2793,7 @@ static gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, { struct gui_data *inst = (struct gui_data *)data; - term_deselect(inst->term); + term_lost_clipboard_ownership(inst->term, CLIP_SYSTEM); if (inst->pasteout_data) sfree(inst->pasteout_data); if (inst->pasteout_data_ctext) @@ -2806,9 +2809,12 @@ static gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, return TRUE; } -void request_paste(void *frontend) +void frontend_request_paste(void *frontend, int clipboard) { struct gui_data *inst = (struct gui_data *)frontend; + + assert(clipboard == CLIP_SYSTEM); + /* * In Unix, pasting is asynchronous: all we can do at the * moment is to call gtk_selection_convert(), and when the data @@ -3007,6 +3013,12 @@ void init_clipboard(struct gui_data *inst) #endif /* JUST_USE_GTK_CLIPBOARD_UTF8 */ +void paste_menu_action(void *frontend) +{ + struct gui_data *inst = (struct gui_data *)frontend; + term_request_paste(inst->term, CLIP_SYSTEM); +} + static void set_window_titles(struct gui_data *inst) { /* @@ -4048,7 +4060,7 @@ 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); + term_copyall(inst->term, CLIP_SYSTEM); } void special_menuitem(GtkMenuItem *item, gpointer data) @@ -4922,6 +4934,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 = CLIP_SYSTEM; + inst->term->mouse_paste_clipboard = CLIP_SYSTEM; inst->logctx = log_init(inst, inst->conf); term_provide_logctx(inst->term, inst->logctx); diff --git a/unix/unix.h b/unix/unix.h index bedb28d0..6c9d11c7 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -119,6 +119,10 @@ unsigned long getticks(void); */ #define FLAG_STDERR_TTY 0x1000 +#define PLATFORM_CLIPBOARDS(X) \ + X(CLIP_SYSTEM, "system clipboard") \ + /* end of list */ + /* The per-session frontend structure managed by gtkwin.c */ struct gui_data; @@ -143,6 +147,9 @@ GtkWidget *make_gtk_toplevel_window(void *frontend); /* Defined in gtkcomm.c */ void gtkcomm_setup(void); +/* Defined in gtkwin.c */ +void paste_menu_action(void *frontend); + /* Things pty.c needs from pterm.c */ const char *get_x_display(void *frontend); int font_dimension(void *frontend, int which);/* 0 for width, 1 for height */ diff --git a/windows/windlg.c b/windows/windlg.c index 8bd02d85..39d2addd 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -140,7 +140,7 @@ static INT_PTR CALLBACK LogProc(HWND hwnd, UINT msg, memcpy(p, sel_nl, sizeof(sel_nl)); p += sizeof(sel_nl); } - write_aclip(NULL, clipdata, size, TRUE); + write_aclip(NULL, CLIP_SYSTEM, clipdata, size, TRUE); sfree(clipdata); } sfree(selitems); diff --git a/windows/window.c b/windows/window.c index 3a67fb87..b8452757 100644 --- a/windows/window.c +++ b/windows/window.c @@ -637,6 +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_paste_clipboard = CLIP_SYSTEM; logctx = log_init(NULL, conf); term_provide_logctx(term, logctx); term_size(term, conf_get_int(conf, CONF_height), @@ -2328,10 +2330,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; case IDM_COPYALL: - term_copyall(term); + term_copyall(term, CLIP_SYSTEM); break; case IDM_PASTE: - request_paste(NULL); + term_request_paste(term, CLIP_SYSTEM); break; case IDM_CLRSB: term_clrsb(term); @@ -2563,7 +2565,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case WM_DESTROYCLIPBOARD: if (!ignore_clip) - term_deselect(term); + term_lost_clipboard_ownership(term, CLIP_SYSTEM); ignore_clip = FALSE; return 0; case WM_PAINT: @@ -4146,7 +4148,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return 0; } if (wParam == VK_INSERT && shift_state == 1) { - request_paste(NULL); + term_request_paste(term, CLIP_SYSTEM); return 0; } if (left_alt && wParam == VK_F4 && conf_get_int(conf, CONF_alt_f4)) { @@ -4861,11 +4863,15 @@ void palette_reset(void *frontend) } } -void write_aclip(void *frontend, char *data, int len, int must_deselect) +void write_aclip(void *frontend, int clipboard, + char *data, int len, int must_deselect) { HGLOBAL clipdata; void *lock; + if (clipboard != CLIP_SYSTEM) + return; + clipdata = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, len + 1); if (!clipdata) return; @@ -4905,13 +4911,17 @@ int cmpCOLORREF(void *va, void *vb) /* * Note: unlike write_aclip() this will not append a nul. */ -void write_clip(void *frontend, wchar_t *data, int *attr, truecolour *truecolour, - int len, int must_deselect) +void write_clip(void *frontend, int clipboard, + wchar_t *data, int *attr, truecolour *truecolour, int len, + int must_deselect) { HGLOBAL clipdata, clipdata2, clipdata3; int len2; void *lock, *lock2, *lock3; + if (clipboard != CLIP_SYSTEM) + return; + len2 = WideCharToMultiByte(CP_ACP, 0, data, len, 0, 0, NULL, NULL); clipdata = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, @@ -5372,8 +5382,10 @@ static void process_clipdata(HGLOBAL clipdata, int unicode) sfree(clipboard_contents); } -void request_paste(void *frontend) +void frontend_request_paste(void *frontend, int clipboard) { + assert(clipboard == CLIP_SYSTEM); + /* * I always thought pasting was synchronous in Windows; the * clipboard access functions certainly _look_ synchronous, diff --git a/windows/winstuff.h b/windows/winstuff.h index 0b535822..39ff9426 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -55,6 +55,10 @@ struct FontSpec *fontspec_new(const char *name, #define PLATFORM_IS_UTF16 /* enable UTF-16 processing when exchanging * wchar_t strings with environment */ +#define PLATFORM_CLIPBOARDS(X) \ + X(CLIP_SYSTEM, "system clipboard") \ + /* end of list */ + /* * Where we can, we use GetWindowLongPtr and friends because they're * more useful on 64-bit platforms, but they're a relatively recent @@ -247,7 +251,7 @@ GLOBAL void *logctx; * which takes the data string in the system code page instead of * Unicode. */ -void write_aclip(void *frontend, char *, int, int); +void write_aclip(void *frontend, int clipboard, char *, int, int); #define WM_NETEVENT (WM_APP + 5)