X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/aca2a702186e9056d0e0789f685b7ffff182f643..8c1616628c6d488feff6ebec2c268aa30e337773:/unix/pterm.c diff --git a/unix/pterm.c b/unix/pterm.c index 9d92bc7b..15c64393 100644 --- a/unix/pterm.c +++ b/unix/pterm.c @@ -34,6 +34,8 @@ #define NCOLOURS (lenof(((Config *)0)->colours)) +GdkAtom compound_text_atom, utf8_string_atom; + struct gui_data { GtkWidget *window, *area, *sbar; GtkBox *hbox; @@ -55,10 +57,10 @@ struct gui_data { char *pasteout_data, *pasteout_data_utf8; int pasteout_data_len, pasteout_data_utf8_len; int font_width, font_height; + int width, height; int ignore_sbar; int mouseptr_visible; guint term_paste_idle_id; - GdkAtom compound_text_atom, utf8_string_atom; int alt_keycode; int alt_digits; char wintitle[sizeof(((Config *)0)->wintitle)]; @@ -72,6 +74,7 @@ struct gui_data { int exited; struct unicode_data ucsdata; Config cfg; + void *eventlogstuff; }; struct draw_ctx { @@ -163,11 +166,12 @@ int askappend(void *frontend, Filename filename) void logevent(void *frontend, char *string) { - /* - * This is not a very helpful function: events are logged - * pretty much exclusively by the back end, and our pty back - * end is self-contained. So we need do nothing. - */ + Terminal *term = (Terminal *)frontend; + struct gui_data *inst = (struct gui_data *)term->frontend; + + log_eventlog(inst->logctx, string); + + logevent_dlg(inst->eventlogstuff, string); } int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */ @@ -371,13 +375,13 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data) w = (event->width - 2*inst->cfg.window_border) / inst->font_width; h = (event->height - 2*inst->cfg.window_border) / inst->font_height; - if (w != inst->cfg.width || h != inst->cfg.height) { + if (w != inst->width || h != inst->height) { if (inst->pixmap) { gdk_pixmap_unref(inst->pixmap); inst->pixmap = NULL; } - inst->cfg.width = w; - inst->cfg.height = h; + inst->cfg.width = inst->width = w; + inst->cfg.height = inst->height = h; need_size = 1; } if (!inst->pixmap) { @@ -1158,8 +1162,11 @@ void request_resize(void *frontend, int w, int h) gtk_widget_set_size_request(inst->area, area_x, area_y); #else gtk_widget_set_usize(inst->area, area_x, area_y); + gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area), area_x, area_y); #endif + gtk_container_dequeue_resize_handler(GTK_CONTAINER(inst->window)); + #if GTK_CHECK_VERSION(2,0,0) gtk_window_resize(GTK_WINDOW(inst->window), area_x + offset_x, area_y + offset_y); @@ -1177,10 +1184,11 @@ static void real_palette_set(struct gui_data *inst, int n, int r, int g, int b) inst->cols[n].green = g * 0x0101; inst->cols[n].blue = b * 0x0101; + gdk_colormap_free_colors(inst->colmap, inst->cols + n, 1); gdk_colormap_alloc_colors(inst->colmap, inst->cols + n, 1, FALSE, FALSE, success); if (!success[0]) - g_error("pterm: couldn't allocate colour %d (#%02x%02x%02x)\n", + g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", appname, n, r, g, b); } @@ -1237,8 +1245,9 @@ void palette_reset(void *frontend) FALSE, FALSE, success); for (i = 0; i < NCOLOURS; i++) { if (!success[i]) - g_error("pterm: couldn't allocate colour %d (#%02x%02x%02x)\n", - i, inst->cfg.colours[i][0], inst->cfg.colours[i][1], inst->cfg.colours[i][2]); + g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", + appname, i, inst->cfg.colours[i][0], + inst->cfg.colours[i][1], inst->cfg.colours[i][2]); } set_window_background(inst); @@ -1298,10 +1307,10 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect) gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 1); gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY, - inst->compound_text_atom, 1); + compound_text_atom, 1); if (inst->pasteout_data_utf8) gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY, - inst->utf8_string_atom, 1); + utf8_string_atom, 1); } } @@ -1309,7 +1318,7 @@ void selection_get(GtkWidget *widget, GtkSelectionData *seldata, guint info, guint time_stamp, gpointer data) { struct gui_data *inst = (struct gui_data *)data; - if (seldata->target == inst->utf8_string_atom) + if (seldata->target == utf8_string_atom) gtk_selection_data_set(seldata, seldata->target, 8, inst->pasteout_data_utf8, inst->pasteout_data_utf8_len); @@ -1352,7 +1361,7 @@ void request_paste(void *frontend) * fall back to an ordinary string. */ gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY, - inst->utf8_string_atom, GDK_CURRENT_TIME); + utf8_string_atom, GDK_CURRENT_TIME); } else { /* * If we're in direct-to-font mode, we disable UTF-8 @@ -1370,7 +1379,7 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata, { struct gui_data *inst = (struct gui_data *)data; - if (seldata->target == inst->utf8_string_atom && seldata->length <= 0) { + if (seldata->target == utf8_string_atom && seldata->length <= 0) { /* * Failed to get a UTF-8 selection string. Try an ordinary * string. @@ -1385,7 +1394,7 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata, */ if (seldata->length <= 0 || (seldata->type != GDK_SELECTION_TYPE_STRING && - seldata->type != inst->utf8_string_atom)) + seldata->type != utf8_string_atom)) return; /* Nothing happens. */ if (inst->pastein_data) @@ -1394,7 +1403,7 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata, inst->pastein_data = snewn(seldata->length, wchar_t); inst->pastein_data_len = seldata->length; inst->pastein_data_len = - mb_to_wc((seldata->type == inst->utf8_string_atom ? + mb_to_wc((seldata->type == utf8_string_atom ? CS_UTF8 : inst->ucsdata.line_codepage), 0, seldata->data, seldata->length, inst->pastein_data, inst->pastein_data_len); @@ -1953,7 +1962,7 @@ void modalfatalbox(char *p, ...) void cmdline_error(char *p, ...) { va_list ap; - fprintf(stderr, "plink: "); + fprintf(stderr, "%s: ", appname); va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); @@ -2018,7 +2027,7 @@ int do_cmdline(int argc, char **argv, int do_everything, #define EXPECTS_ARG { \ if (--argc <= 0) { \ err = 1; \ - fprintf(stderr, "pterm: %s expects an argument\n", p); \ + fprintf(stderr, "%s: %s expects an argument\n", appname, p); \ continue; \ } else \ val = *++argv; \ @@ -2105,7 +2114,8 @@ int do_cmdline(int argc, char **argv, int do_everything, SECOND_PASS_ONLY; if (!gdk_color_parse(val, &col)) { err = 1; - fprintf(stderr, "pterm: unable to parse colour \"%s\"\n", val); + fprintf(stderr, "%s: unable to parse colour \"%s\"\n", + appname, val); } else { int index; index = (!strcmp(p, "-fg") ? 0 : @@ -2134,9 +2144,10 @@ int do_cmdline(int argc, char **argv, int do_everything, pty_argv[argc] = NULL; break; /* finished command-line processing */ } else - err = 1, fprintf(stderr, "pterm: -e expects an argument\n"); + err = 1, fprintf(stderr, "%s: -e expects an argument\n", + appname); - } else if (!strcmp(p, "-T")) { + } else if (!strcmp(p, "-title")) { EXPECTS_ARG; SECOND_PASS_ONLY; strncpy(cfg->wintitle, val, sizeof(cfg->wintitle)); @@ -2195,7 +2206,7 @@ int do_cmdline(int argc, char **argv, int do_everything, } else { err = 1; - fprintf(stderr, "pterm: unrecognized option '%s'\n", p); + fprintf(stderr, "%s: unrecognized option '%s'\n", appname, p); } } @@ -2289,6 +2300,80 @@ void uxsel_input_remove(int id) { gdk_input_remove(id); } +void setup_fonts_ucs(struct gui_data *inst) +{ + int font_charset; + + if (inst->fonts[0]) + gdk_font_unref(inst->fonts[0]); + if (inst->fonts[1]) + gdk_font_unref(inst->fonts[1]); + if (inst->fonts[2]) + gdk_font_unref(inst->fonts[2]); + if (inst->fonts[3]) + gdk_font_unref(inst->fonts[3]); + + inst->fonts[0] = gdk_font_load(inst->cfg.font.name); + if (!inst->fonts[0]) { + fprintf(stderr, "%s: unable to load font \"%s\"\n", appname, + inst->cfg.font.name); + exit(1); + } + font_charset = set_font_info(inst, 0); + if (inst->cfg.boldfont.name[0]) { + inst->fonts[1] = gdk_font_load(inst->cfg.boldfont.name); + if (!inst->fonts[1]) { + fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname, + inst->cfg.boldfont.name); + exit(1); + } + set_font_info(inst, 1); + } else + inst->fonts[1] = NULL; + if (inst->cfg.widefont.name[0]) { + inst->fonts[2] = gdk_font_load(inst->cfg.widefont.name); + if (!inst->fonts[2]) { + fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname, + inst->cfg.widefont.name); + exit(1); + } + set_font_info(inst, 2); + } else + inst->fonts[2] = NULL; + if (inst->cfg.wideboldfont.name[0]) { + inst->fonts[3] = gdk_font_load(inst->cfg.wideboldfont.name); + if (!inst->fonts[3]) { + fprintf(stderr, "%s: unable to load wide/bold font \"%s\"\n", + appname, inst->cfg.wideboldfont.name); + exit(1); + } + set_font_info(inst, 3); + } else + inst->fonts[3] = NULL; + + inst->font_width = gdk_char_width(inst->fonts[0], ' '); + inst->font_height = inst->fonts[0]->ascent + inst->fonts[0]->descent; + + inst->direct_to_font = init_ucs(&inst->ucsdata, + inst->cfg.line_codepage, font_charset); +} + +void set_geom_hints(struct gui_data *inst) +{ + GdkGeometry geom; + geom.min_width = inst->font_width + 2*inst->cfg.window_border; + geom.min_height = inst->font_height + 2*inst->cfg.window_border; + geom.max_width = geom.max_height = -1; + geom.base_width = 2*inst->cfg.window_border; + geom.base_height = 2*inst->cfg.window_border; + geom.width_inc = inst->font_width; + geom.height_inc = inst->font_height; + geom.min_aspect = geom.max_aspect = 0; + gtk_window_set_geometry_hints(GTK_WINDOW(inst->window), inst->area, &geom, + GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | + GDK_HINT_RESIZE_INC); +} + void clear_scrollback_menuitem(GtkMenuItem *item, gpointer data) { struct gui_data *inst = (struct gui_data *)data; @@ -2312,8 +2397,114 @@ void special_menuitem(GtkMenuItem *item, gpointer data) void about_menuitem(GtkMenuItem *item, gpointer data) { - /* struct gui_data *inst = (struct gui_data *)data; */ - about_box(); + struct gui_data *inst = (struct gui_data *)data; + about_box(inst->window); +} + +void event_log_menuitem(GtkMenuItem *item, gpointer data) +{ + struct gui_data *inst = (struct gui_data *)data; + showeventlog(inst->eventlogstuff, inst->window); +} + +void change_settings_menuitem(GtkMenuItem *item, gpointer data) +{ + /* This maps colour indices in inst->cfg to those used in inst->cols. */ + static const int ww[] = { + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, + 0, 1, 2, 3, 4, 5 + }; + struct gui_data *inst = (struct gui_data *)data; + char *title = dupcat(appname, " Reconfiguration", NULL); + Config cfg2, oldcfg; + int i, need_size; + + cfg2 = inst->cfg; /* structure copy */ + + if (do_config_box(title, &cfg2, 1)) { + + oldcfg = inst->cfg; /* structure copy */ + inst->cfg = cfg2; /* structure copy */ + + /* Pass new config data to the logging module */ + log_reconfig(inst->logctx, &cfg2); + /* + * Flush the line discipline's edit buffer in the case + * where local editing has just been disabled. + */ + ldisc_send(inst->ldisc, NULL, 0, 0); + /* Pass new config data to the terminal */ + term_reconfig(inst->term, &cfg2); + /* Pass new config data to the back end */ + inst->back->reconfig(inst->backhandle, &cfg2); + + /* + * Just setting inst->cfg is sufficient to cause colour + * setting changes to appear on the next ESC]R palette + * reset. But we should also check whether any colour + * settings have been changed, and revert the ones that + * have to the new default, on the assumption that the user + * is most likely to want an immediate update. + */ + for (i = 0; i < NCOLOURS; i++) { + if (oldcfg.colours[ww[i]][0] != cfg2.colours[ww[i]][0] || + oldcfg.colours[ww[i]][1] != cfg2.colours[ww[i]][1] || + oldcfg.colours[ww[i]][2] != cfg2.colours[ww[i]][2]) + real_palette_set(inst, i, cfg2.colours[ww[i]][0], + cfg2.colours[ww[i]][1], + cfg2.colours[ww[i]][2]); + } + + /* + * If the scrollbar needs to be shown, hidden, or moved + * from one end to the other of the window, do so now. + */ + if (oldcfg.scrollbar != cfg2.scrollbar) { + if (cfg2.scrollbar) + gtk_widget_show(inst->sbar); + else + gtk_widget_hide(inst->sbar); + } + if (oldcfg.scrollbar_on_left != cfg2.scrollbar_on_left) { + gtk_box_reorder_child(inst->hbox, inst->sbar, + cfg2.scrollbar_on_left ? 0 : 1); + } + + /* + * Change the window title, if required. + */ + if (strcmp(oldcfg.wintitle, cfg2.wintitle)) + set_title(inst, cfg2.wintitle); + + /* + * Redo the whole tangled fonts and Unicode mess if + * necessary. + */ + if (strcmp(oldcfg.font.name, cfg2.font.name) || + strcmp(oldcfg.boldfont.name, cfg2.boldfont.name) || + strcmp(oldcfg.widefont.name, cfg2.widefont.name) || + strcmp(oldcfg.wideboldfont.name, cfg2.wideboldfont.name) || + strcmp(oldcfg.line_codepage, cfg2.line_codepage)) { + setup_fonts_ucs(inst); + need_size = 1; + } else + need_size = 0; + + /* + * Resize the window. + */ + if (oldcfg.width != cfg2.width || oldcfg.height != cfg2.height || + oldcfg.window_border != cfg2.window_border || need_size) { + set_geom_hints(inst); + request_resize(inst, cfg2.width, cfg2.height); + //term_size(inst->term, cfg2.height, cfg2.width, cfg2.savelines); + // where TF is our configure event going?! + } + + term_invalidate(inst->term); + } + sfree(title); } void update_specials_menu(void *frontend) @@ -2354,7 +2545,6 @@ int pt_main(int argc, char **argv) extern Backend *select_backend(Config *cfg); extern int cfgbox(Config *cfg); struct gui_data *inst; - int font_charset; /* defer any child exit handling until we're ready to deal with * it */ @@ -2380,52 +2570,12 @@ int pt_main(int argc, char **argv) if (!*inst->cfg.host && !cfgbox(&inst->cfg)) exit(0); /* config box hit Cancel */ - inst->fonts[0] = gdk_font_load(inst->cfg.font.name); - if (!inst->fonts[0]) { - fprintf(stderr, "pterm: unable to load font \"%s\"\n", - inst->cfg.font.name); - exit(1); - } - font_charset = set_font_info(inst, 0); - if (inst->cfg.boldfont.name[0]) { - inst->fonts[1] = gdk_font_load(inst->cfg.boldfont.name); - if (!inst->fonts[1]) { - fprintf(stderr, "pterm: unable to load bold font \"%s\"\n", - inst->cfg.boldfont.name); - exit(1); - } - set_font_info(inst, 1); - } else - inst->fonts[1] = NULL; - if (inst->cfg.widefont.name[0]) { - inst->fonts[2] = gdk_font_load(inst->cfg.widefont.name); - if (!inst->fonts[2]) { - fprintf(stderr, "pterm: unable to load wide font \"%s\"\n", - inst->cfg.widefont.name); - exit(1); - } - set_font_info(inst, 2); - } else - inst->fonts[2] = NULL; - if (inst->cfg.wideboldfont.name[0]) { - inst->fonts[3] = gdk_font_load(inst->cfg.wideboldfont.name); - if (!inst->fonts[3]) { - fprintf(stderr, "pterm: unable to load wide/bold font \"%s\"\n", - inst->cfg.wideboldfont.name); - exit(1); - } - set_font_info(inst, 3); - } else - inst->fonts[3] = NULL; + if (!compound_text_atom) + compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE); + if (!utf8_string_atom) + utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE); - inst->font_width = gdk_char_width(inst->fonts[0], ' '); - inst->font_height = inst->fonts[0]->ascent + inst->fonts[0]->descent; - - inst->compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE); - inst->utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE); - - inst->direct_to_font = init_ucs(&inst->ucsdata, - inst->cfg.line_codepage, font_charset); + setup_fonts_ucs(inst); inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); @@ -2434,43 +2584,36 @@ int pt_main(int argc, char **argv) */ palette_reset(inst); + inst->width = inst->cfg.width; + inst->height = inst->cfg.height; + inst->area = gtk_drawing_area_new(); gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area), inst->font_width * inst->cfg.width + 2*inst->cfg.window_border, inst->font_height * inst->cfg.height + 2*inst->cfg.window_border); - if (inst->cfg.scrollbar) { - inst->sbar_adjust = GTK_ADJUSTMENT(gtk_adjustment_new(0,0,0,0,0,0)); - inst->sbar = gtk_vscrollbar_new(inst->sbar_adjust); - } + inst->sbar_adjust = GTK_ADJUSTMENT(gtk_adjustment_new(0,0,0,0,0,0)); + inst->sbar = gtk_vscrollbar_new(inst->sbar_adjust); inst->hbox = GTK_BOX(gtk_hbox_new(FALSE, 0)); - if (inst->cfg.scrollbar) { - if (inst->cfg.scrollbar_on_left) - gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); - else - gtk_box_pack_end(inst->hbox, inst->sbar, FALSE, FALSE, 0); - } + /* + * We always create the scrollbar; it remains invisible if + * unwanted, so we can pop it up quickly if it suddenly becomes + * desirable. + */ + if (inst->cfg.scrollbar_on_left) + gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); gtk_box_pack_start(inst->hbox, inst->area, TRUE, TRUE, 0); + if (!inst->cfg.scrollbar_on_left) + gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(inst->window), GTK_WIDGET(inst->hbox)); - { - GdkGeometry geom; - geom.min_width = inst->font_width + 2*inst->cfg.window_border; - geom.min_height = inst->font_height + 2*inst->cfg.window_border; - geom.max_width = geom.max_height = -1; - geom.base_width = 2*inst->cfg.window_border; - geom.base_height = 2*inst->cfg.window_border; - geom.width_inc = inst->font_width; - geom.height_inc = inst->font_height; - geom.min_aspect = geom.max_aspect = 0; - gtk_window_set_geometry_hints(GTK_WINDOW(inst->window), inst->area, &geom, - GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | - GDK_HINT_RESIZE_INC); - } + set_geom_hints(inst); gtk_widget_show(inst->area); if (inst->cfg.scrollbar) gtk_widget_show(inst->sbar); + else + gtk_widget_hide(inst->sbar); gtk_widget_show(GTK_WIDGET(inst->hbox)); if (inst->gotpos) { @@ -2530,6 +2673,7 @@ int pt_main(int argc, char **argv) { GtkWidget *menuitem; char *s; + extern const int use_event_log; inst->menu = gtk_menu_new(); @@ -2542,6 +2686,10 @@ int pt_main(int argc, char **argv) gtk_signal_connect(GTK_OBJECT(menuitem), "activate", \ GTK_SIGNAL_FUNC(func), inst); \ } while (0) + MKMENUITEM("Change Settings", change_settings_menuitem); + MKMENUITEM(NULL, NULL); + if (use_event_log) + MKMENUITEM("Event Log", event_log_menuitem); MKMENUITEM("Special Commands", NULL); inst->specialsmenu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), inst->specialsmenu); @@ -2564,6 +2712,8 @@ int pt_main(int argc, char **argv) inst->currcursor = inst->textcursor; show_mouseptr(inst, 1); + inst->eventlogstuff = eventlogstuff_new(); + inst->term = term_init(&inst->cfg, &inst->ucsdata, inst); inst->logctx = log_init(inst, &inst->cfg); term_provide_logctx(inst->term, inst->logctx);