X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/f579cda810e80c59cc719e0feea999e88ab09907..f160b7b8908cac4a7ca37b49928b7855fe0a11fe:/unix/gtkwin.c diff --git a/unix/gtkwin.c b/unix/gtkwin.c index f969b046..dc8d6607 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -28,6 +28,7 @@ #include "putty.h" #include "terminal.h" +#include "gtkfont.h" #define CAT2(x,y) x ## y #define CAT(x,y) CAT2(x,y) @@ -58,11 +59,7 @@ struct gui_data { *restartitem; GtkWidget *sessionsmenu; GdkPixmap *pixmap; - GdkFont *fonts[4]; /* normal, bold, wide, widebold */ - struct { - int charset; - int is_wide; - } fontinfo[4]; + unifont *fonts[4]; /* normal, bold, wide, widebold */ int xpos, ypos, gotpos, gravity; GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor; GdkColor cols[NALLCOLOURS]; @@ -137,7 +134,7 @@ FontSpec platform_default_fontspec(const char *name) { FontSpec ret; if (!strcmp(name, "Font")) - strcpy(ret.name, "fixed"); + strcpy(ret.name, "server:fixed"); else *ret.name = '\0'; return ret; @@ -155,6 +152,8 @@ Filename platform_default_filename(const char *name) char *platform_default_s(const char *name) { + if (!strcmp(name, "SerialLine")) + return dupstr("/dev/ttyS0"); return NULL; } @@ -189,6 +188,22 @@ int from_backend(void *frontend, int is_stderr, const char *data, int len) return term_data(inst->term, is_stderr, data, len); } +int from_backend_untrusted(void *frontend, const char *data, int len) +{ + struct gui_data *inst = (struct gui_data *)frontend; + return term_data_untrusted(inst->term, data, len); +} + +int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) +{ + struct gui_data *inst = (struct gui_data *)p->frontend; + int ret; + ret = cmdline_get_passwd_input(p, in, inlen); + if (ret == -1) + ret = term_get_userpass_input(inst->term, p, in, inlen); + return ret; +} + void logevent(void *frontend, const char *string) { struct gui_data *inst = (struct gui_data *)frontend; @@ -309,7 +324,7 @@ void set_zoomed(void *frontend, int zoomed) */ #if GTK_CHECK_VERSION(2,0,0) struct gui_data *inst = (struct gui_data *)frontend; - if (iconic) + if (zoomed) gtk_window_maximize(GTK_WINDOW(inst->window)); else gtk_window_unmaximize(GTK_WINDOW(inst->window)); @@ -645,13 +660,12 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) end = 2; } - /* Control-Break is the same as Control-C */ + /* Control-Break sends a Break special to the backend */ if (event->keyval == GDK_Break && (event->state & GDK_CONTROL_MASK)) { - output[1] = '\003'; - use_ucsoutput = FALSE; - end = 2; - special = TRUE; + if (inst->back) + inst->back->special(inst->backhandle, TS_BRK); + return TRUE; } /* We handle Return ourselves, because it needs to be flagged as @@ -706,6 +720,13 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) end = 1 + sprintf(output+1, "\033[Z"); use_ucsoutput = FALSE; } + /* And normal Tab is Tab, if the keymap hasn't already told us. + * (Curiously, at least one version of the MacOS 10.5 X server + * doesn't translate Tab for us. */ + if (event->keyval == GDK_Tab && end <= 1) { + output[1] = '\t'; + end = 2; + } /* * NetHack keypad mode. @@ -713,19 +734,21 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) if (inst->cfg.nethack_keypad) { char *keys = NULL; switch (event->keyval) { - case GDK_KP_1: case GDK_KP_End: keys = "bB"; break; - case GDK_KP_2: case GDK_KP_Down: keys = "jJ"; break; - case GDK_KP_3: case GDK_KP_Page_Down: keys = "nN"; break; - case GDK_KP_4: case GDK_KP_Left: keys = "hH"; break; - case GDK_KP_5: case GDK_KP_Begin: keys = ".."; break; - case GDK_KP_6: case GDK_KP_Right: keys = "lL"; break; - case GDK_KP_7: case GDK_KP_Home: keys = "yY"; break; - case GDK_KP_8: case GDK_KP_Up: keys = "kK"; break; - case GDK_KP_9: case GDK_KP_Page_Up: keys = "uU"; break; + case GDK_KP_1: case GDK_KP_End: keys = "bB\002"; break; + case GDK_KP_2: case GDK_KP_Down: keys = "jJ\012"; break; + case GDK_KP_3: case GDK_KP_Page_Down: keys = "nN\016"; break; + case GDK_KP_4: case GDK_KP_Left: keys = "hH\010"; break; + case GDK_KP_5: case GDK_KP_Begin: keys = "..."; break; + case GDK_KP_6: case GDK_KP_Right: keys = "lL\014"; break; + case GDK_KP_7: case GDK_KP_Home: keys = "yY\031"; break; + case GDK_KP_8: case GDK_KP_Up: keys = "kK\013"; break; + case GDK_KP_9: case GDK_KP_Page_Up: keys = "uU\025"; break; } if (keys) { end = 2; - if (event->state & GDK_SHIFT_MASK) + if (event->state & GDK_CONTROL_MASK) + output[1] = keys[2]; + else if (event->state & GDK_SHIFT_MASK) output[1] = keys[1]; else output[1] = keys[0]; @@ -1185,6 +1208,7 @@ void notify_remote_exit(void *frontend) inst->back->free(inst->backhandle); inst->backhandle = NULL; inst->back = NULL; + term_provide_resize_fn(inst->term, NULL, NULL); update_specials_menu(inst); } gtk_widget_show(inst->restartitem); @@ -1326,17 +1350,29 @@ void request_resize(void *frontend, int w, int h) */ #if GTK_CHECK_VERSION(2,0,0) gtk_widget_set_size_request(inst->area, area_x, area_y); + gtk_window_resize(GTK_WINDOW(inst->window), + area_x + offset_x, area_y + offset_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 - + /* + * I can no longer remember what this call to + * gtk_container_dequeue_resize_handler is for. It was + * introduced in r3092 with no comment, and the commit log + * message was uninformative. I'm _guessing_ its purpose is to + * prevent gratuitous resize processing on the window given + * that we're about to resize it anyway, but I have no idea + * why that's so incredibly vital. + * + * I've tried removing the call, and nothing seems to go + * wrong. I've backtracked to r3092 and tried removing the + * call there, and still nothing goes wrong. So I'm going to + * adopt the working hypothesis that it's superfluous; I won't + * actually remove it from the GTK 1.2 code, but I won't + * attempt to replicate its functionality in the GTK 2 code + * above. + */ 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); -#else gdk_window_resize(inst->window->window, area_x + offset_x, area_y + offset_y); #endif @@ -1374,8 +1410,13 @@ void palette_set(void *frontend, int n, int r, int g, int b) if (n > NALLCOLOURS) return; real_palette_set(inst, n, r, g, b); - if (n == 258) + if (n == 258) { + /* Default Background changed. Ensure space between text area and + * window border is redrawn */ set_window_background(inst); + draw_backing_rect(inst); + gtk_widget_queue_draw(inst->area); + } } void palette_reset(void *frontend) @@ -1407,12 +1448,12 @@ void palette_reset(void *frontend) for (i = 0; i < NEXTCOLOURS; i++) { if (i < 216) { int r = i / 36, g = (i / 6) % 6, b = i % 6; - inst->cols[i+16].red = r * 0x3333; - inst->cols[i+16].green = g * 0x3333; - inst->cols[i+16].blue = b * 0x3333; + inst->cols[i+16].red = r ? r * 0x2828 + 0x3737 : 0; + inst->cols[i+16].green = g ? g * 0x2828 + 0x3737 : 0; + inst->cols[i+16].blue = b ? b * 0x2828 + 0x3737 : 0; } else { int shade = i - 216; - shade = (shade + 1) * 0xFFFF / (NEXTCOLOURS - 216 + 1); + shade = shade * 0x0a0a + 0x0808; inst->cols[i+16].red = inst->cols[i+16].green = inst->cols[i+16].blue = shade; } @@ -1427,7 +1468,13 @@ void palette_reset(void *frontend) inst->cfg.colours[i][1], inst->cfg.colours[i][2]); } + /* Since Default Background may have changed, ensure that space + * between text area and window border is refreshed. */ set_window_background(inst); + if (inst->area && inst->area->window) { + draw_backing_rect(inst); + gtk_widget_queue_draw(inst->area); + } } /* Ensure that all the cut buffers exist - according to the ICCCM, we must @@ -1435,22 +1482,23 @@ void palette_reset(void *frontend) */ void init_cutbuffers() { + unsigned char empty[] = ""; XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER0, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER0, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER1, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER1, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER2, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER2, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER3, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER3, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER4, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER4, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER5, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER5, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER6, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER6, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER7, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER7, XA_STRING, 8, PropModeAppend, empty, 0); } /* Store the data in a cut-buffer. */ @@ -1475,7 +1523,7 @@ char * retrieve_cutbuffer(int * nbytes) return ptr; } -void write_clip(void *frontend, wchar_t * data, int len, int must_deselect) +void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_deselect) { struct gui_data *inst = (struct gui_data *)frontend; if (inst->pasteout_data) @@ -1570,15 +1618,16 @@ void selection_get(GtkWidget *widget, GtkSelectionData *seldata, struct gui_data *inst = (struct gui_data *)data; if (seldata->target == utf8_string_atom) gtk_selection_data_set(seldata, seldata->target, 8, - inst->pasteout_data_utf8, + (unsigned char *)inst->pasteout_data_utf8, inst->pasteout_data_utf8_len); else if (seldata->target == compound_text_atom) gtk_selection_data_set(seldata, seldata->target, 8, - inst->pasteout_data_ctext, + (unsigned char *)inst->pasteout_data_ctext, inst->pasteout_data_ctext_len); else gtk_selection_data_set(seldata, seldata->target, 8, - inst->pasteout_data, inst->pasteout_data_len); + (unsigned char *)inst->pasteout_data, + inst->pasteout_data_len); } gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, @@ -1832,9 +1881,9 @@ void sys_cursor(void *frontend, int x, int y) * may want to perform additional actions on any kind of bell (for * example, taskbar flashing in Windows). */ -void beep(void *frontend, int mode) +void do_beep(void *frontend, int mode) { - if (mode != BELL_VISUAL) + if (mode == BELL_DEFAULT) gdk_beep(); } @@ -1844,6 +1893,8 @@ int char_width(Context ctx, int uc) * Under X, any fixed-width font really _is_ fixed-width. * Double-width characters will be dealt with using a separate * font. For the moment we can simply return 1. + * + * FIXME: but is that also true of Pango? */ return 1; } @@ -1884,7 +1935,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, struct gui_data *inst = dctx->inst; GdkGC *gc = dctx->gc; int ncombining, combining; - int nfg, nbg, t, fontid, shadow, rlen, widefactor; + int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold; int monochrome = gtk_widget_get_visual(inst->area)->depth == 1; if (attr & TATTR_COMBINING) { @@ -1923,10 +1974,27 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, } if ((attr & ATTR_BOLD) && !inst->cfg.bold_colour) { - if (inst->fonts[fontid | 1]) - fontid |= 1; - else - shadow = 1; + bold = 1; + fontid |= 1; + } else { + bold = 0; + } + + if (!inst->fonts[fontid]) { + int i; + /* + * Fall back through font ids with subsets of this one's + * set bits, in order. + */ + for (i = fontid; i-- > 0 ;) { + if (i & ~fontid) + continue; /* some other bit is set */ + if (inst->fonts[i]) { + fontid = i; + break; + } + } + assert(inst->fonts[fontid]); /* we should at least have hit zero */ } if ((lattr & LATTR_MODE) != LATTR_NORM) { @@ -1957,76 +2025,27 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, gdk_gc_set_foreground(gc, &inst->cols[nfg]); { - GdkWChar *gwcs; gchar *gcs; - wchar_t *wcs; - int i; - wcs = snewn(len*ncombining+1, wchar_t); - for (i = 0; i < len*ncombining; i++) { - wcs[i] = text[i]; - } + /* + * FIXME: this length is hardwired on the assumption that + * conversions from wide to multibyte characters will + * never generate more than 10 bytes for a single wide + * character. + */ + gcs = snewn(len*10+1, gchar); - if (inst->fonts[fontid] == NULL) { - /* - * The font for this contingency does not exist. - * Typically this means we've been given ATTR_WIDE - * character and have no wide font. So we display - * nothing at all; such is life. - */ - } else if (inst->fontinfo[fontid].is_wide) { - /* - * At least one version of gdk_draw_text_wc() has a - * weird bug whereby it reads `len' elements of the - * input string, but only draws `len/2'. Hence I'm - * going to make its input array twice as long as it - * theoretically needs to be, and pass in twice the - * actual number of characters. If a fixed gdk actually - * takes the doubled length seriously, then (a) the - * array will stand scrutiny up to the full length, (b) - * the spare elements of the array are full of zeroes - * which will probably be an empty glyph in the font, - * and (c) the clip rectangle should prevent it causing - * trouble anyway. - */ - gwcs = snewn(len*2+1, GdkWChar); - memset(gwcs, 0, sizeof(GdkWChar) * (len*2+1)); - /* - * FIXME: when we have a wide-char equivalent of - * from_unicode, use it instead of this. - */ - for (combining = 0; combining < ncombining; combining++) { - for (i = 0; i <= len; i++) - gwcs[i] = wcs[i + combining]; - gdk_draw_text_wc(inst->pixmap, inst->fonts[fontid], gc, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, - gwcs, len*2); - if (shadow) - gdk_draw_text_wc(inst->pixmap, inst->fonts[fontid], gc, - x*inst->font_width+inst->cfg.window_border+inst->cfg.shadowboldoffset, - y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, - gwcs, len*2); - } - sfree(gwcs); - } else { - gcs = snewn(len+1, gchar); - for (combining = 0; combining < ncombining; combining++) { - wc_to_mb(inst->fontinfo[fontid].charset, 0, - wcs + combining, len, gcs, len, ".", NULL, NULL); - gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc, + for (combining = 0; combining < ncombining; combining++) { + int mblen = wc_to_mb(inst->fonts[fontid]->real_charset, 0, + text + combining, len, gcs, len*10+1, ".", + NULL, NULL); + unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid], x*inst->font_width+inst->cfg.window_border, y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, - gcs, len); - if (shadow) - gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc, - x*inst->font_width+inst->cfg.window_border+inst->cfg.shadowboldoffset, - y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, - gcs, len); - } - sfree(gcs); + gcs, mblen, widefactor > 1, bold, inst->font_width); } - sfree(wcs); + + sfree(gcs); } if (attr & ATTR_UNDER) { @@ -2246,8 +2265,11 @@ GdkCursor *make_mouse_ptr(struct gui_data *inst, int cursor_val) return NULL; } - if (cursor_val >= 0 && !cursor_font) + if (cursor_val >= 0 && !cursor_font) { cursor_font = gdk_font_load("cursor"); + if (cursor_font) + gdk_font_ref(cursor_font); + } /* * Get the text extent of the cursor in question. We use the @@ -2369,7 +2391,7 @@ static void help(FILE *fp) { } } -int do_cmdline(int argc, char **argv, int do_everything, +int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, struct gui_data *inst, Config *cfg) { int err = 0; @@ -2451,15 +2473,16 @@ int do_cmdline(int argc, char **argv, int do_everything, cfg->line_codepage[sizeof(cfg->line_codepage)-1] = '\0'; } else if (!strcmp(p, "-geometry")) { - int flags, x, y, w, h; + int flags, x, y; + unsigned int w, h; EXPECTS_ARG; SECOND_PASS_ONLY; flags = XParseGeometry(val, &x, &y, &w, &h); if (flags & WidthValue) - cfg->width = w; + cfg->width = (int)w; if (flags & HeightValue) - cfg->height = h; + cfg->height = (int)h; if (flags & (XValue | YValue)) { inst->xpos = x; @@ -2574,7 +2597,8 @@ int do_cmdline(int argc, char **argv, int do_everything, exit(1); } else if(p[0] != '-' && (!do_everything || - process_nonoption_arg(p, cfg))) { + process_nonoption_arg(p, cfg, + allow_launch))) { /* do nothing */ } else { @@ -2586,75 +2610,12 @@ int do_cmdline(int argc, char **argv, int do_everything, return err; } -/* - * This function retrieves the character set encoding of a font. It - * returns the character set without the X11 hack (in case the user - * asks to use the font's own encoding). - */ -static int set_font_info(struct gui_data *inst, int fontid) -{ - GdkFont *font = inst->fonts[fontid]; - XFontStruct *xfs = GDK_FONT_XFONT(font); - Display *disp = GDK_FONT_XDISPLAY(font); - Atom charset_registry, charset_encoding; - unsigned long registry_ret, encoding_ret; - int retval = CS_NONE; - - charset_registry = XInternAtom(disp, "CHARSET_REGISTRY", False); - charset_encoding = XInternAtom(disp, "CHARSET_ENCODING", False); - inst->fontinfo[fontid].charset = CS_NONE; - inst->fontinfo[fontid].is_wide = 0; - if (XGetFontProperty(xfs, charset_registry, ®istry_ret) && - XGetFontProperty(xfs, charset_encoding, &encoding_ret)) { - char *reg, *enc; - reg = XGetAtomName(disp, (Atom)registry_ret); - enc = XGetAtomName(disp, (Atom)encoding_ret); - if (reg && enc) { - char *encoding = dupcat(reg, "-", enc, NULL); - retval = inst->fontinfo[fontid].charset = - charset_from_xenc(encoding); - /* FIXME: when libcharset supports wide encodings fix this. */ - if (!strcasecmp(encoding, "iso10646-1")) { - inst->fontinfo[fontid].is_wide = 1; - retval = CS_UTF8; - } - - /* - * Hack for X line-drawing characters: if the primary - * font is encoded as ISO-8859-anything, and has valid - * glyphs in the first 32 char positions, it is assumed - * that those glyphs are the VT100 line-drawing - * character set. - * - * Actually, we'll hack even harder by only checking - * position 0x19 (vertical line, VT100 linedrawing - * `x'). Then we can check it easily by seeing if the - * ascent and descent differ. - */ - if (inst->fontinfo[fontid].charset == CS_ISO8859_1) { - int lb, rb, wid, asc, desc; - gchar text[2]; - - text[1] = '\0'; - text[0] = '\x12'; - gdk_string_extents(inst->fonts[fontid], text, - &lb, &rb, &wid, &asc, &desc); - if (asc != desc) - inst->fontinfo[fontid].charset = CS_ISO8859_1_X11; - } - - sfree(encoding); - } - } - - return retval; -} - int uxsel_input_add(int fd, int rwx) { int flags = 0; if (rwx & 1) flags |= GDK_INPUT_READ; if (rwx & 2) flags |= GDK_INPUT_WRITE; if (rwx & 4) flags |= GDK_INPUT_EXCEPTION; + assert(flags); return gdk_input_add(fd, flags, fd_input_func, NULL); } @@ -2662,158 +2623,75 @@ void uxsel_input_remove(int id) { gdk_input_remove(id); } -char *guess_derived_font_name(GdkFont *font, int bold, int wide) -{ - XFontStruct *xfs = GDK_FONT_XFONT(font); - Display *disp = GDK_FONT_XDISPLAY(font); - Atom fontprop = XInternAtom(disp, "FONT", False); - unsigned long ret; - if (XGetFontProperty(xfs, fontprop, &ret)) { - char *name = XGetAtomName(disp, (Atom)ret); - if (name && name[0] == '-') { - char *strings[13]; - char *dupname, *extrafree = NULL, *ret; - char *p, *q; - int nstr; - - p = q = dupname = dupstr(name); /* skip initial minus */ - nstr = 0; - - while (*p && nstr < lenof(strings)) { - if (*p == '-') { - *p = '\0'; - strings[nstr++] = p+1; - } - p++; - } - - if (nstr < lenof(strings)) - return NULL; /* XLFD was malformed */ - - if (bold) - strings[2] = "bold"; - - if (wide) { - /* 4 is `wideness', which obviously may have changed. */ - /* 5 is additional style, which may be e.g. `ja' or `ko'. */ - strings[4] = strings[5] = "*"; - strings[11] = extrafree = dupprintf("%d", 2*atoi(strings[11])); - } - - ret = dupcat("-", strings[ 0], "-", strings[ 1], "-", strings[ 2], - "-", strings[ 3], "-", strings[ 4], "-", strings[ 5], - "-", strings[ 6], "-", strings[ 7], "-", strings[ 8], - "-", strings[ 9], "-", strings[10], "-", strings[11], - "-", strings[12], NULL); - sfree(extrafree); - sfree(dupname); - - return ret; - } - } - return NULL; -} - void setup_fonts_ucs(struct gui_data *inst) { - int font_charset; - char *name; - int guessed; - if (inst->fonts[0]) - gdk_font_unref(inst->fonts[0]); + unifont_destroy(inst->fonts[0]); if (inst->fonts[1]) - gdk_font_unref(inst->fonts[1]); + unifont_destroy(inst->fonts[1]); if (inst->fonts[2]) - gdk_font_unref(inst->fonts[2]); + unifont_destroy(inst->fonts[2]); if (inst->fonts[3]) - gdk_font_unref(inst->fonts[3]); + unifont_destroy(inst->fonts[3]); - inst->fonts[0] = gdk_font_load(inst->cfg.font.name); + inst->fonts[0] = unifont_create(inst->area, inst->cfg.font.name, + FALSE, FALSE, + inst->cfg.shadowboldoffset, + inst->cfg.shadowbold); 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.shadowbold) { + if (inst->cfg.shadowbold || !inst->cfg.boldfont.name[0]) { inst->fonts[1] = NULL; } else { - 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) { + inst->fonts[1] = unifont_create(inst->area, inst->cfg.boldfont.name, + FALSE, TRUE, + inst->cfg.shadowboldoffset, + inst->cfg.shadowbold); + if (!inst->fonts[1]) { fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname, inst->cfg.boldfont.name); exit(1); } - if (guessed) - sfree(name); } if (inst->cfg.widefont.name[0]) { - name = inst->cfg.widefont.name; - guessed = FALSE; + inst->fonts[2] = unifont_create(inst->area, inst->cfg.widefont.name, + TRUE, FALSE, + inst->cfg.shadowboldoffset, + inst->cfg.shadowbold); + if (!inst->fonts[2]) { + fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname, + inst->cfg.widefont.name); + exit(1); + } } else { - name = guess_derived_font_name(inst->fonts[0], FALSE, TRUE); - guessed = TRUE; - } - inst->fonts[2] = name ? gdk_font_load(name) : NULL; - if (inst->fonts[2]) { - set_font_info(inst, 2); - } else if (!guessed) { - fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname, - inst->cfg.widefont.name); - exit(1); + inst->fonts[2] = NULL; } - if (guessed) - sfree(name); - if (inst->cfg.shadowbold) { + if (inst->cfg.shadowbold || !inst->cfg.wideboldfont.name[0]) { inst->fonts[3] = NULL; } else { - 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); + inst->fonts[3] = unifont_create(inst->area, + inst->cfg.wideboldfont.name, TRUE, + TRUE, inst->cfg.shadowboldoffset, + inst->cfg.shadowbold); + if (!inst->fonts[3]) { + fprintf(stderr, "%s: unable to load wide bold font \"%s\"\n", appname, + inst->cfg.boldfont.name); exit(1); } - if (guessed) - sfree(name); } - inst->font_width = gdk_char_width(inst->fonts[0], ' '); - inst->font_height = inst->fonts[0]->ascent + inst->fonts[0]->descent; + inst->font_width = inst->fonts[0]->width; + inst->font_height = inst->fonts[0]->height; inst->direct_to_font = init_ucs(&inst->ucsdata, inst->cfg.line_codepage, - inst->cfg.utf8_override, font_charset, + inst->cfg.utf8_override, + inst->fonts[0]->public_charset, inst->cfg.vtmode); } @@ -2842,7 +2720,7 @@ void clear_scrollback_menuitem(GtkMenuItem *item, gpointer data) void reset_terminal_menuitem(GtkMenuItem *item, gpointer data) { struct gui_data *inst = (struct gui_data *)data; - term_pwron(inst->term); + term_pwron(inst->term, TRUE); if (inst->ldisc) ldisc_send(inst->ldisc, NULL, 0, 0); } @@ -3213,6 +3091,7 @@ void restart_session_menuitem(GtkMenuItem *item, gpointer data) if (!inst->back) { logevent(inst, "----- Session restarted -----"); + term_pwron(inst->term, FALSE); start_backend(inst); inst->exited = FALSE; } @@ -3260,6 +3139,36 @@ static void update_savedsess_menu(GtkMenuItem *menuitem, gpointer data) get_sesslist(&sesslist, FALSE); /* free up */ } +void set_window_icon(GtkWidget *window, const char *const *const *icon, + int n_icon) +{ + GdkPixmap *iconpm; + GdkBitmap *iconmask; +#if GTK_CHECK_VERSION(2,0,0) + GList *iconlist; + int n; +#endif + + if (!n_icon) + return; + + gtk_widget_realize(window); + iconpm = gdk_pixmap_create_from_xpm_d(window->window, &iconmask, + NULL, (gchar **)icon[0]); + gdk_window_set_icon(window->window, NULL, iconpm, iconmask); + +#if GTK_CHECK_VERSION(2,0,0) + iconlist = NULL; + for (n = 0; n < n_icon; n++) { + iconlist = + g_list_append(iconlist, + gdk_pixbuf_new_from_xpm_data((const gchar **) + icon[n])); + } + gdk_window_set_icon_list(window->window, iconlist); +#endif +} + void update_specials_menu(void *frontend) { struct gui_data *inst = (struct gui_data *)frontend; @@ -3356,6 +3265,8 @@ static void start_backend(struct gui_data *inst) set_icon(inst, title); sfree(title); } + sfree(realhost); + inst->back->provide_logctx(inst->backhandle, inst->logctx); term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle); @@ -3404,15 +3315,23 @@ int pt_main(int argc, char **argv) /* Splatter this argument so it doesn't clutter a ps listing */ memset(argv[1], 0, strlen(argv[1])); } else { - if (do_cmdline(argc, argv, 0, inst, &inst->cfg)) + /* By default, we bring up the config dialog, rather than launching + * a session. This gets set to TRUE if something happens to change + * that (e.g., a hostname is specified on the command-line). */ + int allow_launch = FALSE; + if (do_cmdline(argc, argv, 0, &allow_launch, inst, &inst->cfg)) exit(1); /* pre-defaults pass to get -class */ do_defaults(NULL, &inst->cfg); - if (do_cmdline(argc, argv, 1, inst, &inst->cfg)) + if (do_cmdline(argc, argv, 1, &allow_launch, inst, &inst->cfg)) exit(1); /* post-defaults, do everything */ cmdline_run_saved(&inst->cfg); - if (!*inst->cfg.host && !cfgbox(&inst->cfg)) + if (loaded_session) + allow_launch = TRUE; + + if ((!allow_launch || !cfg_launchable(&inst->cfg)) && + !cfgbox(&inst->cfg)) exit(0); /* config box hit Cancel */ } @@ -3421,6 +3340,8 @@ int pt_main(int argc, char **argv) if (!utf8_string_atom) utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE); + inst->area = gtk_drawing_area_new(); + setup_fonts_ucs(inst); init_cutbuffers(); @@ -3434,7 +3355,6 @@ int pt_main(int argc, char **argv) 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); @@ -3509,6 +3429,12 @@ int pt_main(int argc, char **argv) GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK); + { + extern const char *const *const main_icon[]; + extern const int n_main_icon; + set_window_icon(inst->window, main_icon, n_main_icon); + } + gtk_widget_show(inst->window); set_window_background(inst);