Now that we have `appname', make much wider use of it. In
[u/mdw/putty] / unix / pterm.c
index 177e53a..928d304 100644 (file)
@@ -38,6 +38,7 @@ struct gui_data {
     GtkWidget *window, *area, *sbar;
     GtkBox *hbox;
     GtkAdjustment *sbar_adjust;
+    GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2;
     GdkPixmap *pixmap;
     GdkFont *fonts[4];                 /* normal, bold, wide, widebold */
     struct {
@@ -86,6 +87,23 @@ char *x_get_default(const char *key)
     return XGetDefault(GDK_DISPLAY(), app_name, key);
 }
 
+void connection_fatal(void *frontend, char *p, ...)
+{
+    Terminal *term = (Terminal *)frontend;
+    struct gui_data *inst = (struct gui_data *)term->frontend;
+
+    va_list ap;
+    char *msg;
+    va_start(ap, p);
+    msg = dupvprintf(p, ap);
+    va_end(ap);
+    inst->exited = TRUE;
+    fatal_message_box(inst->window, msg);
+    sfree(msg);
+    if (inst->cfg.close_on_exit == FORCE_ON)
+        cleanup_exit(1);
+}
+
 /*
  * Default settings that are specific to pterm.
  */
@@ -943,6 +961,13 @@ gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
     shift = event->state & GDK_SHIFT_MASK;
     ctrl = event->state & GDK_CONTROL_MASK;
     alt = event->state & GDK_MOD1_MASK;
+
+    if (event->button == 3 && ctrl) {
+       gtk_menu_popup(GTK_MENU(inst->menu), NULL, NULL, NULL, NULL,
+                      event->button, event->time);
+       return TRUE;
+    }
+
     if (event->button == 1)
        button = MBT_LEFT;
     else if (event->button == 2)
@@ -1018,7 +1043,8 @@ gint timer_func(gpointer data)
     struct gui_data *inst = (struct gui_data *)data;
     int exitcode;
 
-    if ((exitcode = inst->back->exitcode(inst->backhandle)) >= 0) {
+    if (!inst->exited &&
+        (exitcode = inst->back->exitcode(inst->backhandle)) >= 0) {
        inst->exited = TRUE;
        if (inst->cfg.close_on_exit == FORCE_ON ||
            (inst->cfg.close_on_exit == AUTO && exitcode == 0))
@@ -1032,10 +1058,17 @@ gint timer_func(gpointer data)
 
 void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
 {
-    select_result(sourcefd,
-                 (condition == GDK_INPUT_READ ? 1 :
-                  condition == GDK_INPUT_WRITE ? 2 :
-                  condition == GDK_INPUT_EXCEPTION ? 4 : -1));
+    /*
+     * We must process exceptional notifications before ordinary
+     * readability ones, or we may go straight past the urgent
+     * marker.
+     */
+    if (condition & GDK_INPUT_EXCEPTION)
+        select_result(sourcefd, 4);
+    if (condition & GDK_INPUT_READ)
+        select_result(sourcefd, 1);
+    if (condition & GDK_INPUT_WRITE)
+        select_result(sourcefd, 2);
 }
 
 void destroy(GtkWidget *widget, gpointer data)
@@ -1916,6 +1949,17 @@ void modalfatalbox(char *p, ...)
     exit(1);
 }
 
+void cmdline_error(char *p, ...)
+{
+    va_list ap;
+    fprintf(stderr, "plink: ");
+    va_start(ap, p);
+    vfprintf(stderr, p, ap);
+    va_end(ap);
+    fputc('\n', stderr);
+    exit(1);
+}
+
 char *get_x_display(void *frontend)
 {
     return gdk_get_display();
@@ -1988,6 +2032,20 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg)
     char *val;
     while (--argc > 0) {
        char *p = *++argv;
+        int ret;
+
+        ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
+                                    do_everything ? 1 : -1, cfg);
+
+       if (ret == -2) {
+           cmdline_error("option \"%s\" requires an argument", p);
+       } else if (ret == 2) {
+           --argc, ++argv;            /* skip next argument */
+            continue;
+       } else if (ret == 1) {
+            continue;
+        }
+
        if (!strcmp(p, "-fn") || !strcmp(p, "-font")) {
            EXPECTS_ARG;
            SECOND_PASS_ONLY;
@@ -2135,6 +2193,10 @@ int do_cmdline(int argc, char **argv, int do_everything, Config *cfg)
            help(stdout);
            exit(0);
            
+       } else if(p[0] != '-' && (!do_everything ||
+                                  process_nonoption_arg(p, cfg))) {
+            /* do nothing */
+
        } else {
            err = 1;
            fprintf(stderr, "pterm: unrecognized option '%s'\n", p);
@@ -2231,6 +2293,66 @@ void uxsel_input_remove(int id) {
     gdk_input_remove(id);
 }
 
+void clear_scrollback_menuitem(GtkMenuItem *item, gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+    term_clrsb(inst->term);
+}
+
+void reset_terminal_menuitem(GtkMenuItem *item, gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+    term_pwron(inst->term);
+    ldisc_send(inst->ldisc, NULL, 0, 0);
+}
+
+void special_menuitem(GtkMenuItem *item, gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+    int code = (int)gtk_object_get_data(GTK_OBJECT(item), "user-data");
+
+    inst->back->special(inst->backhandle, code);
+}
+
+void about_menuitem(GtkMenuItem *item, gpointer data)
+{
+    /* struct gui_data *inst = (struct gui_data *)data; */
+    about_box();
+}
+
+void update_specials_menu(void *frontend)
+{
+    Terminal *term = (Terminal *)frontend;
+    struct gui_data *inst = (struct gui_data *)term->frontend;
+
+    const struct telnet_special *specials;
+
+    specials = inst->back->get_specials(inst->backhandle);
+    gtk_container_foreach(GTK_CONTAINER(inst->specialsmenu),
+                         (GtkCallback)gtk_widget_destroy, NULL);
+    if (specials) {
+       int i;
+       GtkWidget *menuitem;
+       for (i = 0; specials[i].name; i++) {
+           if (*specials[i].name) {
+               menuitem = gtk_menu_item_new_with_label(specials[i].name);
+               gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",
+                                   (gpointer)specials[i].code);
+               gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
+                                  GTK_SIGNAL_FUNC(special_menuitem), inst);
+           } else
+               menuitem = gtk_menu_item_new();
+           gtk_container_add(GTK_CONTAINER(inst->specialsmenu), menuitem);
+           gtk_widget_show(menuitem);
+       }
+       gtk_widget_show(inst->specialsitem1);
+       gtk_widget_show(inst->specialsitem2);
+    } else {
+       gtk_widget_hide(inst->specialsitem1);
+       gtk_widget_hide(inst->specialsitem2);
+    }
+}
+
 int pt_main(int argc, char **argv)
 {
     extern Backend *select_backend(Config *cfg);
@@ -2257,7 +2379,9 @@ int pt_main(int argc, char **argv)
     if (do_cmdline(argc, argv, 1, &inst->cfg))
        exit(1);                       /* post-defaults, do everything */
 
-    if (!cfgbox(&inst->cfg))
+    cmdline_run_saved(&inst->cfg);
+
+    if (!*inst->cfg.host && !cfgbox(&inst->cfg))
        exit(0);                       /* config box hit Cancel */
 
     inst->fonts[0] = gdk_font_load(inst->cfg.font.name);
@@ -2393,6 +2517,39 @@ int pt_main(int argc, char **argv)
 
     set_window_background(inst);
 
+    /*
+     * Set up the Ctrl+rightclick context menu.
+     */
+    {
+       GtkWidget *menuitem;
+       char *s;
+
+       inst->menu = gtk_menu_new();
+
+#define MKMENUITEM(title, func) do { \
+    menuitem = title ? gtk_menu_item_new_with_label(title) : \
+    gtk_menu_item_new(); \
+    gtk_container_add(GTK_CONTAINER(inst->menu), menuitem); \
+    gtk_widget_show(menuitem); \
+    if (func != NULL) \
+       gtk_signal_connect(GTK_OBJECT(menuitem), "activate", \
+                              GTK_SIGNAL_FUNC(func), inst); \
+} while (0)
+       MKMENUITEM("Special Commands", NULL);
+       inst->specialsmenu = gtk_menu_new();
+       gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), inst->specialsmenu);
+       inst->specialsitem1 = menuitem;
+       MKMENUITEM(NULL, NULL);
+       inst->specialsitem2 = menuitem;
+       MKMENUITEM("Clear Scrollback", clear_scrollback_menuitem);
+       MKMENUITEM("Reset Terminal", reset_terminal_menuitem);
+       MKMENUITEM(NULL, NULL);
+       s = dupcat("About ", appname, NULL);
+       MKMENUITEM(s, about_menuitem);
+       sfree(s);
+#undef MKMENUITEM
+    }
+
     inst->textcursor = make_mouse_ptr(inst, GDK_XTERM);
     inst->rawcursor = make_mouse_ptr(inst, GDK_LEFT_PTR);
     inst->blankcursor = make_mouse_ptr(inst, -1);
@@ -2406,13 +2563,24 @@ int pt_main(int argc, char **argv)
 
     uxsel_init();
 
+    term_size(inst->term, inst->cfg.height, inst->cfg.width, inst->cfg.savelines);
+
     inst->back = select_backend(&inst->cfg);
     {
-       char *realhost;
-
-       inst->back->init((void *)inst->term, &inst->backhandle, &inst->cfg,
-                        inst->cfg.host, inst->cfg.port, &realhost,
-                        inst->cfg.tcp_nodelay);
+       char *realhost, *error;
+
+       error = inst->back->init((void *)inst->term, &inst->backhandle,
+                                 &inst->cfg, inst->cfg.host, inst->cfg.port,
+                                 &realhost, inst->cfg.tcp_nodelay);
+
+       if (error) {
+           char *msg = dupprintf("Unable to open connection to %s:\n%s",
+                                  inst->cfg.host, error);
+            inst->exited = TRUE;
+           fatal_message_box(inst->window, msg);
+            sfree(msg);
+           return 0;
+       }
 
         if (inst->cfg.wintitle[0])
             set_title(inst, inst->cfg.wintitle);
@@ -2423,11 +2591,10 @@ int pt_main(int argc, char **argv)
         }
     }
     inst->back->provide_logctx(inst->backhandle, inst->logctx);
+    update_specials_menu(inst->term);
 
     term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle);
 
-    term_size(inst->term, inst->cfg.height, inst->cfg.width, inst->cfg.savelines);
-
     inst->ldisc =
        ldisc_create(&inst->cfg, inst->term, inst->back, inst->backhandle, inst);
     ldisc_send(inst->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */