Add the humble beginnings for a preferences dialog.
authorRoy Marples <roy@marples.name>
Tue, 17 Feb 2009 19:46:55 +0000 (19:46 +0000)
committerRoy Marples <roy@marples.name>
Tue, 17 Feb 2009 19:46:55 +0000 (19:46 +0000)
Makefile
dhcpcd-gtk.h
main.c
menu.c
prefs.c [new file with mode: 0644]
prefs.h [new file with mode: 0644]

index 4820614064087648b09ead5bd93a3ad4c658e4cd..2f2f9a0560822ef6fac21a03870fbfb8b784bf89 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 # Copyright 2008 Roy Marples <roy@marples.name>
 
 PROG=          dhcpcd-gtk
-SRCS=          main.c menu.c wpa.c
+SRCS=          main.c menu.c prefs.c wpa.c
 
 SYSCONFDIR?=   ${PREFIX}/etc/xdg/autostart
 FILESDIR?=     ${SYSCONFDIR}
index db4b5ce8ae661cd2ddd2fa4487099412e1ada85c..c8de94bd8c822a6ed5891d42a89430e096222f0e 100644 (file)
@@ -73,7 +73,7 @@ struct if_msg {
 };
 
 extern DBusGProxy *dbus;
-extern GList *interfaces;
+extern GSList *interfaces;
 
 void notify_close(void);
 #endif
diff --git a/main.c b/main.c
index 446288833f3d7dde87838f9a331358452f713086..292eeeb56784a6efa6ec00d395e7eb31243b9754 100644 (file)
--- a/main.c
+++ b/main.c
@@ -38,7 +38,7 @@
 #include "menu.h"
 
 DBusGProxy *dbus = NULL;
-GList *interfaces = NULL;
+GSList *interfaces = NULL;
 
 static GtkStatusIcon *status_icon;
 static gint ani_timer;
@@ -80,7 +80,7 @@ ignore_if_msg(const struct if_msg *ifm)
 static struct if_msg *
 find_if_msg(const char *iface)
 {
-       GList *gl;
+       GSList *gl;
        struct if_msg *ifm;
 
        for (gl = interfaces; gl; gl = gl->next) {
@@ -363,7 +363,7 @@ update_online(void)
 {
        gboolean ison, iscarrier;
        char *msg, *msgs, *tmp;
-       const GList *gl;
+       const GSList *gl;
        const struct if_msg *ifm;
 
        ison = iscarrier = FALSE;
@@ -445,7 +445,7 @@ dhcpcd_event(_unused DBusGProxy *proxy, GHashTable *config, _unused void *data)
 {
        struct if_msg *ifm, *ifp;
        gboolean rem;
-       GList *gl;
+       GSList *gl;
        char *msg, *title;
        const char *act, *net;
        const char *const *r;
@@ -465,15 +465,15 @@ dhcpcd_event(_unused DBusGProxy *proxy, GHashTable *config, _unused void *data)
                        free_if_msg(ifp);
                        if (rem)
                                interfaces =
-                                       g_list_delete_link(interfaces, gl);
+                                       g_slist_delete_link(interfaces, gl);
                        else
                                gl->data = ifm;
                        break;
                }
        }
        if (ifp == NULL && !rem)
-               interfaces = g_list_prepend(interfaces, ifm);
-       interfaces = g_list_sort(interfaces, if_msg_comparer);
+               interfaces = g_slist_prepend(interfaces, ifm);
+       interfaces = g_slist_sort(interfaces, if_msg_comparer);
        update_online();
 
        /* We should ignore renew and stop so we don't annoy the user */
@@ -521,7 +521,7 @@ foreach_make_ifm(_unused gpointer key, gpointer value, _unused gpointer data)
        if (ignore_if_msg(ifm))
                g_free(ifm);
        else if (ifm)
-               interfaces = g_list_prepend(interfaces, ifm);
+               interfaces = g_slist_prepend(interfaces, ifm);
 }
 
 static void
@@ -530,8 +530,7 @@ dhcpcd_get_interfaces()
        GHashTable *ifs;
        GError *error = NULL;
        GType otype;
-       GList *gl;
-       GSList *gsl;
+       GSList *gl, *gsl;
        GPtrArray *array;
        struct if_msg *ifm;
 
@@ -552,7 +551,7 @@ dhcpcd_get_interfaces()
                G_TYPE_INVALID,
                G_TYPE_STRV, &interface_order, G_TYPE_INVALID))
                error_exit("ListInterfaces", error);
-       interfaces = g_list_sort(interfaces, if_msg_comparer);
+       interfaces = g_slist_sort(interfaces, if_msg_comparer);
 
        otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
        otype = dbus_g_type_get_collection("GPtrArray", otype);
@@ -581,7 +580,7 @@ static void
 check_status(const char *status)
 {
        static char *last = NULL;
-       GList *gl;
+       GSList *gl;
        char *version;
        const char *msg;
        gboolean refresh;
@@ -591,7 +590,7 @@ check_status(const char *status)
        if (g_strcmp0(status, "down") == 0) {
                for (gl = interfaces; gl; gl = gl->next)
                        free_if_msg((struct if_msg *)gl->data);
-               g_list_free(interfaces);
+               g_slist_free(interfaces);
                interfaces = NULL;
                update_online();
                msg = N_(last ?
@@ -681,7 +680,6 @@ main(int argc, char *argv[])
        char *version = NULL;
        GType otype;
        int tries = 5;
-
                
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, NULL);
diff --git a/menu.c b/menu.c
index cf15f4d6eb4112e458d8df615686074375bc8b55..fd459da2740dbf361298d5d7b74f07a2b7015918 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -26,6 +26,7 @@
 
 #include "dhcpcd-gtk.h"
 #include "menu.h"
+#include "prefs.h"
 #include "wpa.h"
 
 static const char *copyright = "Copyright (c) 2009 Roy Marples";
@@ -33,6 +34,13 @@ static const char *copyright = "Copyright (c) 2009 Roy Marples";
 static const char *authors[] = { "Roy Marples <roy@marples.name>", NULL };
 
 static void
+on_pref(_unused GtkMenuItem *item, _unused gpointer data)
+{
+       dhcpcd_prefs();
+}
+
+
+static void
 on_quit(_unused GtkMenuItem *item, _unused gpointer data)
 {
        gtk_main_quit();
@@ -146,14 +154,14 @@ on_activate(GtkStatusIcon *icon, _unused guint button, _unused guint32 atime, _u
 {
        GtkMenu *menu;
        const struct if_msg *ifm;
-       GList *gl;
+       GSList *l;
        size_t n, na;
 
        notify_close();
 
        n = na =0;
-       for (gl = interfaces; gl; gl = gl->next) {
-               ifm = (const struct if_msg *)gl->data;
+       for (l = interfaces; l; l = l->next) {
+               ifm = (const struct if_msg *)l->data;
                if (ifm->wireless) {
                        if (ifm->scan_results != NULL)
                                ++na;
@@ -166,8 +174,8 @@ on_activate(GtkStatusIcon *icon, _unused guint button, _unused guint32 atime, _u
 
        menu = (GtkMenu *)gtk_menu_new();
 
-       for (gl = interfaces; gl; gl = gl->next) {
-               ifm = (const struct if_msg *)gl->data;
+       for (l = interfaces; l; l = l->next) {
+               ifm = (const struct if_msg *)l->data;
                if (!ifm->wireless)
                        continue;
                if (n == 1) {
@@ -199,6 +207,14 @@ on_popup(GtkStatusIcon *icon, guint button, guint32 atime, gpointer data)
 
        menu = (GtkMenu *)gtk_menu_new();
 
+       item = gtk_image_menu_item_new_with_mnemonic(_("_Preferences"));
+       image = gtk_image_new_from_icon_name(GTK_STOCK_PREFERENCES,
+           GTK_ICON_SIZE_MENU);
+       gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
+       g_signal_connect(G_OBJECT(item), "activate",
+           G_CALLBACK(on_pref), icon);
+       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+
        item = gtk_image_menu_item_new_with_mnemonic(_("_Quit"));
        image = gtk_image_new_from_icon_name(GTK_STOCK_QUIT,
            GTK_ICON_SIZE_MENU);
diff --git a/prefs.c b/prefs.c
new file mode 100644 (file)
index 0000000..23bb583
--- /dev/null
+++ b/prefs.c
@@ -0,0 +1,451 @@
+/*
+ * dhcpcd-gtk
+ * Copyright 2009 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dbus/dbus.h>
+
+#include "dhcpcd-gtk.h"
+#include "prefs.h"
+
+static GPtrArray *config;
+static GtkWidget *blocks, *names, *controls;
+static GtkWidget *hostname, *fqdn, *clientid, *duid, *arp, *ipv4ll;
+
+static void
+free_config(GPtrArray **array)
+{
+       GPtrArray *a;
+       guint i;
+       GValueArray *c;
+
+       a = *array;
+       if (a == NULL)
+               return;
+       for (i = 0; i < a->len; i++) {
+               c = g_ptr_array_index(a, i);
+               g_value_array_free(c);
+       }
+       g_ptr_array_free(a, TRUE);
+       *array = NULL;
+}      
+
+static GPtrArray *
+read_config(const char *block, const char *name)
+{
+       GType otype;
+       GError *error;
+       GPtrArray *array;
+
+       error = NULL;
+       otype = dbus_g_type_get_struct("GValueArray",
+           G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+       otype = dbus_g_type_get_collection("GPtrArray", otype);
+       if (!dbus_g_proxy_call(dbus, "GetConfig", &error,
+               G_TYPE_STRING, block, G_TYPE_STRING, name, G_TYPE_INVALID,
+               otype, &array, G_TYPE_INVALID))
+       {
+               g_critical("GetConfig: %s", error->message);
+               g_clear_error(&error);
+               return NULL;
+       }
+       return array;
+}
+
+static gboolean
+get_config(GPtrArray *array, const char *option, const char **value)
+{
+       guint i;
+       GValueArray *c;
+       GValue *val;
+       const char *str;
+
+       if (array == NULL)
+               return FALSE;
+       for (i = 0; i < array->len; i++) {
+               c = g_ptr_array_index(array, i);
+               val = g_value_array_get_nth(c, 0);
+               str = g_value_get_string(val);
+               if (strcmp(str, option) != 0)
+                       continue;
+               if (value != NULL) {
+                       val = g_value_array_get_nth(c, 1);
+                       str = g_value_get_string(val);
+                       if (*str == '\0')
+                               *value = NULL;
+                       else
+                               *value = str;
+               }
+               return TRUE;
+       }
+       if (value != NULL)
+               *value = NULL;
+       return FALSE;
+}
+
+static gboolean
+toggle_generic(gboolean has, const char *val)
+{
+       return (has && (val == NULL || g_strcmp0(val, "\"\"") == 0));
+}
+
+static gboolean
+toggle_generic_neg(gboolean has, _unused const char *val)
+{
+       return !has;
+}
+
+static gboolean
+toggle_fqdn(gboolean has, const char *val)
+{
+       return (has &&
+           (val == NULL ||
+               g_strcmp0(val, "both") == 0 ||
+               g_strcmp0(val, "ptr") == 0));
+}
+
+static void
+set_check(GtkToggleButton *button,
+    GPtrArray *global, GPtrArray *conf, const char *name,
+    gboolean (*test)(gboolean, const char *))
+{
+       const char *val;
+       gboolean has, incons;
+       
+       if (get_config(conf, name, &val)) {
+               has = TRUE;
+               incons = FALSE;
+       } else {
+               has = get_config(global, name, &val);
+               incons = TRUE;
+       }
+       gtk_toggle_button_set_active(button, test(has, val));
+       gtk_toggle_button_set_inconsistent(button, incons);
+}
+
+static void
+show_config(const char *block, const char *name)
+{
+       GPtrArray *global;
+
+       if (block || name)
+               global = read_config(NULL, NULL);
+       else
+               global = NULL;
+       
+       free_config(&config);
+       config = read_config(block, name);
+       set_check(GTK_TOGGLE_BUTTON(hostname), global, config,
+           "hostname", toggle_generic);
+       set_check(GTK_TOGGLE_BUTTON(fqdn), global, config,
+           "fqdn", toggle_fqdn);
+       set_check(GTK_TOGGLE_BUTTON(clientid), global, config,
+           "clientid", toggle_generic);
+       set_check(GTK_TOGGLE_BUTTON(duid), global, config,
+           "duid", toggle_generic);
+       gtk_widget_set_sensitive(duid,
+           gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(clientid)));
+       set_check(GTK_TOGGLE_BUTTON(arp), global, config,
+           "noarp", toggle_generic_neg);
+       set_check(GTK_TOGGLE_BUTTON(ipv4ll), global, config,
+           "noipv4ll", toggle_generic_neg);
+       gtk_widget_set_sensitive(ipv4ll,
+           gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(arp)));
+       free_config(&global);
+}
+
+static char *
+combo_active_text(GtkWidget *widget)
+{
+       GtkListStore *store;
+       GtkTreeIter iter;
+       GValue val;
+       char *text;
+
+       store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)));
+       if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
+               return NULL;
+       memset(&val, 0, sizeof(val));
+       gtk_tree_model_get_value(GTK_TREE_MODEL(store), &iter, 1, &val);
+       text = g_strdup(g_value_get_string(&val));
+       g_value_unset(&val);
+       return text;
+}
+
+static GSList *
+list_interfaces(void)
+{
+       GSList *list, *l;
+       const struct if_msg *ifm;
+
+       list = NULL;
+       for (l = interfaces; l; l = l->next) {
+               ifm = (const struct if_msg *)l->data;
+               list = g_slist_append(list, ifm->ifname);
+       }
+       return list;
+}
+
+static GSList *
+list_ssids(void)
+{
+       GSList *list, *l, *a, *la;
+       const struct if_msg *ifm;
+       const struct if_ap *ifa;
+
+       list = NULL;
+       for (l = interfaces; l; l = l->next) {
+               ifm = (const struct if_msg *)l->data;
+               if (!ifm->wireless)
+                       continue;
+               for (a = ifm->scan_results; a; a = a->next) {
+                       ifa = (const struct if_ap *)a->data;
+                       for (la = list; la; la = la->next)
+                               if (g_strcmp0((const char *)la->data,
+                                       ifa->ssid) == 0)
+                                       break;
+                       if (la == NULL)
+                               list = g_slist_append(list, ifa->ssid);
+               }
+       }
+       return list;
+}
+
+static void
+blocks_on_change(GtkWidget *widget, _unused gpointer data)
+{
+       GtkListStore *store;
+       GtkTreeIter iter;
+       GError *error;
+       char **list, **lp, *block;
+       const char *iname, *nn;
+       GSList *l, *new_names;
+       GtkIconTheme *it;
+       GdkPixbuf *pb;
+       gint n;
+
+       block = combo_active_text(widget);
+       store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
+       gtk_list_store_clear(store);
+       if (strcmp(block, "global") == 0) {
+               g_free(block);
+               gtk_widget_set_sensitive(names, FALSE);
+               gtk_widget_set_sensitive(controls, TRUE);
+               show_config(NULL, NULL);
+               return;
+       }
+       error = NULL;
+       if (!dbus_g_proxy_call(dbus, "GetConfigBlocks", &error,
+               G_TYPE_STRING, block, G_TYPE_INVALID,
+               G_TYPE_STRV, &list, G_TYPE_INVALID))
+       {
+               g_free(block);
+               g_warning("GetConfigBlocks: %s", error->message);
+               g_clear_error(&error);
+               return;
+       }
+
+       it = gtk_icon_theme_get_default();
+       if (g_strcmp0(block, "interface") == 0)
+               new_names = list_interfaces();
+       else
+               new_names = list_ssids();
+
+       n = 0;
+       for (l = new_names; l; l = l->next) {
+               nn = (const char *)l->data;
+               for (lp = list; *lp; lp++)
+                       if (g_strcmp0(nn, *lp) == 0)
+                               break;
+               if (*lp)
+                       iname = "document-save";
+               else
+                       iname = "document-new";
+               pb = gtk_icon_theme_load_icon(it, iname,
+                   GTK_ICON_SIZE_MENU, 0, &error);
+               gtk_list_store_append(store, &iter);
+               gtk_list_store_set(store, &iter, 0, pb, 1, nn, -1);
+               g_object_unref(pb);
+               n++;
+       }
+
+       for (lp = list; *lp; lp++) {
+               for (l = new_names; l; l = l->next)
+                       if (g_strcmp0((const char *)l->data, *lp) == 0)
+                               break;
+               if (l != NULL)
+                       continue;
+               pb = gtk_icon_theme_load_icon(it, "document-save",
+                   GTK_ICON_SIZE_MENU, 0, &error);
+               gtk_list_store_append(store, &iter);
+               gtk_list_store_set(store, &iter, 0, pb, 1, *lp, -1);
+               g_object_unref(pb);
+               n++;
+       }
+       gtk_widget_set_sensitive(names, n);
+       gtk_widget_set_sensitive(controls, FALSE);
+       g_slist_free(new_names);
+       g_strfreev(list);
+       g_free(block);
+}
+
+static void
+names_on_change(GtkWidget *widget, _unused gpointer data)
+{
+       char *block, *name;
+
+       block = combo_active_text(blocks);
+       name = combo_active_text(widget);
+       gtk_widget_set_sensitive(controls, TRUE);
+       show_config(block, name);
+       g_free(block);
+       g_free(name);
+}
+
+static void
+on_toggle(GtkWidget *widget, gpointer data)
+{
+       gboolean active;
+
+       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(widget), FALSE);
+       if (data == NULL)
+               return;
+       active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+       gtk_widget_set_sensitive(GTK_WIDGET((GtkWidget *)data), active);
+}
+
+gboolean
+dhcpcd_prefs(void)
+{
+       GtkWidget *dialog, *hbox, *vbox, *label;
+       gint result;
+       GtkListStore *store;
+       GtkTreeIter iter;
+       GtkCellRenderer *rend;
+       GError *error;
+       GtkIconTheme *it;
+       GdkPixbuf *pb;
+       
+       dialog = gtk_dialog_new_with_buttons("dhcpcd preferences",
+           NULL,
+           GTK_DIALOG_MODAL,
+           GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+           GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+           NULL);
+       gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+       gtk_window_set_icon_name(GTK_WINDOW(dialog), "config-users");
+       gtk_dialog_set_default_response(GTK_DIALOG(dialog),
+           GTK_RESPONSE_ACCEPT);
+
+       hbox = gtk_hbox_new(FALSE, 10);
+       gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
+       label = gtk_label_new("Configuration block:");
+       gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3);
+       store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+       it = gtk_icon_theme_get_default();
+       error = NULL;
+       pb = gtk_icon_theme_load_icon(it, "config-users",
+           GTK_ICON_SIZE_MENU, 0, &error);     
+       gtk_list_store_append(store, &iter);
+       gtk_list_store_set(store, &iter, 0, pb, 1, "global", -1);
+       g_object_unref(pb);
+       pb = gtk_icon_theme_load_icon(it, "network-wired",
+           GTK_ICON_SIZE_MENU, 0, &error);     
+       gtk_list_store_append(store, &iter);
+       gtk_list_store_set(store, &iter, 0, pb, 1, "interface", -1);
+       g_object_unref(pb);
+       pb = gtk_icon_theme_load_icon(it, "network-wireless",
+           GTK_ICON_SIZE_MENU, 0, &error);
+       gtk_list_store_append(store, &iter);
+       gtk_list_store_set(store, &iter, 0, pb, 1, "ssid", -1);
+       g_object_unref(pb);
+       blocks = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
+       rend = gtk_cell_renderer_pixbuf_new();
+       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, FALSE);
+       gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
+           rend, "pixbuf", 0);
+       rend = gtk_cell_renderer_text_new();
+       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, TRUE);
+       gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
+           rend, "text", 1);
+       gtk_combo_box_set_active(GTK_COMBO_BOX(blocks), 0);
+       gtk_box_pack_start(GTK_BOX(hbox), blocks, FALSE, FALSE, 3);
+       label = gtk_label_new("Block name:");
+       gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3);
+       store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+       names = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
+       rend = gtk_cell_renderer_pixbuf_new();
+       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, FALSE);
+       gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names),
+           rend, "pixbuf", 0);
+       rend = gtk_cell_renderer_text_new();
+       gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, TRUE);
+       gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names), rend, "text", 1);
+       gtk_widget_set_sensitive(names, FALSE);
+       gtk_box_pack_start(GTK_BOX(hbox), names, FALSE, FALSE, 3);
+       gtk_signal_connect(GTK_OBJECT(blocks), "changed",
+           G_CALLBACK(blocks_on_change), NULL);
+       gtk_signal_connect(GTK_OBJECT(names), "changed",
+           G_CALLBACK(names_on_change), NULL);
+       
+       vbox = GTK_DIALOG(dialog)->vbox;
+       label = gtk_hseparator_new();
+       gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, FALSE, 3);
+       controls = gtk_hbox_new(FALSE, 10);
+       gtk_box_pack_start(GTK_BOX(vbox), controls, TRUE, TRUE, 0);
+       vbox = gtk_vbox_new(FALSE, 3);
+       gtk_box_pack_start(GTK_BOX(controls), vbox, FALSE, FALSE, 0);
+       hostname = gtk_check_button_new_with_label(_("Send Hostname"));
+       gtk_signal_connect(GTK_OBJECT(hostname), "toggled",
+           G_CALLBACK(on_toggle), NULL);
+       gtk_box_pack_start(GTK_BOX(vbox), hostname, FALSE, FALSE, 3);
+       fqdn = gtk_check_button_new_with_label(_("Send FQDN"));
+       gtk_signal_connect(GTK_OBJECT(fqdn), "toggled",
+           G_CALLBACK(on_toggle), NULL);
+       gtk_box_pack_start(GTK_BOX(vbox), fqdn, FALSE, FALSE, 3);
+       clientid = gtk_check_button_new_with_label(_("Send ClientID"));
+       gtk_box_pack_start(GTK_BOX(vbox), clientid, FALSE, FALSE, 3);
+       duid = gtk_check_button_new_with_label(_("Send DUID"));
+       gtk_signal_connect(GTK_OBJECT(clientid), "toggled",
+           G_CALLBACK(on_toggle), duid);
+       gtk_signal_connect(GTK_OBJECT(duid), "toggled",
+           G_CALLBACK(on_toggle), NULL);
+       gtk_box_pack_start(GTK_BOX(vbox), duid, FALSE, FALSE, 3);
+       arp = gtk_check_button_new_with_label(_("Enable ARP checking"));
+       gtk_box_pack_start(GTK_BOX(vbox), arp, FALSE, FALSE, 3);
+       ipv4ll = gtk_check_button_new_with_label(_("Enable Zeroconf"));
+       gtk_box_pack_start(GTK_BOX(vbox), ipv4ll, FALSE, FALSE, 3);
+       gtk_signal_connect(GTK_OBJECT(arp), "toggled",
+           G_CALLBACK(on_toggle), ipv4ll);
+       gtk_signal_connect(GTK_OBJECT(ipv4ll), "toggled",
+           G_CALLBACK(on_toggle), NULL);
+
+       show_config(NULL, NULL);
+       gtk_widget_show_all(dialog);
+       result = gtk_dialog_run(GTK_DIALOG(dialog));
+       
+       gtk_widget_destroy(dialog);
+       free_config(&config);
+       return TRUE;
+}
diff --git a/prefs.h b/prefs.h
new file mode 100644 (file)
index 0000000..88917a4
--- /dev/null
+++ b/prefs.h
@@ -0,0 +1,34 @@
+/*
+ * dhcpcd-gtk
+ * Copyright 2009 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef PREFS_H
+#define PREFS_H
+
+#include "dhcpcd-gtk.h"
+
+gboolean dhcpcd_prefs(void);
+
+#endif