From 8eed910da111b888ec363493ee55c6057eb61acf Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 9 Apr 2003 18:46:45 +0000 Subject: [PATCH] Event Log for Unix PuTTY. Doesn't yet allow X selection of its 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 | 13 +++- unix/gtkdlg.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- unix/pterm.c | 23 +++++-- unix/ptermm.c | 1 + unix/unix.h | 3 + unix/uxputty.c | 31 +++++++-- 6 files changed, 244 insertions(+), 22 deletions(-) diff --git a/dialog.h b/dialog.h index 078aca19..8daa3320 100644 --- 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; /* diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 267555a3..e6997321 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -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++; +} diff --git a/unix/pterm.c b/unix/pterm.c index 01bc2a18..dad013cf 100644 --- a/unix/pterm.c +++ b/unix/pterm.c @@ -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); diff --git a/unix/ptermm.c b/unix/ptermm.c index 6cdeffc5..22213dcc 100644 --- a/unix/ptermm.c +++ b/unix/ptermm.c @@ -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) { diff --git a/unix/unix.h b/unix/unix.h index d9a57fb0..2cf462c9 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -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); diff --git a/unix/uxputty.c b/unix/uxputty.c index 67364e50..8f2fad1b 100644 --- a/unix/uxputty.c +++ b/unix/uxputty.c @@ -14,10 +14,9 @@ /* * 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 @@ -48,8 +47,28 @@ * * - 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; -- 2.11.0