X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/56b9b9a752e89913fa19001ab85dffa7f95ef307..7374c7790ee32f36855e4257eb15d2fe43e277ea:/unix/gtkdlg.c diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 42998667..19546d9c 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -152,6 +152,8 @@ static void dlg_init(struct dlgparam *dp) dp->coloursel_result.ok = FALSE; dp->treeitems = NULL; dp->window = dp->cancelbutton = dp->currtreeitem = NULL; + dp->flags = 0; + dp->currfocus = NULL; } static void dlg_cleanup(struct dlgparam *dp) @@ -307,15 +309,18 @@ void dlg_listbox_clear(union control *ctrl, void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); - GtkContainer *cont; assert(uc->ctrl->generic.type == CTRL_EDITBOX || uc->ctrl->generic.type == CTRL_LISTBOX); assert(uc->menu != NULL || uc->list != NULL); - cont = (uc->menu ? GTK_CONTAINER(uc->menu) : GTK_CONTAINER(uc->list)); - - gtk_container_foreach(cont, container_remove_and_destroy, cont); + if (uc->menu) { + gtk_container_foreach(GTK_CONTAINER(uc->menu), + container_remove_and_destroy, + GTK_CONTAINER(uc->menu)); + } else { + gtk_list_clear_items(GTK_LIST(uc->list), 0, -1); + } } void dlg_listbox_del(union control *ctrl, void *dlg, int index) @@ -371,7 +376,8 @@ void dlg_listbox_addwithid(union control *ctrl, void *dlg, gtk_container_add(GTK_CONTAINER(uc->menu), menuitem); gtk_widget_show(menuitem); - gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", (gpointer)id); + gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", + GINT_TO_POINTER(id)); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menuitem_activate), dp); } else if (!uc->entry) { @@ -433,7 +439,8 @@ void dlg_listbox_addwithid(union control *ctrl, void *dlg, GTK_SIGNAL_FUNC(widget_focus), dp); gtk_signal_connect(GTK_OBJECT(listitem), "button_press_event", GTK_SIGNAL_FUNC(listitem_button), dp); - gtk_object_set_data(GTK_OBJECT(listitem), "user-data", (gpointer)id); + gtk_object_set_data(GTK_OBJECT(listitem), "user-data", + GINT_TO_POINTER(id)); } else { /* * List item in a combo-box list, which means the sensible @@ -445,7 +452,8 @@ void dlg_listbox_addwithid(union control *ctrl, void *dlg, gtk_container_add(GTK_CONTAINER(uc->list), listitem); gtk_widget_show(listitem); - gtk_object_set_data(GTK_OBJECT(listitem), "user-data", (gpointer)id); + gtk_object_set_data(GTK_OBJECT(listitem), "user-data", + GINT_TO_POINTER(id)); } dp->flags &= ~FLAG_UPDATING_COMBO_LIST; @@ -467,7 +475,7 @@ int dlg_listbox_getid(union control *ctrl, void *dlg, int index) item = GTK_OBJECT(g_list_nth_data(children, index)); g_list_free(children); - return (int)gtk_object_get_data(GTK_OBJECT(item), "user-data"); + return GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(item), "user-data")); } /* dlg_listbox_index returns <0 if no single element is selected. */ @@ -486,6 +494,8 @@ int dlg_listbox_index(union control *ctrl, void *dlg) if (uc->menu) activeitem = gtk_menu_get_active(GTK_MENU(uc->menu)); + else + activeitem = NULL; /* unnecessarily placate gcc */ children = gtk_container_children(GTK_CONTAINER(uc->menu ? uc->menu : uc->list)); @@ -539,7 +549,35 @@ void dlg_listbox_select(union control *ctrl, void *dlg, int index) if (uc->optmenu) { gtk_option_menu_set_history(GTK_OPTION_MENU(uc->optmenu), index); } else { + int nitems; + GList *items; + gdouble newtop, newbot; + gtk_list_select_item(GTK_LIST(uc->list), index); + + /* + * Scroll the list box if necessary to ensure the newly + * selected item is visible. + */ + items = gtk_container_children(GTK_CONTAINER(uc->list)); + nitems = g_list_length(items); + if (nitems > 0) { + int modified = FALSE; + g_list_free(items); + newtop = uc->adj->lower + + (uc->adj->upper - uc->adj->lower) * index / nitems; + newbot = uc->adj->lower + + (uc->adj->upper - uc->adj->lower) * (index+1) / nitems; + if (uc->adj->value > newtop) { + modified = TRUE; + uc->adj->value = newtop; + } else if (uc->adj->value < newbot - uc->adj->page_size) { + modified = TRUE; + uc->adj->value = newbot - uc->adj->page_size; + } + if (modified) + gtk_adjustment_value_changed(uc->adj); + } } } @@ -554,6 +592,17 @@ void dlg_text_set(union control *ctrl, void *dlg, char const *text) gtk_label_set_text(GTK_LABEL(uc->text), text); } +void dlg_label_change(union control *ctrl, void *dlg, char const *text) +{ + /* + * This function is currently only used by the config box to + * switch the labels on the host and port boxes between serial + * and network modes. Since Unix does not (yet) have a serial + * back end, this function can safely do nothing for the + * moment. + */ +} + void dlg_filesel_set(union control *ctrl, void *dlg, Filename fn) { struct dlgparam *dp = (struct dlgparam *)dlg; @@ -1935,7 +1984,8 @@ int get_listitemheight(void) return req.height; } -int do_config_box(const char *title, Config *cfg, int midsession) +int do_config_box(const char *title, Config *cfg, int midsession, + int protcfginfo) { GtkWidget *window, *hbox, *vbox, *cols, *label, *tree, *treescroll, *panels, *panelvbox; @@ -1945,7 +1995,6 @@ int do_config_box(const char *title, Config *cfg, int midsession) GtkTreeItem *treeitemlevels[8]; GtkTree *treelevels[8]; struct dlgparam dp; - struct sesslist sl; struct Shortcuts scs; struct selparam *selparams = NULL; @@ -1953,8 +2002,6 @@ int do_config_box(const char *title, Config *cfg, int midsession) dlg_init(&dp); - get_sesslist(&sl, TRUE); - listitemheight = get_listitemheight(); for (index = 0; index < lenof(scs.sc); index++) { @@ -1964,8 +2011,9 @@ int do_config_box(const char *title, Config *cfg, int midsession) window = gtk_dialog_new(); ctrlbox = ctrl_new_box(); - setup_config_box(ctrlbox, &sl, midsession, 0); - unix_setup_config_box(ctrlbox, midsession, window); + setup_config_box(ctrlbox, midsession, cfg->protocol, protcfginfo); + unix_setup_config_box(ctrlbox, midsession); + gtk_setup_config_box(ctrlbox, midsession, window); gtk_window_set_title(GTK_WINDOW(window), title); hbox = gtk_hbox_new(FALSE, 4); @@ -2149,7 +2197,6 @@ int do_config_box(const char *title, Config *cfg, int midsession) gtk_main(); - get_sesslist(&sl, FALSE); dlg_cleanup(&dp); sfree(selparams); @@ -2269,13 +2316,27 @@ static int string_width(char *text) return req.width; } -void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, - char *keystr, char *fingerprint) +int reallyclose(void *frontend) +{ + char *title = dupcat(appname, " Exit Confirmation", NULL); + int ret = messagebox(GTK_WIDGET(get_window(frontend)), + title, "Are you sure you want to close this session?", + string_width("Most of the width of the above text"), + "Yes", 'y', +1, 1, + "No", 'n', -1, 0, + NULL); + sfree(title); + return ret; +} + +int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, + char *keystr, char *fingerprint, + void (*callback)(void *ctx, int result), void *ctx) { static const char absenttxt[] = "The server's host key is not cached. You have no guarantee " "that the server is the computer you think it is.\n" - "The server's key fingerprint is:\n" + "The server's %s key fingerprint is:\n" "%s\n" "If you trust this host, press \"Accept\" to add the key to " "PuTTY's cache and carry on connecting.\n" @@ -2289,7 +2350,7 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, "cached. This means that either the server administrator " "has changed the host key, or you have actually connected " "to another computer pretending to be the server.\n" - "The new key fingerprint is:\n" + "The new %s key fingerprint is:\n" "%s\n" "If you were expecting this change and trust the new key, " "press \"Accept\" to update PuTTY's cache and continue connecting.\n" @@ -2307,9 +2368,9 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, ret = verify_host_key(host, port, keytype, keystr); if (ret == 0) /* success - key matched OK */ - return; + return 1; - text = dupprintf((ret == 2 ? wrongtxt : absenttxt), fingerprint); + text = dupprintf((ret == 2 ? wrongtxt : absenttxt), keytype, fingerprint); ret = messagebox(GTK_WIDGET(get_window(frontend)), "PuTTY Security Alert", text, @@ -2321,29 +2382,29 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, sfree(text); - if (ret == 0) - cleanup_exit(0); - else if (ret == 2) + if (ret == 2) { store_host_key(host, port, keytype, keystr); + return 1; /* continue with connection */ + } else if (ret == 1) + return 1; /* continue with connection */ + return 0; /* do not continue with connection */ } /* - * Ask whether the selected cipher is acceptable (since it was + * Ask whether the selected algorithm is acceptable (since it was * below the configured 'warn' threshold). - * cs: 0 = both ways, 1 = client->server, 2 = server->client */ -void askcipher(void *frontend, char *ciphername, int cs) +int askalg(void *frontend, const char *algtype, const char *algname, + void (*callback)(void *ctx, int result), void *ctx) { static const char msg[] = - "The first %scipher supported by the server is " + "The first %s supported by the server is " "%s, which is below the configured warning threshold.\n" "Continue with connection?"; char *text; int ret; - text = dupprintf(msg, (cs == 0) ? "" : - (cs == 1) ? "client-to-server " : "server-to-client ", - ciphername); + text = dupprintf(msg, algtype, algname); ret = messagebox(GTK_WIDGET(get_window(frontend)), "PuTTY Security Alert", text, string_width("Continue with connection?"), @@ -2353,9 +2414,9 @@ void askcipher(void *frontend, char *ciphername, int cs) sfree(text); if (ret) { - return; + return 1; } else { - cleanup_exit(0); + return 0; } } @@ -2398,11 +2459,12 @@ static void licence_clicked(GtkButton *button, gpointer data) char *title; char *licence = - "Copyright 1997-2003 Simon Tatham.\n\n" + "Copyright 1997-2006 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" + "Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, " + "Markus Kuhn, 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 " @@ -2478,7 +2540,7 @@ void about_box(void *window) w, FALSE, FALSE, 5); gtk_widget_show(w); - w = gtk_label_new("Copyright 1997-2003 Simon Tatham. All rights reserved"); + w = gtk_label_new("Copyright 1997-2006 Simon Tatham. All rights reserved"); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(aboutbox)->vbox), w, FALSE, FALSE, 5); gtk_widget_show(w); @@ -2495,6 +2557,9 @@ struct eventlog_stuff { union control *listctrl; char **events; int nevents, negsize; + char *seldata; + int sellen; + int ignore_selchange; }; static void eventlog_destroy(GtkWidget *widget, gpointer data) @@ -2502,6 +2567,7 @@ static void eventlog_destroy(GtkWidget *widget, gpointer data) struct eventlog_stuff *es = (struct eventlog_stuff *)data; es->window = NULL; + sfree(es->seldata); dlg_cleanup(&es->dp); ctrl_free_box(es->eventbox); } @@ -2525,8 +2591,82 @@ static void eventlog_list_handler(union control *ctrl, void *dlg, dlg_listbox_add(ctrl, dlg, es->events[i]); } dlg_update_done(ctrl, dlg); + } else if (event == EVENT_SELCHANGE) { + int i; + int selsize = 0; + + /* + * If this SELCHANGE event is happening as a result of + * deliberate deselection because someone else has grabbed + * the selection, the last thing we want to do is pre-empt + * them. + */ + if (es->ignore_selchange) + return; + + /* + * Construct the data to use as the selection. + */ + sfree(es->seldata); + es->seldata = NULL; + es->sellen = 0; + for (i = 0; i < es->nevents; i++) { + if (dlg_listbox_issel(ctrl, dlg, i)) { + int extralen = strlen(es->events[i]); + + if (es->sellen + extralen + 2 > selsize) { + selsize = es->sellen + extralen + 512; + es->seldata = sresize(es->seldata, selsize, char); + } + + strcpy(es->seldata + es->sellen, es->events[i]); + es->sellen += extralen; + es->seldata[es->sellen++] = '\n'; + } + } + + if (gtk_selection_owner_set(es->window, GDK_SELECTION_PRIMARY, + GDK_CURRENT_TIME)) { + extern GdkAtom compound_text_atom; + + gtk_selection_add_target(es->window, GDK_SELECTION_PRIMARY, + GDK_SELECTION_TYPE_STRING, 1); + gtk_selection_add_target(es->window, GDK_SELECTION_PRIMARY, + compound_text_atom, 1); + } + } } + +void eventlog_selection_get(GtkWidget *widget, GtkSelectionData *seldata, + guint info, guint time_stamp, gpointer data) +{ + struct eventlog_stuff *es = (struct eventlog_stuff *)data; + + gtk_selection_data_set(seldata, seldata->target, 8, + es->seldata, es->sellen); +} + +gint eventlog_selection_clear(GtkWidget *widget, GdkEventSelection *seldata, + gpointer data) +{ + struct eventlog_stuff *es = (struct eventlog_stuff *)data; + struct uctrl *uc; + + /* + * Deselect everything in the list box. + */ + uc = dlg_find_byctrl(&es->dp, es->listctrl); + es->ignore_selchange = 1; + gtk_list_unselect_all(GTK_LIST(uc->list)); + es->ignore_selchange = 0; + + sfree(es->seldata); + es->sellen = 0; + es->seldata = NULL; + return TRUE; +} + void showeventlog(void *estuff, void *parentwin) { struct eventlog_stuff *es = (struct eventlog_stuff *)estuff; @@ -2610,6 +2750,10 @@ void showeventlog(void *estuff, void *parentwin) GTK_SIGNAL_FUNC(eventlog_destroy), es); gtk_signal_connect(GTK_OBJECT(window), "key_press_event", GTK_SIGNAL_FUNC(win_key_press), &es->dp); + gtk_signal_connect(GTK_OBJECT(window), "selection_get", + GTK_SIGNAL_FUNC(eventlog_selection_get), es); + gtk_signal_connect(GTK_OBJECT(window), "selection_clear_event", + GTK_SIGNAL_FUNC(eventlog_selection_clear), es); } void *eventlogstuff_new(void) @@ -2620,21 +2764,20 @@ void *eventlogstuff_new(void) return es; } -void logevent_dlg(void *estuff, char *string) +void logevent_dlg(void *estuff, const char *string) { struct eventlog_stuff *es = (struct eventlog_stuff *)estuff; char timebuf[40]; - time_t t; + struct tm tm; 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)); + tm=ltime(); + strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S\t", &tm); es->events[es->nevents] = snewn(strlen(timebuf) + strlen(string) + 1, char); strcpy(es->events[es->nevents], timebuf); @@ -2644,3 +2787,32 @@ void logevent_dlg(void *estuff, char *string) } es->nevents++; } + +int askappend(void *frontend, Filename filename, + void (*callback)(void *ctx, int result), void *ctx) +{ + static const char msgtemplate[] = + "The session log file \"%.*s\" already exists. " + "You can overwrite it with a new session log, " + "append your session log to the end of it, " + "or disable session logging for this session."; + char *message; + char *mbtitle; + int mbret; + + message = dupprintf(msgtemplate, FILENAME_MAX, filename.path); + mbtitle = dupprintf("%s Log to File", appname); + + mbret = messagebox(get_window(frontend), mbtitle, message, + string_width("LINE OF TEXT SUITABLE FOR THE" + " ASKAPPEND WIDTH"), + "Overwrite", 'o', 1, 2, + "Append", 'a', 0, 1, + "Disable", 'd', -1, 0, + NULL); + + sfree(message); + sfree(mbtitle); + + return mbret; +}