📄 gtkdlg.c
字号:
/* * gtkdlg.c - GTK implementation of the PuTTY configuration box. *//* * TODO when porting to GTK 2.0: * * - GtkTree is apparently deprecated and we should switch to * GtkTreeView instead. * - GtkLabel has a built-in mnemonic scheme, so we should at * least consider switching to that from the current adhockery. */#include <assert.h>#include <stdarg.h>#include <ctype.h>#include <time.h>#include <gtk/gtk.h>#include <gdk/gdkkeysyms.h>#include <gdk/gdkx.h>#include <X11/Xlib.h>#include <X11/Xutil.h>#include "gtkcols.h"#include "gtkpanel.h"#ifdef TESTMODE#define PUTTY_DO_GLOBALS /* actually _define_ globals */#endif#include "putty.h"#include "storage.h"#include "dialog.h"#include "tree234.h"struct Shortcut { GtkWidget *widget; struct uctrl *uc; int action;};struct Shortcuts { struct Shortcut sc[128];};struct uctrl { union control *ctrl; GtkWidget *toplevel; void *privdata; int privdata_needs_free; GtkWidget **buttons; int nbuttons; /* for radio buttons */ GtkWidget *entry; /* for editbox, combobox, filesel, fontsel */ GtkWidget *button; /* for filesel, fontsel */ GtkWidget *list; /* for combobox, listbox */ GtkWidget *menu; /* for optionmenu (==droplist) */ GtkWidget *optmenu; /* also for optionmenu */ GtkWidget *text; /* for text */ GtkAdjustment *adj; /* for the scrollbar in a list box */ guint textsig;};struct dlgparam { tree234 *byctrl, *bywidget; void *data; struct { unsigned char r, g, b, ok; } coloursel_result; /* 0-255 */ /* `flags' are set to indicate when a GTK signal handler is being called * due to automatic processing and should not flag a user event. */ int flags; struct Shortcuts *shortcuts; GtkWidget *window, *cancelbutton, *currtreeitem, **treeitems; union control *currfocus, *lastfocus; int ntreeitems; int retval;};#define FLAG_UPDATING_COMBO_LIST 1enum { /* values for Shortcut.action */ SHORTCUT_EMPTY, /* no shortcut on this key */ SHORTCUT_TREE, /* focus a tree item */ SHORTCUT_FOCUS, /* focus the supplied widget */ SHORTCUT_UCTRL, /* do something sane with uctrl */ SHORTCUT_UCTRL_UP, /* uctrl is a draglist, move Up */ SHORTCUT_UCTRL_DOWN, /* uctrl is a draglist, move Down */};/* * Forward references. */static gboolean widget_focus(GtkWidget *widget, GdkEventFocus *event, gpointer data);static void shortcut_add(struct Shortcuts *scs, GtkWidget *labelw, int chr, int action, void *ptr);static int listitem_single_key(GtkWidget *item, GdkEventKey *event, gpointer data);static int listitem_multi_key(GtkWidget *item, GdkEventKey *event, gpointer data);static int listitem_button(GtkWidget *item, GdkEventButton *event, gpointer data);static void menuitem_activate(GtkMenuItem *item, gpointer data);static void coloursel_ok(GtkButton *button, gpointer data);static void coloursel_cancel(GtkButton *button, gpointer data);static void window_destroy(GtkWidget *widget, gpointer data);static int uctrl_cmp_byctrl(void *av, void *bv){ struct uctrl *a = (struct uctrl *)av; struct uctrl *b = (struct uctrl *)bv; if (a->ctrl < b->ctrl) return -1; else if (a->ctrl > b->ctrl) return +1; return 0;}static int uctrl_cmp_byctrl_find(void *av, void *bv){ union control *a = (union control *)av; struct uctrl *b = (struct uctrl *)bv; if (a < b->ctrl) return -1; else if (a > b->ctrl) return +1; return 0;}static int uctrl_cmp_bywidget(void *av, void *bv){ struct uctrl *a = (struct uctrl *)av; struct uctrl *b = (struct uctrl *)bv; if (a->toplevel < b->toplevel) return -1; else if (a->toplevel > b->toplevel) return +1; return 0;}static int uctrl_cmp_bywidget_find(void *av, void *bv){ GtkWidget *a = (GtkWidget *)av; struct uctrl *b = (struct uctrl *)bv; if (a < b->toplevel) return -1; else if (a > b->toplevel) return +1; return 0;}static void dlg_init(struct dlgparam *dp){ dp->byctrl = newtree234(uctrl_cmp_byctrl); dp->bywidget = newtree234(uctrl_cmp_bywidget); 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){ 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) sfree(uc->privdata); sfree(uc->buttons); sfree(uc); } freetree234(dp->bywidget); dp->bywidget = NULL; sfree(dp->treeitems);}static void dlg_add_uctrl(struct dlgparam *dp, struct uctrl *uc){ add234(dp->byctrl, uc); add234(dp->bywidget, 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) return ret; w = w->parent; } while (w); return ret;}void *dlg_get_privdata(union control *ctrl, void *dlg){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); return uc->privdata;}void dlg_set_privdata(union control *ctrl, void *dlg, void *ptr){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); uc->privdata = ptr; uc->privdata_needs_free = FALSE;}void *dlg_alloc_privdata(union control *ctrl, void *dlg, size_t size){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); /* * This is an internal allocation routine, so it's allowed to * use smalloc directly. */ uc->privdata = smalloc(size); uc->privdata_needs_free = FALSE; return uc->privdata;}union control *dlg_last_focused(union control *ctrl, void *dlg){ struct dlgparam *dp = (struct dlgparam *)dlg; if (dp->currfocus != ctrl) return dp->currfocus; else return dp->lastfocus;}void dlg_radiobutton_set(union control *ctrl, void *dlg, int which){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_RADIO); assert(uc->buttons != NULL); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->buttons[which]), TRUE);}int dlg_radiobutton_get(union control *ctrl, void *dlg){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); int i; assert(uc->ctrl->generic.type == CTRL_RADIO); assert(uc->buttons != NULL); for (i = 0; i < uc->nbuttons; i++) if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uc->buttons[i]))) return i; return 0; /* got to return something */}void dlg_checkbox_set(union control *ctrl, void *dlg, int checked){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_CHECKBOX); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uc->toplevel), checked);}int dlg_checkbox_get(union control *ctrl, void *dlg){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_CHECKBOX); return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uc->toplevel));}void dlg_editbox_set(union control *ctrl, void *dlg, char const *text){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX); assert(uc->entry != NULL); gtk_entry_set_text(GTK_ENTRY(uc->entry), text);}void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX); assert(uc->entry != NULL); strncpy(buffer, gtk_entry_get_text(GTK_ENTRY(uc->entry)), length); buffer[length-1] = '\0';}static void container_remove_and_destroy(GtkWidget *w, gpointer data){ GtkContainer *cont = GTK_CONTAINER(data); /* gtk_container_remove will unref the widget for us; we need not. */ gtk_container_remove(cont, w);}/* The `listbox' functions can also apply to combo boxes. */void dlg_listbox_clear(union control *ctrl, void *dlg){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || uc->ctrl->generic.type == CTRL_LISTBOX); assert(uc->menu != NULL || uc->list != NULL); 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){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || uc->ctrl->generic.type == CTRL_LISTBOX); assert(uc->menu != NULL || uc->list != NULL); if (uc->menu) { gtk_container_remove (GTK_CONTAINER(uc->menu), g_list_nth_data(GTK_MENU_SHELL(uc->menu)->children, index)); } else { gtk_list_clear_items(GTK_LIST(uc->list), index, index+1); }}void dlg_listbox_add(union control *ctrl, void *dlg, char const *text){ dlg_listbox_addwithid(ctrl, dlg, text, 0);}/* * Each listbox entry may have a numeric id associated with it. * Note that some front ends only permit a string to be stored at * each position, which means that _if_ you put two identical * strings in any listbox then you MUST not assign them different * IDs and expect to get meaningful results back. */void dlg_listbox_addwithid(union control *ctrl, void *dlg, char const *text, int id){ struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); assert(uc->ctrl->generic.type == CTRL_EDITBOX || uc->ctrl->generic.type == CTRL_LISTBOX); assert(uc->menu != NULL || uc->list != NULL); dp->flags |= FLAG_UPDATING_COMBO_LIST; if (uc->menu) { /* * List item in a drop-down (but non-combo) list. Tabs are * ignored; we just provide a standard menu item with the * text. */ GtkWidget *menuitem = gtk_menu_item_new_with_label(text); gtk_container_add(GTK_CONTAINER(uc->menu), menuitem); gtk_widget_show(menuitem); 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) { /* * List item in a non-combo-box list box. We make all of * these Columns containing GtkLabels. This allows us to do * the nasty force_left hack irrespective of whether there * are tabs in the thing. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -