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;
38 on_pref(_unused GObject *o, gpointer data)
41 prefs_show((DHCPCD_CONNECTION *)data);
52 #if GTK_MAJOR_VERSION == 2
54 url_show(GtkAboutDialog *dialog, const char *url)
58 screen = gtk_widget_get_screen(GTK_WIDGET(dialog));
59 gtk_show_uri(screen, url, GDK_CURRENT_TIME, NULL);
63 email_hook(GtkAboutDialog *dialog, const char *url, _unused gpointer data)
67 address = g_strdup_printf("mailto:%s", url);
68 url_show(dialog, address);
74 url_hook(GtkAboutDialog *dialog, const char *url, _unused gpointer data)
76 url_show(dialog, url);
81 ssid_hook(GtkMenuItem *item, _unused gpointer data)
86 scan = g_object_get_data(G_OBJECT(item), "dhcpcd_wi_scan");
87 wi = wi_scan_find(scan);
89 DHCPCD_CONNECTION *con;
91 con = dhcpcd_if_connection(wi->interface);
95 wpa = dhcpcd_wpa_find(con, wi->interface->ifname);
97 wpa_configure(wpa, scan);
103 on_about(_unused GtkMenuItem *item)
106 gtk_window_set_default_icon_name("network-transmit-receive");
107 #if GTK_MAJOR_VERSION == 2
108 gtk_about_dialog_set_email_hook(email_hook, NULL, NULL);
109 gtk_about_dialog_set_url_hook(url_hook, NULL, NULL);
111 gtk_show_about_dialog(NULL,
113 "copyright", copyright,
114 "website-label", "dhcpcd Website",
115 "website", "http://roy.marples.name/projects/dhcpcd",
117 "logo-icon-name", "network-transmit-receive",
118 "comments", "Part of the dhcpcd project",
123 update_item(WI_SCAN *wi, WI_MENU *m, DHCPCD_WI_SCAN *scan)
130 g_object_set_data(G_OBJECT(m->menu), "dhcpcd_wi_scan", scan);
131 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(m->menu),
132 (wi->interface->up &&
133 g_strcmp0(wi->interface->ssid, scan->ssid)));
135 gtk_label_set_text(GTK_LABEL(m->ssid), scan->ssid);
136 if (scan->flags[0] == '\0')
137 icon = "network-wireless";
139 icon = "network-wireless-encrypted";
140 m->icon = gtk_image_new_from_icon_name(icon,
143 perc = scan->strength.value / 100.0;
144 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(m->bar), perc);
146 if (scan->flags[0] == '\0')
147 gtk_widget_set_tooltip_text(m->menu, scan->bssid);
149 char *tip = g_strconcat(scan->bssid, " ", scan->flags, NULL);
150 gtk_widget_set_tooltip_text(m->menu, tip);
154 g_object_set_data(G_OBJECT(m->menu), "dhcpcd_wi_scan", scan);
158 create_menu(GtkWidget *m, WI_SCAN *wis, DHCPCD_WI_SCAN *scan)
166 wim = g_malloc(sizeof(*wim));
168 wim->menu = gtk_check_menu_item_new();
169 gtk_check_menu_item_set_draw_as_radio(
170 GTK_CHECK_MENU_ITEM(wim->menu), true);
171 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
172 gtk_container_add(GTK_CONTAINER(wim->menu), box);
173 wim->ssid = gtk_label_new(scan->ssid);
174 gtk_box_pack_start(GTK_BOX(box), wim->ssid, TRUE, TRUE, 0);
176 if (wis->interface->up &&
177 g_strcmp0(scan->ssid, wis->interface->ssid) == 0)
178 gtk_check_menu_item_set_active(
179 GTK_CHECK_MENU_ITEM(wim->menu), true);
180 if (scan->flags[0] == '\0')
181 icon = "network-wireless";
183 icon = "network-wireless-encrypted";
184 wim->icon = gtk_image_new_from_icon_name(icon,
186 gtk_box_pack_start(GTK_BOX(box), wim->icon, FALSE, FALSE, 0);
188 wim->bar = gtk_progress_bar_new();
189 gtk_widget_set_size_request(wim->bar, 100, -1);
190 gtk_box_pack_end(GTK_BOX(box), wim->bar, FALSE, TRUE, 0);
191 perc = scan->strength.value / 100.0;
192 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(wim->bar), perc);
194 if (scan->flags[0] == '\0')
195 gtk_widget_set_tooltip_text(wim->menu, scan->bssid);
197 tip = g_strconcat(scan->bssid, " ", scan->flags, NULL);
198 gtk_widget_set_tooltip_text(wim->menu, tip);
202 g_signal_connect(G_OBJECT(wim->menu), "toggled",
203 G_CALLBACK(ssid_hook), NULL);
204 g_object_set_data(G_OBJECT(wim->menu), "dhcpcd_wi_scan", scan);
205 gtk_menu_shell_append(GTK_MENU_SHELL(m), wim->menu);
211 menu_update_scans(WI_SCAN *wi, DHCPCD_WI_SCAN *scans)
218 dhcpcd_wi_scans_free(wi->scans);
223 TAILQ_FOREACH_SAFE(wim, &wi->menus, next, win) {
225 for (s = scans; s; s = s->next) {
226 if (memcmp(wim->scan->bssid, s->bssid,
227 sizeof(s->bssid)) == 0)
230 update_item(wi, wim, s);
234 TAILQ_REMOVE(&wi->menus, wim, next);
235 g_message("removed %s", wim->scan->ssid);
236 gtk_widget_destroy(wim->menu);
243 for (s = scans; s; s = s->next) {
245 TAILQ_FOREACH(wim, &wi->menus, next) {
246 if (memcmp(wim->scan->bssid, s->bssid,
247 sizeof(s->bssid)) == 0)
255 wim = create_menu(wi->ifmenu, wi, s);
256 TAILQ_INSERT_TAIL(&wi->menus, wim, next);
257 gtk_widget_show_all(wim->menu);
258 g_message("added %s", wim->scan->ssid);
262 dhcpcd_wi_scans_free(wi->scans);
265 if (added && gtk_widget_get_visible(wi->ifmenu)) {
266 // gtk_widget_hide(wi->ifmenu);
267 // gtk_menu_popup(GTK_MENU(wi->ifmenu), NULL, NULL,
268 // gtk_status_icon_position_menu, sicon,
269 // 1, gtk_get_current_event_time());
270 // gtk_widget_show(wi->ifmenu);
276 add_scans(WI_SCAN *wi)
282 if (wi->scans == NULL)
286 for (wis = wi->scans; wis; wis = wis->next) {
287 wim = create_menu(m, wi, wis);
288 TAILQ_INSERT_TAIL(&wi->menus, wim, next);
300 TAILQ_FOREACH(wis, &wi_scans, next) {
302 while ((wim = TAILQ_FIRST(&wis->menus))) {
303 TAILQ_REMOVE(&wis->menus, wim, next);
309 gtk_widget_destroy(menu);
310 g_object_ref_sink(menu);
311 g_object_unref(menu);
317 on_activate(GtkStatusIcon *icon)
320 GtkWidget *item, *image;
327 if ((w = TAILQ_FIRST(&wi_scans)) == NULL)
330 if ((l = TAILQ_LAST(&wi_scans, wi_scan_head)) && l != w) {
331 menu = gtk_menu_new();
333 TAILQ_FOREACH(w, &wi_scans, next) {
334 item = gtk_image_menu_item_new_with_label(
335 w->interface->ifname);
336 image = gtk_image_new_from_icon_name(
337 "network-wireless", GTK_ICON_SIZE_MENU);
338 gtk_image_menu_item_set_image(
339 GTK_IMAGE_MENU_ITEM(item), image);
340 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
341 w->ifmenu = add_scans(w);
342 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
347 w->ifmenu = menu = add_scans(w);
350 gtk_widget_show_all(GTK_WIDGET(menu));
351 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
352 gtk_status_icon_position_menu, icon,
353 1, gtk_get_current_event_time());
357 on_popup(GtkStatusIcon *icon, guint button, guint32 atime, gpointer data)
359 DHCPCD_CONNECTION *con;
361 GtkWidget *item, *image;
365 con = (DHCPCD_CONNECTION *)data;
366 mnu = (GtkMenu *)gtk_menu_new();
368 item = gtk_image_menu_item_new_with_mnemonic(_("_Preferences"));
369 image = gtk_image_new_from_icon_name("preferences-system-network",
371 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
372 if (g_strcmp0(dhcpcd_status(con), "down") == 0)
373 gtk_widget_set_sensitive(item, false);
375 g_signal_connect(G_OBJECT(item), "activate",
376 G_CALLBACK(on_pref), data);
377 gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
379 item = gtk_separator_menu_item_new();
380 gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
382 item = gtk_image_menu_item_new_with_mnemonic(_("_About"));
383 image = gtk_image_new_from_icon_name("help-about",
385 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
386 g_signal_connect(G_OBJECT(item), "activate",
387 G_CALLBACK(on_about), icon);
388 gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
390 item = gtk_image_menu_item_new_with_mnemonic(_("_Quit"));
391 image = gtk_image_new_from_icon_name("application-exit",
393 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
394 g_signal_connect(G_OBJECT(item), "activate",
395 G_CALLBACK(on_quit), icon);
396 gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
398 gtk_widget_show_all(GTK_WIDGET(mnu));
399 gtk_menu_popup(GTK_MENU(mnu), NULL, NULL,
400 gtk_status_icon_position_menu, icon, button, atime);
402 gtk_menu_shell_select_first(GTK_MENU_SHELL(mnu), FALSE);
406 menu_init(GtkStatusIcon *icon, DHCPCD_CONNECTION *con)
409 g_signal_connect(G_OBJECT(icon), "activate",
410 G_CALLBACK(on_activate), con);
411 g_signal_connect(G_OBJECT(icon), "popup_menu",
412 G_CALLBACK(on_popup), con);
416 #if GTK_MAJOR_VERSION == 2
418 gtk_box_new(GtkOrientation o, gint s)
421 if (o == GTK_ORIENTATION_HORIZONTAL)
422 return gtk_hbox_new(false, s);
424 return gtk_vbox_new(false, s);