New feature: change bookmark labels.
[tweakr] / modules / tweakr-desktop.c
1 /*
2  * vim:ts=4:sw=4:et:cindent:cino=(0
3  */ 
4
5 #include <config.h>
6 #include <glib.h>
7 #include <glib/gi18n-lib.h>
8
9 #include <gtk/gtk.h>
10 #include <hildon/hildon-picker-button.h>
11 #include <hildon/hildon-touch-selector.h>
12 #include <hildon/hildon-button.h>
13 #include <hildon/hildon-entry.h>
14 #include <hildon/hildon-pannable-area.h>
15 #include <hildon/hildon-defines.h>
16 #include <gconf/gconf-client.h>
17
18 #include "libtweakr-section/tweakr-section.h"
19 #include "libtweakr-section/tweakr-module.h"
20
21
22 #define TWEAKR_TYPE_DESKTOP_SECTION \
23         (tweakr_desktop_section_type)
24 #define TWEAKR_DESKTOP_SECTION(obj) \
25         (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
26         TWEAKR_TYPE_DESKTOP_SECTION, \
27         TweakrDesktopSection))
28 #define TWEAKR_DESKTOP_SECTION_CLASS(k) \
29         (G_TYPE_CHECK_CLASS_CAST((k), \
30         TWEAKR_TYPE_DESKTOP_SECTION, \
31         TweakrDesktopSectionClass))
32 #define TWEAKR_IS_DESKTOP_SECTION(obj) \
33         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
34         TWEAKR_TYPE_DESKTOP_SECTION))
35
36 #define GCONF_BOOKMARKS "/apps/osso/hildon-home/bookmarks"
37 enum
38 {
39     SNAP_NONE,
40     SNAP_SMALL,
41     SNAP_LARGE,
42     SNAP_HUGE
43 };
44
45 enum
46 {
47     SNAP_NONE_VALUE,
48     SNAP_SMALL_VALUE = 8,
49     SNAP_LARGE_VALUE = 16,
50     SNAP_HUGE_VALUE = 32
51 };
52
53 static gint snap_values [] = {
54     SNAP_NONE_VALUE,
55     SNAP_SMALL_VALUE,
56     SNAP_LARGE_VALUE,
57     SNAP_HUGE_VALUE
58 };
59
60 typedef struct
61 {
62     gchar *path;
63     gchar *value;
64     guint modified : 1;
65 } bookmark_t;
66
67 typedef struct _TweakrDesktopSection TweakrDesktopSection;
68 typedef struct _TweakrDesktopSectionClass
69                TweakrDesktopSectionClass;
70
71 struct _TweakrDesktopSection
72 {
73     TweakrSection parent_instance;
74
75     GKeyFile *ini;
76     GtkWidget *snap_button;
77
78     GConfClient *gconf;
79     GtkWidget *bookmarks_button;
80     GtkWidget *bookmarks_dialog;
81     GtkWidget *bookmarks_box;
82     GHashTable *bookmarks_table;
83     guint save_bookmarks : 1;
84 };
85
86 struct _TweakrDesktopSectionClass
87 {
88     TweakrSectionClass parent_class;
89 };
90
91
92 static GType tweakr_desktop_section_get_type (GTypeModule *module);
93 static void tweakr_desktop_section_class_init
94     (TweakrDesktopSectionClass *class);
95 static void tweakr_desktop_section_init
96     (TweakrDesktopSection *section);
97 static void tweakr_desktop_section_dispose (GObject *obj);
98
99 static gboolean _save (TweakrSection *section,
100                        gboolean *requires_restart);
101
102 static GType tweakr_desktop_section_type = 0;
103 static TweakrSectionClass *
104     tweakr_desktop_section_parent_class = NULL;
105
106
107 G_MODULE_EXPORT void
108 tweakr_module_load (TweakrModule *module)
109 {
110     tweakr_desktop_section_get_type (G_TYPE_MODULE (module));
111 }
112
113 G_MODULE_EXPORT void
114 tweakr_module_unload (TweakrModule *module)
115 {
116 }
117
118 static GType
119 tweakr_desktop_section_get_type (GTypeModule *module)
120 {
121     if (!tweakr_desktop_section_type)
122     {
123         static const GTypeInfo section_info =
124         {
125             sizeof (TweakrDesktopSectionClass),
126             (GBaseInitFunc) NULL,
127             (GBaseFinalizeFunc) NULL,
128             (GClassInitFunc) tweakr_desktop_section_class_init,
129             NULL,           /* class_finalize */
130             NULL,           /* class_data     */
131             sizeof (TweakrDesktopSection),
132             0,              /* n_preallocs    */
133             (GInstanceInitFunc) tweakr_desktop_section_init
134         };
135
136         tweakr_desktop_section_type =
137             g_type_module_register_type (module, TWEAKR_TYPE_SECTION,
138                                          "TweakrDesktopSection",
139                                          &section_info, 0);
140     }
141
142     return tweakr_desktop_section_type;
143 }
144
145 static void
146 tweakr_desktop_section_class_init
147     (TweakrDesktopSectionClass *klass)
148 {
149     GObjectClass *object_class = G_OBJECT_CLASS (klass);
150     TweakrSectionClass *section_class =
151         TWEAKR_SECTION_CLASS (klass);
152
153     tweakr_desktop_section_parent_class =
154         g_type_class_peek_parent (klass);
155
156     section_class->name   = "_Desktop";
157     section_class->save = _save;
158
159     object_class->dispose = tweakr_desktop_section_dispose;
160 }
161
162 GtkWidget * _build_snap_to_grid (void)
163 {
164     const gchar *options[] =
165     {
166         _("No"),
167         _("Small"),
168         _("Large"),
169         _("Huge"),
170         NULL
171     };
172     gint i = 0;
173     GtkWidget *button, *selector;
174
175     selector = hildon_touch_selector_new_text ();
176     while (options[i] && options[i] != '\0')
177     {
178         hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector),
179                                            options [i++]);
180     }
181
182     button = hildon_picker_button_new (HILDON_SIZE_AUTO,
183                                        HILDON_BUTTON_ARRANGEMENT_VERTICAL);
184     hildon_gtk_widget_set_theme_size (button, HILDON_SIZE_FINGER_HEIGHT);
185
186     hildon_button_set_title (HILDON_BUTTON (button),
187                              _("Snap icons to grid"));
188     gtk_button_set_alignment (GTK_BUTTON (button), 0.0f, 0.5f);
189     hildon_picker_button_set_selector (HILDON_PICKER_BUTTON (button),
190                                        HILDON_TOUCH_SELECTOR (selector));
191
192     gtk_widget_show (button);
193     return button;
194 }
195
196 static void
197 _bookmark_t_destroy (bookmark_t *b)
198 {
199     g_free (b->path);
200     g_free (b->value);
201     g_free (b);
202 }
203
204 static void
205 _bookmark_clicked (HildonButton *button, TweakrDesktopSection *section)
206 {
207     GtkWidget *dialog, *entry;
208     gint ret;
209
210     dialog = gtk_dialog_new_with_buttons
211             (_("Edit label"),
212              GTK_WINDOW (section->bookmarks_dialog),
213              GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR,
214              GTK_STOCK_OK, GTK_RESPONSE_OK,
215              NULL);
216
217     entry = hildon_entry_new (HILDON_SIZE_FINGER_HEIGHT);
218     hildon_entry_set_text (HILDON_ENTRY (entry),
219                            hildon_button_get_title (button));
220
221     gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
222     gtk_widget_show (entry);
223
224     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), entry,
225                         TRUE, TRUE, 0);
226
227     ret = gtk_dialog_run (GTK_DIALOG (dialog));
228     if (ret == GTK_RESPONSE_OK)
229     {
230         bookmark_t *b;
231         const gchar *label;
232
233         label = hildon_entry_get_text (HILDON_ENTRY (entry));
234         if (label && label[0])
235         {
236             hildon_button_set_title (button, label);
237
238             b = g_hash_table_lookup (section->bookmarks_table, button);
239             if (b)
240             {
241                 g_free (b->value);
242                 b->value = g_strdup (label);
243                 b->modified = TRUE;
244             }
245         }
246     }
247
248     gtk_widget_destroy (dialog);
249 }
250
251 static void
252 _add_bookmark (gchar *bookmark, TweakrDesktopSection *section)
253 {
254     bookmark_t *b;
255     gchar *title, *value, *url;
256     GtkWidget *button;
257
258     b = g_new0 (bookmark_t, 1);
259     b->path = g_strconcat (bookmark, "/label", NULL);
260
261     url   = g_strconcat (bookmark, "/url",   NULL);
262     title = gconf_client_get_string (section->gconf, b->path, NULL);
263     value = gconf_client_get_string (section->gconf, url,   NULL);
264
265     g_free (url);
266
267     button = hildon_button_new_with_text (HILDON_SIZE_FINGER_HEIGHT,
268                                           HILDON_BUTTON_ARRANGEMENT_VERTICAL,
269                                           title, value);
270     gtk_button_set_alignment (GTK_BUTTON (button), 0.0f, 0.5f);
271     gtk_box_pack_start (GTK_BOX (section->bookmarks_box), button,
272                         FALSE, FALSE, 0);
273
274     g_signal_connect (button, "clicked", G_CALLBACK (_bookmark_clicked),
275                                           section);
276
277     if (section->bookmarks_table == NULL)
278     {
279         section->bookmarks_table = g_hash_table_new_full
280             (g_direct_hash, g_direct_equal, NULL,
281              (GDestroyNotify) _bookmark_t_destroy);
282     }
283     g_hash_table_insert (section->bookmarks_table, button, b);
284
285     g_free (title);
286     g_free (value);
287 }
288
289 static void
290 _edit_bookmarks_clicked (GtkButton *button, TweakrDesktopSection *section)
291 {
292     GSList *bookmarks;
293
294     bookmarks = gconf_client_all_dirs (section->gconf, GCONF_BOOKMARKS,
295                                        NULL);
296     if (bookmarks && g_slist_length (bookmarks) > 0)
297     {
298         GtkWidget *panarea;
299         gint ret;
300
301         section->bookmarks_dialog = gtk_dialog_new_with_buttons
302             (_("Edit bookmark labels"),
303              GTK_WINDOW (gtk_widget_get_ancestor
304                          (tweakr_section_get_widget
305                           (TWEAKR_SECTION (section)),
306                           GTK_TYPE_WINDOW)),
307              GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR,
308              GTK_STOCK_OK, GTK_RESPONSE_OK,
309              NULL);
310
311         panarea = hildon_pannable_area_new ();
312         section->bookmarks_box = gtk_vbox_new (FALSE, 0);
313         hildon_pannable_area_add_with_viewport
314             (HILDON_PANNABLE_AREA (panarea), section->bookmarks_box);
315         g_object_set (G_OBJECT (panarea), "height-request",
316                       MIN (350, g_slist_length (bookmarks) * 70), NULL);
317
318         g_slist_foreach (bookmarks, (GFunc) _add_bookmark, section);
319
320         gtk_box_pack_start
321             (GTK_BOX (GTK_DIALOG (section->bookmarks_dialog)->vbox),
322              panarea, TRUE, TRUE, 0);
323
324         gtk_widget_show_all (GTK_DIALOG (section->bookmarks_dialog)->vbox);
325         ret = gtk_dialog_run (GTK_DIALOG (section->bookmarks_dialog));
326         if (ret == GTK_RESPONSE_OK)
327         {
328             section->save_bookmarks = TRUE;
329         }
330         gtk_widget_destroy (section->bookmarks_dialog);
331
332         g_slist_foreach (bookmarks, (GFunc) g_free, NULL);
333         g_slist_free (bookmarks);
334     }
335 }
336
337 GtkWidget *
338 _build_bookmarks_button (TweakrDesktopSection *section)
339 {
340     GtkWidget *button;
341
342     if (!gconf_client_dir_exists (section->gconf, GCONF_BOOKMARKS, NULL))
343     {
344         return NULL;
345     }
346
347     button = hildon_button_new_with_text (HILDON_SIZE_AUTO,
348                                           HILDON_BUTTON_ARRANGEMENT_VERTICAL,
349                                           _("Edit bookmarks labels"), "");
350     gtk_button_set_alignment (GTK_BUTTON (button), 0.0f, 0.5f);
351     hildon_gtk_widget_set_theme_size (button, HILDON_SIZE_FINGER_HEIGHT);
352
353     g_signal_connect (button, "clicked",
354                       G_CALLBACK (_edit_bookmarks_clicked), section);
355     gtk_widget_show (button);
356     return button;
357 }
358
359 static void
360 tweakr_desktop_section_init (TweakrDesktopSection *section)
361 {
362     TweakrSection *iface;
363
364     gint snap_value = SNAP_NONE_VALUE;
365
366     section->snap_button = _build_snap_to_grid ();
367
368     section->ini = g_key_file_new ();
369
370     if (!g_key_file_load_from_file (section->ini, TRANSITIONS,
371                                     G_KEY_FILE_NONE, NULL))
372     {
373         g_warning ("%s: failed to load %s", G_STRFUNC, TRANSITIONS);
374         return;
375     }
376
377     snap_value = g_key_file_get_integer (section->ini, "edit_mode",
378                                          "snap_grid_size", NULL);
379
380     if (snap_value < SNAP_SMALL_VALUE)
381     {
382         hildon_picker_button_set_active
383             (HILDON_PICKER_BUTTON (section->snap_button), SNAP_NONE);
384     }
385     else if (snap_value < SNAP_LARGE_VALUE)
386     {
387         hildon_picker_button_set_active
388             (HILDON_PICKER_BUTTON (section->snap_button), SNAP_SMALL);
389     }
390     else if (snap_value < SNAP_HUGE_VALUE)
391     {
392         hildon_picker_button_set_active
393             (HILDON_PICKER_BUTTON (section->snap_button), SNAP_LARGE);
394     }
395     else
396     {
397         hildon_picker_button_set_active
398             (HILDON_PICKER_BUTTON (section->snap_button), SNAP_HUGE);
399     }
400
401     section->gconf = gconf_client_get_default ();
402     section->bookmarks_button = _build_bookmarks_button (section);
403
404     iface = TWEAKR_SECTION (section);
405     iface->name = _("Desktop");
406     iface->widget = gtk_vbox_new (FALSE, 0);
407     gtk_box_pack_start (GTK_BOX (iface->widget), section->snap_button,
408                         FALSE, FALSE, 0);
409     if (section->bookmarks_button)
410     {
411         gtk_box_pack_start (GTK_BOX (iface->widget),
412                             section->bookmarks_button,
413                             FALSE, FALSE, 0);
414     }
415 }
416
417 static void
418 tweakr_desktop_section_dispose (GObject *obj)
419 {
420     TweakrDesktopSection *section = TWEAKR_DESKTOP_SECTION (obj);
421     if (section->ini)
422     {
423         g_key_file_free (section->ini);
424         section->ini = NULL;
425     }
426
427     if (section->gconf)
428     {
429         g_object_unref (section->gconf);
430         section->gconf = NULL;
431     }
432
433     if (section->bookmarks_table)
434     {
435         g_hash_table_destroy (section->bookmarks_table);
436         section->bookmarks_table = NULL;
437     }
438
439     G_OBJECT_CLASS (tweakr_desktop_section_parent_class)->dispose
440         (obj);
441 }
442
443 static void
444 _save_bookmarks (HildonButton *button, bookmark_t *b,
445                  TweakrDesktopSection *section)
446 {
447     if (b->modified)
448     {
449         gconf_client_set_string (section->gconf, b->path, b->value, NULL);
450     }
451 }
452
453 static gboolean _save (TweakrSection *section,
454                        gboolean *requires_restart)
455 {
456     gchar *argv[3];
457     gint active;
458
459     active = hildon_picker_button_get_active
460         (HILDON_PICKER_BUTTON (TWEAKR_DESKTOP_SECTION
461                                (section)->snap_button));
462
463     argv[0] = g_strdup ("/usr/bin/tweakr-desktop-save");
464     argv[1] = g_strdup_printf ("%d", snap_values[active]);
465     argv[2] = NULL;
466
467     g_spawn_sync ("/home/user", argv, NULL,
468                   G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
469                   NULL, NULL, NULL, NULL, NULL, NULL);
470
471     g_free (argv[0]);
472     g_free (argv[1]);
473
474     if (TWEAKR_DESKTOP_SECTION (section)->save_bookmarks)
475     {
476         g_hash_table_foreach
477             (TWEAKR_DESKTOP_SECTION (section)->bookmarks_table,
478              (GHFunc) _save_bookmarks, section);
479         *requires_restart = TRUE;
480     }
481
482     return TRUE;
483 }
484