Close down the menu when losing dhcpcd connection in dhcpcd-gtk.
[dhcpcd-ui] / src / dhcpcd-gtk / menu.c
1 /*
2  * dhcpcd-gtk
3  * Copyright 2009-2014 Roy Marples <roy@marples.name>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "dhcpcd-gtk.h"
29
30 static const char *copyright = "Copyright (c) 2009-2014 Roy Marples";
31 static const char *authors[] = { "Roy Marples <roy@marples.name>", NULL };
32
33 static GtkWidget *menu;
34
35 static void
36 on_pref(_unused GObject *o, gpointer data)
37 {
38
39         dhcpcd_prefs_show((DHCPCD_CONNECTION *)data);
40 }
41
42 static void
43 on_quit(void)
44 {
45
46         gtk_main_quit();
47 }
48
49 #if GTK_MAJOR_VERSION == 2
50 static void
51 url_show(GtkAboutDialog *dialog, const char *url)
52 {
53         GdkScreen *screen;
54
55         screen = gtk_widget_get_screen(GTK_WIDGET(dialog));
56         gtk_show_uri(screen, url, GDK_CURRENT_TIME, NULL);
57 }
58
59 static void
60 email_hook(GtkAboutDialog *dialog, const char *url, _unused gpointer data)
61 {
62         char *address;
63
64         address = g_strdup_printf("mailto:%s", url);
65         url_show(dialog, address);
66         g_free(address);
67 }
68
69
70 static void
71 url_hook(GtkAboutDialog *dialog, const char *url, _unused gpointer data)
72 {
73         url_show(dialog, url);
74 }
75 #endif
76
77 static void
78 ssid_hook(GtkMenuItem *item, _unused gpointer data)
79 {
80         DHCPCD_WI_SCAN *scan;
81         WI_SCAN *wi;
82
83         scan = g_object_get_data(G_OBJECT(item), "dhcpcd_wi_scan");
84         wi = wi_scan_find(scan);
85         if (wi) {
86                 DHCPCD_CONNECTION *con;
87
88                 con = dhcpcd_if_connection(wi->interface);
89                 if (con) {
90                         DHCPCD_WPA *wpa;
91
92                         wpa = dhcpcd_wpa_find(con, wi->interface->ifname);
93                         if (wpa)
94                                 wpa_configure(wpa, scan);
95                 }
96         }
97 }
98
99 static void
100 on_about(_unused GtkMenuItem *item)
101 {
102
103         gtk_window_set_default_icon_name("network-transmit-receive");
104 #if GTK_MAJOR_VERSION == 2
105         gtk_about_dialog_set_email_hook(email_hook, NULL, NULL);
106         gtk_about_dialog_set_url_hook(url_hook, NULL, NULL);
107 #endif
108         gtk_show_about_dialog(NULL,
109             "version", VERSION,
110             "copyright", copyright,
111             "website-label", "dhcpcd Website",
112             "website", "http://roy.marples.name/projects/dhcpcd",
113             "authors", authors,
114             "logo-icon-name", "network-transmit-receive",
115             "comments", "Part of the dhcpcd project",
116             NULL);
117 }
118
119 void
120 menu_update_scans(DHCPCD_IF *i, DHCPCD_WI_SCAN *scan)
121 {
122         GList *lst, *l;
123         DHCPCD_WI_SCAN *s, *wis;
124
125         if (menu == NULL)
126                 return;
127         lst = gtk_container_get_children(GTK_CONTAINER(menu));
128         for (s = scan; s; s = s->next) {
129                 for (l = lst; l; l = l->next) {
130                         wis = g_object_get_data(G_OBJECT(l->data), "dhcpcd_wi_scan");
131                         if (wis) {
132                                 if (memcmp(wis->bssid, s->bssid,
133                                     sizeof(s->bssid)) == 0)
134                                 {
135                                         g_object_set_data(G_OBJECT(l->data),
136                                             "dhcpcd_wi_scan", s);
137                                         break;
138                                 }
139                         }
140                 }
141         }
142 }
143
144 static GtkWidget *
145 add_scans(WI_SCAN *scan)
146 {
147         DHCPCD_WI_SCAN *wis;
148         GtkWidget *item, *image, *box, *label, *bar;
149         double perc;
150         const char *icon;
151         char *tip;
152
153         if (scan->scans == NULL)
154                 return NULL;
155         menu = gtk_menu_new();
156         for (wis = scan->scans; wis; wis = wis->next) {
157                 item = gtk_check_menu_item_new();
158                 gtk_check_menu_item_set_draw_as_radio(
159                         GTK_CHECK_MENU_ITEM(item), true); 
160                 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
161                 gtk_container_add(GTK_CONTAINER(item), box); 
162                 label = gtk_label_new(wis->ssid);
163                 gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
164
165                 if (g_strcmp0(wis->ssid, scan->interface->ssid) == 0)
166                         gtk_check_menu_item_set_active(
167                                 GTK_CHECK_MENU_ITEM(item), true);
168                 if (wis->flags[0] == '\0')
169                         icon = "network-wireless";
170                 else
171                         icon = "network-wireless-encrypted";
172                 image = gtk_image_new_from_icon_name(icon,
173                     GTK_ICON_SIZE_MENU);
174                 gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
175
176                 bar = gtk_progress_bar_new();
177                 gtk_widget_set_size_request(bar, 100, -1);
178                 gtk_box_pack_end(GTK_BOX(box), bar, FALSE, TRUE, 0);
179                 perc = wis->strength.value / 100.0;
180                 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar), perc);
181
182                 if (wis->flags[0] == '\0')
183                         gtk_widget_set_tooltip_text(item, wis->bssid);
184                 else {
185                         tip = g_strconcat(wis->bssid, " ", wis->flags, NULL);
186                         gtk_widget_set_tooltip_text(item, tip);
187                         g_free(tip);
188                 }
189
190                 gtk_widget_show(label);
191                 gtk_widget_show(bar);
192                 gtk_widget_show(image);
193                 gtk_widget_show(box);
194                 g_signal_connect(G_OBJECT(item), "activate",
195                     G_CALLBACK(ssid_hook), NULL);
196                 g_object_set_data(G_OBJECT(item), "dhcpcd_wi_scan", wis);
197                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
198         }
199         return menu;
200 }
201
202 void
203 dhcpcd_menu_abort(void)
204 {
205
206         if (menu != NULL) {
207                 gtk_widget_destroy(menu);
208                 menu = NULL;
209         }
210 }
211
212 static void
213 on_activate(GtkStatusIcon *icon)
214 {
215         WI_SCAN *w;
216         GtkWidget *item, *image;
217
218         notify_close();
219         if (wi_scans == NULL)
220                 return;
221         if (wi_scans->next) {
222                 menu = gtk_menu_new();
223                 for (w = wi_scans; w; w = w->next) {
224                         item = gtk_image_menu_item_new_with_label(
225                                 w->interface->ifname);
226                         image = gtk_image_new_from_icon_name(
227                                 "network-wireless", GTK_ICON_SIZE_MENU);
228                         gtk_image_menu_item_set_image(
229                                 GTK_IMAGE_MENU_ITEM(item), image);
230                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
231                         gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
232                             add_scans(w));
233                 }
234         } else
235                 menu = add_scans(wi_scans);
236
237         if (menu) {
238                 gtk_widget_show_all(GTK_WIDGET(menu));
239                 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
240                     gtk_status_icon_position_menu, icon,
241                     1, gtk_get_current_event_time());
242         }
243 }
244
245 static void
246 on_popup(GtkStatusIcon *icon, guint button, guint32 atime, gpointer data)
247 {
248         DHCPCD_CONNECTION *con;
249         GtkMenu *mnu;
250         GtkWidget *item, *image;
251
252         notify_close();
253
254         con = (DHCPCD_CONNECTION *)data;
255         mnu = (GtkMenu *)gtk_menu_new();
256
257         item = gtk_image_menu_item_new_with_mnemonic(_("_Preferences"));
258         image = gtk_image_new_from_icon_name(GTK_STOCK_PREFERENCES,
259             GTK_ICON_SIZE_MENU);
260         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
261         if (g_strcmp0(dhcpcd_status(con), "down") == 0)
262                 gtk_widget_set_sensitive(item, false);
263         else
264                 g_signal_connect(G_OBJECT(item), "activate",
265                     G_CALLBACK(on_pref), data);
266         gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
267
268         item = gtk_separator_menu_item_new();
269         gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
270
271         item = gtk_image_menu_item_new_with_mnemonic(_("_About"));
272         image = gtk_image_new_from_icon_name(GTK_STOCK_ABOUT,
273             GTK_ICON_SIZE_MENU);
274         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
275         g_signal_connect(G_OBJECT(item), "activate",
276             G_CALLBACK(on_about), icon);
277         gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
278
279         item = gtk_image_menu_item_new_with_mnemonic(_("_Quit"));
280         image = gtk_image_new_from_icon_name(GTK_STOCK_QUIT,
281             GTK_ICON_SIZE_MENU);
282         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
283         g_signal_connect(G_OBJECT(item), "activate",
284             G_CALLBACK(on_quit), icon);
285         gtk_menu_shell_append(GTK_MENU_SHELL(mnu), item);
286
287         gtk_widget_show_all(GTK_WIDGET(mnu));
288         gtk_menu_popup(GTK_MENU(mnu), NULL, NULL,
289             gtk_status_icon_position_menu, icon, button, atime);
290         if (button == 0)
291                 gtk_menu_shell_select_first(GTK_MENU_SHELL(mnu), FALSE);
292 }
293
294 void
295 menu_init(GtkStatusIcon *icon, DHCPCD_CONNECTION *con)
296 {
297
298         g_signal_connect(G_OBJECT(icon), "activate",
299             G_CALLBACK(on_activate), con);
300         g_signal_connect(G_OBJECT(icon), "popup_menu",
301             G_CALLBACK(on_popup), con);
302 }
303
304
305 #if GTK_MAJOR_VERSION == 2
306 GtkWidget *
307 gtk_box_new(GtkOrientation o, gint s)
308 {
309
310         if (o == GTK_ORIENTATION_HORIZONTAL)
311                 return gtk_hbox_new(false, s);
312         else
313                 return gtk_vbox_new(false, s);
314 }
315 #endif