Avoid structure copies when looping through swb_config_options
[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
56 #define CONTINUOUS_MODE_DEFAULT 0
57
58 #if defined(HILDON) && defined(FREMANTLE)
59 #define _HILDON_SIZE_DEFAULT (HILDON_SIZE_AUTO_WIDTH|HILDON_SIZE_FINGER_HEIGHT)
60 #endif
61
62 struct browser_entry {
63         char *config;
64         char *displayname;
65 };
66 struct browser_entry browsers[] = {
67         { "microb", "MicroB" }, /* First entry is the default! */
68         { "tear", "Tear" },
69         { "fennec", "Mobile Firefox (Fennec)" },
70         { "opera", "Opera Mobile" },
71         { "midori", "Midori" },
72         { "other", "Other" },
73         { NULL, NULL },
74 };
75
76 struct swb_config orig_cfg;
77
78 struct config_widgets {
79 #if defined(HILDON) && defined(FREMANTLE)
80         GtkWidget *continuous_mode_selector;
81         GtkWidget *default_browser_selector;
82 #else
83         GtkWidget *continuous_mode_off_radio;
84         GtkWidget *continuous_mode_on_radio;
85         GtkWidget *default_browser_combo;
86 #endif
87         GtkWidget *other_browser_cmd_entry;
88         GtkWidget *other_browser_cmd_entry_label;
89 };
90 struct config_widgets cw;
91 GtkWidget *dialog;
92
93
94 /**********************************************************************
95  * Configuration routines
96  **********************************************************************/
97
98 #if defined(HILDON) && defined(FREMANTLE)
99
100 static inline int get_continuous_mode(void) {
101         return hildon_touch_selector_get_active(HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector), 0);
102 }
103 static inline void set_continuous_mode(int state) {
104         hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector), 0, state);
105 }
106
107 static inline char *get_default_browser(void) {
108         return browsers[hildon_touch_selector_get_active(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), 0)].config;
109 }
110
111 #else /* !defined(HILDON) || !defined(FREMANTLE) */
112
113 static inline int get_continuous_mode(void) {
114         return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.continuous_mode_on_radio));
115 }
116 static inline void set_continuous_mode(int state) {
117         if (state)
118                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.continuous_mode_on_radio), TRUE);
119         else
120                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.continuous_mode_off_radio), TRUE);
121 }
122
123 static inline char *get_default_browser(void) {
124         return browsers[gtk_combo_box_get_active(GTK_COMBO_BOX(cw.default_browser_combo))].config;
125 }
126
127 #endif /* defined(HILDON) && defined(FREMANTLE) */
128
129 static void set_default_browser(char *browser) {
130         gint i;
131
132         /* Loop through browsers looking for a match */
133         for (i = 0; browsers[i].config && strcmp(browsers[i].config, browser);
134                         ++i);
135
136         if (!browsers[i].config)
137                 /* No match found, set to the default browser */
138                 i = 0;
139
140 #if defined(HILDON) && defined(FREMANTLE)
141         hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), 0, i);
142 #else
143         gtk_combo_box_set_active(GTK_COMBO_BOX(cw.default_browser_combo), i);
144 #endif
145 }
146
147 static inline char *get_other_browser_cmd(void) {
148         return (char *)gtk_entry_get_text(GTK_ENTRY(cw.other_browser_cmd_entry));
149 }
150 static inline void set_other_browser_cmd(char *cmd) {
151         gtk_entry_set_text(GTK_ENTRY(cw.other_browser_cmd_entry), cmd);
152 }
153
154 static void load_config(void) {
155         swb_config_init(&orig_cfg);
156         
157         swb_config_load(&orig_cfg);
158
159         set_continuous_mode(orig_cfg.continuous_mode);
160         set_default_browser(orig_cfg.default_browser);
161         if (orig_cfg.other_browser_cmd)
162                 set_other_browser_cmd(orig_cfg.other_browser_cmd);
163 }
164
165 static void save_config(void) {
166         struct swb_config new_cfg;
167
168         swb_config_copy(&new_cfg, &orig_cfg);
169
170         if (get_continuous_mode() != orig_cfg.continuous_mode) {
171                 new_cfg.continuous_mode = get_continuous_mode();
172                 new_cfg.flags |= SWB_CONFIG_CONTINUOUS_MODE_SET;
173         }
174         if (strcmp(get_default_browser(), orig_cfg.default_browser)) {
175                 new_cfg.default_browser = get_default_browser();
176                 new_cfg.flags |= SWB_CONFIG_DEFAULT_BROWSER_SET;
177         }
178         if ((orig_cfg.other_browser_cmd &&
179              strcmp(get_other_browser_cmd(), orig_cfg.other_browser_cmd)) ||
180             (!orig_cfg.other_browser_cmd &&
181              strlen(get_other_browser_cmd()) > 0)) {
182                 new_cfg.other_browser_cmd = get_other_browser_cmd();
183                 new_cfg.flags |= SWB_CONFIG_OTHER_BROWSER_CMD_SET;
184         }
185
186         swb_config_save(&new_cfg);
187 }
188
189 static void do_reconfig(void) {
190         save_config();
191
192         /* Try to send SIGHUP to any running browser-switchboard process
193            This causes it to reread config files if in continuous_mode, or
194            die so that the config will be reloaded on next start otherwise */
195         system("kill -HUP `pidof browser-switchboard` > /dev/null 2>&1");
196 }
197
198
199 /**********************************************************************
200  * Callbacks
201  **********************************************************************/
202
203 #if defined(HILDON) && defined(FREMANTLE)
204 static void default_browser_selector_callback(GtkWidget *widget,
205                 gint column, gpointer data) {
206 #else
207 static void default_browser_combo_callback(GtkWidget *widget, gpointer data) {
208 #endif
209         if (!strcmp(get_default_browser(), "other")) {
210                 gtk_editable_set_editable(GTK_EDITABLE(cw.other_browser_cmd_entry), TRUE);
211                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry, TRUE);
212                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, TRUE);
213         } else {
214                 gtk_editable_set_editable(GTK_EDITABLE(cw.other_browser_cmd_entry), FALSE); /* FREMANTLE: give the text the greyed-out look */
215                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry, FALSE);
216                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, FALSE);
217         }
218 }
219
220
221 /**********************************************************************
222  * Interface
223  **********************************************************************/
224
225 #if defined(HILDON) && defined(FREMANTLE)
226 /*
227  * Fremantle Hildon dialog
228  */
229 static GtkDialog *swb_config_dialog(gpointer cp_window) {
230         GtkWidget *dialog_vbox;
231
232         GtkWidget *default_browser_selector_button;
233         GtkWidget *continuous_mode_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         cw.default_browser_selector = hildon_touch_selector_new_text();
251         for (i = 0; browsers[i].config; ++i)
252                 hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), browsers[i].displayname);
253         hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), 0, 0);
254         default_browser_selector_button = hildon_picker_button_new(_HILDON_SIZE_DEFAULT, HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
255         hildon_button_set_title(HILDON_BUTTON(default_browser_selector_button),
256                                 "Default browser:");
257         hildon_picker_button_set_selector(HILDON_PICKER_BUTTON(default_browser_selector_button), HILDON_TOUCH_SELECTOR(cw.default_browser_selector));
258         hildon_button_set_alignment(HILDON_BUTTON(default_browser_selector_button),
259                                     0, 0.5, 0, 0);
260         g_signal_connect(G_OBJECT(cw.default_browser_selector), "changed",
261                          G_CALLBACK(default_browser_selector_callback), NULL);
262         gtk_box_pack_start(GTK_BOX(dialog_vbox),
263                            default_browser_selector_button, FALSE, FALSE, 0);
264
265         cw.other_browser_cmd_entry = hildon_entry_new(_HILDON_SIZE_DEFAULT);
266         /* Disable autocapitalization and dictionary features for the entry */
267         input_mode = hildon_gtk_entry_get_input_mode(GTK_ENTRY(cw.other_browser_cmd_entry));
268         input_mode &= ~(HILDON_GTK_INPUT_MODE_AUTOCAP |
269                         HILDON_GTK_INPUT_MODE_DICTIONARY);
270         hildon_gtk_entry_set_input_mode(GTK_ENTRY(cw.other_browser_cmd_entry), input_mode);
271
272         cw.other_browser_cmd_entry_label = hildon_caption_new(NULL,
273                         "Command (%s for URI):",
274                         cw.other_browser_cmd_entry,
275                         NULL, HILDON_CAPTION_OPTIONAL);
276         gtk_widget_set_sensitive(cw.other_browser_cmd_entry, FALSE);
277         gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, FALSE);
278         hildon_gtk_widget_set_theme_size(cw.other_browser_cmd_entry_label, _HILDON_SIZE_DEFAULT);
279         gtk_box_pack_start(GTK_BOX(dialog_vbox),
280                            cw.other_browser_cmd_entry_label, FALSE, FALSE, 0);
281
282         cw.continuous_mode_selector = hildon_touch_selector_new_text();
283         hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector), "Lower memory usage");
284         hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector), "Faster browser startup time");
285
286         continuous_mode_selector_button = hildon_picker_button_new(_HILDON_SIZE_DEFAULT, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
287         hildon_button_set_title(HILDON_BUTTON(continuous_mode_selector_button),
288                                 "Optimize Browser Switchboard for:");
289         hildon_picker_button_set_selector(HILDON_PICKER_BUTTON(continuous_mode_selector_button), HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector));
290         hildon_button_set_alignment(HILDON_BUTTON(continuous_mode_selector_button),
291                                     0, 0, 0, 0);
292         set_continuous_mode(CONTINUOUS_MODE_DEFAULT);
293         gtk_box_pack_start(GTK_BOX(dialog_vbox),
294                            continuous_mode_selector_button, FALSE, FALSE, 0);
295
296         gtk_widget_show_all(dialog);
297         return GTK_DIALOG(dialog);
298 }
299
300 #else /* !defined(HILDON) || !defined(FREMANTLE) */
301 /*
302  * GTK+/Diablo Hildon dialog
303  */
304 static GtkDialog *swb_config_dialog(gpointer cp_window) {
305         GtkWidget *dialog_vbox;
306
307         GtkWidget *options_table;
308         GtkWidget *default_browser_combo_label;
309         GtkWidget *continuous_mode_label;
310         int i;
311 #ifdef HILDON
312         HildonGtkInputMode input_mode;
313 #endif
314
315         dialog = gtk_dialog_new_with_buttons(
316                 "Browser Switchboard",
317                 GTK_WINDOW(cp_window),
318                 GTK_DIALOG_MODAL,
319                 GTK_STOCK_OK,
320                 GTK_RESPONSE_OK,
321                 GTK_STOCK_CANCEL,
322                 GTK_RESPONSE_CANCEL,
323                 NULL);
324
325         dialog_vbox = GTK_DIALOG(dialog)->vbox;
326
327         /* Config options */
328         options_table = gtk_table_new(3, 2, FALSE);
329         gtk_table_set_row_spacings(GTK_TABLE(options_table), 5);
330         gtk_box_pack_start(GTK_BOX(dialog_vbox), options_table, FALSE, FALSE, 0);
331
332         cw.default_browser_combo = gtk_combo_box_new_text();
333         for (i = 0; browsers[i].config; ++i)
334                 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.default_browser_combo),
335                                           browsers[i].displayname);
336         gtk_combo_box_set_active(GTK_COMBO_BOX(cw.default_browser_combo), 0);
337         default_browser_combo_label = gtk_label_new("Default browser:");
338         gtk_misc_set_alignment(GTK_MISC(default_browser_combo_label), 1, 0.5);
339         g_signal_connect(G_OBJECT(cw.default_browser_combo), "changed",
340                          G_CALLBACK(default_browser_combo_callback), NULL);
341         gtk_table_attach(GTK_TABLE(options_table),
342                         default_browser_combo_label,
343                         0, 1,
344                         0, 1,
345                         GTK_FILL, GTK_FILL|GTK_EXPAND,
346                         5, 0);
347         gtk_table_attach(GTK_TABLE(options_table),
348                         cw.default_browser_combo,
349                         1, 2,
350                         0, 1,
351                         GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND,
352                         5, 0);
353
354         cw.other_browser_cmd_entry = gtk_entry_new();
355 #ifdef HILDON
356         /* Disable autocapitalization and dictionary features for the entry */
357         input_mode = hildon_gtk_entry_get_input_mode(GTK_ENTRY(cw.other_browser_cmd_entry));
358         input_mode &= ~(HILDON_GTK_INPUT_MODE_AUTOCAP |
359                         HILDON_GTK_INPUT_MODE_DICTIONARY);
360         hildon_gtk_entry_set_input_mode(GTK_ENTRY(cw.other_browser_cmd_entry), input_mode);
361 #endif
362         cw.other_browser_cmd_entry_label = gtk_label_new("Command (%s for URI):");
363         gtk_misc_set_alignment(GTK_MISC(cw.other_browser_cmd_entry_label), 1, 0.5);
364         gtk_widget_set_sensitive(cw.other_browser_cmd_entry, FALSE);
365         gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, FALSE);
366         gtk_table_attach(GTK_TABLE(options_table),
367                         cw.other_browser_cmd_entry_label,
368                         0, 1,
369                         1, 2,
370                         GTK_FILL, GTK_FILL|GTK_EXPAND,
371                         5, 0);
372         gtk_table_attach(GTK_TABLE(options_table),
373                         cw.other_browser_cmd_entry,
374                         1, 2,
375                         1, 2,
376                         GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND,
377                         5, 0);
378         gtk_table_set_row_spacing(GTK_TABLE(options_table), 1, 15);
379
380         continuous_mode_label = gtk_label_new("Optimize Browser Switchboard for:");
381         gtk_misc_set_alignment(GTK_MISC(continuous_mode_label), 0, 0.5);
382         cw.continuous_mode_off_radio = gtk_radio_button_new_with_label(NULL,
383                         "Lower memory usage");
384         cw.continuous_mode_on_radio = gtk_radio_button_new_with_label_from_widget(
385                         GTK_RADIO_BUTTON(cw.continuous_mode_off_radio),
386                         "Faster browser startup time");
387         set_continuous_mode(CONTINUOUS_MODE_DEFAULT);
388         gtk_table_attach(GTK_TABLE(options_table),
389                         continuous_mode_label,
390                         0, 2,
391                         2, 3,
392                         GTK_FILL, GTK_FILL|GTK_EXPAND,
393                         5, 0);
394         gtk_table_attach(GTK_TABLE(options_table),
395                         cw.continuous_mode_off_radio,
396                         0, 2,
397                         3, 4,
398                         GTK_FILL, GTK_FILL|GTK_EXPAND,
399                         20, 0);
400         gtk_table_attach(GTK_TABLE(options_table),
401                         cw.continuous_mode_on_radio,
402                         0, 2,
403                         4, 5,
404                         GTK_FILL, GTK_FILL|GTK_EXPAND,
405                         20, 5);
406         gtk_table_set_row_spacing(GTK_TABLE(options_table), 3, 0);
407
408
409         gtk_widget_show_all(dialog);
410         return GTK_DIALOG(dialog);
411 }
412
413 #endif /* defined(HILDON) && defined(FREMANTLE) */
414
415
416 /**********************************************************************
417  * Entry
418  **********************************************************************/
419
420 #ifdef HILDON_CP_APPLET
421 /*
422  * Application was started from control panel.
423  */
424 osso_return_t execute(osso_context_t *osso,
425                       gpointer userdata, gboolean user_activated) {
426         GtkDialog *dialog;
427         gint response;
428
429         if (osso == NULL)
430                 return OSSO_ERROR;
431
432         dialog = GTK_DIALOG(swb_config_dialog(userdata));
433         load_config();
434
435         response = gtk_dialog_run(dialog);
436         if (response == GTK_RESPONSE_OK)
437                 do_reconfig();
438
439         gtk_widget_destroy(GTK_WIDGET(dialog));
440
441         return OSSO_OK;
442 }
443 #else
444 /*
445  * Application was started from command line.
446  */
447 int main(int argc, char *argv[]) {
448         GtkDialog *dialog;
449         gint response;
450 #ifdef HILDON
451         HildonProgram *program = NULL;
452 #endif
453
454         gtk_init(&argc, &argv);
455 #ifdef HILDON
456         program = HILDON_PROGRAM(hildon_program_get_instance());
457 #endif
458
459         g_set_application_name("Browser Switchboard");
460
461         dialog = GTK_DIALOG(swb_config_dialog(NULL));
462         load_config();
463
464         response = gtk_dialog_run(dialog);
465         if (response == GTK_RESPONSE_OK)
466                 do_reconfig();
467
468         gtk_widget_destroy(GTK_WIDGET(dialog));
469
470         exit(0);
471 }
472 #endif /* HILDON_CP_APPLET */