Update ChangeLog.
[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     }
105     else
106     {
107         entries = gconf_client_all_entries (plugin->priv->gconf, path, NULL);
108
109         g_slist_foreach (entries, (GFunc) _process_entry, plugin);
110         g_slist_free (entries);
111
112         profile_set_profile ("general");
113
114         basename = g_path_get_basename (path);
115         hildon_button_set_value (HILDON_BUTTON (plugin->priv->button), basename);
116         gconf_client_set_string (plugin->priv->gconf,
117                                  GCONF_PATH "/current-preset", basename, NULL);
118         g_free (basename);
119     }
120
121     gtk_dialog_response (GTK_DIALOG (plugin->priv->dialog), GTK_RESPONSE_OK);
122     hildon_banner_show_information (NULL, NULL,
123                                     _("Preset activated."));
124 }
125
126 static void
127 _add_preset (gchar *preset, TweakrProfileStatusPlugin *plugin)
128 {
129     GtkWidget *button;
130     gchar *basename;
131
132     basename = g_path_get_basename (preset);
133     button = hildon_button_new_with_text
134         (HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL,
135          basename, NULL);
136     gtk_button_set_alignment (GTK_BUTTON (button), 0.0f, 0.5f);
137     gtk_box_pack_start (GTK_BOX (plugin->priv->box), button, FALSE, FALSE, 0);
138     g_object_set_data_full (G_OBJECT (button), "path", preset,
139                             (GDestroyNotify) g_free);
140     g_signal_connect (button, "clicked", G_CALLBACK (_preset_clicked),
141                       plugin);
142 }
143
144 static void
145 _button_clicked (HildonButton *b, TweakrProfileStatusPlugin *plugin)
146 {
147     GtkWidget *panarea;
148     gint ret;
149     GSList *presets;
150     GtkWidget *parent;
151
152     parent = gtk_widget_get_ancestor (GTK_WIDGET (b), GTK_TYPE_WINDOW);
153     gtk_widget_hide (parent);
154
155     plugin->priv->dialog = gtk_dialog_new ();
156     gtk_window_set_modal (GTK_WINDOW (plugin->priv->dialog), TRUE);
157     gtk_window_set_title (GTK_WINDOW (plugin->priv->dialog),
158                           _("Select preset"));
159
160     panarea = hildon_pannable_area_new ();
161     plugin->priv->box = gtk_vbox_new (FALSE, 0);
162
163     hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (panarea),
164                                             plugin->priv->box);
165     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugin->priv->dialog)->vbox),
166                         panarea, TRUE, TRUE, 0);
167
168     presets = gconf_client_all_dirs (plugin->priv->gconf, GCONF_PATH, NULL);
169
170     g_object_set (G_OBJECT (panarea), "height-request",
171                   MIN (350, (g_slist_length (presets) + 1) * 70), NULL);
172     /*                        For the hardcoded Silent: ^ */
173
174     g_slist_foreach (presets, (GFunc) _add_preset, plugin);
175
176     /* Add hard coded Silent profile. */
177     {
178         GtkWidget *button;
179
180         button = hildon_button_new_with_text
181             (HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL,
182              dgettext("osso-profiles", "profi_bd_silent"), NULL);
183         gtk_button_set_alignment (GTK_BUTTON (button), 0.0f, 0.5f);
184         gtk_box_pack_start (GTK_BOX (plugin->priv->box), button, FALSE, FALSE, 0);
185         g_object_set_data_full (G_OBJECT (button), "path", "silent", NULL);
186         g_signal_connect (button, "clicked", G_CALLBACK (_preset_clicked),
187                           plugin);
188     }
189
190     gtk_widget_show_all (GTK_DIALOG (plugin->priv->dialog)->vbox);
191     ret = gtk_dialog_run (GTK_DIALOG (plugin->priv->dialog));
192     gtk_widget_destroy (plugin->priv->dialog);
193
194     g_slist_free (presets);
195 }
196
197 static void
198 _reshow_profile_button_real (GtkWidget *widget,
199                              TweakrProfileStatusPlugin *plugin)
200 {
201     if (g_strcmp0 (G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (widget)),
202                    "ProfilesStatusMenuItem")  == 0)
203     {
204         gtk_widget_show (widget);
205     }
206 }
207
208 static void
209 _hide_profile_button_real (GtkWidget *widget,
210                           TweakrProfileStatusPlugin *plugin)
211 {
212     if (g_strcmp0 (G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (widget)),
213                    "ProfilesStatusMenuItem")  == 0)
214     {
215         gtk_widget_hide (widget);
216     }
217 }
218
219 static GtkWidget *
220 _find_hds_container (TweakrProfileStatusPlugin *plugin)
221 {
222     GtkWidget *parent;
223     const gchar *class_name;
224
225     parent = gtk_widget_get_parent (plugin->priv->button);
226     class_name = G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (G_OBJECT (parent)));
227     while (parent != NULL && g_strcmp0 (class_name, "HDStatusMenuBox") != 0)
228     {
229         parent = gtk_widget_get_parent (parent);
230         if (parent != NULL)
231             class_name =
232                 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (G_OBJECT (parent)));
233     }
234
235     return parent;
236 }
237
238 static void
239 _reshow_profile_button (TweakrProfileStatusPlugin *plugin, gpointer data)
240 {
241     GtkWidget *container;
242
243     container = _find_hds_container (plugin);
244     if (container != NULL)
245         gtk_container_foreach (GTK_CONTAINER (container),
246                                (GtkCallback) _reshow_profile_button_real,
247                                plugin);
248 }
249
250 static void
251 _hide_profile_button (TweakrProfileStatusPlugin *plugin, gpointer data)
252 {
253     GtkWidget *container;
254
255     container = _find_hds_container (plugin);
256     if (container != NULL)
257         gtk_container_foreach (GTK_CONTAINER (container),
258                                (GtkCallback) _hide_profile_button_real,
259                                plugin);
260 }
261
262 static void
263 _create_main_button (TweakrProfileStatusPlugin *plugin)
264 {
265     gchar *current;
266     GtkWidget *image;
267
268     plugin->priv->button = hildon_button_new
269         (HILDON_SIZE_AUTO | HILDON_SIZE_FINGER_HEIGHT,
270          HILDON_BUTTON_ARRANGEMENT_VERTICAL);
271     hildon_button_set_title (HILDON_BUTTON (plugin->priv->button),
272                              dgettext ("osso-profiles", "profi_ti_menu_plugin"));
273
274     current = gconf_client_get_string (plugin->priv->gconf,
275                                        GCONF_PATH "/current-preset",
276                                        NULL);
277
278     hildon_button_set_value (HILDON_BUTTON (plugin->priv->button), current);
279     g_free (current);
280     gtk_button_set_alignment (GTK_BUTTON (plugin->priv->button), 0.0f, 0.5f);
281
282     image = gtk_image_new_from_icon_name ("general_profile",
283                                           GTK_ICON_SIZE_BUTTON);
284     hildon_button_set_image (HILDON_BUTTON (plugin->priv->button), image);
285     hildon_button_set_style (HILDON_BUTTON (plugin->priv->button),
286                              HILDON_BUTTON_STYLE_PICKER);
287     g_signal_connect (G_OBJECT (plugin->priv->button), "clicked",
288                       G_CALLBACK (_button_clicked), plugin);
289
290     gtk_container_add (GTK_CONTAINER (plugin), plugin->priv->button);
291
292     /* Now go ahead and hide the real Profile button. Nasty, I know. */
293     if (GTK_WIDGET_REALIZED (plugin))
294         _hide_profile_button (plugin, NULL);
295     else
296         g_signal_connect (plugin, "realize",
297                           G_CALLBACK (_hide_profile_button), NULL);
298
299     g_signal_connect (plugin, "unrealize",
300                       G_CALLBACK (_reshow_profile_button), NULL);
301
302
303     gtk_widget_show_all (plugin->priv->button);
304 }
305
306 static void
307 _current_preset_changed_cb (GConfClient *client, guint notify_id,
308                             GConfEntry *entry,
309                             TweakrProfileStatusPlugin *plugin)
310 {
311     if (plugin->priv->button == NULL)
312     {
313         _create_main_button (plugin);
314         gtk_widget_show (GTK_WIDGET (plugin));
315     }
316     else
317     {
318         hildon_button_set_value (HILDON_BUTTON (plugin->priv->button),
319                                  gconf_value_get_string (entry->value));
320     }
321 }
322
323
324 static void
325 tweakr_profile_status_plugin_class_finalize
326     (TweakrProfileStatusPluginClass *klass)
327 {
328 }
329
330 static void
331 tweakr_profile_status_plugin_dispose (GObject *obj)
332 {
333     TweakrProfileStatusPlugin *plugin = TWEAKR_PROFILE_STATUS_PLUGIN (obj);
334
335     if (plugin->priv->gconf != NULL)
336     {
337         if (plugin->priv->notify_id)
338         {
339             gconf_client_notify_remove (plugin->priv->gconf,
340                                         plugin->priv->notify_id);
341             plugin->priv->notify_id = 0;
342         }
343
344         gconf_client_remove_dir (plugin->priv->gconf, GCONF_PATH, NULL);
345         g_object_unref (plugin->priv->gconf);
346         plugin->priv->gconf = NULL;
347     }
348
349     G_OBJECT_CLASS (tweakr_profile_status_plugin_parent_class)->dispose (obj);
350 }
351
352 static void
353 tweakr_profile_status_plugin_class_init
354     (TweakrProfileStatusPluginClass *klass)
355 {
356     GObjectClass *object_class = G_OBJECT_CLASS (klass);
357
358     object_class->dispose = tweakr_profile_status_plugin_dispose;
359
360     g_type_class_add_private (klass,
361                               sizeof (TweakrProfileStatusPluginPrivate));
362 }
363
364 static void
365 tweakr_profile_status_plugin_init (TweakrProfileStatusPlugin *plugin)
366 {
367     gchar *current;
368
369     plugin->priv = TWEAKR_PROFILE_STATUS_PLUGIN_GET_PRIVATE (plugin);
370
371     plugin->priv->gconf = gconf_client_get_default ();
372     gconf_client_add_dir (plugin->priv->gconf, GCONF_PATH,
373                           GCONF_CLIENT_PRELOAD_NONE, NULL);
374     plugin->priv->notify_id = gconf_client_notify_add
375         (plugin->priv->gconf, GCONF_PATH "/current-preset",
376          (GConfClientNotifyFunc) _current_preset_changed_cb, plugin,
377          NULL, NULL);
378
379     current = gconf_client_get_string (plugin->priv->gconf,
380                                        GCONF_PATH "/current-preset",
381                                        NULL);
382
383     if (current == NULL)
384         return;
385
386     _create_main_button (plugin);
387     gtk_widget_show (GTK_WIDGET (plugin));
388     g_free (current);
389 }
390