From 47e4e7359053574f16061e9d692394fc9f2f3b74 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 5 Apr 2003 16:05:00 +0000 Subject: [PATCH] Ctrl+rightclick now pops up a context menu in Unix PuTTY and pterm. 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 | 5 ++- Recipe | 2 +- putty.h | 6 ++++ unix/gtkdlg.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++ unix/pterm.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- unix/ptermm.c | 36 ++++++++++++++++--- unix/unix.h | 1 + unix/uxcfg.c | 12 +++++-- unix/uxputty.c | 13 ++----- 9 files changed, 258 insertions(+), 28 deletions(-) diff --git a/CHECKLST.txt b/CHECKLST.txt index 6c72898b..b5d13191 100644 --- a/CHECKLST.txt +++ b/CHECKLST.txt @@ -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 79187e61..6bb4fa10 100644 --- 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 cff103bb..76bfe002 100644 --- 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 diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index a454d8bb..267555a3 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -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); +} diff --git a/unix/pterm.c b/unix/pterm.c index 57c8d028..928d304b 100644 --- a/unix/pterm.c +++ b/unix/pterm.c @@ -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); diff --git a/unix/ptermm.c b/unix/ptermm.c index 128f3102..6bc0ea2c 100644 --- a/unix/ptermm.c +++ b/unix/ptermm.c @@ -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); diff --git a/unix/unix.h b/unix/unix.h index 8c4b5fd9..d9a57fb0 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -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); diff --git a/unix/uxcfg.c b/unix/uxcfg.c index 97bcdc9b..ff683686 100644 --- a/unix/uxcfg.c +++ b/unix/uxcfg.c @@ -10,23 +10,29 @@ #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 diff --git a/unix/uxputty.c b/unix/uxputty.c index dcfbd200..16904028 100644 --- a/unix/uxputty.c +++ b/unix/uxputty.c @@ -20,12 +20,7 @@ * 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) @@ -63,10 +58,6 @@ * 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; -- 2.11.0