Config UI: Only offer the user browsers that are installed
[browser-switch] / config-ui / browser-switchboard-cp.c
1 /*
2  * browser-switchboard-cp.c -- a hildon-control-panel applet for
3  * selecting the default browser for Browser Switchboard
4  * 
5  * Copyright (C) 2009-2010 Steven Luo
6  * Copyright (C) 2009-2010 Faheem Pervez
7  * 
8  * Derived from services-cp.c from maemo-control-services
9  * Copyright (c) 2008 Janne Kataja <janne.kataja@iki.fi>
10  * Copyright (c) 2008 Nokia Corporation
11  * 
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
25  * USA.
26  */
27
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <glib.h>
35 #include <glib/gstdio.h>
36 #include <gtk/gtk.h>
37
38 #ifdef HILDON
39 #include <hildon/hildon-banner.h>
40 #include <hildon/hildon-program.h>
41
42 #ifdef FREMANTLE
43 #include <hildon/hildon-touch-selector.h>
44 #include <hildon/hildon-picker-button.h>
45 #include <hildon/hildon-caption.h>
46 #include <hildon/hildon-entry.h>
47 #endif /* FREMANTLE */
48
49 #ifdef HILDON_CP_APPLET
50 #include <hildon-cp-plugin/hildon-cp-plugin-interface.h>
51 #endif /* HILDON_CP_APPLET */
52 #endif /* HILDON */
53
54 #include "config.h"
55 #include "browsers.h"
56
57 #define CONTINUOUS_MODE_DEFAULT 0
58
59 #if defined(HILDON) && defined(FREMANTLE)
60 #define _HILDON_SIZE_DEFAULT (HILDON_SIZE_AUTO_WIDTH|HILDON_SIZE_FINGER_HEIGHT)
61 #endif
62
63 struct swb_config orig_cfg;
64
65 struct config_widgets {
66 #if defined(HILDON) && defined(FREMANTLE)
67         GtkWidget *default_browser_selector;
68 #else
69         GtkWidget *continuous_mode_off_radio;
70         GtkWidget *continuous_mode_on_radio;
71         GtkWidget *default_browser_combo;
72 #endif
73         GtkWidget *other_browser_cmd_entry;
74         GtkWidget *other_browser_cmd_entry_label;
75 };
76 struct config_widgets cw;
77 GtkWidget *dialog;
78
79
80 struct browser_entry *installed_browsers;
81 void init_installed_browsers(void) {
82         struct browser_entry *cur = browsers;
83         unsigned int count = 0;
84
85         installed_browsers = calloc(sizeof browsers, 1);
86         if (!installed_browsers)
87                 exit(1);
88
89         count = 0;
90         for (; cur->config; ++cur)
91                 if (!cur->binary || !access(cur->binary, X_OK))
92                         installed_browsers[count++] = *cur;
93 }
94
95 /**********************************************************************
96  * Configuration routines
97  **********************************************************************/
98
99 #if defined(HILDON) && defined(FREMANTLE)
100
101 static inline char *get_default_browser(void) {
102         return installed_browsers[hildon_touch_selector_get_active(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), 0)].config;
103 }
104
105 #else /* !defined(HILDON) || !defined(FREMANTLE) */
106
107 static inline int get_continuous_mode(void) {
108         return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.continuous_mode_on_radio));
109 }
110 static inline void set_continuous_mode(int state) {
111         if (state)
112                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.continuous_mode_on_radio), TRUE);
113         else
114                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.continuous_mode_off_radio), TRUE);
115 }
116
117 static inline char *get_default_browser(void) {
118         return installed_browsers[gtk_combo_box_get_active(GTK_COMBO_BOX(cw.default_browser_combo))].config;
119 }
120
121 #endif /* defined(HILDON) && defined(FREMANTLE) */
122
123 static void set_default_browser(char *browser) {
124         gint i;
125
126         /* Loop through browsers looking for a match */
127         for (i = 0;
128              installed_browsers[i].config && strcmp(installed_browsers[i].config, browser);
129              ++i);
130
131         if (!installed_browsers[i].config)
132                 /* No match found, set to the default browser */
133                 i = 0;
134
135 #if defined(HILDON) && defined(FREMANTLE)
136         hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), 0, i);
137 #else
138         gtk_combo_box_set_active(GTK_COMBO_BOX(cw.default_browser_combo), i);
139 #endif
140 }
141
142 static inline char *get_other_browser_cmd(void) {
143         return (char *)gtk_entry_get_text(GTK_ENTRY(cw.other_browser_cmd_entry));
144 }
145 static inline void set_other_browser_cmd(char *cmd) {
146         gtk_entry_set_text(GTK_ENTRY(cw.other_browser_cmd_entry), cmd);
147 }
148
149 static void load_config(void) {
150         swb_config_init(&orig_cfg);
151         
152         swb_config_load(&orig_cfg);
153
154 #ifndef FREMANTLE
155         set_continuous_mode(orig_cfg.continuous_mode);
156 #endif
157         set_default_browser(orig_cfg.default_browser);
158         if (orig_cfg.other_browser_cmd)
159                 set_other_browser_cmd(orig_cfg.other_browser_cmd);
160 }
161
162 static void save_config(void) {
163         struct swb_config new_cfg;
164
165         swb_config_copy(&new_cfg, &orig_cfg);
166
167 #ifndef FREMANTLE
168         if (get_continuous_mode() != orig_cfg.continuous_mode) {
169                 new_cfg.continuous_mode = get_continuous_mode();
170                 new_cfg.flags |= SWB_CONFIG_CONTINUOUS_MODE_SET;
171         }
172 #endif
173         if (strcmp(get_default_browser(), orig_cfg.default_browser)) {
174                 new_cfg.default_browser = get_default_browser();
175                 new_cfg.flags |= SWB_CONFIG_DEFAULT_BROWSER_SET;
176         }
177         if (strlen(get_other_browser_cmd()) == 0) {
178                 new_cfg.other_browser_cmd = NULL;
179                 new_cfg.flags &= ~SWB_CONFIG_OTHER_BROWSER_CMD_SET;
180         } else if (!(orig_cfg.other_browser_cmd &&
181                      !strcmp(get_other_browser_cmd(),
182                              orig_cfg.other_browser_cmd))) {
183                 new_cfg.other_browser_cmd = get_other_browser_cmd();
184                 new_cfg.flags |= SWB_CONFIG_OTHER_BROWSER_CMD_SET;
185         }
186
187         swb_config_save(&new_cfg);
188 }
189
190 static void do_reconfig(void) {
191         save_config();
192
193         /* Try to send SIGHUP to any running browser-switchboard process
194            This causes it to reread config files if in continuous_mode, or
195            die so that the config will be reloaded on next start otherwise */
196         system("kill -HUP `pidof browser-switchboard` > /dev/null 2>&1");
197 }
198
199
200 /**********************************************************************
201  * Callbacks
202  **********************************************************************/
203
204 #if defined(HILDON) && defined(FREMANTLE)
205 static void default_browser_selector_callback(GtkWidget *widget,
206                 gint column, gpointer data) {
207 #else
208 static void default_browser_combo_callback(GtkWidget *widget, gpointer data) {
209 #endif
210         if (!strcmp(get_default_browser(), "other")) {
211                 gtk_editable_set_editable(GTK_EDITABLE(cw.other_browser_cmd_entry), TRUE);
212                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry, TRUE);
213                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, TRUE);
214         } else {
215                 gtk_editable_set_editable(GTK_EDITABLE(cw.other_browser_cmd_entry), FALSE); /* FREMANTLE: give the text the greyed-out look */
216                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry, FALSE);
217                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, FALSE);
218         }
219 }
220
221
222 /**********************************************************************
223  * Interface
224  **********************************************************************/
225
226 #if defined(HILDON) && defined(FREMANTLE)
227 /*
228  * Fremantle Hildon dialog
229  */
230 static GtkDialog *swb_config_dialog(gpointer cp_window) {
231         GtkWidget *dialog_vbox;
232
233         GtkWidget *default_browser_selector_button;
234         int i;
235         HildonGtkInputMode input_mode;
236
237         dialog = gtk_dialog_new_with_buttons(
238                 "Browser Switchboard",
239                 GTK_WINDOW(cp_window),
240                 GTK_DIALOG_MODAL,
241                 GTK_STOCK_OK,
242                 GTK_RESPONSE_OK,
243                 GTK_STOCK_CANCEL,
244                 GTK_RESPONSE_CANCEL,
245                 NULL);
246
247         dialog_vbox = GTK_DIALOG(dialog)->vbox;
248
249         /* Config options */
250         init_installed_browsers();
251         cw.default_browser_selector = hildon_touch_selector_new_text();
252         for (i = 0; installed_browsers[i].config; ++i)
253                 hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), installed_browsers[i].displayname);
254         hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), 0, 0);
255         default_browser_selector_button = hildon_picker_button_new(_HILDON_SIZE_DEFAULT, HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
256         hildon_button_set_title(HILDON_BUTTON(default_browser_selector_button),
257                                 "Default browser:");
258         hildon_picker_button_set_selector(HILDON_PICKER_BUTTON(default_browser_selector_button), HILDON_TOUCH_SELECTOR(cw.default_browser_selector));
259         hildon_button_set_alignment(HILDON_BUTTON(default_browser_selector_button),
260                                     0, 0.5, 0, 0);
261         g_signal_connect(G_OBJECT(cw.default_browser_selector), "changed",
262                          G_CALLBACK(default_browser_selector_callback), NULL);
263         gtk_box_pack_start(GTK_BOX(dialog_vbox),
264                            default_browser_selector_button, FALSE, FALSE, 0);
265
266         cw.other_browser_cmd_entry = hildon_entry_new(_HILDON_SIZE_DEFAULT);
267         /* Disable autocapitalization and dictionary features for the entry */
268         input_mode = hildon_gtk_entry_get_input_mode(GTK_ENTRY(cw.other_browser_cmd_entry));
269         input_mode &= ~(HILDON_GTK_INPUT_MODE_AUTOCAP |
270                         HILDON_GTK_INPUT_MODE_DICTIONARY);
271         hildon_gtk_entry_set_input_mode(GTK_ENTRY(cw.other_browser_cmd_entry), input_mode);
272
273         cw.other_browser_cmd_entry_label = hildon_caption_new(NULL,
274                         "Command (%s for URI):",
275                         cw.other_browser_cmd_entry,
276                         NULL, HILDON_CAPTION_OPTIONAL);
277         gtk_widget_set_sensitive(cw.other_browser_cmd_entry, FALSE);
278         gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, FALSE);
279         hildon_gtk_widget_set_theme_size(cw.other_browser_cmd_entry_label, _HILDON_SIZE_DEFAULT);
280         gtk_box_pack_start(GTK_BOX(dialog_vbox),
281                            cw.other_browser_cmd_entry_label, FALSE, FALSE, 0);
282
283         gtk_widget_show_all(dialog);
284         return GTK_DIALOG(dialog);
285 }
286
287 #else /* !defined(HILDON) || !defined(FREMANTLE) */
288 /*
289  * GTK+/Diablo Hildon dialog
290  */
291 static GtkDialog *swb_config_dialog(gpointer cp_window) {
292         GtkWidget *dialog_vbox;
293
294         GtkWidget *options_table;
295         GtkWidget *default_browser_combo_label;
296         GtkWidget *continuous_mode_label;
297         int i;
298 #ifdef HILDON
299         HildonGtkInputMode input_mode;
300 #endif
301
302         dialog = gtk_dialog_new_with_buttons(
303                 "Browser Switchboard",
304                 GTK_WINDOW(cp_window),
305                 GTK_DIALOG_MODAL,
306                 GTK_STOCK_OK,
307                 GTK_RESPONSE_OK,
308                 GTK_STOCK_CANCEL,
309                 GTK_RESPONSE_CANCEL,
310                 NULL);
311
312         dialog_vbox = GTK_DIALOG(dialog)->vbox;
313
314         /* Config options */
315         options_table = gtk_table_new(3, 2, FALSE);
316         gtk_table_set_row_spacings(GTK_TABLE(options_table), 5);
317         gtk_box_pack_start(GTK_BOX(dialog_vbox), options_table, FALSE, FALSE, 0);
318
319         init_installed_browsers();
320         cw.default_browser_combo = gtk_combo_box_new_text();
321         for (i = 0; installed_browsers[i].config; ++i)
322                 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.default_browser_combo),
323                                           installed_browsers[i].displayname);
324         gtk_combo_box_set_active(GTK_COMBO_BOX(cw.default_browser_combo), 0);
325         default_browser_combo_label = gtk_label_new("Default browser:");
326         gtk_misc_set_alignment(GTK_MISC(default_browser_combo_label), 1, 0.5);
327         g_signal_connect(G_OBJECT(cw.default_browser_combo), "changed",
328                          G_CALLBACK(default_browser_combo_callback), NULL);
329         gtk_table_attach(GTK_TABLE(options_table),
330                         default_browser_combo_label,
331                         0, 1,
332                         0, 1,
333                         GTK_FILL, GTK_FILL|GTK_EXPAND,
334                         5, 0);
335         gtk_table_attach(GTK_TABLE(options_table),
336                         cw.default_browser_combo,
337                         1, 2,
338                         0, 1,
339                         GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND,
340                         5, 0);
341
342         cw.other_browser_cmd_entry = gtk_entry_new();
343 #ifdef HILDON
344         /* Disable autocapitalization and dictionary features for the entry */
345         input_mode = hildon_gtk_entry_get_input_mode(GTK_ENTRY(cw.other_browser_cmd_entry));
346         input_mode &= ~(HILDON_GTK_INPUT_MODE_AUTOCAP |
347                         HILDON_GTK_INPUT_MODE_DICTIONARY);
348         hildon_gtk_entry_set_input_mode(GTK_ENTRY(cw.other_browser_cmd_entry), input_mode);
349 #endif
350         cw.other_browser_cmd_entry_label = gtk_label_new("Command (%s for URI):");
351         gtk_misc_set_alignment(GTK_MISC(cw.other_browser_cmd_entry_label), 1, 0.5);
352         gtk_widget_set_sensitive(cw.other_browser_cmd_entry, FALSE);
353         gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, FALSE);
354         gtk_table_attach(GTK_TABLE(options_table),
355                         cw.other_browser_cmd_entry_label,
356                         0, 1,
357                         1, 2,
358                         GTK_FILL, GTK_FILL|GTK_EXPAND,
359                         5, 0);
360         gtk_table_attach(GTK_TABLE(options_table),
361                         cw.other_browser_cmd_entry,
362                         1, 2,
363                         1, 2,
364                         GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND,
365                         5, 0);
366         gtk_table_set_row_spacing(GTK_TABLE(options_table), 1, 15);
367
368         continuous_mode_label = gtk_label_new("Optimize Browser Switchboard for:");
369         gtk_misc_set_alignment(GTK_MISC(continuous_mode_label), 0, 0.5);
370         cw.continuous_mode_off_radio = gtk_radio_button_new_with_label(NULL,
371                         "Lower memory usage");
372         cw.continuous_mode_on_radio = gtk_radio_button_new_with_label_from_widget(
373                         GTK_RADIO_BUTTON(cw.continuous_mode_off_radio),
374                         "Faster browser startup time");
375         set_continuous_mode(CONTINUOUS_MODE_DEFAULT);
376         gtk_table_attach(GTK_TABLE(options_table),
377                         continuous_mode_label,
378                         0, 2,
379                         2, 3,
380                         GTK_FILL, GTK_FILL|GTK_EXPAND,
381                         5, 0);
382         gtk_table_attach(GTK_TABLE(options_table),
383                         cw.continuous_mode_off_radio,
384                         0, 2,
385                         3, 4,
386                         GTK_FILL, GTK_FILL|GTK_EXPAND,
387                         20, 0);
388         gtk_table_attach(GTK_TABLE(options_table),
389                         cw.continuous_mode_on_radio,
390                         0, 2,
391                         4, 5,
392                         GTK_FILL, GTK_FILL|GTK_EXPAND,
393                         20, 5);
394         gtk_table_set_row_spacing(GTK_TABLE(options_table), 3, 0);
395
396
397         gtk_widget_show_all(dialog);
398         return GTK_DIALOG(dialog);
399 }
400
401 #endif /* defined(HILDON) && defined(FREMANTLE) */
402
403
404 /**********************************************************************
405  * Entry
406  **********************************************************************/
407
408 #ifdef HILDON_CP_APPLET
409 /*
410  * Application was started from control panel.
411  */
412 osso_return_t execute(osso_context_t *osso,
413                       gpointer userdata, gboolean user_activated) {
414         GtkDialog *dialog;
415         gint response;
416
417         if (osso == NULL)
418                 return OSSO_ERROR;
419
420         dialog = GTK_DIALOG(swb_config_dialog(userdata));
421         load_config();
422
423         response = gtk_dialog_run(dialog);
424         if (response == GTK_RESPONSE_OK)
425                 do_reconfig();
426
427         gtk_widget_destroy(GTK_WIDGET(dialog));
428
429         return OSSO_OK;
430 }
431 #else
432 /*
433  * Application was started from command line.
434  */
435 int main(int argc, char *argv[]) {
436         GtkDialog *dialog;
437         gint response;
438 #ifdef HILDON
439         HildonProgram *program = NULL;
440 #endif
441
442         gtk_init(&argc, &argv);
443 #ifdef HILDON
444         program = HILDON_PROGRAM(hildon_program_get_instance());
445 #endif
446
447         g_set_application_name("Browser Switchboard");
448
449         dialog = GTK_DIALOG(swb_config_dialog(NULL));
450         load_config();
451
452         response = gtk_dialog_run(dialog);
453         if (response == GTK_RESPONSE_OK)
454                 do_reconfig();
455
456         gtk_widget_destroy(GTK_WIDGET(dialog));
457
458         exit(0);
459 }
460 #endif /* HILDON_CP_APPLET */