X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/48f1bc4426f0c95919978b1eddd4744390355801..f4ec081845e8411db28bda8e91f6ce83f0a0703f:/unix/pterm.c diff --git a/unix/pterm.c b/unix/pterm.c index 1e6db62b..c52b9208 100644 --- a/unix/pterm.c +++ b/unix/pterm.c @@ -22,6 +22,7 @@ #include #include #include +#include #define PUTTY_DO_GLOBALS /* actually _define_ globals */ @@ -81,6 +82,7 @@ struct gui_data { void *eventlogstuff; char *progname, **gtkargvstart; int ngtkargs; + guint32 input_event_time; /* Timestamp of the most recent input event. */ }; struct draw_ctx { @@ -447,6 +449,9 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) wchar_t ucsoutput[2]; int ucsval, start, end, special, use_ucsoutput; + /* Remember the timestamp. */ + inst->input_event_time = event->time; + /* By default, nothing is generated. */ end = start = 0; special = use_ucsoutput = FALSE; @@ -1021,6 +1026,9 @@ gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) struct gui_data *inst = (struct gui_data *)data; int shift, ctrl, alt, x, y, button, act; + /* Remember the timestamp. */ + inst->input_event_time = event->time; + show_mouseptr(inst, 1); if (event->button == 4 && event->type == GDK_BUTTON_PRESS) { @@ -1077,6 +1085,9 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) struct gui_data *inst = (struct gui_data *)data; int shift, ctrl, alt, x, y, button; + /* Remember the timestamp. */ + inst->input_event_time = event->time; + show_mouseptr(inst, 1); shift = event->state & GDK_SHIFT_MASK; @@ -1322,6 +1333,51 @@ void palette_reset(void *frontend) set_window_background(inst); } +/* Ensure that all the cut buffers exist - according to the ICCCM, we must + * do this before we start using cut buffers. + */ +void init_cutbuffers() +{ + XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), + XA_CUT_BUFFER0, XA_STRING, 8, PropModeAppend, "", 0); + XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), + XA_CUT_BUFFER1, XA_STRING, 8, PropModeAppend, "", 0); + XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), + XA_CUT_BUFFER2, XA_STRING, 8, PropModeAppend, "", 0); + XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), + XA_CUT_BUFFER3, XA_STRING, 8, PropModeAppend, "", 0); + XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), + XA_CUT_BUFFER4, XA_STRING, 8, PropModeAppend, "", 0); + XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), + XA_CUT_BUFFER5, XA_STRING, 8, PropModeAppend, "", 0); + XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), + XA_CUT_BUFFER6, XA_STRING, 8, PropModeAppend, "", 0); + XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), + XA_CUT_BUFFER7, XA_STRING, 8, PropModeAppend, "", 0); +} + +/* Store the data in a cut-buffer. */ +void store_cutbuffer(char * ptr, int len) +{ + /* ICCCM says we must rotate the buffers before storing to buffer 0. */ + XRotateBuffers(GDK_DISPLAY(), 1); + XStoreBytes(GDK_DISPLAY(), ptr, len); +} + +/* Retrieve data from a cut-buffer. + * Returned data needs to be freed with XFree(). + */ +char * retrieve_cutbuffer(int * nbytes) +{ + char * ptr; + ptr = XFetchBytes(GDK_DISPLAY(), nbytes); + if (nbytes <= 0 && ptr != 0) { + XFree(ptr); + ptr = 0; + } + return ptr; +} + void write_clip(void *frontend, wchar_t * data, int len, int must_deselect) { struct gui_data *inst = (struct gui_data *)frontend; @@ -1390,8 +1446,10 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect) sresize(inst->pasteout_data, inst->pasteout_data_len, char); } + store_cutbuffer(inst->pasteout_data, inst->pasteout_data_len); + if (gtk_selection_owner_set(inst->area, GDK_SELECTION_PRIMARY, - GDK_CURRENT_TIME)) { + inst->input_event_time)) { gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 1); if (inst->pasteout_data_ctext) @@ -1427,6 +1485,7 @@ gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, gpointer data) { struct gui_data *inst = (struct gui_data *)data; + term_deselect(inst->term); if (inst->pasteout_data) sfree(inst->pasteout_data); @@ -1461,14 +1520,16 @@ void request_paste(void *frontend) * fall back to an ordinary string. */ gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY, - utf8_string_atom, GDK_CURRENT_TIME); + utf8_string_atom, + inst->input_event_time); } else { /* * If we're in direct-to-font mode, we disable UTF-8 * pasting, and go straight to ordinary string data. */ gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY, - GDK_SELECTION_TYPE_STRING, GDK_CURRENT_TIME); + GDK_SELECTION_TYPE_STRING, + inst->input_event_time); } } @@ -1483,6 +1544,7 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata, char *text; int length, count, ret; int free_list_required = 0; + int free_required = 0; int charset; if (seldata->target == utf8_string_atom && seldata->length <= 0) { @@ -1491,7 +1553,8 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata, * text next. */ gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY, - compound_text_atom, GDK_CURRENT_TIME); + compound_text_atom, + inst->input_event_time); return; } @@ -1501,46 +1564,62 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata, * string. */ gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY, - GDK_SELECTION_TYPE_STRING, GDK_CURRENT_TIME); + GDK_SELECTION_TYPE_STRING, + inst->input_event_time); return; } /* - * Any other failure should just go foom. + * If we have data, but it's not of a type we can deal with, + * we have to ignore the data. */ - if (seldata->length <= 0 || - (seldata->type != GDK_SELECTION_TYPE_STRING && - seldata->type != compound_text_atom && - seldata->type != utf8_string_atom)) - return; /* Nothing happens. */ - + if (seldata->length > 0 && + seldata->type != GDK_SELECTION_TYPE_STRING && + seldata->type != compound_text_atom && + seldata->type != utf8_string_atom) + return; /* - * Convert COMPOUND_TEXT into UTF-8. + * If we have no data, try looking in a cut buffer. */ - if (seldata->type == compound_text_atom) { - tp.value = seldata->data; - tp.encoding = (Atom) seldata->type; - tp.format = seldata->format; - tp.nitems = seldata->length; - ret = Xutf8TextPropertyToTextList(GDK_DISPLAY(), &tp, &list, &count); - if (ret != 0 || count != 1) { - /* - * Compound text failed; fall back to STRING. - */ - gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY, - GDK_SELECTION_TYPE_STRING, GDK_CURRENT_TIME); + if (seldata->length <= 0) { + text = retrieve_cutbuffer(&length); + if (length == 0) return; - } - text = list[0]; - length = strlen(list[0]); - charset = CS_UTF8; - free_list_required = 1; + /* Xterm is rumoured to expect Latin-1, though I havn't checked the + * source, so use that as a de-facto standard. */ + charset = CS_ISO8859_1; + free_required = 1; } else { - text = (char *)seldata->data; - length = seldata->length; - charset = (seldata->type == utf8_string_atom ? - CS_UTF8 : inst->ucsdata.line_codepage); + /* + * Convert COMPOUND_TEXT into UTF-8. + */ + if (seldata->type == compound_text_atom) { + tp.value = seldata->data; + tp.encoding = (Atom) seldata->type; + tp.format = seldata->format; + tp.nitems = seldata->length; + ret = Xutf8TextPropertyToTextList(GDK_DISPLAY(), &tp, + &list, &count); + if (ret != 0 || count != 1) { + /* + * Compound text failed; fall back to STRING. + */ + gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY, + GDK_SELECTION_TYPE_STRING, + inst->input_event_time); + return; + } + text = list[0]; + length = strlen(list[0]); + charset = CS_UTF8; + free_list_required = 1; + } else { + text = (char *)seldata->data; + length = seldata->length; + charset = (seldata->type == utf8_string_atom ? + CS_UTF8 : inst->ucsdata.line_codepage); + } } if (inst->pastein_data) @@ -1559,6 +1638,8 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata, if (free_list_required) XFreeStringList(list); + if (free_required) + XFree(text); } gint idle_paste_func(gpointer data) @@ -2542,23 +2623,27 @@ void setup_fonts_ucs(struct gui_data *inst) } font_charset = set_font_info(inst, 0); - if (inst->cfg.boldfont.name[0]) { - name = inst->cfg.boldfont.name; - guessed = FALSE; + if (inst->cfg.shadowbold) { + inst->fonts[1] = NULL; } else { - name = guess_derived_font_name(inst->fonts[0], TRUE, FALSE); - guessed = TRUE; - } - inst->fonts[1] = name ? gdk_font_load(name) : NULL; - if (inst->fonts[1]) { - set_font_info(inst, 1); - } else if (!guessed) { - fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname, - inst->cfg.boldfont.name); - exit(1); + if (inst->cfg.boldfont.name[0]) { + name = inst->cfg.boldfont.name; + guessed = FALSE; + } else { + name = guess_derived_font_name(inst->fonts[0], TRUE, FALSE); + guessed = TRUE; + } + inst->fonts[1] = name ? gdk_font_load(name) : NULL; + if (inst->fonts[1]) { + set_font_info(inst, 1); + } else if (!guessed) { + fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname, + inst->cfg.boldfont.name); + exit(1); + } + if (guessed) + sfree(name); } - if (guessed) - sfree(name); if (inst->cfg.widefont.name[0]) { name = inst->cfg.widefont.name; @@ -2578,33 +2663,37 @@ void setup_fonts_ucs(struct gui_data *inst) if (guessed) sfree(name); - if (inst->cfg.wideboldfont.name[0]) { - name = inst->cfg.wideboldfont.name; - guessed = FALSE; + if (inst->cfg.shadowbold) { + inst->fonts[3] = NULL; } else { - /* - * Here we have some choices. We can widen the bold font, - * bolden the wide font, or widen and bolden the standard - * font. Try them all, in that order! - */ - if (inst->cfg.widefont.name[0]) - name = guess_derived_font_name(inst->fonts[2], TRUE, FALSE); - else if (inst->cfg.boldfont.name[0]) - name = guess_derived_font_name(inst->fonts[1], FALSE, TRUE); - else - name = guess_derived_font_name(inst->fonts[0], TRUE, TRUE); - guessed = TRUE; - } - inst->fonts[3] = name ? gdk_font_load(name) : NULL; - if (inst->fonts[3]) { - set_font_info(inst, 3); - } else if (!guessed) { - fprintf(stderr, "%s: unable to load wide/bold font \"%s\"\n", appname, - inst->cfg.wideboldfont.name); - exit(1); + if (inst->cfg.wideboldfont.name[0]) { + name = inst->cfg.wideboldfont.name; + guessed = FALSE; + } else { + /* + * Here we have some choices. We can widen the bold font, + * bolden the wide font, or widen and bolden the standard + * font. Try them all, in that order! + */ + if (inst->cfg.widefont.name[0]) + name = guess_derived_font_name(inst->fonts[2], TRUE, FALSE); + else if (inst->cfg.boldfont.name[0]) + name = guess_derived_font_name(inst->fonts[1], FALSE, TRUE); + else + name = guess_derived_font_name(inst->fonts[0], TRUE, TRUE); + guessed = TRUE; + } + inst->fonts[3] = name ? gdk_font_load(name) : NULL; + if (inst->fonts[3]) { + set_font_info(inst, 3); + } else if (!guessed) { + fprintf(stderr, "%s: unable to load wide/bold font \"%s\"\n", appname, + inst->cfg.wideboldfont.name); + exit(1); + } + if (guessed) + sfree(name); } - if (guessed) - sfree(name); inst->font_width = gdk_char_width(inst->fonts[0], ' '); inst->font_height = inst->fonts[0]->ascent + inst->fonts[0]->descent; @@ -2761,7 +2850,8 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) strcmp(oldcfg.widefont.name, cfg2.widefont.name) || strcmp(oldcfg.wideboldfont.name, cfg2.wideboldfont.name) || strcmp(oldcfg.line_codepage, cfg2.line_codepage) || - oldcfg.vtmode != cfg2.vtmode) { + oldcfg.vtmode != cfg2.vtmode || + oldcfg.shadowbold != cfg2.shadowbold) { setup_fonts_ucs(inst); need_size = 1; } else @@ -3092,6 +3182,7 @@ int pt_main(int argc, char **argv) utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE); setup_fonts_ucs(inst); + init_cutbuffers(); inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);