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