Update changelog and bump version to 0.0.17-2.
[tweakr] / modules / tweakr-profile-status-menu-widget.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.h>
11 #include <hildon/hildon-button.h>
12 #include <hildon/hildon-pannable-area.h>
13 #include <libhildondesktop/libhildondesktop.h>
14
15 #include <gconf/gconf-client.h>
16
17 #include <libprofile.h>
18
19 #define TYPE_TWEAKR_PROFILE_STATUS_PLUGIN \
20         (tweakr_profile_status_plugin_get_type ())
21 #define TWEAKR_PROFILE_STATUS_PLUGIN(obj) \
22         (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
23         TYPE_TWEAKR_PROFILE_STATUS_PLUGIN, \
24         TweakrProfileStatusPlugin))
25 #define TWEAKR_PROFILE_STATUS_PLUGIN_CLASS(klass) \
26         (G_TYPE_CHECK_CLASS_CAST ((klass), \
27         TYPE_TWEAKR_PROFILE_STATUS_PLUGIN, \
28         TweakrProfileStatusPluginClass))
29 #define IS_TWEAKR_PROFILE_STATUS_PLUGIN(obj) \
30         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
31         TYPE_TWEAKR_PROFILE_STATUS_PLUGIN))
32 #define IS_TWEAKR_PROFILE_STATUS_PLUGIN_CLASS(klass) \
33         (G_TYPE_CHECK_CLASS_TYPE ((klass), \
34         TYPE_TWEAKR_PROFILE_STATUS_PLUGIN))
35 #define TWEAKR_PROFILE_STATUS_PLUGIN_GET_CLASS(obj) \
36         (G_TYPE_INSTANCE_GET_CLASS ((obj), \
37         TYPE_TWEAKR_PROFILE_STATUS_PLUGIN, \
38         TweakrProfileStatusPluginClass))
39
40 typedef struct _TweakrProfileStatusPlugin        TweakrProfileStatusPlugin;
41 typedef struct _TweakrProfileStatusPluginClass
42                TweakrProfileStatusPluginClass;
43 typedef struct _TweakrProfileStatusPluginPrivate
44                TweakrProfileStatusPluginPrivate; 
45
46 struct _TweakrProfileStatusPlugin
47 {
48     HDStatusMenuItem parent;
49
50     TweakrProfileStatusPluginPrivate *priv;
51 };
52
53 struct _TweakrProfileStatusPluginClass
54 {
55     HDStatusMenuItemClass parent;
56 };
57
58 GType tweakr_profile_status_plugin_get_type (void);
59
60 #define TWEAKR_PROFILE_STATUS_PLUGIN_GET_PRIVATE(obj) \
61         (G_TYPE_INSTANCE_GET_PRIVATE (obj, \
62         TYPE_TWEAKR_PROFILE_STATUS_PLUGIN, \
63         TweakrProfileStatusPluginPrivate))
64
65 #define GCONF_PATH "/system/tweakr"
66
67 struct _TweakrProfileStatusPluginPrivate
68 {
69     GtkWidget *button;
70     GtkWidget *dialog;
71     GtkWidget *box;
72     GConfClient *gconf;
73     guint notify_id;
74 };
75
76 HD_DEFINE_PLUGIN_MODULE (TweakrProfileStatusPlugin,
77                          tweakr_profile_status_plugin,
78                          HD_TYPE_STATUS_MENU_ITEM);
79
80 static void
81 _process_entry (GConfEntry *entry, TweakrProfileStatusPlugin *plugin)
82 {
83     gchar *basename;
84
85     basename = g_path_get_basename (entry->key);
86
87     profile_set_value ("general", basename,
88                          gconf_value_get_string (entry->value));
89
90     g_free (basename);
91     gconf_entry_free (entry);
92 }
93
94 static void
95 _preset_clicked (HildonButton *button, TweakrProfileStatusPlugin *plugin)
96 {
97     GSList *entries;
98     const gchar *path = g_object_get_data (G_OBJECT (button), "path");
99     gchar *basename;
100
101     if (strcmp (path, "silent") == 0)
102     {
103         profile_set_profile ("silent");
104         basename = g_strdup (dgettext("osso-profiles", "profi_bd_silent"));
105     }
106     else
107     {
108         entries = gconf_client_all_entries (plugin->priv->gconf, path, NULL);
109
110         g_slist_foreach (entries, (GFunc) _process_entry, plugin);
111         g_slist_free (entries);
112
113         profile_set_profile ("general");
114
115         basename = g_path_get_basename (path);
116     }
117
118     hildon_button_set_value (HILDON_BUTTON (plugin->priv->button), basename);
119     gconf_client_set_string (plugin->priv->gconf,
120                              GCONF_PATH "/current-preset", basename, NULL);
121     g_free (basename);
122
123     gtk_dialog_response (GTK_DIALOG (plugin->priv->dialog), GTK_RESPONSE_OK);
124     hildon_banner_show_information (NULL, NULL,
125                                     _("Preset activated."));
126 }
127
128 static void
129 _add_preset (gchar *preset, TweakrProfileStatusPlugin *plugin)
130 {
131     GtkWidget *button;
132     gchar *basename;
133
134     basename = g_path_get_basename (preset);
135     button = hildon_button_new_with_text
136         (HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL,
137          basename, NULL);
138     gtk_button_set_alignment (GTK_BUTTON (button), 0.0f, 0.5f);
139     gtk_box_pack_start (GTK_BOX (plugin->priv->box), button, FALSE, FALSE, 0);
140     g_object_set_data_full (G_OBJECT (button), "path", preset,
141                             (GDestroyNotify) g_free);
142     g_signal_connect (button, "clicked", G_CALLBACK (_preset_clicked),
143                       plugin);
144 }
145
146 static void
147 _button_clicked (HildonButton *b, TweakrProfileStatusPlugin *plugin)
148 {
149     GtkWidget *panarea;
150     gint ret;
151     GSList *presets;
152     GtkWidget *parent;
153
154     parent = gtk_widget_get_ancestor (GTK_WIDGET (b), GTK_TYPE_WINDOW);
155     gtk_widget_hide (parent);
156
157     plugin->priv->dialog = gtk_dialog_new ();
158     gtk_window_set_modal (GTK_WINDOW (plugin->priv->dialog), TRUE);
159     gtk_window_set_title (GTK_WINDOW (plugin->priv->dialog),
160                           _("Select preset"));
161
162     panarea = hildon_pannable_area_new ();
163     plugin->priv->box = gtk_vbox_new (FALSE, 0);
164
165     hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (panarea),
166                                             plugin->priv->box);
167     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugin->priv->dialog)->vbox),
168                         panarea, TRUE, TRUE, 0);
169
170     presets = gconf_client_all_dirs (plugin->priv->gconf, GCONF_PATH, NULL);
171
172     g_object_set (G_OBJECT (panarea), "height-request",
173                   MIN (350, (g_slist_length (presets) + 1) * 70), NULL);
174     /*                        For the hardcoded Silent: ^ */
175
176     g_slist_foreach (presets, (GFunc) _add_preset, plugin);
177
178     /* Add hard coded Silent profile. */
179     {
180         GtkWidget *button;
181
182         button = hildon_button_new_with_text
183             (HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL,
184              dgettext("osso-profiles", "profi_bd_silent"), NULL);
185         gtk_button_set_alignment (GTK_BUTTON (button), 0.0f, 0.5f);
186         gtk_box_pack_start (GTK_BOX (plugin->priv->box), button, FALSE, FALSE, 0);
187         g_object_set_data_full (G_OBJECT (button), "path", "silent", NULL);
188         g_signal_connect (button, "clicked", G_CALLBACK (_preset_clicked),
189                           plugin);
190     }
191
192     gtk_widget_show_all (GTK_DIALOG (plugin->priv->dialog)->vbox);
193     ret = gtk_dialog_run (GTK_DIALOG (plugin->priv->dialog));
194     gtk_widget_destroy (plugin->priv->dialog);
195
196     g_slist_free (presets);
197 }
198
199 static void
200 _reshow_profile_button_real (GtkWidget *widget,
201                              TweakrProfileStatusPlugin *plugin)
202 {
203     if (g_strcmp0 (G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (widget)),
204                    "ProfilesStatusMenuItem")  == 0)
205     {
206         gtk_widget_show (widget);
207     }
208 }
209
210 static void
211 _hide_profile_button_real (GtkWidget *widget,
212                           TweakrProfileStatusPlugin *plugin)
213 {
214     if (g_strcmp0 (G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (widget)),
215                    "ProfilesStatusMenuItem")  == 0)
216     {
217         gtk_widget_hide (widget);
218     }
219 }
220
221 static GtkWidget *
222 _find_hds_container (TweakrProfileStatusPlugin *plugin)
223 {
224     GtkWidget *parent;
225     const gchar *class_name;
226
227     parent = gtk_widget_get_parent (plugin->priv->button);
228     class_name = G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (G_OBJECT (parent)));
229     while (parent != NULL && g_strcmp0 (class_name, "HDStatusMenuBox") != 0)
230     {
231         parent = gtk_widget_get_parent (parent);
232         if (parent != NULL)
233             class_name =
234                 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (G_OBJECT (parent)));
235     }
236
237     return parent;
238 }
239
240 static void
241 _reshow_profile_button (TweakrProfileStatusPlugin *plugin, gpointer data)
242 {
243     GtkWidget *container;
244
245     container = _find_hds_container (plugin);
246     if (container != NULL)
247         gtk_container_foreach (GTK_CONTAINER (container),
248                                (GtkCallback) _reshow_profile_button_real,
249                                plugin);
250 }
251
252 static void
253 _hide_profile_button (TweakrProfileStatusPlugin *plugin, gpointer data)
254 {
255     GtkWidget *container;
256
257     container = _find_hds_container (plugin);
258     if (container != NULL)
259         gtk_container_foreach (GTK_CONTAINER (container),
260                                (GtkCallback) _hide_profile_button_real,
261                                plugin);
262 }
263
264 static void
265 _create_main_button (TweakrProfileStatusPlugin *plugin)
266 {
267     gchar *current;
268     GtkWidget *image;
269
270     plugin->priv->button = hildon_button_new
271         (HILDON_SIZE_AUTO | HILDON_SIZE_FINGER_HEIGHT,
272          HILDON_BUTTON_ARRANGEMENT_VERTICAL);
273     hildon_button_set_title (HILDON_BUTTON (plugin->priv->button),
274                              dgettext ("osso-profiles", "profi_ti_menu_plugin"));
275
276     current = gconf_client_get_string (plugin->priv->gconf,
277                                        GCONF_PATH "/current-preset",
278                                        NULL);
279
280     hildon_button_set_value (HILDON_BUTTON (plugin->priv->button), current);
281     g_free (current);
282     gtk_button_set_alignment (GTK_BUTTON (plugin->priv->button), 0.0f, 0.5f);
283
284     image = gtk_image_new_from_icon_name ("general_profile",
285                                           GTK_ICON_SIZE_BUTTON);
286     hildon_button_set_image (HILDON_BUTTON (plugin->priv->button), image);
287     hildon_button_set_style (HILDON_BUTTON (plugin->priv->button),
288                              HILDON_BUTTON_STYLE_PICKER);
289     g_signal_connect (G_OBJECT (plugin->priv->button), "clicked",
290                       G_CALLBACK (_button_clicked), plugin);
291
292     gtk_container_add (GTK_CONTAINER (plugin), plugin->priv->button);
293
294     /* Now go ahead and hide the real Profile button. Nasty, I know. */
295     if (GTK_WIDGET_REALIZED (plugin))
296         _hide_profile_button (plugin, NULL);
297     else
298         g_signal_connect (plugin, "realize",
299                           G_CALLBACK (_hide_profile_button), NULL);
300
301     g_signal_connect (plugin, "unrealize",
302                       G_CALLBACK (_reshow_profile_button), NULL);
303
304
305     gtk_widget_show_all (plugin->priv->button);
306 }
307
308 static void
309 _current_preset_changed_cb (GConfClient *client, guint notify_id,
310                             GConfEntry *entry,
311                             TweakrProfileStatusPlugin *plugin)
312 {
313     if (plugin->priv->button == NULL)
314     {
315         _create_main_button (plugin);
316         gtk_widget_show (GTK_WIDGET (plugin));
317     }
318     else
319     {
320         hildon_button_set_value (HILDON_BUTTON (plugin->priv->button),
321                                  gconf_value_get_string (entry->value));
322     }
323 }
324
325
326 static void
327 tweakr_profile_status_plugin_class_finalize
328     (TweakrProfileStatusPluginClass *klass)
329 {
330 }
331
332 static void
333 tweakr_profile_status_plugin_dispose (GObject *obj)
334 {
335     TweakrProfileStatusPlugin *plugin = TWEAKR_PROFILE_STATUS_PLUGIN (obj);
336
337     if (plugin->priv->gconf != NULL)
338     {
339         if (plugin->priv->notify_id)
340         {
341             gconf_client_notify_remove (plugin->priv->gconf,
342                                         plugin->priv->notify_id);
343             plugin->priv->notify_id = 0;
344         }
345
346         gconf_client_remove_dir (plugin->priv->gconf, GCONF_PATH, NULL);
347         g_object_unref (plugin->priv->gconf);
348         plugin->priv->gconf = NULL;
349     }
350
351     G_OBJECT_CLASS (tweakr_profile_status_plugin_parent_class)->dispose (obj);
352 }
353
354 static void
355 tweakr_profile_status_plugin_class_init
356     (TweakrProfileStatusPluginClass *klass)
357 {
358     GObjectClass *object_class = G_OBJECT_CLASS (klass);
359
360     object_class->dispose = tweakr_profile_status_plugin_dispose;
361
362     g_type_class_add_private (klass,
363                               sizeof (TweakrProfileStatusPluginPrivate));
364 }
365
366 static void
367 tweakr_profile_status_plugin_init (TweakrProfileStatusPlugin *plugin)
368 {
369     gchar *current;
370
371     plugin->priv = TWEAKR_PROFILE_STATUS_PLUGIN_GET_PRIVATE (plugin);
372
373     plugin->priv->gconf = gconf_client_get_default ();
374     gconf_client_add_dir (plugin->priv->gconf, GCONF_PATH,
375                           GCONF_CLIENT_PRELOAD_NONE, NULL);
376     plugin->priv->notify_id = gconf_client_notify_add
377         (plugin->priv->gconf, GCONF_PATH "/current-preset",
378          (GConfClientNotifyFunc) _current_preset_changed_cb, plugin,
379          NULL, NULL);
380
381     current = gconf_client_get_string (plugin->priv->gconf,
382                                        GCONF_PATH "/current-preset",
383                                        NULL);
384
385     if (current == NULL)
386         return;
387
388     _create_main_button (plugin);
389     gtk_widget_show (GTK_WIDGET (plugin));
390     g_free (current);
391 }
392