⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gtkdlg.c

📁 远程登陆工具软件源码 用于远程登陆unix
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * 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 1

enum {				       /* 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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -