3 * Copyright 2009-2014 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
28 #include "dhcpcd-gtk.h"
30 static const char *copyright = "Copyright (c) 2009-2014 Roy Marples";
31 static const char *authors[] = { "Roy Marples <roy@marples.name>", NULL };
33 static GtkStatusIcon *sicon;
34 static GtkWidget *menu;
37 typedef struct wi_menu {
46 static GList *wi_menus;
49 on_pref(_unused GObject *o, gpointer data)
52 dhcpcd_prefs_show((DHCPCD_CONNECTION *)data);
62 #if GTK_MAJOR_VERSION == 2
64 url_show(GtkAboutDialog *dialog, const char *url)
68 screen = gtk_widget_get_screen(GTK_WIDGET(dialog));
69 gtk_show_uri(screen, url, GDK_CURRENT_TIME, NULL);
73 email_hook(GtkAboutDialog *dialog, const char *url, _unused gpointer data)
77 address = g_strdup_printf("mailto:%s", url);
78 url_show(dialog, address);
84 url_hook(GtkAboutDialog *dialog, const char *url, _unused gpointer data)
86 url_show(dialog, url);
91 ssid_hook(GtkMenuItem *item, _unused gpointer data)
96 scan = g_object_get_data(G_OBJECT(item), "dhcpcd_wi_scan");
97 wi = wi_scan_find(scan);
99 DHCPCD_CONNECTION *con;
101 con = dhcpcd_if_connection(wi->interface);
105 wpa = dhcpcd_wpa_find(con, wi->interface->ifname);
107 wpa_configure(wpa, scan);
113 on_about(_unused GtkMenuItem *item)
116 gtk_window_set_default_icon_name("network-transmit-receive");
117 #if GTK_MAJOR_VERSION == 2
118 gtk_about_dialog_set_email_hook(email_hook, NULL, NULL);
119 gtk_about_dialog_set_url_hook(url_hook, NULL, NULL);
121 gtk_show_about_dialog(NULL,
123 "copyright", copyright,
124 "website-label", "dhcpcd Website",
125 "website", "http://roy.marples.name/projects/dhcpcd",
127 "logo-icon-name", "network-transmit-receive",
128 "comments", "Part of the dhcpcd project",
133 update_item(WI_MENU *m, DHCPCD_WI_SCAN *scan)
138 gtk_label_set_text(GTK_LABEL(m->ssid), scan->ssid);
139 if (scan->flags[0] == '\0')
140 icon = "network-wireless";
142 icon = "network-wireless-encrypted";
143 m->icon = gtk_image_new_from_icon_name(icon,
146 perc = scan->strength.value / 100.0;
147 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(m->bar), perc);
149 if (scan->flags[0] == '\0')
150 gtk_widget_set_tooltip_text(m->menu, scan->bssid);
152 char *tip = g_strconcat(scan->bssid, " ", scan->flags, NULL);
153 gtk_widget_set_tooltip_text(m->menu, tip);
157 g_object_set_data(G_OBJECT(m->menu), "dhcpcd_wi_scan", scan);
161 create_menu(GtkWidget *m, WI_SCAN *scan, DHCPCD_WI_SCAN *wis)
169 wim = g_malloc(sizeof(*wim));
170 wim->interface = scan->interface;
172 wim->menu = gtk_check_menu_item_new();
173 gtk_check_menu_item_set_draw_as_radio(
174 GTK_CHECK_MENU_ITEM(wim->menu), true);
175 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
176 gtk_container_add(GTK_CONTAINER(wim->menu), box);
177 wim->ssid = gtk_label_new(wis->ssid);
178 gtk_box_pack_start(GTK_BOX(box), wim->ssid, TRUE, TRUE, 0);
180 if (g_strcmp0(wis->ssid, scan->interface->ssid) == 0)
181 gtk_check_menu_item_set_active(
182 GTK_CHECK_MENU_ITEM(wim->menu), true);
183 if (wis->flags[0] == '\0')
184 icon = "network-wireless";
186 icon = "network-wireless-encrypted";
187 wim->icon = gtk_image_new_from_icon_name(icon,
189 gtk_box_pack_start(GTK_BOX(box), wim->icon, FALSE, FALSE, 0);
191 wim->bar = gtk_progress_bar_new();
192 gtk_widget_set_size_request(wim->bar, 100, -1);
193 gtk_box_pack_end(GTK_BOX(box), wim->bar, FALSE, TRUE, 0);
194 perc = wis->strength.value / 100.0;
195 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(wim->bar), perc);
197 if (wis->flags[0] == '\0')
198 gtk_widget_set_tooltip_text(wim->menu, wis->bssid);
200 tip = g_strconcat(wis->bssid, " ", wis->flags, NULL);
201 gtk_widget_set_tooltip_text(wim->menu, tip);
205 g_signal_connect(G_OBJECT(wim->menu), "activate",
206 G_CALLBACK(ssid_hook), NULL);
207 g_object_set_data(G_OBJECT(wim->menu), "dhcpcd_wi_scan", wis);
208 gtk_menu_shell_append(GTK_MENU_SHELL(m), wim->menu);
214 menu_update_scans(WI_SCAN *wi, DHCPCD_WI_SCAN *scans)
224 wim = (WI_MENU *)item->data;
225 if (wim->interface != wi->interface)
228 for (s = scans; s; s = s->next) {
229 if (memcmp(wim->scan->bssid, s->bssid,
230 sizeof(s->bssid)) == 0)
237 g_message("removed %s", wim->scan->ssid);
238 gtk_widget_destroy(wim->menu);
240 wi_menus = g_list_delete_link(wi_menus, item);
247 for (s = scans; s; s = s->next) {
249 for (item = wi_menus; item; item = item->next) {
250 wim = (WI_MENU *)item->data;
251 if (memcmp(wim->scan->bssid, s->bssid,
252 sizeof(s->bssid)) == 0)
260 wim = create_menu(wi->menu, wi, s);
261 gtk_widget_show_all(wim->menu);
262 g_message("added %s", wim->scan->ssid);
263 wi_menus = g_list_append(wi_menus, wim);
267 gtk_widget_hide(wi->menu);
268 gtk_menu_popup(GTK_MENU(wi->menu), NULL, NULL,
269 gtk_status_icon_position_menu, sicon,
270 1, gtk_get_current_event_time());
271 gtk_widget_show(wi->menu);
277 add_scans(WI_SCAN *scan)
283 if (scan->scans == NULL)
287 for (wis = scan->scans; wis; wis = wis->next) {
288 wim = create_menu(m, scan, wis);
289 wi_menus = g_list_append(wi_menus, wim);
295 dhcpcd_menu_abort(void)
299 g_free(wi_menus->data);
300 wi_menus = g_list_delete_link(wi_menus, wi_menus);
304 gtk_widget_destroy(menu);
305 g_object_ref_sink(menu);
306 g_object_unref(menu);
312 on_activate(GtkStatusIcon *icon)
315 GtkWidget *item, *image;
320 if (wi_scans == NULL)
322 if (wi_scans->next) {
323 menu = gtk_menu_new();
325 for (w = wi_scans; w; w = w->next) {
326 item = gtk_image_menu_item_new_with_label(
327 w->interface->ifname);
328 image = gtk_image_new_from_icon_name(
329 "network-wireless", GTK_ICON_SIZE_MENU);
330 gtk_image_menu_item_set_image(
331 GTK_IMAGE_MENU_ITEM(item), image);
332 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
333 w->menu = add_scans(w);
334 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
337 } else if (wi_scans->scans) {
339 wi_scans->menu = menu = add_scans(wi_scans);
344 gtk_widget_show_all(GTK_WIDGET(menu));
345 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
346 gtk_status_icon_position_menu, icon,
347 1, gtk_get_current_event_time());
352 on_popup(GtkStatusIcon *icon, guint button, guint32 atime, gpointer data)
354 DHCPCD_CONNECTION *con;
356 GtkWidget *item, *image;
360 con = (DHCPCD_CONNECTION *)data;
361 mnu = (GtkMenu *)gtk_menu_new();
363 item = gtk_image_menu_item_new_with_mnemonic(_("_Preferences"));
364 image = gtk_image_new_from_icon_name(GTK_STOCK_PREFERENCES,
366 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
367 if (g_strcmp0(dhcpcd_status(con), "down") == 0)
368 gtk_widget_set_sensitive(item, false);
370 g_signal_connect(G_OBJECT(item), "activate",
371 G_CALLBACK(on_pref), data);
372 gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
374 item = gtk_separator_menu_item_new();
375 gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
377 item = gtk_image_menu_item_new_with_mnemonic(_("_About"));
378 image = gtk_image_new_from_icon_name(GTK_STOCK_ABOUT,
380 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
381 g_signal_connect(G_OBJECT(item), "activate",
382 G_CALLBACK(on_about), icon);
383 gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
385 item = gtk_image_menu_item_new_with_mnemonic(_("_Quit"));
386 image = gtk_image_new_from_icon_name(GTK_STOCK_QUIT,
388 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
389 g_signal_connect(G_OBJECT(item), "activate",
390 G_CALLBACK(on_quit), icon);
391 gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
393 gtk_widget_show_all(GTK_WIDGET(mnu));
394 gtk_menu_popup(GTK_MENU(mnu), NULL, NULL,
395 gtk_status_icon_position_menu, icon, button, atime);
397 gtk_menu_shell_select_first(GTK_MENU_SHELL(mnu), FALSE);
401 menu_init(GtkStatusIcon *icon, DHCPCD_CONNECTION *con)
404 g_signal_connect(G_OBJECT(icon), "activate",
405 G_CALLBACK(on_activate), con);
406 g_signal_connect(G_OBJECT(icon), "popup_menu",
407 G_CALLBACK(on_popup), con);
411 #if GTK_MAJOR_VERSION == 2
413 gtk_box_new(GtkOrientation o, gint s)
416 if (o == GTK_ORIENTATION_HORIZONTAL)
417 return gtk_hbox_new(false, s);
419 return gtk_vbox_new(false, s);