latest update
[hildon] / hildon-widgets / hildon-volumebar.c
1 /*
2  * This file is part of hildon-libs
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Luc Pionchon <luc.pionchon@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /*
26  * @file hildon-volumebar.c
27  *
28  * This file contains the implementation of the Hildon Volumebar.
29  * It is a base class for Hildon Vertical Volumebar and for
30  * Hildon Horizontal Volumebar classes.
31  *
32  */
33
34 #include <gtk/gtkwindow.h>
35 #include <gtk/gtksignal.h>
36 #include <gdk/gdkkeysyms.h>
37
38 #include "hildon-volumebar.h"
39 #include "hildon-volumebar-range.h"
40 #include "hildon-volumebar-private.h"
41
42 static GtkContainerClass *parent_class;
43
44 static void
45 hildon_volumebar_class_init(HildonVolumebarClass * volumebar_class);       
46 static void 
47 hildon_volumebar_init(HildonVolumebar * volumebar);
48
49 static void 
50 hildon_child_forall(GtkContainer * container,
51                     gboolean include_internals,
52                     GtkCallback callback,
53                     gpointer callback_data);
54 static void 
55 hildon_volumebar_destroy(GtkObject * self);
56
57 static void hildon_volumebar_set_property(GObject * object,
58                                            guint prop_id,
59                                            const GValue * value,
60                                            GParamSpec * pspec);
61 static void hildon_volumebar_get_property(GObject * object,
62                                            guint prop_id,
63                                            GValue * value, 
64                                            GParamSpec * pspec);
65
66 static void mute_toggled (HildonVolumebar *self);
67
68 static gboolean
69 hildon_volumebar_key_press(GtkWidget * widget,
70                            GdkEventKey * event);
71
72
73 enum 
74 {
75     MUTE_TOGGLED_SIGNAL,
76     LEVEL_CHANGED_SIGNAL,
77     LAST_SIGNAL
78 };
79
80 enum {
81     PROP_NONE = 0,
82     PROP_HILDON_HAS_MUTE,
83     PROP_HILDON_FOCUSABLE,
84     PROP_HILDON_LEVEL,
85     PROP_HILDON_MUTE
86 };
87
88 static guint signals[LAST_SIGNAL] = { 0 };
89
90 GType 
91 hildon_volumebar_get_type(void)
92 {
93     static GType volumebar_type = 0;
94
95     if (!volumebar_type) {
96         static const GTypeInfo volumebar_info = {
97             sizeof(HildonVolumebarClass),
98             NULL,       /* base_init */
99             NULL,       /* base_finalize */
100             (GClassInitFunc) hildon_volumebar_class_init,
101             NULL,       /* class_finalize */
102             NULL,       /* class_data */
103             sizeof(HildonVolumebar),
104             0,  /* n_preallocs */
105             (GInstanceInitFunc) hildon_volumebar_init,
106         };
107         volumebar_type = g_type_register_static(GTK_TYPE_CONTAINER,
108                                                 "HildonVolumebar",
109                                                 &volumebar_info, 0);
110     }
111     return volumebar_type;
112 }
113
114 static void 
115 hildon_volumebar_class_init(HildonVolumebarClass *volumebar_class)
116 {
117     GtkContainerClass *container_class =
118         GTK_CONTAINER_CLASS(volumebar_class);
119     GObjectClass *object_class = G_OBJECT_CLASS(volumebar_class);
120
121     parent_class = g_type_class_peek_parent(volumebar_class);
122
123     g_type_class_add_private(volumebar_class,
124                              sizeof(HildonVolumebarPrivate));
125
126     /* Because we derived our widget from GtkContainer, we should also
127        override forall method */
128     volumebar_class->mute_toggled = mute_toggled;
129     container_class->forall = hildon_child_forall;
130     GTK_WIDGET_CLASS(volumebar_class)->key_press_event = hildon_volumebar_key_press;
131     GTK_OBJECT_CLASS(volumebar_class)->destroy = hildon_volumebar_destroy;
132
133     signals[MUTE_TOGGLED_SIGNAL] = g_signal_new("mute_toggled",
134                                                 G_OBJECT_CLASS_TYPE
135                                                 (object_class),
136                                                 G_SIGNAL_RUN_LAST |
137                                                 G_SIGNAL_ACTION,
138                                                 G_STRUCT_OFFSET
139                                                 (HildonVolumebarClass,
140                                                  mute_toggled), NULL, NULL,
141                                                 gtk_marshal_VOID__VOID,
142                                                 G_TYPE_NONE, 0);
143
144     signals[LEVEL_CHANGED_SIGNAL] = g_signal_new("level_changed",
145                                                  G_OBJECT_CLASS_TYPE
146                                                  (object_class),
147                                                  G_SIGNAL_RUN_LAST |
148                                                  G_SIGNAL_ACTION,
149                                                  G_STRUCT_OFFSET
150                                                  (HildonVolumebarClass,
151                                                   level_changed), NULL,
152                                                  NULL,
153                                                  gtk_marshal_VOID__VOID,
154                                                  G_TYPE_NONE, 0);
155     
156     object_class->set_property = hildon_volumebar_set_property;
157     object_class->get_property = hildon_volumebar_get_property; 
158
159     /*This kind of property could be usefull in the gtkcontainer*/
160     g_object_class_install_property(object_class,
161                                     PROP_HILDON_FOCUSABLE, 
162                                     g_param_spec_boolean("can-focus",
163                                     "The widget focusablility",
164                                 "The widget focusablility. TRUE is focusable",
165                                     TRUE,
166                                     G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
167
168     g_object_class_install_property(object_class,
169                                     PROP_HILDON_HAS_MUTE, 
170                                     g_param_spec_boolean("has_mute",
171                                     "Show/Hide the mute button",
172                "Whether the mute button is visible. Default value: TRUE",
173                                     TRUE,
174                                     G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
175
176     g_object_class_install_property(object_class,
177                                     PROP_HILDON_LEVEL,
178                                     g_param_spec_double("level",
179                                                         "Level",
180                                                         "Current volume level",
181                                                         0.0,
182                                                         100.0,
183                                                         50.0,
184                                                         G_PARAM_READWRITE));
185
186     g_object_class_install_property(object_class,
187                                     PROP_HILDON_MUTE,
188                                     g_param_spec_boolean("mute",
189                                                          "Mute",
190                                                          "Whether volume is muted",
191                                                          FALSE,
192                                                          G_PARAM_READWRITE));
193                                     
194
195 }
196
197 static void 
198 hildon_volumebar_init(HildonVolumebar * volumebar)
199 {
200     HildonVolumebarPrivate *priv;
201
202     priv = HILDON_VOLUMEBAR_GET_PRIVATE(volumebar);
203
204     /* Should set GTK_NO_WINDOW flag, because widget is derived from
205        GtkContainer */
206     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(volumebar), GTK_NO_WINDOW);
207     GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(volumebar), GTK_CAN_FOCUS);
208     
209     priv->tbutton = GTK_TOGGLE_BUTTON(gtk_toggle_button_new());
210     g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
211 }
212
213 static void
214 hildon_child_forall(GtkContainer * container,
215                     gboolean include_internals,
216                     GtkCallback callback, gpointer callback_data)
217 {
218     HildonVolumebar *vbar;
219     HildonVolumebarPrivate *priv;
220
221     vbar = HILDON_VOLUMEBAR(container);
222     priv = HILDON_VOLUMEBAR_GET_PRIVATE(vbar);
223
224     g_return_if_fail(callback != NULL);
225
226     if (!include_internals)
227         return;
228
229     (*callback) (GTK_WIDGET(priv->tbutton), callback_data);
230     (*callback) (GTK_WIDGET(priv->volumebar), callback_data);
231 }
232
233 static void 
234 hildon_volumebar_destroy(GtkObject * self)
235 {
236     HildonVolumebarPrivate *priv;
237
238     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
239
240     if (priv->tbutton) {
241         gtk_widget_unparent(GTK_WIDGET(priv->tbutton));
242         priv->tbutton = NULL;
243     }
244     if (priv->volumebar) {
245         gtk_widget_unparent(GTK_WIDGET(priv->volumebar));
246         priv->volumebar = NULL;
247     }
248
249     if (GTK_OBJECT_CLASS(parent_class)->destroy)
250         GTK_OBJECT_CLASS(parent_class)->destroy(self);
251 }
252
253 static void
254 hildon_volumebar_set_property(GObject * object,
255                               guint prop_id,
256                               const GValue * value, 
257                               GParamSpec * pspec)
258 {  
259     HildonVolumebar *vbar = HILDON_VOLUMEBAR(object);
260     HildonVolumebarPrivate *priv;
261
262     priv = HILDON_VOLUMEBAR_GET_PRIVATE(vbar)
263
264     switch (prop_id) {
265     case PROP_HILDON_HAS_MUTE:
266         if (g_value_get_boolean(value))
267             gtk_widget_show(GTK_WIDGET(priv->tbutton));
268         else
269             gtk_widget_hide(GTK_WIDGET(priv->tbutton));
270         break;
271     case PROP_HILDON_FOCUSABLE:
272         g_object_set( G_OBJECT(priv->volumebar), "can-focus", 
273                       g_value_get_boolean(value), NULL );
274         break;
275     case PROP_HILDON_LEVEL:
276         hildon_volumebar_set_level(HILDON_VOLUMEBAR(priv->volumebar),
277                                    g_value_get_double(value));
278         break;
279     case PROP_HILDON_MUTE:
280         hildon_volumebar_set_mute(HILDON_VOLUMEBAR(priv->volumebar),
281                                   g_value_get_boolean(value));
282         break;
283     default:
284         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
285
286         break;
287     }
288 }
289
290 static void
291 hildon_volumebar_get_property(GObject * object,
292                               guint prop_id, GValue * value, 
293                               GParamSpec * pspec)
294 {
295     HildonVolumebar *vb = HILDON_VOLUMEBAR(object);
296     HildonVolumebarPrivate *priv = HILDON_VOLUMEBAR_GET_PRIVATE(vb);
297
298     switch (prop_id) {
299     case PROP_HILDON_HAS_MUTE:
300         g_value_set_boolean(value, GTK_WIDGET_VISIBLE(priv->tbutton));
301         break;
302     case PROP_HILDON_FOCUSABLE:
303         g_value_set_boolean(value, GTK_WIDGET_CAN_FOCUS(priv->volumebar));
304         break;
305     case PROP_HILDON_LEVEL:
306         g_value_set_double(value, hildon_volumebar_get_level(vb));
307         break;
308     case PROP_HILDON_MUTE:
309         g_value_set_boolean(value, hildon_volumebar_get_mute(vb));
310         break;
311     default:
312         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
313         break;
314     }
315 }
316
317 /**
318  * hildon_volumebar_level_change:
319  * @self: a HildonVolumebar widget.
320  *
321  * Emits "level_changed" signal to the given volumebar. This function
322  * is mainly used by derived classes.
323  */
324 void 
325 hildon_volumebar_level_change(HildonVolumebar * self)
326 {
327     g_return_if_fail(HILDON_IS_VOLUMEBAR(self));
328     g_signal_emit_by_name(GTK_WIDGET(self), "level_changed");
329 }
330
331 /**
332  * hildon_volumebar_set_level:
333  * @self: volumebar to change level on
334  * @level: new level
335  *
336  * Sets new volumelevel for this #HildonVolumebar.
337  **/
338 void 
339 hildon_volumebar_set_level(HildonVolumebar * self, gdouble level)
340 {
341     HildonVolumebarPrivate *priv;
342
343     g_return_if_fail(self);
344
345     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
346    
347     /* No need to clamp the level to legal values here as volumebarrange
348      * will do it anyway. And here we don't know the correct values anyway.
349      */
350     hildon_volumebar_range_set_level(priv->volumebar, level);
351 }
352
353 /**
354  * hildon_volumebar_get_level:
355  * @self: volumebar to query level on
356  *
357  * Gets the volumelevel of this #HildonVolumebar.
358  *
359  * Return value: Volume level.
360  **/
361 gdouble 
362 hildon_volumebar_get_level(HildonVolumebar * self)
363 {
364     HildonVolumebarPrivate *priv;
365
366     g_return_val_if_fail(self, -1);
367
368     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
369
370     return hildon_volumebar_range_get_level(priv->volumebar);
371 }
372
373 /**
374  * hildon_volumebar_set_mute:
375  * @self: volumebar to work on
376  * @mute: mute ON/OFF
377  *
378  * Sets mute status for this #HildonVolumebar.
379  *
380  **/
381 void 
382 hildon_volumebar_set_mute(HildonVolumebar * self, gboolean mute)
383 {
384     HildonVolumebarPrivate *priv;
385     gboolean focusable = TRUE;
386     
387     g_return_if_fail(self);
388
389     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
390     gtk_widget_set_sensitive(GTK_WIDGET(priv->volumebar), !mute);
391     
392     focusable = GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (priv->volumebar));
393     
394     if (mute){   
395         if (focusable){
396
397             g_object_set (G_OBJECT (priv->tbutton), "can-focus", TRUE, NULL);
398             gtk_widget_grab_focus (GTK_WIDGET(priv->tbutton));
399         }
400     }
401     else
402     {
403         g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
404         
405         if (focusable){
406             gtk_widget_grab_focus (GTK_WIDGET (self));
407         }
408         else{
409             GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (self), 
410                                                       GTK_TYPE_WINDOW);
411             gtk_window_set_focus (GTK_WINDOW (win), NULL);
412         }
413     }
414
415     gtk_toggle_button_set_active(priv->tbutton, mute);
416 }
417
418 /**
419  * hildon_volumebar_get_mute:
420  * @self: volumebar to query mute status
421  *
422  * Gets mute status of this #HildonVolumebar (ON/OFF).
423  *
424  * Return value: Mute status as #gboolean value.
425  **/
426 gboolean 
427 hildon_volumebar_get_mute(HildonVolumebar * self)
428 {
429     HildonVolumebarPrivate *priv;
430
431     g_return_val_if_fail(self, TRUE);
432
433     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
434
435     return gtk_toggle_button_get_active(priv->tbutton);
436 }
437
438 /**
439  * hildon_volumebar_get_adjustment
440  * @self : A #HildonVolumebar
441  * 
442  * Gets the GtkAdjustment used in volumebar. This can be handy
443  * to give to hildon_appview_set_connected_adjustment which
444  * will allow changing the volume with increase / decrease
445  * hardware buttons.
446  *
447  * This is a temporary solution until volumebar is restructured to
448  * be a child class of GtkRange.
449  * 
450  * Return value: A @GtkAdjustment used by volumebar.
451  **/
452 GtkAdjustment * 
453 hildon_volumebar_get_adjustment (HildonVolumebar * self)
454 {
455     HildonVolumebarPrivate *priv;
456
457     g_return_val_if_fail(self, NULL);
458
459     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
460
461     return gtk_range_get_adjustment (GTK_RANGE (priv->volumebar));
462 }
463
464 static void
465 mute_toggled (HildonVolumebar *self)
466 {
467   /* only call hildon_volumebar_set_mute. everything is done there */
468   hildon_volumebar_set_mute (self, hildon_volumebar_get_mute(self));
469 }
470
471 static gboolean
472 hildon_volumebar_key_press (GtkWidget * widget,
473                             GdkEventKey * event)
474 {
475     HildonVolumebarPrivate *priv;
476     
477     g_return_val_if_fail(widget, FALSE);
478     g_return_val_if_fail(event, FALSE);
479
480     priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
481     
482     if (event->keyval == GDK_Return && GTK_WIDGET_VISIBLE(priv->tbutton)) {
483         gtk_toggle_button_set_active(priv->tbutton, 
484                 !hildon_volumebar_get_mute(HILDON_VOLUMEBAR(widget)));
485         return TRUE;
486     }
487
488     return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
489 }