1ed654bf4f0f3fcd715747f81686b847c793dcb0
[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 Steven Luo
6  * 
7  * Derived from services-cp.c from maemo-control-services
8  * Copyright (c) 2008 Janne Kataja <janne.kataja@iki.fi>
9  * Copyright (c) 2008 Nokia Corporation
10  * 
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2, or (at your option)
14  * any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
24  * USA.
25  */
26
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #include <gtk/gtk.h>
35 #ifdef HILDON
36 #include <hildon/hildon-banner.h>
37 #include <hildon/hildon-program.h>
38 #ifdef HILDON_CP_APPLET
39 #include <hildon-cp-plugin/hildon-cp-plugin-interface.h>
40 #endif
41 #endif
42
43 #include "configfile.h"
44
45 struct browser_entry {
46         char *config;
47         char *displayname;
48 };
49 struct browser_entry browsers[] = {
50         { "microb", "MicroB" }, /* First entry is the default! */
51         { "tear", "Tear" },
52         { "fennec", "Mobile Firefox (Fennec)" },
53         { "midori", "Midori" },
54         { "other", "Other" },
55         { NULL, NULL },
56 };
57
58 struct config_widgets {
59         GtkWidget *continuous_mode_check;
60         GtkWidget *default_browser_combo;
61         GtkWidget *other_browser_cmd_entry;
62         GtkWidget *other_browser_cmd_entry_label;
63 };
64 struct config_widgets cw;
65 GtkWidget *dialog;
66
67
68 /**********************************************************************
69  * Configuration routines
70  **********************************************************************/
71
72 static inline int get_continuous_mode(void) {
73         return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw.continuous_mode_check));
74 }
75 static inline void set_continuous_mode(int state) {
76         return gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cw.continuous_mode_check), (gboolean)state);
77 }
78
79 static inline char *get_default_browser(void) {
80         return browsers[gtk_combo_box_get_active(GTK_COMBO_BOX(cw.default_browser_combo))].config;
81 }
82 static void set_default_browser(char *browser) {
83         gint i;
84
85         /* Loop through browsers looking for a match */
86         for (i = 0; browsers[i].config && strcmp(browsers[i].config, browser);
87                         ++i);
88
89         if (!browsers[i].config)
90                 /* No match found, set to the default browser */
91                 i = 0;
92
93         gtk_combo_box_set_active(GTK_COMBO_BOX(cw.default_browser_combo), i);
94 }
95
96 static inline char *get_other_browser_cmd(void) {
97         return (char *)gtk_entry_get_text(GTK_ENTRY(cw.other_browser_cmd_entry));
98 }
99 static inline void set_other_browser_cmd(char *cmd) {
100         gtk_entry_set_text(GTK_ENTRY(cw.other_browser_cmd_entry), cmd);
101 }
102
103 static void load_config(void) {
104         FILE *fp;
105         int continuous_mode_seen = 0;
106         int default_browser_seen = 0;
107         int other_browser_cmd_seen = 0;
108         struct swb_config_line line;
109
110         if (!(fp = open_config_file()))
111                 return;
112
113         /* Parse the config file
114            TODO: should we handle errors differently than EOF? */
115         if (!parse_config_file_begin())
116                 goto out;
117         while (!parse_config_file_line(fp, &line)) {
118                 if (line.parsed) {
119                         if (!strcmp(line.key, "continuous_mode")) {
120                                 if (!continuous_mode_seen) {
121                                         set_continuous_mode(atoi(line.value));
122                                         continuous_mode_seen = 1;
123                                 }
124                         } else if (!strcmp(line.key, "default_browser")) {
125                                 if (!default_browser_seen) {
126                                         set_default_browser(line.value);
127                                         default_browser_seen = 1;
128                                 }
129                         } else if (!strcmp(line.key, "other_browser_cmd")) {
130                                 if (!other_browser_cmd_seen) {
131                                         set_other_browser_cmd(line.value);
132                                         other_browser_cmd_seen = 1;
133                                 }
134                         }
135                 }
136                 free(line.key);
137                 free(line.value);
138         }
139         parse_config_file_end();
140
141 out:
142         fclose(fp);
143         return;
144 }
145
146 static void save_config(void) {
147         FILE *fp = NULL, *tmpfp = NULL;
148         char *homedir, *tempfile, *newfile;
149         size_t len;
150         int continuous_mode_seen = 0;
151         int default_browser_seen = 0;
152         int other_browser_cmd_seen = 0;
153         struct swb_config_line line;
154
155         /* Put together the path to the new config file and the tempfile */
156         if (!(homedir = getenv("HOME")))
157                 homedir = DEFAULT_HOMEDIR;
158         len = strlen(homedir) + strlen(CONFIGFILE_LOC) + 1;
159         if (!(newfile = calloc(len, sizeof(char))))
160                 return;
161         /* 4 = strlen(".tmp") */
162         if (!(tempfile = calloc(len+4, sizeof(char)))) {
163                 free(newfile);
164                 return;
165         }
166         snprintf(newfile, len, "%s%s", homedir, CONFIGFILE_LOC);
167         snprintf(tempfile, len+4, "%s%s", newfile, ".tmp");
168
169         /* Open the temporary file for writing */
170         if (!(tmpfp = fopen(tempfile, "w")))
171                 /* TODO: report the error somehow? */
172                 goto out;
173
174         /* Open the old config file, if it exists */
175         if ((fp = open_config_file()) && parse_config_file_begin()) {
176                 /* Copy the old config file over to the new one line by line,
177                    replacing old config values with new ones
178                    TODO: should we handle errors differently than EOF? */
179                 while (!parse_config_file_line(fp, &line)) {
180                         if (line.parsed) {
181                                 /* Is a config line, print the new value here */
182                                 if (!strcmp(line.key, "continuous_mode")) {
183                                         if (!continuous_mode_seen) {
184                                                 fprintf(tmpfp, "%s = %d\n",
185                                                         line.key,
186                                                         get_continuous_mode());
187                                                 continuous_mode_seen = 1;
188                                         }
189                                 } else if (!strcmp(line.key,
190                                                         "default_browser")) {
191                                         if (!default_browser_seen) {
192                                                 fprintf(tmpfp, "%s = \"%s\"\n",
193                                                         line.key,
194                                                         get_default_browser());
195                                                 default_browser_seen = 1;
196                                         }
197                                 } else if (!strcmp(line.key,
198                                                         "other_browser_cmd")) {
199                                         if (!other_browser_cmd_seen &&
200                                             strlen(get_other_browser_cmd())>0) {
201                                                 fprintf(tmpfp, "%s = \"%s\"\n",
202                                                         line.key,
203                                                         get_other_browser_cmd());
204                                                 other_browser_cmd_seen = 1;
205                                         }
206                                 }
207                         } else {
208                                 /* Just copy the old line over */
209                                 fprintf(tmpfp, "%s\n", line.key);
210                         }
211                         free(line.key);
212                         free(line.value);
213                 }
214                 parse_config_file_end();
215         }
216
217         /* If we haven't written them yet, write out the new config values */
218         if (!continuous_mode_seen)
219                 fprintf(tmpfp, "%s = %d\n",
220                         "continuous_mode", get_continuous_mode());
221         if (!default_browser_seen)
222                 fprintf(tmpfp, "%s = \"%s\"\n",
223                         "default_browser", get_default_browser());
224         if (!other_browser_cmd_seen && strlen(get_other_browser_cmd()) > 0)
225                 fprintf(tmpfp, "%s = \"%s\"\n",
226                         "other_browser_cmd", get_other_browser_cmd());
227
228         /* Replace the old config file with the new one */
229         fclose(tmpfp);
230         tmpfp = NULL;
231         rename(tempfile, newfile);
232
233 out:
234         free(newfile);
235         free(tempfile);
236         if (tmpfp)
237                 fclose(tmpfp);
238         if (fp)
239                 fclose(fp);
240         return;
241 }
242
243 /**********************************************************************
244  * Callbacks
245  **********************************************************************/
246
247 static void default_browser_combo_callback(GtkWidget *widget, gpointer data) {
248         if (!strcmp(get_default_browser(), "other")) {
249                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry, TRUE);
250                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, TRUE);
251         } else {
252                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry, FALSE);
253                 gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, FALSE);
254         }
255 }
256
257 static inline void close_dialog(void) {
258         gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_NONE);
259 }
260
261 static void ok_callback(GtkWidget *widget, gpointer data) {
262         save_config();
263         /* TODO: is there any cleanup necessary? */
264         close_dialog();
265 }
266
267 static void cancel_callback(GtkWidget *widget, gpointer data) {
268         /* TODO: is there any cleanup necessary? */
269         close_dialog();
270 }
271
272
273 /**********************************************************************
274  * Interface
275  **********************************************************************/
276
277 static GtkDialog *swb_config_dialog(void) {
278         GtkWidget *dialog_vbox;
279
280         GtkWidget *options_table;
281         GtkWidget *default_browser_combo_label;
282         int i;
283
284         GtkWidget *action_area;
285         GtkWidget *okbutton, *cancelbutton;
286
287         dialog = gtk_dialog_new();
288         /* Doesn't seem to be necessary?
289            gtk_widget_set_size_request(GTK_WIDGET(dialog), 580, 180); */
290         gtk_window_set_title (GTK_WINDOW(dialog), "Browser Switchboard");
291         gtk_window_set_type_hint (GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
292
293         dialog_vbox = GTK_DIALOG(dialog)->vbox;
294
295         /* Config options */
296         options_table = gtk_table_new(3, 2, FALSE);
297         gtk_table_set_row_spacings(GTK_TABLE(options_table), 10);
298         gtk_table_set_col_spacings(GTK_TABLE(options_table), 10);
299         gtk_box_pack_start(GTK_BOX(dialog_vbox), options_table, FALSE, FALSE, 0);
300
301         cw.default_browser_combo = gtk_combo_box_new_text();
302         for (i = 0; browsers[i].config; ++i)
303                 gtk_combo_box_append_text(GTK_COMBO_BOX(cw.default_browser_combo),
304                                           browsers[i].displayname);
305         gtk_combo_box_set_active(GTK_COMBO_BOX(cw.default_browser_combo), 0);
306         default_browser_combo_label = gtk_label_new("Default browser:");
307         gtk_misc_set_alignment(GTK_MISC(default_browser_combo_label), 1, 0.5);
308         g_signal_connect(G_OBJECT(cw.default_browser_combo), "changed",
309                          G_CALLBACK(default_browser_combo_callback), NULL);
310         gtk_table_attach(GTK_TABLE(options_table),
311                         default_browser_combo_label,
312                         0, 1,
313                         0, 1,
314                         GTK_FILL, GTK_FILL|GTK_EXPAND,
315                         0, 0);
316         gtk_table_attach_defaults(GTK_TABLE(options_table),
317                         cw.default_browser_combo,
318                         1, 2,
319                         0, 1);
320         gtk_table_set_row_spacing(GTK_TABLE(options_table), 0, 5);
321
322         cw.other_browser_cmd_entry = gtk_entry_new();
323         cw.other_browser_cmd_entry_label = gtk_label_new("Command (%s for URI):");
324         gtk_misc_set_alignment(GTK_MISC(cw.other_browser_cmd_entry_label), 1, 0.5);
325         gtk_widget_set_sensitive(cw.other_browser_cmd_entry, FALSE);
326         gtk_widget_set_sensitive(cw.other_browser_cmd_entry_label, FALSE);
327         gtk_table_attach(GTK_TABLE(options_table),
328                         cw.other_browser_cmd_entry_label,
329                         0, 1,
330                         1, 2,
331                         0, GTK_FILL|GTK_EXPAND,
332                         0, 0);
333         gtk_table_attach_defaults(GTK_TABLE(options_table),
334                         cw.other_browser_cmd_entry,
335                         1, 2,
336                         1, 2);
337
338         cw.continuous_mode_check = gtk_check_button_new_with_label("Run browser launcher continuously in the background");
339         gtk_table_attach_defaults(GTK_TABLE(options_table),
340                         cw.continuous_mode_check,
341                         0, 2,
342                         2, 3);
343
344
345         /* Dialog buttons */
346         action_area = GTK_DIALOG(dialog)->action_area;
347
348         okbutton = gtk_button_new_from_stock(GTK_STOCK_OK);
349         g_signal_connect(G_OBJECT(okbutton), "clicked",
350                          G_CALLBACK(ok_callback), NULL);
351         gtk_box_pack_start(GTK_BOX(action_area), okbutton, FALSE, FALSE, 0);
352
353         cancelbutton = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
354         g_signal_connect(G_OBJECT(cancelbutton), "clicked",
355                          G_CALLBACK(cancel_callback), NULL);
356         gtk_box_pack_start(GTK_BOX(action_area), cancelbutton, FALSE, FALSE, 0);
357
358         gtk_widget_show_all(dialog);
359         return GTK_DIALOG(dialog);
360 }
361
362
363 /**********************************************************************
364  * Entry
365  **********************************************************************/
366
367 #ifdef HILDON_CP_APPLET
368 /*
369  * Application was started from control panel.
370  */
371 osso_return_t execute(osso_context_t *osso,
372                       gpointer userdata, gboolean user_activated) {
373         HildonProgram *program;
374         GtkDialog *dialog;
375
376         program = HILDON_PROGRAM(hildon_program_get_instance());
377         if (osso == NULL)
378                 return OSSO_ERROR;
379
380         dialog = GTK_DIALOG(swb_config_dialog());
381         load_config();
382         gtk_dialog_run(dialog);
383         gtk_widget_destroy(GTK_WIDGET(dialog));
384
385         return OSSO_OK;
386 }
387 #else
388 /*
389  * Application was started from command line.
390  */
391 int main(int argc, char *argv[]) {
392         GtkDialog *dialog;
393 #ifdef HILDON
394         HildonProgram *program = NULL;
395         program = HILDON_PROGRAM(hildon_program_get_instance());
396 #endif
397
398         gtk_init(&argc, &argv);
399
400         g_set_application_name("Browser Switchboard");
401
402         dialog = GTK_DIALOG(swb_config_dialog());
403         load_config();
404         gtk_dialog_run(dialog);
405         gtk_widget_destroy(GTK_WIDGET(dialog));
406
407         exit(0);
408 }
409 #endif