1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Add a system of clipboard identifiers.

This lays some groundwork for making PuTTY's cut and paste handling
more flexible in the area of which clipboard(s) it reads and writes,
if more than one is available on the system.

I've introduced a system of list macros which define an enumeration of
integer clipboard ids, some defined centrally in putty.h (at present
just a CLIP_NULL which never has any text in it, because that seems
like the sort of thing that will come in useful for configuring a
given copy or paste UI action to be ignored) and some defined per
platform. All the front end functions that copy and paste take a
clipboard id, and the Terminal structure is now configured at startup
to tell it which clipboard id it should paste from on a mouse click,
and which it should copy from on a selection.

However, I haven't actually added _real_ support for multiple X11
clipboards, in that the Unix front end supports a single CLIP_SYSTEM
regardless of whether it's in OS X or GTK mode. So this is currently a
NFC refactoring which does nothing but prepare the way for real
changes to come.
This commit is contained in:
Simon Tatham 2017-12-09 12:00:13 +00:00
parent 9bff5595a2
commit 1829719639
10 changed files with 115 additions and 35 deletions

View File

@ -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); }

29
putty.h
View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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[] = {

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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,

View File

@ -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)