X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/330f49beb368e6eedcacbf4306c9936d24660a24..887035a593c8c0a1af853657c80046e17dc5581a:/unix/pterm.c diff --git a/unix/pterm.c b/unix/pterm.c index d4b8f4d3..c072e7a9 100644 --- a/unix/pterm.c +++ b/unix/pterm.c @@ -11,11 +11,14 @@ #include #include #include +#include +#include #include #include #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" +#include "terminal.h" #define CAT2(x,y) x ## y #define CAT(x,y) CAT2(x,y) @@ -41,6 +44,7 @@ struct gui_data { int mouseptr_visible; guint term_paste_idle_id; GdkAtom compound_text_atom; + int alt_keycode; char wintitle[sizeof(((Config *)0)->wintitle)]; char icontitle[sizeof(((Config *)0)->wintitle)]; }; @@ -79,6 +83,14 @@ void logevent(char *string) */ } +int font_dimension(int which) /* 0 for width, 1 for height */ +{ + if (which) + return inst->font_height; + else + return inst->font_width; +} + /* * Translate a raw mouse button designation (LEFT, MIDDLE, RIGHT) * into a cooked one (SELECT, EXTEND, PASTE). @@ -150,7 +162,7 @@ void set_zorder(int top) */ void refresh_window(void) { - term_invalidate(); + term_invalidate(term); } /* @@ -245,10 +257,8 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data) struct gui_data *inst = (struct gui_data *)data; int w, h, need_size = 0; -printf("configure %d x %d\n", event->width, event->height); w = (event->width - 2*cfg.window_border) / inst->font_width; h = (event->height - 2*cfg.window_border) / inst->font_height; -printf(" = %d x %d\n", w, h); if (w != cfg.width || h != cfg.height) { if (inst->pixmap) { @@ -258,7 +268,6 @@ printf(" = %d x %d\n", w, h); cfg.width = w; cfg.height = h; need_size = 1; -printf("need size\n"); } if (!inst->pixmap) { GdkGC *gc; @@ -278,7 +287,7 @@ printf("need size\n"); } if (need_size) { - term_size(h, w, cfg.savelines); + term_size(term, h, w, cfg.savelines); } return TRUE; @@ -312,6 +321,25 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) char output[32]; int start, end; + /* By default, nothing is generated. */ + end = start = 0; + + /* + * If Alt is being released after typing an Alt+numberpad + * sequence, we should generate the code that was typed. + */ + if (event->type == GDK_KEY_RELEASE && + (event->keyval == GDK_Meta_L || event->keyval == GDK_Alt_L || + event->keyval == GDK_Meta_R || event->keyval == GDK_Alt_R) && + inst->alt_keycode >= 0) { +#ifdef KEY_DEBUGGING + printf("Alt key up, keycode = %d\n", inst->alt_keycode); +#endif + output[0] = inst->alt_keycode; + end = 1; + goto done; + } + if (event->type == GDK_KEY_PRESS) { #ifdef KEY_DEBUGGING { @@ -325,21 +353,69 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) #endif /* - * NYI: - * - alt+numpad - * - Compose key (!!! requires Unicode faff before even trying) + * NYI: Compose key (!!! requires Unicode faff before even trying) */ /* + * If Alt has just been pressed, we start potentially + * accumulating an Alt+numberpad code. We do this by + * setting alt_keycode to -1 (nothing yet but plausible). + */ + if ((event->keyval == GDK_Meta_L || event->keyval == GDK_Alt_L || + event->keyval == GDK_Meta_R || event->keyval == GDK_Alt_R)) { + inst->alt_keycode = -1; + goto done; /* this generates nothing else */ + } + + /* + * If we're seeing a numberpad key press with Mod1 down, + * consider adding it to alt_keycode if that's sensible. + * Anything _else_ with Mod1 down cancels any possibility + * of an ALT keycode: we set alt_keycode to -2. + */ + if ((event->state & GDK_MOD1_MASK) && inst->alt_keycode != -2) { + int digit = -1; + switch (event->keyval) { + case GDK_KP_0: case GDK_KP_Insert: digit = 0; break; + case GDK_KP_1: case GDK_KP_End: digit = 1; break; + case GDK_KP_2: case GDK_KP_Down: digit = 2; break; + case GDK_KP_3: case GDK_KP_Page_Down: digit = 3; break; + case GDK_KP_4: case GDK_KP_Left: digit = 4; break; + case GDK_KP_5: case GDK_KP_Begin: digit = 5; break; + case GDK_KP_6: case GDK_KP_Right: digit = 6; break; + case GDK_KP_7: case GDK_KP_Home: digit = 7; break; + case GDK_KP_8: case GDK_KP_Up: digit = 8; break; + case GDK_KP_9: case GDK_KP_Page_Up: digit = 9; break; + } + if (digit < 0) + inst->alt_keycode = -2; /* it's invalid */ + else { +#ifdef KEY_DEBUGGING + printf("Adding digit %d to keycode %d", digit, + inst->alt_keycode); +#endif + if (inst->alt_keycode == -1) + inst->alt_keycode = digit; /* one-digit code */ + else + inst->alt_keycode = inst->alt_keycode * 10 + digit; +#ifdef KEY_DEBUGGING + printf(" gives new code %d\n", inst->alt_keycode); +#endif + /* Having used this digit, we now do nothing more with it. */ + goto done; + } + } + + /* * Shift-PgUp and Shift-PgDn don't even generate keystrokes * at all. */ if (event->keyval == GDK_Page_Up && (event->state & GDK_SHIFT_MASK)) { - term_scroll(0, -cfg.height/2); + term_scroll(term, 0, -cfg.height/2); return TRUE; } if (event->keyval == GDK_Page_Down && (event->state & GDK_SHIFT_MASK)) { - term_scroll(0, +cfg.height/2); + term_scroll(term, 0, +cfg.height/2); return TRUE; } @@ -356,9 +432,10 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) strncpy(output+1, event->string, 31); output[31] = '\0'; end = strlen(output); - if (event->state & GDK_MOD1_MASK) + if (event->state & GDK_MOD1_MASK) { start = 0; - else + if (end == 1) end = 0; + } else start = 1; /* Control-` is the same as Control-\ (unless gtk has a better idea) */ @@ -399,6 +476,12 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) output[1] = cfg.bksp_is_delete ? '\x7F' : '\x08'; end = 2; } + /* For Shift Backspace, do opposite of what is configured. */ + if (event->keyval == GDK_BackSpace && + (event->state & GDK_SHIFT_MASK)) { + output[1] = cfg.bksp_is_delete ? '\x08' : '\x7F'; + end = 2; + } /* Shift-Tab is ESC [ Z */ if (event->keyval == GDK_ISO_Left_Tab || @@ -435,7 +518,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) /* * Application keypad mode. */ - if (app_keypad_keys && !cfg.no_applic_k) { + if (term->app_keypad_keys && !cfg.no_applic_k) { int xkey = 0; switch (event->keyval) { case GDK_Num_Lock: xkey = 'P'; break; @@ -473,7 +556,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) case GDK_KP_Decimal: case GDK_KP_Delete: xkey = 'n'; break; } if (xkey) { - if (vt52_mode) { + if (term->vt52_mode) { if (xkey >= 'P' && xkey <= 'S') end = 1 + sprintf(output+1, "\033%c", xkey); else @@ -581,7 +664,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) if (cfg.funky_type == 3 && code <= 6) code = "\0\2\1\4\5\3\6"[code]; - if (vt52_mode && code > 0 && code <= 6) { + if (term->vt52_mode && code > 0 && code <= 6) { end = 1 + sprintf(output+1, "\x1B%c", " HLMEIG"[code]); goto done; } @@ -620,13 +703,14 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) } goto done; } - if ((vt52_mode || cfg.funky_type == 4) && code >= 11 && code <= 24) { + if ((term->vt52_mode || cfg.funky_type == 4) && + code >= 11 && code <= 24) { int offt = 0; if (code > 15) offt++; if (code > 21) offt++; - if (vt52_mode) + if (term->vt52_mode) end = 1 + sprintf(output+1, "\x1B%c", code + 'P' - 11 - offt); else @@ -639,7 +723,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) goto done; } if (cfg.funky_type == 2 && code >= 11 && code <= 14) { - if (vt52_mode) + if (term->vt52_mode) end = 1 + sprintf(output+1, "\x1B%c", code + 'P' - 11); else end = 1 + sprintf(output+1, "\x1BO%c", code + 'P' - 11); @@ -677,9 +761,9 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * app cursor keys mode they do ESC O A instead. * Ctrl toggles the two modes. */ - if (vt52_mode) { + if (term->vt52_mode) { end = 1 + sprintf(output+1, "\033%c", xkey); - } else if (!app_cursor_keys ^ + } else if (!term->app_cursor_keys ^ !(event->state & GDK_CONTROL_MASK)) { end = 1 + sprintf(output+1, "\033O%c", xkey); } else { @@ -688,23 +772,24 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) goto done; } } + goto done; + } - done: + done: + if (end-start > 0) { #ifdef KEY_DEBUGGING - { - int i; - printf("generating sequence:"); - for (i = start; i < end; i++) - printf(" %02x", (unsigned char) output[i]); - printf("\n"); - } + int i; + printf("generating sequence:"); + for (i = start; i < end; i++) + printf(" %02x", (unsigned char) output[i]); + printf("\n"); #endif - if (end-start > 0) { - ldisc_send(output+start, end-start, 1); - show_mouseptr(0); - term_out(); - } + + ldisc_send(output+start, end-start, 1); + show_mouseptr(0); + term_seen_key_event(term); + term_out(term); } return TRUE; @@ -717,6 +802,15 @@ gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) show_mouseptr(1); + if (event->button == 4 && event->type == GDK_BUTTON_PRESS) { + term_scroll(term, 0, -5); + return TRUE; + } + if (event->button == 5 && event->type == GDK_BUTTON_PRESS) { + term_scroll(term, 0, +5); + return TRUE; + } + shift = event->state & GDK_SHIFT_MASK; ctrl = event->state & GDK_CONTROL_MASK; alt = event->state & GDK_MOD1_MASK; @@ -744,7 +838,7 @@ gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) x = (event->x - cfg.window_border) / inst->font_width; y = (event->y - cfg.window_border) / inst->font_height; - term_mouse(button, act, x, y, shift, ctrl, alt); + term_mouse(term, button, act, x, y, shift, ctrl, alt); return TRUE; } @@ -771,7 +865,7 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) x = (event->x - cfg.window_border) / inst->font_width; y = (event->y - cfg.window_border) / inst->font_height; - term_mouse(button, MA_DRAG, x, y, shift, ctrl, alt); + term_mouse(term, button, MA_DRAG, x, y, shift, ctrl, alt); return TRUE; } @@ -793,7 +887,8 @@ gint timer_func(gpointer data) exit(0); } - term_update(); + term_update(term); + term_blink(term, 0); return TRUE; } @@ -819,8 +914,9 @@ void pty_input_func(gpointer data, gint sourcefd, GdkInputCondition condition) exit(1); } if (ret > 0) - from_backend(0, buf, ret); - term_out(); + from_backend(term, 0, buf, ret); + term_blink(term, 1); + term_out(term); } void destroy(GtkWidget *widget, gpointer data) @@ -830,9 +926,9 @@ void destroy(GtkWidget *widget, gpointer data) gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) { - has_focus = event->in; - term_out(); - term_update(); + term->has_focus = event->in; + term_out(term); + term_update(term); show_mouseptr(1); return FALSE; } @@ -853,9 +949,68 @@ void set_raw_mouse_mode(int activate) void request_resize(int w, int h) { - gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area), - inst->font_width * w + 2*cfg.window_border, - inst->font_height * h + 2*cfg.window_border); + int large_x, large_y; + int offset_x, offset_y; + int area_x, area_y; + GtkRequisition inner, outer; + + /* + * This is a heinous hack dreamed up by the gnome-terminal + * people to get around a limitation in gtk. The problem is + * that in order to set the size correctly we really need to be + * calling gtk_window_resize - but that needs to know the size + * of the _whole window_, not the drawing area. So what we do + * is to set an artificially huge size request on the drawing + * area, recompute the resulting size request on the window, + * and look at the difference between the two. That gives us + * the x and y offsets we need to translate drawing area size + * into window size for real, and then we call + * gtk_window_resize. + */ + + /* + * We start by retrieving the current size of the whole window. + * Adding a bit to _that_ will give us a value we can use as a + * bogus size request which guarantees to be bigger than the + * current size of the drawing area. + */ + get_window_pixels(&large_x, &large_y); + large_x += 32; + large_y += 32; + +#if GTK_CHECK_VERSION(2,0,0) + gtk_widget_set_size_request(inst->area, large_x, large_y); +#else + gtk_widget_set_usize(inst->area, large_x, large_y); +#endif + gtk_widget_size_request(inst->area, &inner); + gtk_widget_size_request(inst->window, &outer); + + offset_x = outer.width - inner.width; + offset_y = outer.height - inner.height; + + area_x = inst->font_width * w + 2*cfg.window_border; + area_y = inst->font_height * h + 2*cfg.window_border; + + /* + * Now we must set the size request on the drawing area back to + * something sensible before we commit the real resize. Best + * way to do this, I think, is to set it to what the size is + * really going to end up being. + */ +#if GTK_CHECK_VERSION(2,0,0) + gtk_widget_set_size_request(inst->area, area_x, area_y); +#else + gtk_widget_set_usize(inst->area, area_x, area_y); +#endif + +#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 } void real_palette_set(int n, int r, int g, int b) @@ -947,7 +1102,7 @@ void selection_get(GtkWidget *widget, GtkSelectionData *seldata, gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, gpointer data) { - term_deselect(); + term_deselect(term); if (inst->pasteout_data) sfree(inst->pasteout_data); inst->pasteout_data = NULL; @@ -983,9 +1138,9 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata, mb_to_wc(0, 0, seldata->data, seldata->length, inst->pastein_data, inst->pastein_data_len); - term_do_paste(); + term_do_paste(term); - if (term_paste_pending()) + if (term_paste_pending(term)) inst->term_paste_idle_id = gtk_idle_add(idle_paste_func, inst); } @@ -993,8 +1148,8 @@ gint idle_paste_func(gpointer data) { struct gui_data *inst = (struct gui_data *)data; - if (term_paste_pending()) - term_paste(); + if (term_paste_pending(term)) + term_paste(term); else gtk_idle_remove(inst->term_paste_idle_id); @@ -1044,7 +1199,7 @@ void scrollbar_moved(GtkAdjustment *adj, gpointer data) if (!cfg.scrollbar) return; if (!inst->ignore_sbar) - term_scroll(1, (int)adj->value); + term_scroll(term, 1, (int)adj->value); } void sys_cursor(int x, int y) @@ -1090,17 +1245,15 @@ void free_ctx(Context ctx) * * We are allowed to fiddle with the contents of `text'. */ -void do_text(Context ctx, int x, int y, char *text, int len, - unsigned long attr, int lattr) +void do_text_internal(Context ctx, int x, int y, char *text, int len, + unsigned long attr, int lattr) { - int nfg, nbg, t; + int nfg, nbg, t, fontid, shadow; GdkGC *gc = (GdkGC *)ctx; /* * NYI: * - Unicode, code pages, and ATTR_WIDE for CJK support. - * - cursor shapes other than block - * - shadow bolding */ nfg = 2 * ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); @@ -1119,12 +1272,20 @@ void do_text(Context ctx, int x, int y, char *text, int len, nbg = NCOLOURS-1; } + fontid = shadow = 0; + if ((attr & ATTR_BOLD) && !cfg.bold_colour) { + if (inst->fonts[1]) + fontid = 1; + else + shadow = 1; + } + if (lattr != LATTR_NORM) { x *= 2; - if (x >= cols) + if (x >= term->cols) return; - if (x + len*2 > cols) - len = (cols-x)/2; /* trim to LH half */ + if (x + len*2 > term->cols) + len = (term->cols-x)/2; /* trim to LH half */ } gdk_gc_set_foreground(gc, &inst->cols[nbg]); @@ -1134,11 +1295,18 @@ void do_text(Context ctx, int x, int y, char *text, int len, len*inst->font_width, inst->font_height); gdk_gc_set_foreground(gc, &inst->cols[nfg]); - gdk_draw_text(inst->pixmap, inst->fonts[0], gc, + gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc, x*inst->font_width+cfg.window_border, y*inst->font_height+cfg.window_border+inst->fonts[0]->ascent, text, len); + if (shadow) { + gdk_draw_text(inst->pixmap, inst->fonts[fontid], gc, + x*inst->font_width+cfg.window_border + cfg.shadowboldoffset, + y*inst->font_height+cfg.window_border+inst->fonts[0]->ascent, + text, len); + } + if (attr & ATTR_UNDER) { int uheight = inst->fonts[0]->ascent + 1; if (uheight >= inst->font_height) @@ -1184,6 +1352,22 @@ void do_text(Context ctx, int x, int y, char *text, int len, len * inst->font_width, inst->font_height-i-1); } } + } +} + +void do_text(Context ctx, int x, int y, char *text, int len, + unsigned long attr, int lattr) +{ + GdkGC *gc = (GdkGC *)ctx; + + do_text_internal(ctx, x, y, text, len, attr, lattr); + + if (lattr != LATTR_NORM) { + x *= 2; + if (x >= term->cols) + return; + if (x + len*2 > term->cols) + len = (term->cols-x)/2; /* trim to LH half */ len *= 2; } @@ -1201,28 +1385,91 @@ void do_cursor(Context ctx, int x, int y, char *text, int len, int passive; GdkGC *gc = (GdkGC *)ctx; - /* - * NYI: cursor shapes other than block - */ if (attr & TATTR_PASCURS) { attr &= ~TATTR_PASCURS; passive = 1; } else passive = 0; - do_text(ctx, x, y, text, len, attr, lattr); - if (passive) { + if ((attr & TATTR_ACTCURS) && cfg.cursor_type != 0) { + attr &= ~TATTR_ACTCURS; + } + do_text_internal(ctx, x, y, text, len, attr, lattr); + + if (lattr != LATTR_NORM) { + x *= 2; + if (x >= term->cols) + return; + if (x + len*2 > term->cols) + len = (term->cols-x)/2; /* trim to LH half */ + len *= 2; + } + + if (cfg.cursor_type == 0) { + /* + * An active block cursor will already have been done by + * the above do_text call, so we only need to do anything + * if it's passive. + */ + if (passive) { + gdk_gc_set_foreground(gc, &inst->cols[NCOLOURS-1]); + gdk_draw_rectangle(inst->pixmap, gc, 0, + x*inst->font_width+cfg.window_border, + y*inst->font_height+cfg.window_border, + len*inst->font_width-1, inst->font_height-1); + } + } else { + int uheight; + int startx, starty, dx, dy, length, i; + + int char_width; + + if ((attr & ATTR_WIDE) || lattr != LATTR_NORM) + char_width = 2*inst->font_width; + else + char_width = inst->font_width; + + if (cfg.cursor_type == 1) { + uheight = inst->fonts[0]->ascent + 1; + if (uheight >= inst->font_height) + uheight = inst->font_height - 1; + + startx = x * inst->font_width + cfg.window_border; + starty = y * inst->font_height + cfg.window_border + uheight; + dx = 1; + dy = 0; + length = len * char_width; + } else { + int xadjust = 0; + if (attr & TATTR_RIGHTCURS) + xadjust = char_width - 1; + startx = x * inst->font_width + cfg.window_border + xadjust; + starty = y * inst->font_height + cfg.window_border; + dx = 0; + dy = 1; + length = inst->font_height; + } + gdk_gc_set_foreground(gc, &inst->cols[NCOLOURS-1]); - gdk_draw_rectangle(inst->pixmap, gc, 0, - x*inst->font_width+cfg.window_border, - y*inst->font_height+cfg.window_border, - len*inst->font_width-1, inst->font_height-1); - gdk_draw_pixmap(inst->area->window, gc, inst->pixmap, - x*inst->font_width+cfg.window_border, - y*inst->font_height+cfg.window_border, - x*inst->font_width+cfg.window_border, - y*inst->font_height+cfg.window_border, - len*inst->font_width, inst->font_height); + if (passive) { + for (i = 0; i < length; i++) { + if (i % 2 == 0) { + gdk_draw_point(inst->pixmap, gc, startx, starty); + } + startx += dx; + starty += dy; + } + } else { + gdk_draw_line(inst->pixmap, gc, startx, starty, + startx + (length-1) * dx, starty + (length-1) * dy); + } } + + gdk_draw_pixmap(inst->area->window, gc, inst->pixmap, + x*inst->font_width+cfg.window_border, + y*inst->font_height+cfg.window_border, + x*inst->font_width+cfg.window_border, + y*inst->font_height+cfg.window_border, + len*inst->font_width, inst->font_height); } GdkCursor *make_mouse_ptr(int cursor_val) @@ -1333,26 +1580,101 @@ char *get_x_display(void) return gdk_get_display(); } -int main(int argc, char **argv) +char *app_name = "pterm"; + +int do_cmdline(int argc, char **argv, int do_everything) { - extern int pty_master_fd; /* declared in pty.c */ - extern char **pty_argv; /* declared in pty.c */ int err = 0; + extern char **pty_argv; /* declared in pty.c */ - gtk_init(&argc, &argv); + /* + * Macros to make argument handling easier. + */ +#define EXPECTS_ARG do { \ + if (--argc <= 0) { \ + err = 1; \ + fprintf(stderr, "pterm: %s expects an argument\n", p); \ + } else \ + val = *++argv; \ +} while (0) +#define SECOND_PASS_ONLY do { \ + if (!do_everything) continue; \ +} while (0) - do_defaults(NULL, &cfg); + /* + * TODO: + * + * finish -geometry + */ + char *val; while (--argc > 0) { char *p = *++argv; - if (!strcmp(p, "-fn")) { - if (--argc > 0) { - strncpy(cfg.font, *++argv, sizeof(cfg.font)); - cfg.font[sizeof(cfg.font)-1] = '\0'; - } else - err = 1, fprintf(stderr, "pterm: -fn expects an argument\n"); - } - if (!strcmp(p, "-e")) { + if (!strcmp(p, "-fn") || !strcmp(p, "-font")) { + EXPECTS_ARG; + SECOND_PASS_ONLY; + strncpy(cfg.font, val, sizeof(cfg.font)); + cfg.font[sizeof(cfg.font)-1] = '\0'; + + } else if (!strcmp(p, "-fb")) { + EXPECTS_ARG; + SECOND_PASS_ONLY; + strncpy(cfg.boldfont, val, sizeof(cfg.boldfont)); + cfg.boldfont[sizeof(cfg.boldfont)-1] = '\0'; + + } else if (!strcmp(p, "-geometry")) { + int flags, x, y, w, h; + EXPECTS_ARG; + SECOND_PASS_ONLY; + + flags = XParseGeometry(val, &x, &y, &w, &h); + if (flags & WidthValue) + cfg.width = w; + if (flags & HeightValue) + cfg.height = h; + + /* + * Apparently setting the initial window position is + * difficult in GTK 1.2. Not entirely sure why this + * should be. 2.0 has gtk_window_parse_geometry(), + * which would help... For the moment, though, I can't + * be bothered with this. + */ + + } else if (!strcmp(p, "-sl")) { + EXPECTS_ARG; + SECOND_PASS_ONLY; + cfg.savelines = atoi(val); + + } else if (!strcmp(p, "-fg") || !strcmp(p, "-bg") || + !strcmp(p, "-bfg") || !strcmp(p, "-bbg") || + !strcmp(p, "-cfg") || !strcmp(p, "-cbg")) { + GdkColor col; + + EXPECTS_ARG; + SECOND_PASS_ONLY; + if (!gdk_color_parse(val, &col)) { + err = 1; + fprintf(stderr, "pterm: unable to parse colour \"%s\"\n", val); + } else { + int index; + index = (!strcmp(p, "-fg") ? 0 : + !strcmp(p, "-bg") ? 2 : + !strcmp(p, "-bfg") ? 1 : + !strcmp(p, "-bbg") ? 3 : + !strcmp(p, "-cfg") ? 4 : + !strcmp(p, "-cbg") ? 5 : -1); + assert(index != -1); + cfg.colours[index][0] = col.red / 256; + cfg.colours[index][1] = col.green / 256; + cfg.colours[index][2] = col.blue / 256; + } + + } else if (!strcmp(p, "-e")) { + /* This option swallows all further arguments. */ + if (!do_everything) + break; + if (--argc > 0) { int i; pty_argv = smalloc((argc+1) * sizeof(char *)); @@ -1363,41 +1685,95 @@ int main(int argc, char **argv) break; /* finished command-line processing */ } else err = 1, fprintf(stderr, "pterm: -e expects an argument\n"); - } - if (!strcmp(p, "-T")) { - if (--argc > 0) { - strncpy(cfg.wintitle, *++argv, sizeof(cfg.wintitle)); - cfg.wintitle[sizeof(cfg.wintitle)-1] = '\0'; - } else - err = 1, fprintf(stderr, "pterm: -T expects an argument\n"); - } - if (!strcmp(p, "-log")) { - if (--argc > 0) { - strncpy(cfg.logfilename, *++argv, sizeof(cfg.logfilename)); - cfg.logfilename[sizeof(cfg.logfilename)-1] = '\0'; - cfg.logtype = LGTYP_DEBUG; - } else - err = 1, fprintf(stderr, "pterm: -log expects an argument\n"); - } - if (!strcmp(p, "-hide")) { - cfg.hide_mouseptr = 1; - } - if (!strcmp(p, "-ut-")) { + + } else if (!strcmp(p, "-T")) { + EXPECTS_ARG; + SECOND_PASS_ONLY; + strncpy(cfg.wintitle, val, sizeof(cfg.wintitle)); + cfg.wintitle[sizeof(cfg.wintitle)-1] = '\0'; + + } else if (!strcmp(p, "-log")) { + EXPECTS_ARG; + SECOND_PASS_ONLY; + strncpy(cfg.logfilename, val, sizeof(cfg.logfilename)); + cfg.logfilename[sizeof(cfg.logfilename)-1] = '\0'; + cfg.logtype = LGTYP_DEBUG; + + } else if (!strcmp(p, "-ut-") || !strcmp(p, "+ut")) { + SECOND_PASS_ONLY; cfg.stamp_utmp = 0; - } - if (!strcmp(p, "-ls-")) { + + } else if (!strcmp(p, "-ut")) { + SECOND_PASS_ONLY; + cfg.stamp_utmp = 1; + + } else if (!strcmp(p, "-ls-") || !strcmp(p, "+ls")) { + SECOND_PASS_ONLY; cfg.login_shell = 0; - } - if (!strcmp(p, "-nethack")) { + + } else if (!strcmp(p, "-ls")) { + SECOND_PASS_ONLY; + cfg.login_shell = 1; + + } else if (!strcmp(p, "-nethack")) { + SECOND_PASS_ONLY; cfg.nethack_keypad = 1; - } - if (!strcmp(p, "-sb-")) { + + } else if (!strcmp(p, "-sb-") || !strcmp(p, "+sb")) { + SECOND_PASS_ONLY; + cfg.scrollbar = 0; + + } else if (!strcmp(p, "-sb")) { + SECOND_PASS_ONLY; cfg.scrollbar = 0; + + } else if (!strcmp(p, "-name")) { + EXPECTS_ARG; + app_name = val; + + } else if (!strcmp(p, "-xrm")) { + EXPECTS_ARG; + provide_xrm_string(val); + + } else { + err = 1; + fprintf(stderr, "pterm: unrecognized option '%s'\n", p); } } + return err; +} + +int main(int argc, char **argv) +{ + extern int pty_master_fd; /* declared in pty.c */ + extern void pty_pre_init(void); /* declared in pty.c */ + + pty_pre_init(); + + gtk_init(&argc, &argv); + + if (do_cmdline(argc, argv, 0)) /* pre-defaults pass to get -class */ + exit(1); + do_defaults(NULL, &cfg); + if (do_cmdline(argc, argv, 1)) /* post-defaults, do everything */ + exit(1); + inst->fonts[0] = gdk_font_load(cfg.font); - inst->fonts[1] = NULL; /* FIXME: what about bold font? */ + if (!inst->fonts[0]) { + fprintf(stderr, "pterm: unable to load font \"%s\"\n", cfg.font); + exit(1); + } + if (cfg.boldfont[0]) { + inst->fonts[1] = gdk_font_load(cfg.boldfont); + if (!inst->fonts[1]) { + fprintf(stderr, "pterm: unable to load bold font \"%s\"\n", + cfg.boldfont); + exit(1); + } + } else + inst->fonts[1] = NULL; + inst->font_width = gdk_char_width(inst->fonts[0], ' '); inst->font_height = inst->fonts[0]->ascent + inst->fonts[0]->descent; @@ -1426,11 +1802,13 @@ int main(int argc, char **argv) inst->sbar = gtk_vscrollbar_new(inst->sbar_adjust); } inst->hbox = GTK_BOX(gtk_hbox_new(FALSE, 0)); + if (cfg.scrollbar) { + if (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); + } gtk_box_pack_start(inst->hbox, inst->area, TRUE, TRUE, 0); - if (cfg.scrollbar) - gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); - - gtk_window_set_policy(GTK_WINDOW(inst->window), FALSE, TRUE, TRUE); gtk_container_add(GTK_CONTAINER(inst->window), GTK_WIDGET(inst->hbox)); @@ -1455,6 +1833,8 @@ int main(int argc, char **argv) GTK_SIGNAL_FUNC(delete_window), inst); gtk_signal_connect(GTK_OBJECT(inst->window), "key_press_event", GTK_SIGNAL_FUNC(key_event), inst); + gtk_signal_connect(GTK_OBJECT(inst->window), "key_release_event", + GTK_SIGNAL_FUNC(key_event), inst); gtk_signal_connect(GTK_OBJECT(inst->window), "focus_in_event", GTK_SIGNAL_FUNC(focus_event), inst); gtk_signal_connect(GTK_OBJECT(inst->window), "focus_out_event", @@ -1497,13 +1877,15 @@ int main(int argc, char **argv) inst->currcursor = inst->textcursor; show_mouseptr(1); + term = term_init(); + back = &pty_backend; - back->init(NULL, 0, NULL, 0); + back->init((void *)term, NULL, 0, NULL, 0); - gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst); + term_size(term, cfg.height, cfg.width, cfg.savelines); + ldisc_send(NULL, 0, 0); /* cause ldisc to notice changes */ - term_init(); - term_size(cfg.height, cfg.width, cfg.savelines); + gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst); gtk_main();