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
29 #include "dhcpcd-config.h"
30 #include "dhcpcd-gtk.h"
33 static GtkWidget *dialog, *blocks, *names, *controls, *clear, *rebind;
34 static GtkWidget *autoconf, *address, *router, *dns_servers, *dns_search;
35 static GPtrArray *config;
36 static char *block, *name;
39 show_config(GPtrArray *array)
44 if (get_config_static(array, "ip_address=", &val) != -1)
47 get_config(array, "inform", &val);
50 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autoconf), autocnf);
51 gtk_entry_set_text(GTK_ENTRY(address), val ? val : "");
52 get_config_static(array, "routers=", &val);
53 gtk_entry_set_text(GTK_ENTRY(router), val ? val : "");
54 get_config_static(array, "domain_name_servers=", &val);
55 gtk_entry_set_text(GTK_ENTRY(dns_servers), val ? val : "");
56 get_config_static(array, "domain_search=", &val);
57 gtk_entry_set_text(GTK_ENTRY(dns_search), val ? val : "");
61 combo_active_text(GtkWidget *widget)
68 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)));
69 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
71 memset(&val, 0, sizeof(val));
72 gtk_tree_model_get_value(GTK_TREE_MODEL(store), &iter, 1, &val);
73 text = g_strdup(g_value_get_string(&val));
79 make_config(GPtrArray *array)
84 a = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(autoconf));
85 val = gtk_entry_get_text(GTK_ENTRY(address));
88 set_option(array, false, "inform", a ? val : NULL);
89 set_option(array, true, "ip_address=", a ? NULL : val);
91 val = gtk_entry_get_text(GTK_ENTRY(router));
92 if (a && *val == '\0')
94 set_option(array, true, "routers=", val);
96 val = gtk_entry_get_text(GTK_ENTRY(dns_servers));
97 if (a && *val == '\0')
99 set_option(array, true, "domain_name_servers=", val);
101 val = gtk_entry_get_text(GTK_ENTRY(dns_search));
102 if (a && *val == '\0')
104 set_option(array, true, "domain_search=", val);
108 set_name_active_icon(const char *iname)
116 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
117 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(names), &iter))
119 it = gtk_icon_theme_get_default();
120 pb = gtk_icon_theme_load_icon(it, iname,
121 GTK_ICON_SIZE_MENU, 0, NULL);
123 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
124 gtk_list_store_set(store, &iter, 0, pb, -1);
126 gtk_tree_model_row_changed(GTK_TREE_MODEL(store), path, &iter);
127 gtk_tree_path_free(path);
132 list_interfaces(void)
135 const struct if_msg *ifm;
138 for (l = interfaces; l; l = l->next) {
139 ifm = (const struct if_msg *)l->data;
140 list = g_slist_append(list, ifm->ifname);
148 GSList *list, *l, *a, *la;
149 const struct if_msg *ifm;
150 const struct if_ap *ifa;
153 for (l = interfaces; l; l = l->next) {
154 ifm = (const struct if_msg *)l->data;
157 for (a = ifm->scan_results; a; a = a->next) {
158 ifa = (const struct if_ap *)a->data;
159 for (la = list; la; la = la->next)
160 if (g_strcmp0((const char *)la->data,
164 list = g_slist_append(list, ifa->ssid);
171 blocks_on_change(GtkWidget *widget)
177 const char *iname, *nn;
178 GSList *l, *new_names;
185 save_config(block, name, config);
186 free_config(&config);
192 block = combo_active_text(widget);
193 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
194 gtk_list_store_clear(store);
196 if (!dbus_g_proxy_call(dbus, "GetConfigBlocks", &error,
197 G_TYPE_STRING, block, G_TYPE_INVALID,
198 G_TYPE_STRV, &list, G_TYPE_INVALID))
200 g_warning("GetConfigBlocks: %s", error->message);
201 g_clear_error(&error);
205 it = gtk_icon_theme_get_default();
206 if (g_strcmp0(block, "interface") == 0)
207 new_names = list_interfaces();
209 new_names = list_ssids();
212 for (l = new_names; l; l = l->next) {
213 nn = (const char *)l->data;
214 for (lp = list; *lp; lp++)
215 if (g_strcmp0(nn, *lp) == 0)
218 iname = "document-save";
220 iname = "document-new";
221 pb = gtk_icon_theme_load_icon(it, iname,
222 GTK_ICON_SIZE_MENU, 0, &error);
223 gtk_list_store_append(store, &iter);
224 gtk_list_store_set(store, &iter, 0, pb, 1, nn, -1);
229 for (lp = list; *lp; lp++) {
230 for (l = new_names; l; l = l->next)
231 if (g_strcmp0((const char *)l->data, *lp) == 0)
235 pb = gtk_icon_theme_load_icon(it, "document-save",
236 GTK_ICON_SIZE_MENU, 0, &error);
237 gtk_list_store_append(store, &iter);
238 gtk_list_store_set(store, &iter, 0, pb, 1, *lp, -1);
242 gtk_widget_set_sensitive(names, n);
243 g_slist_free(new_names);
248 names_on_change(void)
253 save_config(block, name, config);
256 name = combo_active_text(names);
257 free_config(&config);
258 config = load_config(block, name);
260 gtk_widget_set_sensitive(controls, name ? true : false);
261 gtk_widget_set_sensitive(clear, name ? true : false);
262 gtk_widget_set_sensitive(rebind, name ? true : false);
266 valid_address(const char *val, bool allow_cidr)
273 addr = g_strdup(val);
275 p = strchr(addr, '/');
280 cidr = g_ascii_strtoll(p, &e, 10);
281 if (cidr < 0 || cidr > 32 ||
282 errno != 0 || *e != '\0')
289 retval = inet_aton(addr, &in) == 0 ? false : true;
298 address_lost_focus(GtkEntry *entry)
302 val = gtk_entry_get_text(entry);
303 if (*val != '\0' && !valid_address(val, true))
304 gtk_entry_set_text(entry, "");
309 entry_lost_focus(GtkEntry *entry)
314 val = gtk_entry_get_text(entry);
315 a = g_strsplit(val, " ", 0);
316 for (p = a; *p; p++) {
317 if (**p != '\0' && !valid_address(*p, false)) {
318 gtk_entry_set_text(entry, "");
330 free_config(&config);
331 config = g_ptr_array_new();
332 if (save_config(block, name, config)) {
333 set_name_active_icon("document-new");
339 rebind_interface(const char *iface)
344 if (!dbus_g_proxy_call(dbus, "Rebind", &error,
345 G_TYPE_STRING, iface, G_TYPE_INVALID, G_TYPE_INVALID))
347 g_critical("Rebind: %s: %s", iface, error->message);
348 g_clear_error(&error);
356 const struct if_msg *ifm;
359 if (save_config(block, name, config)) {
360 set_name_active_icon(config->len == 0 ?
361 "document-new" : "document-save");
363 if (g_strcmp0(block, "interface") == 0)
364 rebind_interface(name);
366 for (l = interfaces; l; l = l->next) {
367 ifm = (const struct if_msg *)l->data;
368 if (g_strcmp0(ifm->ssid, name) == 0)
369 rebind_interface(ifm->ifname);
381 save_config(block, name, config);
386 free_config(&config);
391 dhcpcd_prefs_close(void)
394 if (dialog != NULL) {
395 gtk_widget_destroy(dialog);
401 dhcpcd_prefs_show(void)
403 GtkWidget *dialog_vbox, *hbox, *vbox, *table, *w;
406 GtkCellRenderer *rend;
412 gtk_window_present(GTK_WINDOW(dialog));
416 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
417 g_signal_connect(G_OBJECT(dialog), "destroy", on_destroy, NULL);
419 gtk_window_set_title(GTK_WINDOW(dialog), _("dhcpcd preferences"));
420 gtk_window_set_resizable(GTK_WINDOW(dialog), false);
421 gtk_window_set_icon_name(GTK_WINDOW(dialog), "config-users");
422 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
423 gtk_window_set_type_hint(GTK_WINDOW(dialog),
424 GDK_WINDOW_TYPE_HINT_DIALOG);
426 dialog_vbox = gtk_vbox_new(false, 10);
427 gtk_container_set_border_width(GTK_CONTAINER(dialog), 10);
428 gtk_container_add(GTK_CONTAINER(dialog), dialog_vbox);
430 hbox = gtk_hbox_new(false, 0);
431 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, false, false, 3);
432 w = gtk_label_new("Configure:");
433 gtk_box_pack_start(GTK_BOX(hbox), w, false, false, 3);
434 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
435 it = gtk_icon_theme_get_default();
437 pb = gtk_icon_theme_load_icon(it, "network-wired",
438 GTK_ICON_SIZE_MENU, 0, &error);
439 gtk_list_store_append(store, &iter);
440 gtk_list_store_set(store, &iter, 0, pb, 1, "interface", -1);
442 pb = gtk_icon_theme_load_icon(it, "network-wireless",
443 GTK_ICON_SIZE_MENU, 0, &error);
444 gtk_list_store_append(store, &iter);
445 gtk_list_store_set(store, &iter, 0, pb, 1, "ssid", -1);
447 blocks = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
448 rend = gtk_cell_renderer_pixbuf_new();
449 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, false);
450 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
452 rend = gtk_cell_renderer_text_new();
453 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, true);
454 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
456 gtk_combo_box_set_active(GTK_COMBO_BOX(blocks), 0);
457 gtk_box_pack_start(GTK_BOX(hbox), blocks, false, false, 3);
458 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
459 names = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
460 rend = gtk_cell_renderer_pixbuf_new();
461 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, false);
462 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names),
464 rend = gtk_cell_renderer_text_new();
465 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, true);
466 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names), rend, "text", 1);
467 gtk_widget_set_sensitive(names, false);
468 gtk_box_pack_start(GTK_BOX(hbox), names, false, false, 3);
469 g_signal_connect(G_OBJECT(blocks), "changed",
470 G_CALLBACK(blocks_on_change), NULL);
471 g_signal_connect(G_OBJECT(names), "changed",
472 G_CALLBACK(names_on_change), NULL);
474 w = gtk_hseparator_new();
475 gtk_box_pack_start(GTK_BOX(dialog_vbox), w, true, false, 3);
476 controls = gtk_vbox_new(false, 10);
477 gtk_widget_set_sensitive(controls, false);
478 gtk_box_pack_start(GTK_BOX(dialog_vbox), controls, true, true, 0);
479 vbox = gtk_vbox_new(false, 3);
480 gtk_box_pack_start(GTK_BOX(controls), vbox, false, false, 0);
481 autoconf = gtk_check_button_new_with_label(
482 _("Automatically configure empty options"));
483 gtk_box_pack_start(GTK_BOX(vbox), autoconf, false, false, 3);
484 table = gtk_table_new(6, 2, false);
485 gtk_box_pack_start(GTK_BOX(controls), table, false, false, 0);
487 #define attach_label(a, b, c, d, e) \
489 gtk_misc_set_alignment(GTK_MISC(a), 0.0, 0.5); \
490 gtk_table_attach(GTK_TABLE(table), a, b, c, d, e, \
491 GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 3, 3); \
493 #define attach_entry(a, b, c, d, e) \
494 gtk_table_attach(GTK_TABLE(table), a, b, c, d, e, \
495 GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 3, 3);
497 w = gtk_label_new(_("IP Address:"));
498 address = gtk_entry_new();
499 gtk_entry_set_max_length(GTK_ENTRY(address), 15);
500 g_signal_connect(G_OBJECT(address), "focus-out-event",
501 G_CALLBACK(address_lost_focus), NULL);
502 attach_label(w, 0, 1, 0, 1);
503 attach_entry(address, 1, 2, 0, 1);
505 w = gtk_label_new(_("Router:"));
506 router = gtk_entry_new();
507 gtk_entry_set_max_length(GTK_ENTRY(router), 12);
508 g_signal_connect(G_OBJECT(router), "focus-out-event",
509 G_CALLBACK(entry_lost_focus), NULL);
510 attach_label(w, 0, 1, 2, 3);
511 attach_entry(router, 1, 2, 2, 3);
513 w = gtk_label_new(_("DNS Servers:"));
514 dns_servers = gtk_entry_new();
515 g_signal_connect(G_OBJECT(dns_servers), "focus-out-event",
516 G_CALLBACK(entry_lost_focus), NULL);
517 attach_label(w, 0, 1, 3, 4);
518 attach_entry(dns_servers, 1, 2, 3, 4);
520 w = gtk_label_new(_("DNS Search:"));
521 dns_search = gtk_entry_new();
522 attach_label(w, 0, 1, 4, 5);
523 attach_entry(dns_search, 1, 2, 4, 5);
525 hbox = gtk_hbox_new(false, 10);
526 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, true, true, 3);
527 clear = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
528 gtk_widget_set_sensitive(clear, false);
529 gtk_box_pack_start(GTK_BOX(hbox), clear, false, false, 0);
530 g_signal_connect(G_OBJECT(clear), "clicked", on_clear, NULL);
531 rebind = gtk_button_new_with_mnemonic(_("_Rebind"));
532 gtk_widget_set_sensitive(rebind, false);
533 w = gtk_image_new_from_stock(GTK_STOCK_EXECUTE,
534 GTK_ICON_SIZE_BUTTON);
535 gtk_button_set_image(GTK_BUTTON(rebind), w);
536 gtk_box_pack_start(GTK_BOX(hbox), rebind, false, false, 0);
537 g_signal_connect(G_OBJECT(rebind), "clicked", on_rebind, NULL);
538 w = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
539 gtk_box_pack_end(GTK_BOX(hbox), w, false, false, 0);
540 g_signal_connect(G_OBJECT(w), "clicked",
541 dhcpcd_prefs_close, NULL);
543 blocks_on_change(blocks);
545 gtk_widget_show_all(dialog);