Only edit desktop bookmarks that are on some view.
[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     gchar *view_path;
263
264     b = g_new0 (bookmark_t, 1);
265     b->path = g_strconcat (bookmark, "/label", NULL);
266
267     url   = g_strconcat (bookmark, "/url",   NULL);
268     title = gconf_client_get_string (section->gconf, b->path, NULL);
269     value = gconf_client_get_string (section->gconf, url,     NULL);
270
271     g_free (url);
272
273     bookmark_name = g_path_get_basename (bookmark);
274     applet_path = g_strconcat (GCONF_APPLETS, "/BookmarkShortcut:",
275                                bookmark_name, NULL);
276     view_path = g_strconcat (applet_path, "/view", NULL);
277     if (applet_path &&
278         gconf_client_dir_exists (section->gconf, applet_path, NULL) &&
279         gconf_client_get_int (section->gconf, view_path, NULL) != 0)
280     {
281         button = hildon_button_new_with_text
282             (HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL,
283              title, value);
284         gtk_button_set_alignment (GTK_BUTTON (button), 0.0f, 0.5f);
285         gtk_box_pack_start (GTK_BOX (section->bookmarks_box), button,
286                             FALSE, FALSE, 0);
287
288         g_signal_connect (button, "clicked", G_CALLBACK (_bookmark_clicked),
289                                               section);
290
291         if (section->bookmarks_table == NULL)
292         {
293             section->bookmarks_table = g_hash_table_new_full
294                 (g_direct_hash, g_direct_equal, NULL,
295                  (GDestroyNotify) _bookmark_t_destroy);
296         }
297         g_hash_table_insert (section->bookmarks_table, button, b);
298     }
299     else
300     {
301         _bookmark_t_destroy (b);
302     }
303
304     g_free (title);
305     g_free (value);
306     g_free (bookmark_name);
307     g_free (applet_path);
308     g_free (view_path);
309 }
310
311 static void
312 _edit_bookmarks_clicked (GtkButton *button, TweakrDesktopSection *section)
313 {
314     GSList *bookmarks;
315
316     bookmarks = gconf_client_all_dirs (section->gconf, GCONF_BOOKMARKS,
317                                        NULL);
318     if (bookmarks && g_slist_length (bookmarks) > 0)
319     {
320         GtkWidget *panarea;
321         gint ret;
322
323         if (section->bookmarks_dialog == NULL)
324         {
325             section->bookmarks_dialog = gtk_dialog_new_with_buttons
326                 (_("Edit desktop bookmarks"),
327                  GTK_WINDOW (gtk_widget_get_ancestor
328                              (tweakr_section_get_widget
329                               (TWEAKR_SECTION (section)),
330                               GTK_TYPE_WINDOW)),
331                  GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR,
332                  GTK_STOCK_OK, GTK_RESPONSE_OK,
333                  NULL);
334
335             panarea = hildon_pannable_area_new ();
336             section->bookmarks_box = gtk_vbox_new (FALSE, 0);
337             hildon_pannable_area_add_with_viewport
338                 (HILDON_PANNABLE_AREA (panarea), section->bookmarks_box);
339             g_object_set (G_OBJECT (panarea), "height-request",
340                           MIN (350, g_slist_length (bookmarks) * 70), NULL);
341
342             g_slist_foreach (bookmarks, (GFunc) _add_bookmark, section);
343
344             gtk_box_pack_start
345                 (GTK_BOX (GTK_DIALOG (section->bookmarks_dialog)->vbox),
346                  panarea, TRUE, TRUE, 0);
347         }
348         gtk_widget_show_all (GTK_DIALOG (section->bookmarks_dialog)->vbox);
349         ret = gtk_dialog_run (GTK_DIALOG (section->bookmarks_dialog));
350         if (ret == GTK_RESPONSE_OK)
351         {
352             section->save_bookmarks = TRUE;
353         }
354         gtk_widget_hide (section->bookmarks_dialog);
355
356         g_slist_foreach (bookmarks, (GFunc) g_free, NULL);
357         g_slist_free (bookmarks);
358     }
359 }
360
361 static GtkWidget *
362 _build_bookmarks_button (TweakrDesktopSection *section)
363 {
364     GtkWidget *button;
365
366     if (!gconf_client_dir_exists (section->gconf, GCONF_BOOKMARKS, NULL))
367     {
368         return NULL;
369     }
370
371     button = hildon_button_new_with_text (HILDON_SIZE_AUTO,
372                                           HILDON_BUTTON_ARRANGEMENT_VERTICAL,
373                                           _("Edit desktop bookmarks"), "");
374     gtk_button_set_alignment (GTK_BUTTON (button), 0.0f, 0.5f);
375     hildon_gtk_widget_set_theme_size (button, HILDON_SIZE_FINGER_HEIGHT);
376
377     g_signal_connect (button, "clicked",
378                       G_CALLBACK (_edit_bookmarks_clicked), section);
379     gtk_widget_show (button);
380     return button;
381 }
382
383 static void
384 tweakr_desktop_section_init (TweakrDesktopSection *section)
385 {
386     TweakrSection *iface;
387
388     gint snap_value = SNAP_NONE_VALUE;
389
390     section->ini = g_key_file_new ();
391
392     if (!g_key_file_load_from_file (section->ini, TRANSITIONS,
393                                     G_KEY_FILE_NONE, NULL))
394     {
395         g_warning ("%s: failed to load %s", G_STRFUNC, TRANSITIONS);
396         return;
397     }
398
399     if (g_key_file_has_key (section->ini, "edit_mode", "snap_grid_size",
400                             NULL))
401     {
402         section->snap_button = _build_snap_to_grid ();
403
404         snap_value = g_key_file_get_integer (section->ini, "edit_mode",
405                                              "snap_grid_size", NULL);
406
407         if (snap_value < SNAP_SMALL_VALUE)
408         {
409             hildon_picker_button_set_active
410                 (HILDON_PICKER_BUTTON (section->snap_button), SNAP_NONE);
411         }
412         else if (snap_value < SNAP_LARGE_VALUE)
413         {
414             hildon_picker_button_set_active
415                 (HILDON_PICKER_BUTTON (section->snap_button), SNAP_SMALL);
416         }
417         else if (snap_value < SNAP_HUGE_VALUE)
418         {
419             hildon_picker_button_set_active
420                 (HILDON_PICKER_BUTTON (section->snap_button), SNAP_LARGE);
421         }
422         else
423         {
424             hildon_picker_button_set_active
425                 (HILDON_PICKER_BUTTON (section->snap_button), SNAP_HUGE);
426         }
427     }
428     section->gconf = gconf_client_get_default ();
429     section->bookmarks_button = _build_bookmarks_button (section);
430
431     iface = TWEAKR_SECTION (section);
432     iface->name = _("Desktop");
433     iface->widget = gtk_vbox_new (FALSE, 0);
434
435     if (section->snap_button)
436     {
437         gtk_box_pack_start (GTK_BOX (iface->widget), section->snap_button,
438                             FALSE, FALSE, 0);
439     }
440     if (section->bookmarks_button)
441     {
442         gtk_box_pack_start (GTK_BOX (iface->widget),
443                             section->bookmarks_button,
444                             FALSE, FALSE, 0);
445     }
446 }
447
448 static void
449 tweakr_desktop_section_dispose (GObject *obj)
450 {
451     TweakrDesktopSection *section = TWEAKR_DESKTOP_SECTION (obj);
452     if (section->ini)
453     {
454         g_key_file_free (section->ini);
455         section->ini = NULL;
456     }
457
458     if (section->gconf)
459     {
460         g_object_unref (section->gconf);
461         section->gconf = NULL;
462     }
463
464     if (section->bookmarks_table)
465     {
466         g_hash_table_destroy (section->bookmarks_table);
467         section->bookmarks_table = NULL;
468     }
469
470     G_OBJECT_CLASS (tweakr_desktop_section_parent_class)->dispose
471         (obj);
472 }
473
474 static void
475 _save_bookmarks (HildonButton *button, bookmark_t *b,
476                  TweakrDesktopSection *section)
477 {
478     if (b->modified)
479     {
480         gconf_client_set_string (section->gconf, b->path, b->value, NULL);
481     }
482 }
483
484 static gboolean _save (TweakrSection *section,
485                        gboolean *requires_restart)
486 {
487     gchar *argv[3];
488     gint active;
489
490     active = hildon_picker_button_get_active
491         (HILDON_PICKER_BUTTON (TWEAKR_DESKTOP_SECTION
492                                (section)->snap_button));
493
494     argv[0] = g_strdup ("/usr/bin/tweakr-desktop-save");
495     argv[1] = g_strdup_printf ("%d", snap_values[active]);
496     argv[2] = NULL;
497
498     g_spawn_sync ("/home/user", argv, NULL,
499                   G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
500                   NULL, NULL, NULL, NULL, NULL, NULL);
501
502     g_free (argv[0]);
503     g_free (argv[1]);
504
505     if (TWEAKR_DESKTOP_SECTION (section)->save_bookmarks)
506     {
507         g_hash_table_foreach
508             (TWEAKR_DESKTOP_SECTION (section)->bookmarks_table,
509              (GHFunc) _save_bookmarks, section);
510         *requires_restart = TRUE;
511     }
512
513     return TRUE;
514 }
515