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;
37 free_config(GPtrArray **array)
46 for (i = 0; i < a->len; i++) {
47 c = g_ptr_array_index(a, i);
48 g_value_array_free(c);
50 g_ptr_array_free(a, TRUE);
55 read_config(const char *block, const char *name)
62 otype = dbus_g_type_get_struct("GValueArray",
63 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
64 otype = dbus_g_type_get_collection("GPtrArray", otype);
65 if (!dbus_g_proxy_call(dbus, "GetConfig", &error,
66 G_TYPE_STRING, block, G_TYPE_STRING, name, G_TYPE_INVALID,
67 otype, &array, G_TYPE_INVALID))
69 g_critical("GetConfig: %s", error->message);
70 g_clear_error(&error);
77 save_config(const char *block, const char *name)
83 otype = dbus_g_type_get_struct("GValueArray",
84 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
85 otype = dbus_g_type_get_collection("GPtrArray", otype);
86 if (!dbus_g_proxy_call(dbus, "SetConfig", &error,
87 G_TYPE_STRING, block, G_TYPE_STRING, name,
88 otype, config, G_TYPE_INVALID, G_TYPE_INVALID))
90 g_critical("SetConfig: %s", error->message);
91 g_clear_error(&error);
96 get_config(GPtrArray *array, const char *option, const char **value)
105 for (i = 0; i < array->len; i++) {
106 c = g_ptr_array_index(array, i);
107 val = g_value_array_get_nth(c, 0);
108 str = g_value_get_string(val);
109 if (strcmp(str, option) != 0)
112 val = g_value_array_get_nth(c, 1);
113 str = g_value_get_string(val);
127 toggle_generic(gboolean has, const char *val)
129 return (has && (val == NULL || g_strcmp0(val, "\"\"") == 0));
133 toggle_generic_neg(gboolean has, _unused const char *val)
139 toggle_fqdn(gboolean has, const char *val)
143 g_strcmp0(val, "both") == 0 ||
144 g_strcmp0(val, "ptr") == 0));
148 set_check(GtkToggleButton *button,
149 GPtrArray *global, GPtrArray *conf, const char *name,
150 gboolean (*test)(gboolean, const char *))
153 gboolean has, incons;
155 if (get_config(conf, name, &val)) {
158 } else if (global == NULL) {
162 has = get_config(global, name, &val);
165 gtk_toggle_button_set_active(button, test(has, val));
166 gtk_toggle_button_set_inconsistent(button, incons);
170 show_config(const char *block, const char *name)
175 global = read_config(NULL, NULL);
179 free_config(&config);
180 config = read_config(block, name);
181 set_check(GTK_TOGGLE_BUTTON(hostname), global, config,
182 "hostname", toggle_generic);
183 set_check(GTK_TOGGLE_BUTTON(fqdn), global, config,
184 "fqdn", toggle_fqdn);
185 set_check(GTK_TOGGLE_BUTTON(clientid), global, config,
186 "clientid", toggle_generic);
187 set_check(GTK_TOGGLE_BUTTON(duid), global, config,
188 "duid", toggle_generic);
189 gtk_widget_set_sensitive(duid,
190 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(clientid)));
191 set_check(GTK_TOGGLE_BUTTON(arp), global, config,
192 "noarp", toggle_generic_neg);
193 set_check(GTK_TOGGLE_BUTTON(ipv4ll), global, config,
194 "noipv4ll", toggle_generic_neg);
195 gtk_widget_set_sensitive(ipv4ll,
196 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(arp)));
197 free_config(&global);
201 combo_active_text(GtkWidget *widget)
208 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)));
209 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
211 memset(&val, 0, sizeof(val));
212 gtk_tree_model_get_value(GTK_TREE_MODEL(store), &iter, 1, &val);
213 text = g_strdup(g_value_get_string(&val));
219 list_interfaces(void)
222 const struct if_msg *ifm;
225 for (l = interfaces; l; l = l->next) {
226 ifm = (const struct if_msg *)l->data;
227 list = g_slist_append(list, ifm->ifname);
235 GSList *list, *l, *a, *la;
236 const struct if_msg *ifm;
237 const struct if_ap *ifa;
240 for (l = interfaces; l; l = l->next) {
241 ifm = (const struct if_msg *)l->data;
244 for (a = ifm->scan_results; a; a = a->next) {
245 ifa = (const struct if_ap *)a->data;
246 for (la = list; la; la = la->next)
247 if (g_strcmp0((const char *)la->data,
251 list = g_slist_append(list, ifa->ssid);
258 blocks_on_change(GtkWidget *widget, _unused gpointer data)
263 char **list, **lp, *block;
264 const char *iname, *nn;
265 GSList *l, *new_names;
270 block = combo_active_text(widget);
271 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
272 gtk_list_store_clear(store);
273 if (strcmp(block, "global") == 0) {
275 gtk_widget_set_sensitive(names, FALSE);
276 gtk_widget_set_sensitive(controls, TRUE);
277 show_config(NULL, NULL);
281 if (!dbus_g_proxy_call(dbus, "GetConfigBlocks", &error,
282 G_TYPE_STRING, block, G_TYPE_INVALID,
283 G_TYPE_STRV, &list, G_TYPE_INVALID))
286 g_warning("GetConfigBlocks: %s", error->message);
287 g_clear_error(&error);
291 it = gtk_icon_theme_get_default();
292 if (g_strcmp0(block, "interface") == 0)
293 new_names = list_interfaces();
295 new_names = list_ssids();
298 for (l = new_names; l; l = l->next) {
299 nn = (const char *)l->data;
300 for (lp = list; *lp; lp++)
301 if (g_strcmp0(nn, *lp) == 0)
304 iname = "document-save";
306 iname = "document-new";
307 pb = gtk_icon_theme_load_icon(it, iname,
308 GTK_ICON_SIZE_MENU, 0, &error);
309 gtk_list_store_append(store, &iter);
310 gtk_list_store_set(store, &iter, 0, pb, 1, nn, -1);
315 for (lp = list; *lp; lp++) {
316 for (l = new_names; l; l = l->next)
317 if (g_strcmp0((const char *)l->data, *lp) == 0)
321 pb = gtk_icon_theme_load_icon(it, "document-save",
322 GTK_ICON_SIZE_MENU, 0, &error);
323 gtk_list_store_append(store, &iter);
324 gtk_list_store_set(store, &iter, 0, pb, 1, *lp, -1);
328 gtk_widget_set_sensitive(names, n);
329 gtk_widget_set_sensitive(controls, FALSE);
330 g_slist_free(new_names);
336 names_on_change(GtkWidget *widget, _unused gpointer data)
340 block = combo_active_text(blocks);
341 name = combo_active_text(widget);
342 gtk_widget_set_sensitive(controls, TRUE);
343 show_config(block, name);
349 on_toggle(GtkWidget *widget, gpointer data)
353 gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(widget), FALSE);
356 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
357 gtk_widget_set_sensitive(GTK_WIDGET((GtkWidget *)data), active);
363 free_config(&config);
368 dhcpcd_prefs_close(void)
371 gtk_widget_destroy(dialog);
383 block = combo_active_text(blocks);
384 name = combo_active_text(names);
385 free_config(&config);
386 if (g_strcmp0(block, "global") == 0) {
387 config = g_ptr_array_sized_new(3);
388 memset(&val, 0, sizeof(val));
389 g_value_init(&val, G_TYPE_STRING);
390 array = g_value_array_new(2);
391 g_value_set_static_string(&val, "hostname");
392 array = g_value_array_append(array, &val);
393 g_value_set_static_string(&val, "");
394 array = g_value_array_append(array, &val);
395 g_ptr_array_add(config, array);
396 array = g_value_array_new(2);
397 g_value_set_static_string(&val, "option");
398 array = g_value_array_append(array, &val);
399 g_value_set_static_string(&val, "domain_name_servers, "
400 "domain_name, domain_search, host_name");
401 array = g_value_array_append(array, &val);
402 g_ptr_array_add(config, array);
403 array = g_value_array_new(2);
404 g_value_set_static_string(&val, "option");
405 array = g_value_array_append(array, &val);
406 g_value_set_static_string(&val, "ntp_servers");
407 array = g_value_array_append(array, &val);
408 g_ptr_array_add(config, array);
410 config = g_ptr_array_new();
411 save_config(name ? block : NULL, name);
412 show_config(name ? block : NULL, name);
418 dhcpcd_prefs_show(void)
420 GtkWidget *dialog_vbox, *hbox, *vbox, *label;
423 GtkCellRenderer *rend;
429 gtk_window_present(GTK_WINDOW(dialog));
433 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
434 gtk_signal_connect(GTK_OBJECT(dialog), "destroy", on_destroy, NULL);
436 gtk_window_set_title(GTK_WINDOW(dialog), _("dhcpcd preferences"));
437 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
438 gtk_window_set_icon_name(GTK_WINDOW(dialog), "config-users");
439 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
440 gtk_window_set_type_hint(GTK_WINDOW(dialog),
441 GDK_WINDOW_TYPE_HINT_DIALOG);
443 dialog_vbox = gtk_vbox_new(FALSE, 3);
444 gtk_container_add(GTK_CONTAINER(dialog), dialog_vbox);
446 hbox = gtk_hbox_new(FALSE, 10);
447 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, FALSE, FALSE, 3);
448 label = gtk_label_new("Configuration block:");
449 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3);
450 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
451 it = gtk_icon_theme_get_default();
453 pb = gtk_icon_theme_load_icon(it, "config-users",
454 GTK_ICON_SIZE_MENU, 0, &error);
455 gtk_list_store_append(store, &iter);
456 gtk_list_store_set(store, &iter, 0, pb, 1, "global", -1);
458 pb = gtk_icon_theme_load_icon(it, "network-wired",
459 GTK_ICON_SIZE_MENU, 0, &error);
460 gtk_list_store_append(store, &iter);
461 gtk_list_store_set(store, &iter, 0, pb, 1, "interface", -1);
463 pb = gtk_icon_theme_load_icon(it, "network-wireless",
464 GTK_ICON_SIZE_MENU, 0, &error);
465 gtk_list_store_append(store, &iter);
466 gtk_list_store_set(store, &iter, 0, pb, 1, "ssid", -1);
468 blocks = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
469 rend = gtk_cell_renderer_pixbuf_new();
470 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, FALSE);
471 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
473 rend = gtk_cell_renderer_text_new();
474 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, TRUE);
475 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
477 gtk_combo_box_set_active(GTK_COMBO_BOX(blocks), 0);
478 gtk_box_pack_start(GTK_BOX(hbox), blocks, FALSE, FALSE, 3);
479 label = gtk_label_new("Block name:");
480 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3);
481 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
482 names = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
483 rend = gtk_cell_renderer_pixbuf_new();
484 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, FALSE);
485 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names),
487 rend = gtk_cell_renderer_text_new();
488 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, TRUE);
489 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names), rend, "text", 1);
490 gtk_widget_set_sensitive(names, FALSE);
491 gtk_box_pack_start(GTK_BOX(hbox), names, FALSE, FALSE, 3);
492 gtk_signal_connect(GTK_OBJECT(blocks), "changed",
493 G_CALLBACK(blocks_on_change), NULL);
494 gtk_signal_connect(GTK_OBJECT(names), "changed",
495 G_CALLBACK(names_on_change), NULL);
497 label = gtk_hseparator_new();
498 gtk_box_pack_start(GTK_BOX(dialog_vbox), label, TRUE, FALSE, 3);
499 controls = gtk_hbox_new(FALSE, 10);
500 gtk_box_pack_start(GTK_BOX(dialog_vbox), controls, TRUE, TRUE, 0);
501 vbox = gtk_vbox_new(FALSE, 3);
502 gtk_box_pack_start(GTK_BOX(controls), vbox, FALSE, FALSE, 0);
503 hostname = gtk_check_button_new_with_label(_("Send Hostname"));
504 gtk_signal_connect(GTK_OBJECT(hostname), "toggled",
505 G_CALLBACK(on_toggle), NULL);
506 gtk_box_pack_start(GTK_BOX(vbox), hostname, FALSE, FALSE, 3);
507 fqdn = gtk_check_button_new_with_label(_("Send FQDN"));
508 gtk_signal_connect(GTK_OBJECT(fqdn), "toggled",
509 G_CALLBACK(on_toggle), NULL);
510 gtk_box_pack_start(GTK_BOX(vbox), fqdn, FALSE, FALSE, 3);
511 clientid = gtk_check_button_new_with_label(_("Send ClientID"));
512 gtk_box_pack_start(GTK_BOX(vbox), clientid, FALSE, FALSE, 3);
513 duid = gtk_check_button_new_with_label(_("Send DUID"));
514 gtk_signal_connect(GTK_OBJECT(clientid), "toggled",
515 G_CALLBACK(on_toggle), duid);
516 gtk_signal_connect(GTK_OBJECT(duid), "toggled",
517 G_CALLBACK(on_toggle), NULL);
518 gtk_box_pack_start(GTK_BOX(vbox), duid, FALSE, FALSE, 3);
519 arp = gtk_check_button_new_with_label(_("Enable ARP checking"));
520 gtk_box_pack_start(GTK_BOX(vbox), arp, FALSE, FALSE, 3);
521 ipv4ll = gtk_check_button_new_with_label(_("Enable Zeroconf"));
522 gtk_box_pack_start(GTK_BOX(vbox), ipv4ll, FALSE, FALSE, 3);
523 gtk_signal_connect(GTK_OBJECT(arp), "toggled",
524 G_CALLBACK(on_toggle), ipv4ll);
525 gtk_signal_connect(GTK_OBJECT(ipv4ll), "toggled",
526 G_CALLBACK(on_toggle), NULL);
528 hbox = gtk_hbox_new(FALSE, 0);
529 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, TRUE, TRUE, 3);
530 label = gtk_button_new_from_stock(GTK_STOCK_REDO);
531 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
532 gtk_signal_connect(GTK_OBJECT(label), "clicked", on_redo, NULL);
533 label = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
534 gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0);
535 gtk_signal_connect(GTK_OBJECT(label), "clicked",
536 dhcpcd_prefs_close, NULL);
538 show_config(NULL, NULL);
539 gtk_widget_show_all(dialog);