3 * Copyright 2009-2012 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 <sys/types.h>
32 #include "dhcpcd-gtk.h"
34 static GtkWidget *dialog, *blocks, *names, *controls, *clear, *rebind;
35 static GtkWidget *autoconf, *address, *router, *dns_servers, *dns_search;
36 static DHCPCD_CONFIG *config;
37 static char *block, *name;
38 static DHCPCD_IF *iface;
41 show_config(DHCPCD_CONFIG *conf)
46 if ((val = dhcpcd_config_get_static(conf, "ip_address=")) != NULL)
49 if ((val = dhcpcd_config_get(conf, "inform")) == NULL &&
50 (iface && iface->flags & IFF_POINTOPOINT))
55 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autoconf), autocnf);
56 gtk_entry_set_text(GTK_ENTRY(address), val ? val : "");
57 val = dhcpcd_config_get_static(conf, "routers=");
58 gtk_entry_set_text(GTK_ENTRY(router), val ? val : "");
59 val = dhcpcd_config_get_static(conf, "domain_name_servers=");
60 gtk_entry_set_text(GTK_ENTRY(dns_servers), val ? val : "");
61 val = dhcpcd_config_get_static(conf, "domain_search=");
62 gtk_entry_set_text(GTK_ENTRY(dns_search), val ? val : "");
66 combo_active_text(GtkWidget *widget)
73 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(widget)));
74 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter))
76 memset(&val, 0, sizeof(val));
77 gtk_tree_model_get_value(GTK_TREE_MODEL(store), &iter, 1, &val);
78 text = g_strdup(g_value_get_string(&val));
84 set_option(DHCPCD_CONFIG **conf, bool s, const char *opt, const char *val,
90 r = dhcpcd_config_set_static(conf, opt, val);
92 r = dhcpcd_config_set(conf, opt, val);
95 g_error("libdhcpcd: %s", strerror(errno));
102 make_config(DHCPCD_CONFIG **conf)
104 const char *val, ns[] = "";
108 a = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(autoconf));
109 if (iface && iface->flags & IFF_POINTOPOINT)
110 set_option(conf, true, "ip_address=", a ? NULL : ns, &ret);
112 val = gtk_entry_get_text(GTK_ENTRY(address));
115 set_option(conf, false, "inform", a ? val : NULL, &ret);
116 set_option(conf, true, "ip_address=", a ? NULL : val, &ret);
119 val = gtk_entry_get_text(GTK_ENTRY(router));
120 if (a && *val == '\0')
122 set_option(conf, true, "routers=", val, &ret);
124 val = gtk_entry_get_text(GTK_ENTRY(dns_servers));
125 if (a && *val == '\0')
127 set_option(conf, true, "domain_name_servers=", val, &ret);
129 val = gtk_entry_get_text(GTK_ENTRY(dns_search));
130 if (a && *val == '\0')
132 set_option(conf, true, "domain_search=", val, &ret);
138 load_icon(const char *iname)
142 if (!gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height))
144 return gtk_icon_theme_load_icon(gtk_icon_theme_get_default(),
145 iname, MIN(width, height), 0, NULL);
149 set_name_active_icon(const char *iname)
156 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
157 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(names), &iter))
159 pb = load_icon(iname);
161 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
162 gtk_list_store_set(store, &iter, 0, pb, -1);
164 gtk_tree_model_row_changed(GTK_TREE_MODEL(store), path, &iter);
165 gtk_tree_path_free(path);
170 list_interfaces(DHCPCD_CONNECTION *con)
176 for (i = dhcpcd_interfaces(con); i; i = i->next)
177 if (strcmp(i->type, "ipv4") == 0)
178 list = g_slist_append(list, i->ifname);
183 list_ssids(WI_SCAN *scans)
190 for (w = scans; w; w = w->next) {
191 for (wis = w->scans; wis; wis = wis->next) {
192 for (l = list; l; l = l->next)
193 if (g_strcmp0((const char *)l->data,
197 list = g_slist_append(list, wis->ssid);
204 blocks_on_change(GtkWidget *widget, gpointer data)
206 DHCPCD_CONNECTION *con;
210 const char *iname, *nn;
211 GSList *l, *new_names;
216 con = (DHCPCD_CONNECTION *)data;
218 if (make_config(&config))
219 dhcpcd_config_save(con, block, name, config);
220 dhcpcd_config_free(config);
227 block = combo_active_text(widget);
228 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
229 gtk_list_store_clear(store);
230 list = dhcpcd_config_blocks_get(con, block);
232 it = gtk_icon_theme_get_default();
233 if (g_strcmp0(block, "interface") == 0)
234 new_names = list_interfaces(con);
236 new_names = list_ssids(wi_scans);
239 for (l = new_names; l; l = l->next) {
240 nn = (const char *)l->data;
241 for (lp = list; *lp; lp++)
242 if (g_strcmp0(nn, *lp) == 0)
245 iname = "document-save";
247 iname = "document-new";
248 pb = load_icon(iname);
249 gtk_list_store_append(store, &iter);
250 gtk_list_store_set(store, &iter, 0, pb, 1, nn, -1);
255 for (lp = list; *lp; lp++) {
256 for (l = new_names; l; l = l->next)
257 if (g_strcmp0((const char *)l->data, *lp) == 0)
261 pb = load_icon("document-save");
262 gtk_list_store_append(store, &iter);
263 gtk_list_store_set(store, &iter, 0, pb, 1, *lp, -1);
267 gtk_widget_set_sensitive(names, n);
268 g_slist_free(new_names);
273 names_on_change(_unused GtkWidget *widget, gpointer data)
275 DHCPCD_CONNECTION *con;
278 con = (DHCPCD_CONNECTION *)data;
280 if (make_config(&config))
281 dhcpcd_config_save(con, block, name, config);
284 name = combo_active_text(names);
285 dhcpcd_config_free(config);
287 if (g_strcmp0(block, "interface") == 0) {
288 for (i = dhcpcd_interfaces(con); i; i = i->next)
289 if (g_strcmp0(name, i->ifname) == 0) {
294 gtk_widget_set_sensitive(address,
295 iface && (iface->flags & IFF_POINTOPOINT) == 0);
297 config = dhcpcd_config_load(con, block, name);
298 if (config == NULL && dhcpcd_error(con))
299 g_error("libdhcpcd: %s", dhcpcd_error(con));
303 gtk_widget_set_sensitive(controls, name ? true : false);
304 gtk_widget_set_sensitive(clear, name ? true : false);
305 gtk_widget_set_sensitive(rebind, name ? true : false);
309 valid_address(const char *val, bool allow_cidr)
316 addr = g_strdup(val);
318 p = strchr(addr, '/');
323 cidr = g_ascii_strtoll(p, &e, 10);
324 if (cidr < 0 || cidr > 32 ||
325 errno != 0 || *e != '\0')
332 retval = inet_aton(addr, &in) == 0 ? false : true;
341 address_lost_focus(GtkEntry *entry)
345 val = gtk_entry_get_text(entry);
346 if (*val != '\0' && !valid_address(val, true))
347 gtk_entry_set_text(entry, "");
352 entry_lost_focus(GtkEntry *entry)
357 val = gtk_entry_get_text(entry);
358 a = g_strsplit(val, " ", 0);
359 for (p = a; *p; p++) {
360 if (**p != '\0' && !valid_address(*p, false)) {
361 gtk_entry_set_text(entry, "");
370 on_clear(_unused GtkObject *o, gpointer data)
372 DHCPCD_CONNECTION *con;
374 con = (DHCPCD_CONNECTION *)data;
375 dhcpcd_config_free(config);
377 if (dhcpcd_config_save(con, block, name, config)) {
378 set_name_active_icon("document-new");
384 on_rebind(_unused GtkWidget *widget, gpointer data)
386 DHCPCD_CONNECTION *con;
389 con = (DHCPCD_CONNECTION *)data;
390 if (make_config(&config) &&
391 dhcpcd_config_save(con, block, name, config)) {
392 set_name_active_icon(config == NULL ?
393 "document-new" : "document-save");
395 if (g_strcmp0(block, "interface") == 0)
396 dhcpcd_rebind(con, iface);
398 for (i = dhcpcd_interfaces(con); i; i = i->next) {
399 if (g_strcmp0(i->ssid, name) == 0)
400 dhcpcd_rebind(con, i);
403 if (dhcpcd_error(con))
404 g_warning("libdhcpcd: %s", dhcpcd_error(con));
409 on_destroy(_unused GtkObject *o, gpointer data)
412 if (make_config(&config))
413 dhcpcd_config_save((DHCPCD_CONNECTION *)data,
414 block, name, config);
419 dhcpcd_config_free(config);
425 dhcpcd_prefs_close(void)
427 if (dialog != NULL) {
428 gtk_widget_destroy(dialog);
434 dhcpcd_prefs_abort(void)
438 dhcpcd_prefs_close();
442 dhcpcd_prefs_show(DHCPCD_CONNECTION *con)
444 GtkWidget *dialog_vbox, *hbox, *vbox, *table, *w;
447 GtkCellRenderer *rend;
451 gtk_window_present(GTK_WINDOW(dialog));
455 if (g_strcmp0(dhcpcd_status(con), "down") == 0)
458 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
459 g_signal_connect(G_OBJECT(dialog), "destroy",
460 G_CALLBACK(on_destroy), con);
462 gtk_window_set_title(GTK_WINDOW(dialog), _("Network Preferences"));
463 gtk_window_set_resizable(GTK_WINDOW(dialog), false);
464 gtk_window_set_icon_name(GTK_WINDOW(dialog),
465 "network-transmit-receive");
466 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
467 gtk_window_set_type_hint(GTK_WINDOW(dialog),
468 GDK_WINDOW_TYPE_HINT_DIALOG);
470 dialog_vbox = gtk_vbox_new(false, 10);
471 gtk_container_set_border_width(GTK_CONTAINER(dialog), 10);
472 gtk_container_add(GTK_CONTAINER(dialog), dialog_vbox);
474 hbox = gtk_hbox_new(false, 0);
475 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, false, false, 3);
476 w = gtk_label_new("Configure:");
477 gtk_box_pack_start(GTK_BOX(hbox), w, false, false, 3);
478 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
479 pb = load_icon("network-wired");
480 gtk_list_store_append(store, &iter);
481 gtk_list_store_set(store, &iter, 0, pb, 1, "interface", -1);
483 pb = load_icon("network-wireless");
484 gtk_list_store_append(store, &iter);
485 gtk_list_store_set(store, &iter, 0, pb, 1, "ssid", -1);
487 blocks = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
488 rend = gtk_cell_renderer_pixbuf_new();
489 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, false);
490 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
492 rend = gtk_cell_renderer_text_new();
493 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(blocks), rend, true);
494 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(blocks),
496 gtk_combo_box_set_active(GTK_COMBO_BOX(blocks), 0);
497 gtk_box_pack_start(GTK_BOX(hbox), blocks, false, false, 3);
498 store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
499 names = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
500 rend = gtk_cell_renderer_pixbuf_new();
501 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, false);
502 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names),
504 rend = gtk_cell_renderer_text_new();
505 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(names), rend, true);
506 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names), rend, "text", 1);
507 gtk_widget_set_sensitive(names, false);
508 gtk_box_pack_start(GTK_BOX(hbox), names, false, false, 3);
509 g_signal_connect(G_OBJECT(blocks), "changed",
510 G_CALLBACK(blocks_on_change), con);
511 g_signal_connect(G_OBJECT(names), "changed",
512 G_CALLBACK(names_on_change), con);
514 w = gtk_hseparator_new();
515 gtk_box_pack_start(GTK_BOX(dialog_vbox), w, true, false, 3);
516 controls = gtk_vbox_new(false, 10);
517 gtk_widget_set_sensitive(controls, false);
518 gtk_box_pack_start(GTK_BOX(dialog_vbox), controls, true, true, 0);
519 vbox = gtk_vbox_new(false, 3);
520 gtk_box_pack_start(GTK_BOX(controls), vbox, false, false, 0);
521 autoconf = gtk_check_button_new_with_label(
522 _("Automatically configure empty options"));
523 gtk_box_pack_start(GTK_BOX(vbox), autoconf, false, false, 3);
524 table = gtk_table_new(6, 2, false);
525 gtk_box_pack_start(GTK_BOX(controls), table, false, false, 0);
527 #define attach_label(a, b, c, d, e) \
529 gtk_misc_set_alignment(GTK_MISC(a), 0.0, 0.5); \
530 gtk_table_attach(GTK_TABLE(table), a, b, c, d, e, \
531 GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 3, 3); \
533 #define attach_entry(a, b, c, d, e) \
534 gtk_table_attach(GTK_TABLE(table), a, b, c, d, e, \
535 GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 3, 3);
537 w = gtk_label_new(_("IP Address:"));
538 address = gtk_entry_new();
539 gtk_entry_set_max_length(GTK_ENTRY(address), 18);
540 g_signal_connect(G_OBJECT(address), "focus-out-event",
541 G_CALLBACK(address_lost_focus), NULL);
542 attach_label(w, 0, 1, 0, 1);
543 attach_entry(address, 1, 2, 0, 1);
545 w = gtk_label_new(_("Router:"));
546 router = gtk_entry_new();
547 gtk_entry_set_max_length(GTK_ENTRY(router), 15);
548 g_signal_connect(G_OBJECT(router), "focus-out-event",
549 G_CALLBACK(entry_lost_focus), NULL);
550 attach_label(w, 0, 1, 2, 3);
551 attach_entry(router, 1, 2, 2, 3);
553 w = gtk_label_new(_("DNS Servers:"));
554 dns_servers = gtk_entry_new();
555 g_signal_connect(G_OBJECT(dns_servers), "focus-out-event",
556 G_CALLBACK(entry_lost_focus), NULL);
557 attach_label(w, 0, 1, 3, 4);
558 attach_entry(dns_servers, 1, 2, 3, 4);
560 w = gtk_label_new(_("DNS Search:"));
561 dns_search = gtk_entry_new();
562 attach_label(w, 0, 1, 4, 5);
563 attach_entry(dns_search, 1, 2, 4, 5);
565 hbox = gtk_hbox_new(false, 10);
566 gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, true, true, 3);
567 clear = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
568 gtk_widget_set_sensitive(clear, false);
569 gtk_box_pack_start(GTK_BOX(hbox), clear, false, false, 0);
570 g_signal_connect(G_OBJECT(clear), "clicked",
571 G_CALLBACK(on_clear), con);
572 rebind = gtk_button_new_with_mnemonic(_("_Rebind"));
573 gtk_widget_set_sensitive(rebind, false);
574 w = gtk_image_new_from_stock(GTK_STOCK_EXECUTE,
575 GTK_ICON_SIZE_BUTTON);
576 gtk_button_set_image(GTK_BUTTON(rebind), w);
577 gtk_box_pack_start(GTK_BOX(hbox), rebind, false, false, 0);
578 g_signal_connect(G_OBJECT(rebind), "clicked",
579 G_CALLBACK(on_rebind), con);
580 w = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
581 gtk_box_pack_end(GTK_BOX(hbox), w, false, false, 0);
582 g_signal_connect(G_OBJECT(w), "clicked",
583 G_CALLBACK(dhcpcd_prefs_close), NULL);
585 blocks_on_change(blocks, con);
587 gtk_widget_show_all(dialog);