Add the humble beginnings for a preferences dialog.
[dhcpcd-ui] / menu.c
1 /*
2  * dhcpcd-gtk
3  * Copyright 2009 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 "dhcpcd-gtk.h"
28 #include "menu.h"
29 #include "prefs.h"
30 #include "wpa.h"
31
32 static const char *copyright = "Copyright (c) 2009 Roy Marples";
33
34 static const char *authors[] = { "Roy Marples <roy@marples.name>", NULL };
35
36 static void
37 on_pref(_unused GtkMenuItem *item, _unused gpointer data)
38 {
39         dhcpcd_prefs();
40 }
41
42
43 static void
44 on_quit(_unused GtkMenuItem *item, _unused gpointer data)
45 {
46         gtk_main_quit();
47 }
48
49 static void
50 on_help(_unused GtkMenuItem *item, _unused gpointer data)
51 {
52 }
53
54 static void
55 url_show(GtkAboutDialog *dialog, const char *url)
56 {
57         GdkScreen *screen;
58
59         screen = gtk_widget_get_screen(GTK_WIDGET(dialog));
60         gtk_show_uri(screen, url, GDK_CURRENT_TIME, NULL);
61 }
62
63 static void
64 email_hook(GtkAboutDialog *dialog, const char *url, _unused gpointer p)
65 {
66         char *address;
67
68         address = g_strdup_printf("mailto:%s", url);
69         url_show(dialog, address);
70         g_free(address);
71 }
72
73 static void
74 url_hook(GtkAboutDialog *dialog, const char *url, _unused gpointer p)
75 {
76         url_show(dialog, url);
77 }
78
79 static void
80 ssid_hook(_unused GtkMenuItem *item, gpointer data)
81 {
82         wpa_configure((const struct if_ap *)data);
83 }
84
85 static void
86 on_about(_unused GtkMenuItem *item, _unused gpointer data)
87 {
88         gtk_window_set_default_icon_name(GTK_STOCK_NETWORK);
89         gtk_about_dialog_set_email_hook(email_hook, NULL, NULL);
90         gtk_about_dialog_set_url_hook(url_hook, NULL, NULL);
91         gtk_show_about_dialog(NULL,
92             "version", VERSION,
93             "copyright", copyright,
94             "website-label", "dhcpcd Website",
95             "website", "http://roy.marples.name/projects/dhcpcd",
96             "authors", authors,
97             "logo-icon-name", GTK_STOCK_NETWORK,
98             NULL);
99 }
100
101 static void
102 add_scan_results(GtkMenu *menu, const struct if_msg *ifm)
103 {
104         GSList *gl;
105         const struct if_ap *ifa;
106         GtkWidget *item, *image, *box, *label, *bar;
107         double perc;
108         int strength;
109         const char *icon;
110         char *tip;
111
112         for (gl = ifm->scan_results; gl; gl = gl->next) {
113                 ifa = (const struct if_ap *)gl->data;
114                 item = gtk_check_menu_item_new();
115                 gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(item), TRUE); 
116                 box = gtk_hbox_new(FALSE, 6);
117                 gtk_container_add(GTK_CONTAINER(item), box); 
118                 label = gtk_label_new(ifa->ssid);
119                 gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
120
121                 if (g_strcmp0(ifm->ssid, ifa->ssid) == 0)
122                         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
123                 if (ifa->flags == NULL)
124                         icon = "network-wireless";
125                 else
126                         icon = "network-wireless-encrypted";
127                 image = gtk_image_new_from_icon_name(icon,
128                     GTK_ICON_SIZE_MENU);
129                 gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
130
131                 bar = gtk_progress_bar_new();
132                 gtk_widget_set_size_request(bar, 100, -1);
133                 gtk_box_pack_end(GTK_BOX(box), bar, FALSE, TRUE, 0);
134                 strength = CLAMP(ifa->quality, 0, 100);
135                 perc = strength / 100.0;
136                 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar), perc);
137
138                 tip = g_strconcat(ifa->bssid, " ", ifa->flags, NULL);
139                 gtk_widget_set_tooltip_text(item, tip);
140                 g_free(tip);
141
142                 gtk_widget_show(label);
143                 gtk_widget_show(bar);
144                 gtk_widget_show(image);
145                 gtk_widget_show(box);
146                 g_signal_connect(G_OBJECT(item), "activate",
147                     G_CALLBACK(ssid_hook), gl->data);
148                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
149         }
150 }
151
152 static void
153 on_activate(GtkStatusIcon *icon, _unused guint button, _unused guint32 atime, _unused gpointer data)
154 {
155         GtkMenu *menu;
156         const struct if_msg *ifm;
157         GSList *l;
158         size_t n, na;
159
160         notify_close();
161
162         n = na =0;
163         for (l = interfaces; l; l = l->next) {
164                 ifm = (const struct if_msg *)l->data;
165                 if (ifm->wireless) {
166                         if (ifm->scan_results != NULL)
167                                 ++na;
168                         if (++n > 1 && na != 0)
169                                 break;
170                 }
171         }
172         if (n == 0 || (n == 1 && na == 0))
173                 return;
174
175         menu = (GtkMenu *)gtk_menu_new();
176
177         for (l = interfaces; l; l = l->next) {
178                 ifm = (const struct if_msg *)l->data;
179                 if (!ifm->wireless)
180                         continue;
181                 if (n == 1) {
182                         add_scan_results(menu, ifm);
183                         break;
184                 }
185 #if 0
186                 item = gtk_image_menu_item_new_with_label(ifm->name);
187                 image = gtk_image_new_from_icon_name("network-wireless",
188                     GTK_ICON_SIZE_MENU);
189                 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
190
191                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
192 #endif
193         }
194         gtk_widget_show_all(GTK_WIDGET(menu));
195         gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
196             gtk_status_icon_position_menu, icon,
197             1, gtk_get_current_event_time());
198 }
199
200 static void
201 on_popup(GtkStatusIcon *icon, guint button, guint32 atime, gpointer data)
202 {
203         GtkMenu *menu;
204         GtkWidget *item, *image;
205
206         notify_close();
207
208         menu = (GtkMenu *)gtk_menu_new();
209
210         item = gtk_image_menu_item_new_with_mnemonic(_("_Preferences"));
211         image = gtk_image_new_from_icon_name(GTK_STOCK_PREFERENCES,
212             GTK_ICON_SIZE_MENU);
213         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
214         g_signal_connect(G_OBJECT(item), "activate",
215             G_CALLBACK(on_pref), icon);
216         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
217
218         item = gtk_image_menu_item_new_with_mnemonic(_("_Quit"));
219         image = gtk_image_new_from_icon_name(GTK_STOCK_QUIT,
220             GTK_ICON_SIZE_MENU);
221         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
222         g_signal_connect(G_OBJECT(item), "activate",
223             G_CALLBACK(on_quit), icon);
224         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
225
226         item = gtk_separator_menu_item_new();
227         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
228
229         item = gtk_image_menu_item_new_with_mnemonic(_("_Help"));
230         image = gtk_image_new_from_icon_name(GTK_STOCK_HELP,
231             GTK_ICON_SIZE_MENU);
232         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
233         g_signal_connect(G_OBJECT(item), "activate",
234             G_CALLBACK(on_help), icon);
235         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
236
237         item = gtk_image_menu_item_new_with_mnemonic(_("_About"));
238         image = gtk_image_new_from_icon_name(GTK_STOCK_ABOUT,
239             GTK_ICON_SIZE_MENU);
240         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
241         g_signal_connect(G_OBJECT(item), "activate",
242             G_CALLBACK(on_about), icon);
243         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
244
245         gtk_widget_show_all(GTK_WIDGET(menu));
246         gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
247             gtk_status_icon_position_menu, data, button, atime);
248         if (button == 0)
249                 gtk_menu_shell_select_first(GTK_MENU_SHELL(menu), FALSE);
250 }
251
252 void
253 menu_init(GtkStatusIcon *icon)
254 {
255         g_signal_connect_object(G_OBJECT(icon), "activate",
256             G_CALLBACK(on_activate), icon, 0);
257         g_signal_connect_object(G_OBJECT(icon), "popup_menu",
258             G_CALLBACK(on_popup), icon, 0);
259 }