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