Ctrl+rightclick now pops up a context menu in Unix PuTTY and pterm.
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 5 Apr 2003 16:05:00 +0000 (16:05 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 5 Apr 2003 16:05:00 +0000 (16:05 +0000)
This menu is not yet fully populated, but it has an About box (yet
another licence location :-/ ) and supports the new configurable
specials menu (thus making Unix PuTTY do one tiny thing which
OpenSSH-in-a-pterm can't :-).

git-svn-id: svn://svn.tartarus.org/sgt/putty@3062 cda61777-01e9-0310-a592-d414129be87e

CHECKLST.txt
Recipe
putty.h
unix/gtkdlg.c
unix/pterm.c
unix/ptermm.c
unix/unix.h
unix/uxcfg.c
unix/uxputty.c

index 6c72898..b5d1319 100644 (file)
@@ -25,6 +25,9 @@ The resource files:
     + the copyright date appears twice, once in the About box and
       once in the Licence box. Don't forget to change both!
  - putty/mac/mac_res.r
+ - putty/unix/gtkdlg.c
+    + the copyright date appears twice, once in the About box and
+      once in the Licence box. Don't forget to change both!
 
 The documentation (both the preamble blurb and the licence appendix):
 
@@ -34,7 +37,7 @@ The documentation (both the preamble blurb and the licence appendix):
 The website:
 
  - putty-website/licence.html
+
 Before tagging a release
 ------------------------
 
diff --git a/Recipe b/Recipe
index 79187e6..6bb4fa1 100644 (file)
--- a/Recipe
+++ b/Recipe
@@ -154,7 +154,7 @@ puttygen : [G] puttygen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
 
 pterm    : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs
          + logging uxprint settings pty uxsel be_none uxstore signal CHARSET
-        + cmdline ptermm
+        + cmdline ptermm UXCFG version
 putty    : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs
          + logging uxprint settings pty uxsel be_all uxstore signal CHARSET
         + uxputty NONSSH UXSSH UXMISC logging ux_x11 UXCFG
diff --git a/putty.h b/putty.h
index cff103b..76bfe00 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -305,6 +305,12 @@ extern struct backend_list {
 extern const int be_default_protocol;
 
 /*
+ * Name of this particular application, for use in the config box
+ * and other pieces of text.
+ */
+extern const char *const appname;
+
+/*
  * IMPORTANT POLICY POINT: everything in this structure which wants
  * to be treated like an integer must be an actual, honest-to-
  * goodness `int'. No enum-typed variables. This is because parts
index a454d8b..267555a 100644 (file)
@@ -2355,3 +2355,104 @@ void fatalbox(char *p, ...)
     sfree(msg);
     cleanup_exit(1);
 }
+
+static GtkWidget *aboutbox = NULL;
+
+static void about_close_clicked(GtkButton *button, gpointer data)
+{
+    gtk_widget_destroy(aboutbox);
+    aboutbox = NULL;
+}
+
+static void licence_clicked(GtkButton *button, gpointer data)
+{
+    char *title;
+
+    char *licence =
+       "Copyright 1997-2003 Simon Tatham.\n\n"
+
+       "Portions copyright Robert de Bath, Joris van Rantwijk, Delian "
+       "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas "
+       "Barry, Justin Bradford, Ben Harris, and CORE SDI S.A.\n\n"
+
+       "Permission is hereby granted, free of charge, to any person "
+       "obtaining a copy of this software and associated documentation "
+       "files (the ""Software""), to deal in the Software without restriction, "
+       "including without limitation the rights to use, copy, modify, merge, "
+       "publish, distribute, sublicense, and/or sell copies of the Software, "
+       "and to permit persons to whom the Software is furnished to do so, "
+       "subject to the following conditions:\n\n"
+
+       "The above copyright notice and this permission notice shall be "
+       "included in all copies or substantial portions of the Software.\n\n"
+
+       "THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT "
+       "WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, "
+       "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
+       "MERCHANTABILITY, FITNESS FOR A PARTICULAR "
+       "PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE "
+       "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES "
+       "OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, "
+       "TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN "
+       "CONNECTION WITH THE SOFTWARE OR THE USE OR "
+       "OTHER DEALINGS IN THE SOFTWARE.";
+
+    title = dupcat(appname, " Licence", NULL);
+    assert(aboutbox != NULL);
+    messagebox(aboutbox, title, licence,
+              string_width("LONGISH LINE OF TEXT SO THE LICENCE"
+                           " BOX ISN'T EXCESSIVELY TALL AND THIN"),
+              "OK", 'o', 1, 1, NULL);
+    sfree(title);
+}
+
+void about_box(void)
+{
+    GtkWidget *w;
+    char *title;
+
+    if (aboutbox) {
+        gtk_widget_grab_focus(aboutbox);
+       return;
+    }
+
+    aboutbox = gtk_dialog_new();
+    gtk_container_set_border_width(GTK_CONTAINER(aboutbox), 10);
+    title = dupcat("About ", appname, NULL);
+    gtk_window_set_title(GTK_WINDOW(aboutbox), title);
+    sfree(title);
+
+    w = gtk_button_new_with_label("Close");
+    GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
+    gtk_window_set_default(GTK_WINDOW(aboutbox), w);
+    gtk_box_pack_end(GTK_BOX(GTK_DIALOG(aboutbox)->action_area),
+                    w, FALSE, FALSE, 0);
+    gtk_signal_connect(GTK_OBJECT(w), "clicked",
+                      GTK_SIGNAL_FUNC(about_close_clicked), NULL);
+    gtk_widget_show(w);
+
+    w = gtk_button_new_with_label("View Licence");
+    GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
+    gtk_box_pack_end(GTK_BOX(GTK_DIALOG(aboutbox)->action_area),
+                    w, FALSE, FALSE, 0);
+    gtk_signal_connect(GTK_OBJECT(w), "clicked",
+                      GTK_SIGNAL_FUNC(licence_clicked), NULL);
+    gtk_widget_show(w);
+
+    w = gtk_label_new(appname);
+    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(aboutbox)->vbox),
+                      w, FALSE, FALSE, 0);
+    gtk_widget_show(w);
+
+    w = gtk_label_new(ver);
+    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(aboutbox)->vbox),
+                      w, FALSE, FALSE, 5);
+    gtk_widget_show(w);
+
+    w = gtk_label_new("Copyright 1997-2003 Simon Tatham. All rights reserved");
+    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(aboutbox)->vbox),
+                      w, FALSE, FALSE, 5);
+    gtk_widget_show(w);
+
+    gtk_widget_show(aboutbox);
+}
index 57c8d02..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 {
@@ -148,14 +149,6 @@ void ldisc_update(void *frontend, int echo, int edit)
      */
 }
 
-void update_specials_menu(void *frontend)
-{
-    /*
-     * When I implement a context menu in pterm, I will need to
-     * support this function properly.
-     */
-}
-
 int askappend(void *frontend, Filename filename)
 {
     /*
@@ -968,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)
@@ -2293,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);
@@ -2457,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);
@@ -2498,6 +2591,7 @@ 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);
 
index 128f310..6bc0ea2 100644 (file)
@@ -7,6 +7,37 @@
 
 #include "putty.h"
 
+const char *const appname = "pterm";
+
+/*
+ * Another bunch of temporary stub functions. These ones will want
+ * removing by means of implementing them properly: libcharset
+ * should invent its own sensible format for codepage names and a
+ * means of enumerating them, and printer_enum needs to be dealt
+ * with somehow or other too.
+ */
+
+char *cp_name(int codepage)
+{
+    return "";
+}
+char *cp_enumerate(int index)
+{
+    return NULL;
+}
+int decode_codepage(char *cp_name)
+{
+    return -2;
+}
+
+printer_enum *printer_start_enum(int *nprinters_ptr) {
+    *nprinters_ptr = 0;
+    return NULL;
+}
+char *printer_get_name(printer_enum *pe, int i) { return NULL;
+}
+void printer_finish_enum(printer_enum *pe) { }
+
 Backend *select_backend(Config *cfg)
 {
     return &pty_backend;
@@ -17,11 +48,6 @@ int cfgbox(Config *cfg)
     return 1;                         /* no-op in pterm */
 }
 
-void fatal_message_box(void *window, char *msg)
-{
-    /* also a no-op in pterm */
-}
-
 void cleanup_exit(int code)
 {
     exit(code);
index 8c4b5fd..d9a57fb 100644 (file)
@@ -60,6 +60,7 @@ void *get_window(void *frontend);      /* void * to avoid depending on gtk.h */
 
 /* Things pterm.c needs from gtkdlg.c */
 void fatal_message_box(void *window, char *msg);
+void about_box(void);
 
 /* Things pterm.c needs from {ptermm,uxputty}.c */
 char *make_default_wintitle(char *hostname);
index 97bcdc9..ff68368 100644 (file)
 #include "dialog.h"
 #include "storage.h"
 
+static void about_handler(union control *ctrl, void *dlg,
+                         void *data, int event)
+{
+    if (event == EVENT_ACTION) {
+       about_box();
+    }
+}
+
 void unix_setup_config_box(struct controlbox *b, int midsession)
 {
     struct controlset *s, *s2;
     union control *c;
     int i;
 
-#ifdef FIXME
     if (!midsession) {
        /*
         * Add the About button to the standard panel.
         */
        s = ctrl_getset(b, "", "", "");
        c = ctrl_pushbutton(s, "About", 'a', HELPCTX(no_help),
-                           about_handler, P(hwndp));
+                           about_handler, P(NULL));
        c->generic.column = 0;
     }
-#endif
 
     /*
      * The Config structure contains two Unix-specific elements
index dcfbd20..1690402 100644 (file)
  *    have uxcfg.c remove the drop-down list completely, since you
  *    can't sensibly provide an enumerated list of lpr commands!).
  * 
- *  - Ctrl+right-click for a context menu (also in Windows for
- *    consistency, I think). This should contain pretty much
- *    everything in the Windows PuTTY menu, and a subset of that in
- *    pterm:
- * 
- *     - Telnet special commands (not in pterm :-)
+ *  - Remainder of the context menu:
  * 
  *     - Event Log (this means we must implement the Event Log; not
  *       in pterm)
  *          to get hold of the application name.
  * 
  *     - Copy All to Clipboard (for what that's worth)
- * 
- *     - Clear Scrollback and Reset Terminal
- * 
- *     - About (and uxcfg.c must also supply the about box)
  */
 
 /*
@@ -111,6 +102,8 @@ char *printer_get_name(printer_enum *pe, int i) { return NULL;
 }
 void printer_finish_enum(printer_enum *pe) { }
 
+const char *const appname = "PuTTY";
+
 Backend *select_backend(Config *cfg)
 {
     int i;