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;
34 static GtkWidget *autoconf, *address, *router, *dns_servers, *dns_search;
35 static GtkWidget *ntp_servers;
36 static GPtrArray *config;
37 static char *block, *name;
38 static bool ignore_change;
41 show_config(GPtrArray *array)
47 if (get_static_config(array, "ip_address=", &val) != -1)
50 get_config(array, 0, "inform", &val);
53 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autoconf), autocnf);
54 gtk_entry_set_text(GTK_ENTRY(address), val ? val : "");
55 get_static_config(array, "routers=", &val);
56 gtk_entry_set_text(GTK_ENTRY(router), val ? val : "");
57 get_static_config(array, "domain_name_servers=", &val);
58 gtk_entry_set_text(GTK_ENTRY(dns_servers), val ? val : "");
59 get_static_config(array, "domain_name_search=", &val);
60 gtk_entry_set_text(GTK_ENTRY(dns_search), val ? val : "");
61 get_static_config(array, "ntp_servers=", &val);
62 gtk_entry_set_text(GTK_ENTRY(ntp_servers), val ? val : "");
63 ignore_change = FALSE;
67 combo_active_text(GtkWidget *widget)
74 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)));
75 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
77 memset(&val, 0, sizeof(val));
78 gtk_tree_model_get_value(GTK_TREE_MODEL(store), &iter, 1, &val);
79 text = g_strdup(g_value_get_string(&val));
85 make_config(GPtrArray *array)
90 a = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(autoconf));
91 val = gtk_entry_get_text(GTK_ENTRY(address));
94 set_option(array, false, "inform", a ? val : NULL);
95 set_option(array, true, "ip_address=", a ? NULL : val);
97 val = gtk_entry_get_text(GTK_ENTRY(router));
98 if (a && *val == '\0')
100 set_option(array, true, "routers=", val);
102 val = gtk_entry_get_text(GTK_ENTRY(dns_servers));
103 if (a && *val == '\0')
105 set_option(array, true, "domain_name_servers=", val);
107 val = gtk_entry_get_text(GTK_ENTRY(dns_search));
108 if (a && *val == '\0')
110 set_option(array, true, "domain_name_search=", val);
112 val = gtk_entry_get_text(GTK_ENTRY(ntp_servers));
113 if (a && *val == '\0')
115 set_option(array, true, "ntp_servers=", val);
119 set_name_active_icon(const char *iname)
127 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
128 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(names), &iter))
130 it = gtk_icon_theme_get_default();
131 pb = gtk_icon_theme_load_icon(it, iname,
132 GTK_ICON_SIZE_MENU, 0, NULL);
134 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
135 gtk_list_store_set(store, &iter, 0, pb, -1);
137 gtk_tree_model_row_changed(GTK_TREE_MODEL(store), path, &iter);
138 gtk_tree_path_free(path);
143 list_interfaces(void)
146 const struct if_msg *ifm;
149 for (l = interfaces; l; l = l->next) {
150 ifm = (const struct if_msg *)l->data;
151 list = g_slist_append(list, ifm->ifname);
159 GSList *list, *l, *a, *la;
160 const struct if_msg *ifm;
161 const struct if_ap *ifa;
164 for (l = interfaces; l; l = l->next) {
165 ifm = (const struct if_msg *)l->data;
168 for (a = ifm->scan_results; a; a = a->next) {
169 ifa = (const struct if_ap *)a->data;
170 for (la = list; la; la = la->next)
171 if (g_strcmp0((const char *)la->data,
175 list = g_slist_append(list, ifa->ssid);
182 blocks_on_change(GtkWidget *widget)
188 const char *iname, *nn;
189 GSList *l, *new_names;
196 save_config(block, name, config);
201 block = combo_active_text(widget);
202 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
203 gtk_list_store_clear(store);
205 if (!dbus_g_proxy_call(dbus, "GetConfigBlocks", &error,
206 G_TYPE_STRING, block, G_TYPE_INVALID,
207 G_TYPE_STRV, &list, G_TYPE_INVALID))
209 g_warning("GetConfigBlocks: %s", error->message);
210 g_clear_error(&error);
214 it = gtk_icon_theme_get_default();
215 if (g_strcmp0(block, "interface") == 0)
216 new_names = list_interfaces();
218 new_names = list_ssids();
221 for (l = new_names; l; l = l->next) {
222 nn = (const char *)l->data;
223 for (lp = list; *lp; lp++)
224 if (g_strcmp0(nn, *lp) == 0)
227 iname = "document-save";
229 iname = "document-new";
230 pb = gtk_icon_theme_load_icon(it, iname,
231 GTK_ICON_SIZE_MENU, 0, &error);
232 gtk_list_store_append(store, &iter);
233 gtk_list_store_set(store, &iter, 0, pb, 1, nn, -1);
238 for (lp = list; *lp; lp++) {
239 for (l = new_names; l; l = l->next)
240 if (g_strcmp0((const char *)l->data, *lp) == 0)
244 pb = gtk_icon_theme_load_icon(it, "document-save",
245 GTK_ICON_SIZE_MENU, 0, &error);
246 gtk_list_store_append(store, &iter);
247 gtk_list_store_set(store, &iter, 0, pb, 1, *lp, -1);
251 gtk_widget_set_sensitive(names, n);
252 gtk_widget_set_sensitive(controls, FALSE);
253 g_slist_free(new_names);
258 names_on_change(void)
263 save_config(block, name, config);
266 gtk_widget_set_sensitive(controls, TRUE);
267 name = combo_active_text(names);
268 config = load_config(block, name, config);
273 valid_address(const char *val, bool allow_cidr)
280 addr = g_strdup(val);
282 p = strchr(addr, '/');
287 cidr = g_ascii_strtoll(p, &e, 10);
288 if (cidr < 0 || cidr > 32 ||
289 errno != 0 || *e != '\0')
296 retval = inet_aton(addr, &in) == 0 ? false : true;
305 address_lost_focus(GtkEntry *entry)
309 val = gtk_entry_get_text(entry);
310 if (*val != '\0' && !valid_address(val, true))
311 gtk_entry_set_text(entry, "");
316 entry_lost_focus(GtkEntry *entry)
321 val = gtk_entry_get_text(entry);
322 a = g_strsplit(val, " ", 0);
323 for (p = a; *p; p++) {
324 if (**p != '\0' && !valid_address(*p, false)) {
325 gtk_entry_set_text(entry, "");
337 free_config(&config);
338 config = g_ptr_array_new();
339 if (save_config(block, name, config)) {
340 set_name_active_icon("document-new");
349 free_config(&config);
354 dhcpcd_prefs_close(void)
357 if (dialog != NULL) {
360 save_config(block, name, config);
362 gtk_widget_destroy(dialog);
368 dhcpcd_prefs_show(void)
370 GtkWidget *dialog_vbox, *hbox, *vbox, *table, *w;
373 GtkCellRenderer *rend;
379 gtk_window_present(GTK_WINDOW(dialog));
383 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
384 g_signal_connect(G_OBJECT(dialog), "destroy", on_destroy, NULL);
386 gtk_window_set_title(GTK_WINDOW(dialog), _("dhcpcd preferences"));
387 gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
388 gtk_window_set_icon_name(GTK_WINDOW(dialog), "config-users");
389 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
390 gtk_window_set_type_hint(GTK_WINDOW(dialog),
391 GDK_WINDOW_TYPE_HINT_DIALOG);
393 dialog_vbox = gtk_vbox_new(FALSE, 10);
394 gtk_container_set_border_width(GTK_CONTAINER(dialog), 10);
395 gtk_container_add(GTK_CONTAINER(dialog), dialog_vbox);
397 hbox = gtk_hbox_new(FALSE, 0);
398 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, FALSE, FALSE, 3);
399 w = gtk_label_new("Configure:");
400 gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 3);
401 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
402 it = gtk_icon_theme_get_default();
404 pb = gtk_icon_theme_load_icon(it, "network-wired",
405 GTK_ICON_SIZE_MENU, 0, &error);
406 gtk_list_store_append(store, &iter);
407 gtk_list_store_set(store, &iter, 0, pb, 1, "interface", -1);
409 pb = gtk_icon_theme_load_icon(it, "network-wireless",
410 GTK_ICON_SIZE_MENU, 0, &error);
411 gtk_list_store_append(store, &iter);
412 gtk_list_store_set(store, &iter, 0, pb, 1, "ssid", -1);
414 blocks = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
415 rend = gtk_cell_renderer_pixbuf_new();
416 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, FALSE);
417 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
419 rend = gtk_cell_renderer_text_new();
420 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, TRUE);
421 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
423 gtk_combo_box_set_active(GTK_COMBO_BOX(blocks), 0);
424 gtk_box_pack_start(GTK_BOX(hbox), blocks, FALSE, FALSE, 3);
425 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
426 names = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
427 rend = gtk_cell_renderer_pixbuf_new();
428 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, FALSE);
429 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names),
431 rend = gtk_cell_renderer_text_new();
432 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, TRUE);
433 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names), rend, "text", 1);
434 gtk_widget_set_sensitive(names, FALSE);
435 gtk_box_pack_start(GTK_BOX(hbox), names, FALSE, FALSE, 3);
436 g_signal_connect(G_OBJECT(blocks), "changed",
437 G_CALLBACK(blocks_on_change), NULL);
438 g_signal_connect(G_OBJECT(names), "changed",
439 G_CALLBACK(names_on_change), NULL);
441 w = gtk_hseparator_new();
442 gtk_box_pack_start(GTK_BOX(dialog_vbox), w, TRUE, FALSE, 3);
443 controls = gtk_vbox_new(FALSE, 10);
444 gtk_box_pack_start(GTK_BOX(dialog_vbox), controls, TRUE, TRUE, 0);
445 vbox = gtk_vbox_new(FALSE, 3);
446 gtk_box_pack_start(GTK_BOX(controls), vbox, FALSE, FALSE, 0);
447 autoconf = gtk_check_button_new_with_label(
448 _("Automatically configure empty options"));
449 gtk_box_pack_start(GTK_BOX(vbox), autoconf, FALSE, FALSE, 3);
450 table = gtk_table_new(6, 2, FALSE);
451 gtk_box_pack_start(GTK_BOX(controls), table, FALSE, FALSE, 0);
453 #define attach_label(a, b, c, d, e) \
455 gtk_misc_set_alignment(GTK_MISC(a), 0.0, 0.5); \
456 gtk_table_attach(GTK_TABLE(table), a, b, c, d, e, \
457 GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 3, 3); \
459 #define attach_entry(a, b, c, d, e) \
460 gtk_table_attach(GTK_TABLE(table), a, b, c, d, e, \
461 GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 3, 3); \
463 w = gtk_label_new(_("IP Address:"));
464 address = gtk_entry_new();
465 gtk_entry_set_max_length(GTK_ENTRY(address), 15);
466 g_signal_connect(G_OBJECT(address), "focus-out-event",
467 G_CALLBACK(address_lost_focus), NULL);
468 attach_label(w, 0, 1, 0, 1);
469 attach_entry(address, 1, 2, 0, 1);
471 w = gtk_label_new(_("Router:"));
472 router = gtk_entry_new();
473 gtk_entry_set_max_length(GTK_ENTRY(router), 12);
474 g_signal_connect(G_OBJECT(router), "focus-out-event",
475 G_CALLBACK(entry_lost_focus), NULL);
476 attach_label(w, 0, 1, 2, 3);
477 attach_entry(router, 1, 2, 2, 3);
479 w = gtk_label_new(_("DNS Servers:"));
480 dns_servers = gtk_entry_new();
481 g_signal_connect(G_OBJECT(dns_servers), "focus-out-event",
482 G_CALLBACK(entry_lost_focus), NULL);
483 attach_label(w, 0, 1, 3, 4);
484 attach_entry(dns_servers, 1, 2, 3, 4);
486 w = gtk_label_new(_("DNS Search:"));
487 dns_search = gtk_entry_new();
488 attach_label(w, 0, 1, 4, 5);
489 attach_entry(dns_search, 1, 2, 4, 5);
491 w = gtk_label_new(_("NTP Servers:"));
492 ntp_servers = gtk_entry_new();
493 g_signal_connect(G_OBJECT(ntp_servers), "focus-out-event",
494 G_CALLBACK(entry_lost_focus), NULL);
495 attach_label(w, 0, 1, 5, 6);
496 attach_entry(ntp_servers, 1, 2, 5, 6);
498 hbox = gtk_hbox_new(FALSE, 0);
499 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, TRUE, TRUE, 3);
500 w = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
501 gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 0);
502 g_signal_connect(G_OBJECT(w), "clicked", on_clear, NULL);
503 w = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
504 gtk_box_pack_end(GTK_BOX(hbox), w, FALSE, FALSE, 0);
505 g_signal_connect(G_OBJECT(w), "clicked",
506 dhcpcd_prefs_close, NULL);
508 blocks_on_change(blocks);
510 gtk_widget_show_all(dialog);