c52ac73f96deb17ec744bed95a37432b68c8fd5a
[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 #include <gtk/gtksignal.h>
33 #include <gdk/gdkkeysyms.h>
34
35 #include "hildon-volumebar.h"
36 #include "hildon-volumebar-range.h"
37 #include "hildon-volumebar-private.h"
38
39 static GtkContainerClass *parent_class;
40
41 static void
42 hildon_volumebar_class_init(HildonVolumebarClass * volumebar_class);       
43 static void 
44 hildon_volumebar_init(HildonVolumebar * volumebar);
45
46 static void 
47 hildon_child_forall(GtkContainer * container,
48                     gboolean include_internals,
49                     GtkCallback callback,
50                     gpointer callback_data);
51 static void 
52 hildon_volumebar_destroy(GtkObject * self);
53
54 static void hildon_volumebar_set_property(GObject * object,
55                                            guint prop_id,
56                                            const GValue * value,
57                                            GParamSpec * pspec);
58 static void hildon_volumebar_get_property(GObject * object,
59                                            guint prop_id,
60                                            GValue * value, 
61                                            GParamSpec * pspec);
62
63 static void mute_toggled (HildonVolumebar *self, gpointer data);
64
65 static gboolean
66 hildon_volumebar_key_press(GtkWidget * widget,
67                            GdkEventKey * event,
68                            gpointer data);
69
70
71 enum 
72 {
73     MUTE_TOGGLED_SIGNAL,
74     LEVEL_CHANGED_SIGNAL,
75     LAST_SIGNAL
76 };
77
78 enum {
79     PROP_NONE = 0,
80     PROP_HILDON_HAS_MUTE,
81     PROP_HILDON_FOCUSABLE
82 };
83
84 static guint signals[LAST_SIGNAL] = { 0 };
85
86 GType 
87 hildon_volumebar_get_type(void)
88 {
89     static GType volumebar_type = 0;
90
91     if (!volumebar_type) {
92         static const GTypeInfo volumebar_info = {
93             sizeof(HildonVolumebarClass),
94             NULL,       /* base_init */
95             NULL,       /* base_finalize */
96             (GClassInitFunc) hildon_volumebar_class_init,
97             NULL,       /* class_finalize */
98             NULL,       /* class_data */
99             sizeof(HildonVolumebar),
100             0,  /* n_preallocs */
101             (GInstanceInitFunc) hildon_volumebar_init,
102         };
103         volumebar_type = g_type_register_static(GTK_TYPE_CONTAINER,
104                                                 "HildonVolumebar",
105                                                 &volumebar_info, 0);
106     }
107     return volumebar_type;
108 }
109
110 static void 
111 hildon_volumebar_class_init(HildonVolumebarClass *volumebar_class)
112 {
113     GtkContainerClass *container_class =
114         GTK_CONTAINER_CLASS(volumebar_class);
115     GObjectClass *object_class = G_OBJECT_CLASS(volumebar_class);
116
117     parent_class = g_type_class_peek_parent(volumebar_class);
118
119     g_type_class_add_private(volumebar_class,
120                              sizeof(HildonVolumebarPrivate));
121
122     /* Because we derived our widget from GtkContainer, we should also
123        override forall method */
124     container_class->forall = hildon_child_forall;
125     GTK_OBJECT_CLASS(volumebar_class)->destroy = hildon_volumebar_destroy;
126
127     signals[MUTE_TOGGLED_SIGNAL] = g_signal_new("mute_toggled",
128                                                 G_OBJECT_CLASS_TYPE
129                                                 (object_class),
130                                                 G_SIGNAL_RUN_LAST |
131                                                 G_SIGNAL_ACTION,
132                                                 G_STRUCT_OFFSET
133                                                 (HildonVolumebarClass,
134                                                  mute_toggled), NULL, NULL,
135                                                 gtk_marshal_VOID__VOID,
136                                                 G_TYPE_NONE, 0);
137
138     signals[LEVEL_CHANGED_SIGNAL] = g_signal_new("level_changed",
139                                                  G_OBJECT_CLASS_TYPE
140                                                  (object_class),
141                                                  G_SIGNAL_RUN_LAST |
142                                                  G_SIGNAL_ACTION,
143                                                  G_STRUCT_OFFSET
144                                                  (HildonVolumebarClass,
145                                                   level_changed), NULL,
146                                                  NULL,
147                                                  gtk_marshal_VOID__VOID,
148                                                  G_TYPE_NONE, 0);
149     
150     object_class->set_property = hildon_volumebar_set_property;
151     object_class->get_property = hildon_volumebar_get_property; 
152
153     /*This kind of property could be usefull in the gtkcontainer*/
154     g_object_class_install_property(object_class,
155                                     PROP_HILDON_FOCUSABLE, 
156                                     g_param_spec_boolean("can-focus",
157                                     "The widget focusablility",
158                                 "The widget focusablility. TRUE is focusable",
159                                     TRUE,
160                                     G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
161
162     g_object_class_install_property(object_class,
163                                     PROP_HILDON_HAS_MUTE, 
164                                     g_param_spec_boolean("has_mute",
165                                     "Show/Hide the mute button",
166                "Whether the mute button is visible. Default value: TRUE",
167                                     TRUE,
168                                     G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
169
170 }
171
172 static void 
173 hildon_volumebar_init(HildonVolumebar * volumebar)
174 {
175     HildonVolumebarPrivate *priv;
176
177     priv = HILDON_VOLUMEBAR_GET_PRIVATE(volumebar);
178
179     /* Should set GTK_NO_WINDOW flag, because widget is derived from
180        GtkContainer */
181     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(volumebar), GTK_NO_WINDOW);
182     GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(volumebar), GTK_CAN_FOCUS);
183     
184     priv->tbutton = GTK_TOGGLE_BUTTON(gtk_toggle_button_new());
185     g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
186     g_signal_connect (G_OBJECT (volumebar), "mute_toggled",
187                       G_CALLBACK (mute_toggled), NULL);
188     
189     /* set keypress handler (select hardkey) */
190     g_signal_connect(G_OBJECT(volumebar), "key-press-event",
191             G_CALLBACK(hildon_volumebar_key_press),
192             NULL);
193
194 }
195
196 static void
197 hildon_child_forall(GtkContainer * container,
198                     gboolean include_internals,
199                     GtkCallback callback, gpointer callback_data)
200 {
201     HildonVolumebar *vbar;
202     HildonVolumebarPrivate *priv;
203
204     vbar = HILDON_VOLUMEBAR(container);
205     priv = HILDON_VOLUMEBAR_GET_PRIVATE(vbar);
206
207     g_return_if_fail(callback != NULL);
208
209     if (!include_internals)
210         return;
211
212     (*callback) (GTK_WIDGET(priv->tbutton), callback_data);
213     (*callback) (GTK_WIDGET(priv->volumebar), callback_data);
214 }
215
216 static void 
217 hildon_volumebar_destroy(GtkObject * self)
218 {
219     HildonVolumebarPrivate *priv;
220
221     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
222
223     if (priv->tbutton) {
224         gtk_widget_unparent(GTK_WIDGET(priv->tbutton));
225         priv->tbutton = NULL;
226     }
227     if (priv->volumebar) {
228         gtk_widget_unparent(GTK_WIDGET(priv->volumebar));
229         priv->volumebar = NULL;
230     }
231
232     if (GTK_OBJECT_CLASS(parent_class)->destroy)
233         GTK_OBJECT_CLASS(parent_class)->destroy(self);
234 }
235
236 static void
237 hildon_volumebar_set_property(GObject * object,
238                               guint prop_id,
239                               const GValue * value, 
240                               GParamSpec * pspec)
241 {  
242     HildonVolumebar *vbar = HILDON_VOLUMEBAR(object);
243     HildonVolumebarPrivate *priv;
244     gboolean has_mute = TRUE;
245
246     priv = HILDON_VOLUMEBAR_GET_PRIVATE(vbar)
247
248     switch (prop_id) {
249     case PROP_HILDON_HAS_MUTE:
250         has_mute = g_value_get_boolean(value);
251
252         if (has_mute)
253         {
254             gtk_widget_show(GTK_WIDGET(priv->tbutton));
255
256         }
257         else
258         {
259             gtk_widget_hide(GTK_WIDGET(priv->tbutton));
260         }
261         
262         break;
263     case PROP_HILDON_FOCUSABLE:
264         g_object_set( G_OBJECT(priv->volumebar), "can-focus", 
265                       g_value_get_boolean(value), NULL );
266         break;
267     default:
268         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
269
270         break;
271     }
272 }
273
274 static void
275 hildon_volumebar_get_property(GObject * object,
276                               guint prop_id, GValue * value, 
277                               GParamSpec * pspec)
278 {
279   HildonVolumebarPrivate *priv;
280   priv = HILDON_VOLUMEBAR_GET_PRIVATE(object)
281     switch (prop_id) {
282     case PROP_HILDON_HAS_MUTE:
283         g_value_set_boolean(value, g_value_get_boolean(value));
284         break;
285      case PROP_HILDON_FOCUSABLE:
286         g_value_set_boolean(value, g_value_get_boolean(value));
287         g_object_set( G_OBJECT(priv->volumebar), "can-focus", 
288                       g_value_get_boolean(value), NULL );
289     default:
290         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
291         break;
292     }
293 }
294
295 /**
296  * hildon_volumebar_level_change:
297  * @self: a HildonVolumebar widget.
298  *
299  * Emits "level_changed" signal to the given volumebar. This function
300  * is mainly used by derived classes.
301  */
302 void 
303 hildon_volumebar_level_change(HildonVolumebar * self)
304 {
305     g_return_if_fail(HILDON_IS_VOLUMEBAR(self));
306     g_signal_emit_by_name(GTK_WIDGET(self), "level_changed");
307 }
308
309 /**
310  * hildon_volumebar_set_level:
311  * @self: volumebar to change level on
312  * @level: new level
313  *
314  * Sets new volumelevel for this #HildonVolumebar.
315  **/
316 void 
317 hildon_volumebar_set_level(HildonVolumebar * self, gdouble level)
318 {
319     HildonVolumebarPrivate *priv;
320
321     g_return_if_fail(self);
322
323     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
324    
325     /* No need to clamp the level to legal values here as volumebarrange
326      * will do it anyway. And here we don't know the correct values anyway.
327      */
328     hildon_volumebar_range_set_level(priv->volumebar, level);
329 }
330
331 /**
332  * hildon_volumebar_get_level:
333  * @self: volumebar to query level on
334  *
335  * Gets the volumelevel of this #HildonVolumebar.
336  *
337  * Return value: Volume level.
338  **/
339 gdouble 
340 hildon_volumebar_get_level(HildonVolumebar * self)
341 {
342     HildonVolumebarPrivate *priv;
343
344     g_return_val_if_fail(self, -1);
345
346     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
347
348     return hildon_volumebar_range_get_level(priv->volumebar);
349 }
350
351 /**
352  * hildon_volumebar_set_mute:
353  * @self: volumebar to work on
354  * @mute: mute ON/OFF
355  *
356  * Sets mute status for this #HildonVolumebar.
357  *
358  **/
359 void 
360 hildon_volumebar_set_mute(HildonVolumebar * self, gboolean mute)
361 {
362     HildonVolumebarPrivate *priv;
363
364     g_return_if_fail(self);
365
366     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
367     gtk_widget_set_sensitive(GTK_WIDGET(priv->volumebar), !mute);
368     
369     if (mute){   
370         g_object_set (G_OBJECT (priv->tbutton), "can-focus", TRUE, NULL);
371         gtk_widget_grab_focus (GTK_WIDGET(priv->tbutton));
372     }
373     else
374     {
375         g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
376         gtk_widget_grab_focus (GTK_WIDGET (self));
377     }
378 }
379
380 /**
381  * hildon_volumebar_get_mute:
382  * @self: volumebar to query mute status
383  *
384  * Gets mute status of this #HildonVolumebar (ON/OFF).
385  *
386  * Return value: Mute status as #gboolean value.
387  **/
388 gboolean 
389 hildon_volumebar_get_mute(HildonVolumebar * self)
390 {
391     HildonVolumebarPrivate *priv;
392
393     g_return_val_if_fail(self, TRUE);
394
395     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
396
397     return gtk_toggle_button_get_active(priv->tbutton);
398 }
399
400 /**
401  * hildon_volumebar_get_adjustment
402  * @self : A #HildonVolumebar
403  * 
404  * Gets the GtkAdjustment used in volumebar. This can be handy
405  * to give to hildon_appview_set_connected_adjustment which
406  * will allow changing the volume with increase / decrease
407  * hardware buttons.
408  *
409  * This is a temporary solution until volumebar is restructured to
410  * be a child class of GtkRange.
411  * 
412  * Return value: A @GtkAdjustment used by volumebar.
413  **/
414 GtkAdjustment * 
415 hildon_volumebar_get_adjustment (HildonVolumebar * self)
416 {
417     HildonVolumebarPrivate *priv;
418
419     g_return_val_if_fail(self, NULL);
420
421     priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
422
423     return gtk_range_get_adjustment (GTK_RANGE (priv->volumebar));
424 }
425
426 static void
427 mute_toggled (HildonVolumebar *self, gpointer data)
428 {
429   /* only call hildon_volumebar_set_mute. everything is done there */
430   hildon_volumebar_set_mute (self, hildon_volumebar_get_mute(self));
431 }
432
433 static gboolean
434 hildon_volumebar_key_press (GtkWidget * widget,
435                             GdkEventKey * event,
436                             gpointer data)
437 {
438     HildonVolumebarPrivate *priv;
439     
440     g_return_val_if_fail(widget, FALSE);
441     g_return_val_if_fail(event, FALSE);
442
443     priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
444     
445     if (event->keyval == GDK_Return) {
446         gtk_toggle_button_set_active(priv->tbutton, 
447                 !hildon_volumebar_get_mute(HILDON_VOLUMEBAR(widget)));
448         return TRUE;
449     }
450
451     return FALSE;
452 }