Event Log for Unix PuTTY. Doesn't yet allow X selection of its
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Wed, 9 Apr 2003 18:46:45 +0000 (18:46 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Wed, 9 Apr 2003 18:46:45 +0000 (18:46 +0000)
contents, and doesn't automatically maintain scroll position at the
bottom when new entries are added while the list is open, but it's a
start.

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

dialog.h
unix/gtkdlg.c
unix/pterm.c
unix/ptermm.c
unix/unix.h
unix/uxputty.c

index 078aca1..8daa332 100644 (file)
--- a/dialog.h
+++ b/dialog.h
@@ -305,9 +305,16 @@ union control {
         */
        int draglist;
        /*
-        * If this is set, the list can have more than one element
-        * selected at a time. This is not guaranteed to work on a
-        * drop-down list, so don't try it!
+        * If this is non-zero, the list can have more than one
+        * element selected at a time. This is not guaranteed to
+        * work on a drop-down list, so don't try it!
+        * 
+        * Different non-zero values request slightly different
+        * types of multi-selection (this may well be meaningful
+        * only in GTK, so everyone else can ignore it if they
+        * want). 1 means the list box expects to have individual
+        * items selected, whereas 2 means it expects the user to
+        * want to select a large contiguous range at a time.
         */
        int multisel;
        /*
index 267555a..e699732 100644 (file)
@@ -14,6 +14,7 @@
 #include <assert.h>
 #include <stdarg.h>
 #include <ctype.h>
+#include <time.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkx.h>
@@ -158,6 +159,7 @@ static void dlg_cleanup(struct dlgparam *dp)
     struct uctrl *uc;
 
     freetree234(dp->byctrl);          /* doesn't free the uctrls inside */
+    dp->byctrl = NULL;
     while ( (uc = index234(dp->bywidget, 0)) != NULL) {
        del234(dp->bywidget, uc);
        if (uc->privdata_needs_free)
@@ -166,6 +168,7 @@ static void dlg_cleanup(struct dlgparam *dp)
        sfree(uc);
     }
     freetree234(dp->bywidget);
+    dp->bywidget = NULL;
     sfree(dp->treeitems);
 }
 
@@ -177,12 +180,16 @@ static void dlg_add_uctrl(struct dlgparam *dp, struct uctrl *uc)
 
 static struct uctrl *dlg_find_byctrl(struct dlgparam *dp, union control *ctrl)
 {
+    if (!dp->byctrl)
+       return NULL;
     return find234(dp->byctrl, ctrl, uctrl_cmp_byctrl_find);
 }
 
 static struct uctrl *dlg_find_bywidget(struct dlgparam *dp, GtkWidget *w)
 {
     struct uctrl *ret = NULL;
+    if (!dp->bywidget)
+       return NULL;
     do {
        ret = find234(dp->bywidget, w, uctrl_cmp_bywidget_find);
        if (ret)
@@ -1471,7 +1478,10 @@ GtkWidget *layout_ctrls(struct dlgparam *dp, struct Shortcuts *scs,
                                    GTK_SIGNAL_FUNC(widget_focus), dp);
             } else {
                 uc->list = gtk_list_new();
-                if (ctrl->listbox.multisel) {
+                if (ctrl->listbox.multisel == 2) {
+                    gtk_list_set_selection_mode(GTK_LIST(uc->list),
+                                                GTK_SELECTION_EXTENDED);
+                } else if (ctrl->listbox.multisel == 1) {
                     gtk_list_set_selection_mode(GTK_LIST(uc->list),
                                                 GTK_SELECTION_MULTIPLE);
                 } else {
@@ -1895,6 +1905,15 @@ void shortcut_add(struct Shortcuts *scs, GtkWidget *labelw,
        }
 }
 
+int get_listitemheight(void)
+{
+    GtkWidget *listitem = gtk_list_item_new_with_label("foo");
+    GtkRequisition req;
+    gtk_widget_size_request(listitem, &req);
+    gtk_widget_unref(listitem);
+    return req.height;
+}
+
 int do_config_box(const char *title, Config *cfg)
 {
     GtkWidget *window, *hbox, *vbox, *cols, *label,
@@ -1913,16 +1932,10 @@ int do_config_box(const char *title, Config *cfg)
 
     dlg_init(&dp);
 
-    {
-        GtkWidget *listitem = gtk_list_item_new_with_label("foo");
-        GtkRequisition req;
-        gtk_widget_size_request(listitem, &req);
-        listitemheight = req.height;
-        gtk_widget_unref(listitem);
-    }
-
     get_sesslist(&sl, TRUE);
 
+    listitemheight = get_listitemheight();
+
     for (index = 0; index < lenof(scs.sc); index++) {
        scs.sc[index].action = SHORTCUT_EMPTY;
     }
@@ -2456,3 +2469,167 @@ void about_box(void)
 
     gtk_widget_show(aboutbox);
 }
+
+struct eventlog_stuff {
+    GtkWidget *parentwin, *window;
+    struct controlbox *eventbox;
+    struct Shortcuts scs;
+    struct dlgparam dp;
+    union control *listctrl;
+    char **events;
+    int nevents, negsize;
+};
+
+static void eventlog_destroy(GtkWidget *widget, gpointer data)
+{
+    struct eventlog_stuff *es = (struct eventlog_stuff *)data;
+
+    es->window = NULL;
+    dlg_cleanup(&es->dp);
+    ctrl_free_box(es->eventbox);
+}
+static void eventlog_ok_handler(union control *ctrl, void *dlg,
+                               void *data, int event)
+{
+    if (event == EVENT_ACTION)
+       dlg_end(dlg, 0);
+}
+static void eventlog_list_handler(union control *ctrl, void *dlg,
+                                 void *data, int event)
+{
+    struct eventlog_stuff *es = (struct eventlog_stuff *)data;
+
+    if (event == EVENT_REFRESH) {
+       int i;
+
+       dlg_update_start(ctrl, dlg);
+       dlg_listbox_clear(ctrl, dlg);
+       for (i = 0; i < es->nevents; i++) {
+           dlg_listbox_add(ctrl, dlg, es->events[i]);
+       }
+       dlg_update_done(ctrl, dlg);
+    }
+}
+void showeventlog(void *estuff, void *parentwin)
+{
+    struct eventlog_stuff *es = (struct eventlog_stuff *)estuff;
+    GtkWidget *window, *w0, *w1;
+    GtkWidget *parent = GTK_WIDGET(parentwin);
+    struct controlset *s0, *s1;
+    union control *c;
+    int listitemheight, index;
+    char *title;
+
+    if (es->window) {
+        gtk_widget_grab_focus(es->window);
+       return;
+    }
+
+    dlg_init(&es->dp);
+
+    for (index = 0; index < lenof(es->scs.sc); index++) {
+       es->scs.sc[index].action = SHORTCUT_EMPTY;
+    }
+
+    es->eventbox = ctrl_new_box();
+
+    s0 = ctrl_getset(es->eventbox, "", "", "");
+    ctrl_columns(s0, 3, 33, 34, 33);
+    c = ctrl_pushbutton(s0, "Close", 'c', HELPCTX(no_help),
+                       eventlog_ok_handler, P(NULL));
+    c->button.column = 1;
+    c->button.isdefault = TRUE;
+
+    s1 = ctrl_getset(es->eventbox, "x", "", "");
+    es->listctrl = c = ctrl_listbox(s1, NULL, NO_SHORTCUT, HELPCTX(no_help),
+                                   eventlog_list_handler, P(es));
+    c->listbox.height = 10;
+    c->listbox.multisel = 2;
+    c->listbox.ncols = 3;
+    c->listbox.percentages = snewn(3, int);
+    c->listbox.percentages[0] = 25;
+    c->listbox.percentages[1] = 10;
+    c->listbox.percentages[2] = 65;
+
+    listitemheight = get_listitemheight();
+
+    es->window = window = gtk_dialog_new();
+    title = dupcat(appname, " Event Log", NULL);
+    gtk_window_set_title(GTK_WINDOW(window), title);
+    sfree(title);
+    w0 = layout_ctrls(&es->dp, &es->scs, s0,
+                     listitemheight, GTK_WINDOW(window));
+    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->action_area),
+                      w0, TRUE, TRUE, 0);
+    gtk_widget_show(w0);
+    w1 = layout_ctrls(&es->dp, &es->scs, s1,
+                     listitemheight, GTK_WINDOW(window));
+    gtk_container_set_border_width(GTK_CONTAINER(w1), 10);
+    gtk_widget_set_usize(w1, 20 +
+                        string_width("LINE OF TEXT GIVING WIDTH OF EVENT LOG"
+                                     " IS QUITE LONG 'COS SSH LOG ENTRIES"
+                                     " ARE WIDE"), -1);
+    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox),
+                      w1, TRUE, TRUE, 0);
+    gtk_widget_show(w1);
+
+    es->dp.data = es;
+    es->dp.shortcuts = &es->scs;
+    es->dp.lastfocus = NULL;
+    es->dp.retval = 0;
+    es->dp.window = window;
+
+    dlg_refresh(NULL, &es->dp);
+
+    if (parent) {
+       gint x, y, w, h, dx, dy;
+       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE);
+       gdk_window_get_origin(parent->window, &x, &y);
+       gdk_window_get_size(parent->window, &w, &h);
+       dx = x + w/4;
+       dy = y + h/4;
+       gtk_widget_set_uposition(GTK_WIDGET(window), dx, dy);
+       gtk_window_set_transient_for(GTK_WINDOW(window),
+                                    GTK_WINDOW(parent));
+    } else
+       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+    gtk_widget_show(window);
+
+    gtk_signal_connect(GTK_OBJECT(window), "destroy",
+                      GTK_SIGNAL_FUNC(eventlog_destroy), es);
+    gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
+                      GTK_SIGNAL_FUNC(win_key_press), &es->dp);
+}
+
+void *eventlogstuff_new(void)
+{
+    struct eventlog_stuff *es;
+    es = snew(struct eventlog_stuff);
+    memset(es, 0, sizeof(*es));
+    return es;
+}
+
+void logevent_dlg(void *estuff, char *string)
+{
+    struct eventlog_stuff *es = (struct eventlog_stuff *)estuff;
+
+    char timebuf[40];
+    time_t t;
+
+    if (es->nevents >= es->negsize) {
+       es->negsize += 64;
+       es->events = sresize(es->events, es->negsize, char *);
+    }
+
+    time(&t);
+    strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S\t",
+            localtime(&t));
+
+    es->events[es->nevents] = snewn(strlen(timebuf) + strlen(string) + 1, char);
+    strcpy(es->events[es->nevents], timebuf);
+    strcat(es->events[es->nevents], string);
+    if (es->window) {
+       dlg_listbox_add(es->listctrl, &es->dp, es->events[es->nevents]);
+    }
+    es->nevents++;
+}
index 01bc2a1..dad013c 100644 (file)
@@ -72,6 +72,7 @@ struct gui_data {
     int exited;
     struct unicode_data ucsdata;
     Config cfg;
+    void *eventlogstuff;
 };
 
 struct draw_ctx {
@@ -163,11 +164,12 @@ int askappend(void *frontend, Filename filename)
 
 void logevent(void *frontend, char *string)
 {
-    /*
-     * This is not a very helpful function: events are logged
-     * pretty much exclusively by the back end, and our pty back
-     * end is self-contained. So we need do nothing.
-     */
+    Terminal *term = (Terminal *)frontend;
+    struct gui_data *inst = (struct gui_data *)term->frontend;
+
+    log_eventlog(inst->logctx, string);
+
+    logevent_dlg(inst->eventlogstuff, string);
 }
 
 int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */
@@ -2316,6 +2318,12 @@ void about_menuitem(GtkMenuItem *item, gpointer data)
     about_box();
 }
 
+void event_log_menuitem(GtkMenuItem *item, gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+    showeventlog(inst->eventlogstuff, inst->window);
+}
+
 void update_specials_menu(void *frontend)
 {
     Terminal *term = (Terminal *)frontend;
@@ -2530,6 +2538,7 @@ int pt_main(int argc, char **argv)
     {
        GtkWidget *menuitem;
        char *s;
+       extern const int use_event_log;
 
        inst->menu = gtk_menu_new();
 
@@ -2542,6 +2551,8 @@ int pt_main(int argc, char **argv)
        gtk_signal_connect(GTK_OBJECT(menuitem), "activate", \
                               GTK_SIGNAL_FUNC(func), inst); \
 } while (0)
+       if (use_event_log)
+           MKMENUITEM("Event Log", event_log_menuitem);
        MKMENUITEM("Special Commands", NULL);
        inst->specialsmenu = gtk_menu_new();
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), inst->specialsmenu);
@@ -2564,6 +2575,8 @@ int pt_main(int argc, char **argv)
     inst->currcursor = inst->textcursor;
     show_mouseptr(inst, 1);
 
+    inst->eventlogstuff = eventlogstuff_new();
+
     inst->term = term_init(&inst->cfg, &inst->ucsdata, inst);
     inst->logctx = log_init(inst, &inst->cfg);
     term_provide_logctx(inst->term, inst->logctx);
index 6cdeffc..22213dc 100644 (file)
@@ -8,6 +8,7 @@
 #include "putty.h"
 
 const char *const appname = "pterm";
+const int use_event_log = 0;          /* pterm doesn't need it */
 
 Backend *select_backend(Config *cfg)
 {
index d9a57fb..2cf462c 100644 (file)
@@ -61,6 +61,9 @@ 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);
+void *eventlogstuff_new(void);
+void showeventlog(void *estuff, void *parentwin);
+void logevent_dlg(void *estuff, char *string);
 
 /* Things pterm.c needs from {ptermm,uxputty}.c */
 char *make_default_wintitle(char *hostname);
index 67364e5..8f2fad1 100644 (file)
 /*
  * TODO:
  * 
- *  - Remainder of the context menu:
+ *  - Copy-and-paste from the Event Log.
  * 
- *     - Event Log (this means we must implement the Event Log; not
- *       in pterm)
+ *  - Remainder of the context menu:
  * 
  *     - New Session and Duplicate Session (perhaps in pterm, in fact?!)
  *        + Duplicate Session will be fun, since we must work out
  * 
  *     - Change Settings
  *        + we must also implement mid-session reconfig in pterm.c.
- *        + note this also requires config.c and uxcfg.c to be able
- *          to get hold of the application name.
+ *       + This will require some work. We have to throw the new
+ *         config at the log module, the ldisc, the terminal, and
+ *         the backend; that's the easy bit. But within pterm.c
+ *         itself we must also: 
+ *           - redo the colour palette if necessary
+ *             * might be nice to move this over into terminal.c.
+ *               That way we could check which palette entries in
+ *               cfg have actually been _changed_ during
+ *               reconfiguration, and only update those ones in
+ *               the currently visible palette. Also it'd save
+ *               some of this hassle in the next port.
+ *           - enable/disable/move the scroll bar if necessary
+ *           - change the window title if necessary
+ *           - reinitialise the fonts
+ *          - resize the window if necessary (may be required
+ *            either by terminal size change or font size change
+ *            or both)
+ *           - redraw everything, just to be safe.
+ *       + In particular, among the above chaos, we must look into
+ *         how the choice of font affects the choice of codepage
+ *         since the Unix default is to derive the latter from the
+ *         former.
  * 
  *     - Copy All to Clipboard (for what that's worth)
  */
@@ -88,6 +107,8 @@ int cfgbox(Config *cfg)
 
 static int got_host = 0;
 
+const int use_event_log = 1;
+
 int process_nonoption_arg(char *arg, Config *cfg)
 {
     char *p, *q = arg;