3 * Copyright 2009 Roy Marples <roy@marples.name>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <dbus/dbus.h>
29 #include "dhcpcd-gtk.h"
32 static GPtrArray *config;
33 static GtkWidget *dialog, *blocks, *names, *controls;
34 static GtkWidget *hostname, *fqdn, *clientid, *duid, *arp, *ipv4ll;
35 static gboolean ignore_change;
38 free_config(GPtrArray **array)
47 for (i = 0; i < a->len; i++) {
48 c = g_ptr_array_index(a, i);
49 g_value_array_free(c);
51 g_ptr_array_free(a, TRUE);
56 read_config(const char *block, const char *name)
63 otype = dbus_g_type_get_struct("GValueArray",
64 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
65 otype = dbus_g_type_get_collection("GPtrArray", otype);
66 if (!dbus_g_proxy_call(dbus, "GetConfig", &error,
67 G_TYPE_STRING, block, G_TYPE_STRING, name, G_TYPE_INVALID,
68 otype, &array, G_TYPE_INVALID))
70 g_critical("GetConfig: %s", error->message);
71 g_clear_error(&error);
78 get_config(GPtrArray *array, const char *option, const char **value)
87 for (i = 0; i < array->len; i++) {
88 c = g_ptr_array_index(array, i);
89 val = g_value_array_get_nth(c, 0);
90 str = g_value_get_string(val);
91 if (strcmp(str, option) != 0)
94 val = g_value_array_get_nth(c, 1);
95 str = g_value_get_string(val);
109 combo_active_text(GtkWidget *widget)
116 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)));
117 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
119 memset(&val, 0, sizeof(val));
120 gtk_tree_model_get_value(GTK_TREE_MODEL(store), &iter, 1, &val);
121 text = g_strdup(g_value_get_string(&val));
127 set_name_active_icon(const char *iname)
135 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
136 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(names), &iter))
138 it = gtk_icon_theme_get_default();
139 pb = gtk_icon_theme_load_icon(it, iname,
140 GTK_ICON_SIZE_MENU, 0, NULL);
142 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
143 gtk_list_store_set(store, &iter, 0, pb, -1);
145 gtk_tree_model_row_changed(GTK_TREE_MODEL(store), path, &iter);
146 gtk_tree_path_free(path);
151 set_option(const char *option, const char *value)
157 block = combo_active_text(blocks);
158 name = combo_active_text(names);
160 if (!dbus_g_proxy_call(dbus, "SetConfigValue", &error,
161 G_TYPE_STRING, name ? block : "",
162 G_TYPE_STRING, name ? name : "",
163 G_TYPE_STRING, option, G_TYPE_STRING, value,
164 G_TYPE_INVALID, G_TYPE_INVALID))
166 g_critical("SetConfigValue: %s", error->message);
167 g_clear_error(&error);
173 set_name_active_icon("document-save");
178 unset_option(const char *option)
184 block = combo_active_text(blocks);
185 name = combo_active_text(names);
187 if (!dbus_g_proxy_call(dbus, "RemoveConfigOption", &error,
188 G_TYPE_STRING, name ? block : "" ,
189 G_TYPE_STRING, name ? name : "",
190 G_TYPE_STRING, option,
191 G_TYPE_INVALID, G_TYPE_INVALID))
193 g_critical("RemoveConfigOption: %s", error->message);
194 g_clear_error(&error);
200 set_name_active_icon("document-save");
205 toggle_generic(gboolean has, const char *val)
207 return (has && (val == NULL || g_strcmp0(val, "\"\"") == 0));
211 toggle_generic_neg(gboolean has, _unused const char *val)
217 toggle_fqdn(gboolean has, const char *val)
221 g_strcmp0(val, "both") == 0 ||
222 g_strcmp0(val, "ptr") == 0));
226 set_check(GtkToggleButton *button,
227 GPtrArray *global, GPtrArray *conf, const char *name,
228 gboolean (*test)(gboolean, const char *))
231 gboolean has, incons;
233 if (get_config(conf, name, &val)) {
236 } else if (global == NULL) {
240 has = get_config(global, name, &val);
243 gtk_toggle_button_set_active(button, test(has, val));
244 gtk_toggle_button_set_inconsistent(button, incons);
248 show_config(const char *block, const char *name)
252 ignore_change = TRUE;
254 global = read_config(NULL, NULL);
258 free_config(&config);
259 config = read_config(block, name);
260 set_check(GTK_TOGGLE_BUTTON(hostname), global, config,
261 "hostname", toggle_generic);
262 set_check(GTK_TOGGLE_BUTTON(fqdn), global, config,
263 "fqdn", toggle_fqdn);
264 set_check(GTK_TOGGLE_BUTTON(clientid), global, config,
265 "clientid", toggle_generic);
266 set_check(GTK_TOGGLE_BUTTON(duid), global, config,
267 "duid", toggle_generic);
268 gtk_widget_set_sensitive(duid,
269 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(clientid)));
270 set_check(GTK_TOGGLE_BUTTON(arp), global, config,
271 "noarp", toggle_generic_neg);
272 set_check(GTK_TOGGLE_BUTTON(ipv4ll), global, config,
273 "noipv4ll", toggle_generic_neg);
274 gtk_widget_set_sensitive(ipv4ll,
275 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(arp)));
276 free_config(&global);
277 ignore_change = FALSE;
281 list_interfaces(void)
284 const struct if_msg *ifm;
287 for (l = interfaces; l; l = l->next) {
288 ifm = (const struct if_msg *)l->data;
289 list = g_slist_append(list, ifm->ifname);
297 GSList *list, *l, *a, *la;
298 const struct if_msg *ifm;
299 const struct if_ap *ifa;
302 for (l = interfaces; l; l = l->next) {
303 ifm = (const struct if_msg *)l->data;
306 for (a = ifm->scan_results; a; a = a->next) {
307 ifa = (const struct if_ap *)a->data;
308 for (la = list; la; la = la->next)
309 if (g_strcmp0((const char *)la->data,
313 list = g_slist_append(list, ifa->ssid);
320 blocks_on_change(GtkWidget *widget, _unused gpointer data)
325 char **list, **lp, *block;
326 const char *iname, *nn;
327 GSList *l, *new_names;
332 block = combo_active_text(widget);
333 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
334 gtk_list_store_clear(store);
335 if (strcmp(block, "global") == 0) {
337 gtk_widget_set_sensitive(names, FALSE);
338 gtk_widget_set_sensitive(controls, TRUE);
339 show_config(NULL, NULL);
343 if (!dbus_g_proxy_call(dbus, "GetConfigBlocks", &error,
344 G_TYPE_STRING, block, G_TYPE_INVALID,
345 G_TYPE_STRV, &list, G_TYPE_INVALID))
348 g_warning("GetConfigBlocks: %s", error->message);
349 g_clear_error(&error);
353 it = gtk_icon_theme_get_default();
354 if (g_strcmp0(block, "interface") == 0)
355 new_names = list_interfaces();
357 new_names = list_ssids();
360 for (l = new_names; l; l = l->next) {
361 nn = (const char *)l->data;
362 for (lp = list; *lp; lp++)
363 if (g_strcmp0(nn, *lp) == 0)
366 iname = "document-save";
368 iname = "document-new";
369 pb = gtk_icon_theme_load_icon(it, iname,
370 GTK_ICON_SIZE_MENU, 0, &error);
371 gtk_list_store_append(store, &iter);
372 gtk_list_store_set(store, &iter, 0, pb, 1, nn, -1);
377 for (lp = list; *lp; lp++) {
378 for (l = new_names; l; l = l->next)
379 if (g_strcmp0((const char *)l->data, *lp) == 0)
383 pb = gtk_icon_theme_load_icon(it, "document-save",
384 GTK_ICON_SIZE_MENU, 0, &error);
385 gtk_list_store_append(store, &iter);
386 gtk_list_store_set(store, &iter, 0, pb, 1, *lp, -1);
390 gtk_widget_set_sensitive(names, n);
391 gtk_widget_set_sensitive(controls, FALSE);
392 g_slist_free(new_names);
398 names_on_change(GtkWidget *widget, _unused gpointer data)
402 block = combo_active_text(blocks);
403 name = combo_active_text(widget);
404 gtk_widget_set_sensitive(controls, TRUE);
405 show_config(block, name);
411 _on_toggle_set(GtkWidget *widget, gpointer data, gboolean set)
413 gboolean active, result;
417 gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(widget), FALSE);
418 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
419 if ((active && set) || (!active && !set))
420 result = set_option((const char *)data, "");
422 result = unset_option((const char *)data);
424 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
429 on_toggle_set(GtkWidget *widget, gpointer data)
431 _on_toggle_set(widget, data, TRUE);
435 on_toggle_unset(GtkWidget *widget, gpointer data)
437 _on_toggle_set(widget, data, FALSE);
441 on_toggle_set_sens(GtkWidget *widget, gpointer data)
445 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
446 gtk_widget_set_sensitive(GTK_WIDGET((GtkWidget *)data), active);
452 free_config(&config);
457 dhcpcd_prefs_close(void)
460 gtk_widget_destroy(dialog);
471 block = combo_active_text(blocks);
472 name = combo_active_text(names);
474 if (!dbus_g_proxy_call(dbus, "SetDefaultConfig", &error,
475 G_TYPE_STRING, name ? block : "",
476 G_TYPE_STRING, name ? name : "",
480 g_critical("SetDefaultConfig: %s", error->message);
481 g_clear_error(&error);
483 set_name_active_icon("document-new");
484 show_config(name ? block : NULL, name);
490 dhcpcd_prefs_show(void)
492 GtkWidget *dialog_vbox, *hbox, *vbox, *label;
495 GtkCellRenderer *rend;
501 gtk_window_present(GTK_WINDOW(dialog));
505 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
506 gtk_signal_connect(GTK_OBJECT(dialog), "destroy", on_destroy, NULL);
508 gtk_window_set_title(GTK_WINDOW(dialog), _("dhcpcd preferences"));
509 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
510 gtk_window_set_icon_name(GTK_WINDOW(dialog), "config-users");
511 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
512 gtk_window_set_type_hint(GTK_WINDOW(dialog),
513 GDK_WINDOW_TYPE_HINT_DIALOG);
515 dialog_vbox = gtk_vbox_new(FALSE, 3);
516 gtk_container_add(GTK_CONTAINER(dialog), dialog_vbox);
518 hbox = gtk_hbox_new(FALSE, 10);
519 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, FALSE, FALSE, 3);
520 label = gtk_label_new("Configuration block:");
521 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3);
522 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
523 it = gtk_icon_theme_get_default();
525 pb = gtk_icon_theme_load_icon(it, "config-users",
526 GTK_ICON_SIZE_MENU, 0, &error);
527 gtk_list_store_append(store, &iter);
528 gtk_list_store_set(store, &iter, 0, pb, 1, "global", -1);
530 pb = gtk_icon_theme_load_icon(it, "network-wired",
531 GTK_ICON_SIZE_MENU, 0, &error);
532 gtk_list_store_append(store, &iter);
533 gtk_list_store_set(store, &iter, 0, pb, 1, "interface", -1);
535 pb = gtk_icon_theme_load_icon(it, "network-wireless",
536 GTK_ICON_SIZE_MENU, 0, &error);
537 gtk_list_store_append(store, &iter);
538 gtk_list_store_set(store, &iter, 0, pb, 1, "ssid", -1);
540 blocks = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
541 rend = gtk_cell_renderer_pixbuf_new();
542 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, FALSE);
543 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
545 rend = gtk_cell_renderer_text_new();
546 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, TRUE);
547 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
549 gtk_combo_box_set_active(GTK_COMBO_BOX(blocks), 0);
550 gtk_box_pack_start(GTK_BOX(hbox), blocks, FALSE, FALSE, 3);
551 label = gtk_label_new("Block name:");
552 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3);
553 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
554 names = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
555 rend = gtk_cell_renderer_pixbuf_new();
556 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, FALSE);
557 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names),
559 rend = gtk_cell_renderer_text_new();
560 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, TRUE);
561 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names), rend, "text", 1);
562 gtk_widget_set_sensitive(names, FALSE);
563 gtk_box_pack_start(GTK_BOX(hbox), names, FALSE, FALSE, 3);
564 gtk_signal_connect(GTK_OBJECT(blocks), "changed",
565 G_CALLBACK(blocks_on_change), NULL);
566 gtk_signal_connect(GTK_OBJECT(names), "changed",
567 G_CALLBACK(names_on_change), NULL);
569 label = gtk_hseparator_new();
570 gtk_box_pack_start(GTK_BOX(dialog_vbox), label, TRUE, FALSE, 3);
571 controls = gtk_hbox_new(FALSE, 10);
572 gtk_box_pack_start(GTK_BOX(dialog_vbox), controls, TRUE, TRUE, 0);
573 vbox = gtk_vbox_new(FALSE, 3);
574 gtk_box_pack_start(GTK_BOX(controls), vbox, FALSE, FALSE, 0);
575 hostname = gtk_check_button_new_with_label(_("Send Hostname"));
576 gtk_signal_connect(GTK_OBJECT(hostname), "toggled",
577 G_CALLBACK(on_toggle_set), UNCONST("hostname"));
578 gtk_box_pack_start(GTK_BOX(vbox), hostname, FALSE, FALSE, 3);
579 fqdn = gtk_check_button_new_with_label(_("Send FQDN"));
580 gtk_signal_connect(GTK_OBJECT(fqdn), "toggled",
581 G_CALLBACK(on_toggle_set), UNCONST("fqdn"));
582 gtk_box_pack_start(GTK_BOX(vbox), fqdn, FALSE, FALSE, 3);
583 clientid = gtk_check_button_new_with_label(_("Send ClientID"));
584 gtk_signal_connect(GTK_OBJECT(clientid), "toggled",
585 G_CALLBACK(on_toggle_set), UNCONST("clientid"));
586 gtk_box_pack_start(GTK_BOX(vbox), clientid, FALSE, FALSE, 3);
587 duid = gtk_check_button_new_with_label(_("Send DUID"));
588 gtk_signal_connect(GTK_OBJECT(duid), "toggled",
589 G_CALLBACK(on_toggle_set), UNCONST("duid"));
590 gtk_signal_connect_after(GTK_OBJECT(clientid), "toggled",
591 G_CALLBACK(on_toggle_set_sens), duid);
592 gtk_box_pack_start(GTK_BOX(vbox), duid, FALSE, FALSE, 3);
593 arp = gtk_check_button_new_with_label(_("Enable ARP checking"));
594 gtk_signal_connect(GTK_OBJECT(arp), "toggled",
595 G_CALLBACK(on_toggle_unset), UNCONST("noarp"));
596 gtk_box_pack_start(GTK_BOX(vbox), arp, FALSE, FALSE, 3);
597 ipv4ll = gtk_check_button_new_with_label(_("Enable Zeroconf"));
598 gtk_box_pack_start(GTK_BOX(vbox), ipv4ll, FALSE, FALSE, 3);
599 gtk_signal_connect(GTK_OBJECT(ipv4ll), "toggled",
600 G_CALLBACK(on_toggle_unset), UNCONST("noipv4ll"));
601 gtk_signal_connect_after(GTK_OBJECT(arp), "toggled",
602 G_CALLBACK(on_toggle_set_sens), ipv4ll);
604 hbox = gtk_hbox_new(FALSE, 0);
605 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, TRUE, TRUE, 3);
606 label = gtk_button_new_from_stock(GTK_STOCK_REDO);
607 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
608 gtk_signal_connect(GTK_OBJECT(label), "clicked", on_redo, NULL);
609 label = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
610 gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0);
611 gtk_signal_connect(GTK_OBJECT(label), "clicked",
612 dhcpcd_prefs_close, NULL);
614 show_config(NULL, NULL);
615 gtk_widget_show_all(dialog);