2 * This file is part of hildon-libs
4 * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
6 * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
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; version 2.1 of
11 * the License or any later version.
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.
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
26 * SECTION:hildon-volumebar
27 * @short_description: Base class for widgets that display a volume bar
28 * @see_also: #HildonHVolumebar, #HildonVVolumebar
30 * #HildonVolumebar is a base class for widgets that display a volume bar that
31 * allows increasing or decreasing volume within a predefined range, and muting
32 * the volume when users click the mute icon.
35 #include <gtk/gtkwindow.h>
36 #include <gtk/gtksignal.h>
37 #include <gdk/gdkkeysyms.h>
39 #include "hildon-volumebar.h"
40 #include "hildon-volumebar-range.h"
41 #include "hildon-volumebar-private.h"
43 static GtkContainerClass *parent_class;
46 hildon_volumebar_class_init(HildonVolumebarClass * volumebar_class);
48 hildon_volumebar_init(HildonVolumebar * volumebar);
51 hildon_child_forall(GtkContainer * container,
52 gboolean include_internals,
54 gpointer callback_data);
56 hildon_volumebar_destroy(GtkObject * self);
58 static void hildon_volumebar_set_property(GObject * object,
62 static void hildon_volumebar_get_property(GObject * object,
67 static void mute_toggled (HildonVolumebar *self);
70 hildon_volumebar_key_press(GtkWidget * widget,
84 PROP_HILDON_FOCUSABLE,
89 static guint signals[LAST_SIGNAL] = { 0 };
92 hildon_volumebar_get_type(void)
94 static GType volumebar_type = 0;
96 if (!volumebar_type) {
97 static const GTypeInfo volumebar_info = {
98 sizeof(HildonVolumebarClass),
100 NULL, /* base_finalize */
101 (GClassInitFunc) hildon_volumebar_class_init,
102 NULL, /* class_finalize */
103 NULL, /* class_data */
104 sizeof(HildonVolumebar),
106 (GInstanceInitFunc) hildon_volumebar_init,
108 volumebar_type = g_type_register_static(GTK_TYPE_CONTAINER,
112 return volumebar_type;
116 hildon_volumebar_class_init(HildonVolumebarClass *volumebar_class)
118 GObjectClass *gobject_class = G_OBJECT_CLASS (volumebar_class);
119 GtkObjectClass *object_class = GTK_OBJECT_CLASS(volumebar_class);
120 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(volumebar_class);
121 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(volumebar_class);
123 parent_class = g_type_class_peek_parent(volumebar_class);
125 g_type_class_add_private(volumebar_class,
126 sizeof(HildonVolumebarPrivate));
128 /* Because we derived our widget from GtkContainer, we should also
129 override forall method */
130 volumebar_class->mute_toggled = mute_toggled;
131 container_class->forall = hildon_child_forall;
132 widget_class->key_press_event = hildon_volumebar_key_press;
133 object_class->destroy = hildon_volumebar_destroy;
135 signals[MUTE_TOGGLED_SIGNAL] = g_signal_new("mute_toggled",
141 (HildonVolumebarClass,
142 mute_toggled), NULL, NULL,
143 gtk_marshal_VOID__VOID,
146 signals[LEVEL_CHANGED_SIGNAL] = g_signal_new("level_changed",
152 (HildonVolumebarClass,
153 level_changed), NULL,
155 gtk_marshal_VOID__VOID,
158 gobject_class->set_property = hildon_volumebar_set_property;
159 gobject_class->get_property = hildon_volumebar_get_property;
161 /*This kind of property could be usefull in the gtkcontainer*/
162 g_object_class_install_property(gobject_class,
163 PROP_HILDON_FOCUSABLE,
164 g_param_spec_boolean("can-focus",
165 "The widget focusablility",
166 "The widget focusablility. TRUE is focusable",
168 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
170 g_object_class_install_property(gobject_class,
171 PROP_HILDON_HAS_MUTE,
172 g_param_spec_boolean("has_mute",
173 "Show/Hide the mute button",
174 "Whether the mute button is visible. Default value: TRUE",
176 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
178 g_object_class_install_property(gobject_class,
180 g_param_spec_double("level",
182 "Current volume level",
188 g_object_class_install_property(gobject_class,
190 g_param_spec_boolean("mute",
192 "Whether volume is muted",
198 hildon_volumebar_init(HildonVolumebar * volumebar)
200 HildonVolumebarPrivate *priv;
202 priv = HILDON_VOLUMEBAR_GET_PRIVATE(volumebar);
204 /* Should set GTK_NO_WINDOW flag, because widget is derived from
206 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(volumebar), GTK_NO_WINDOW);
207 GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(volumebar), GTK_CAN_FOCUS);
209 /* Initialize mute button */
210 priv->tbutton = GTK_TOGGLE_BUTTON(gtk_toggle_button_new());
211 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
215 hildon_child_forall(GtkContainer * container,
216 gboolean include_internals,
217 GtkCallback callback, gpointer callback_data)
219 HildonVolumebarPrivate *priv;
221 g_assert(HILDON_IS_VOLUMEBAR(container));
222 g_assert(callback != NULL);
224 priv = HILDON_VOLUMEBAR_GET_PRIVATE(container);
226 /* No external children */
227 if (!include_internals)
230 /* Execute callback for both internals */
231 (*callback) (GTK_WIDGET(priv->tbutton), callback_data);
232 (*callback) (GTK_WIDGET(priv->volumebar), callback_data);
236 hildon_volumebar_destroy(GtkObject * self)
238 HildonVolumebarPrivate *priv;
240 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
243 gtk_widget_unparent(GTK_WIDGET(priv->tbutton));
244 priv->tbutton = NULL;
246 if (priv->volumebar) {
247 gtk_widget_unparent(GTK_WIDGET(priv->volumebar));
248 priv->volumebar = NULL;
251 if (GTK_OBJECT_CLASS(parent_class)->destroy)
252 GTK_OBJECT_CLASS(parent_class)->destroy(self);
256 hildon_volumebar_set_property(GObject * object,
258 const GValue * value,
261 HildonVolumebarPrivate *priv;
263 priv = HILDON_VOLUMEBAR_GET_PRIVATE(object);
266 case PROP_HILDON_HAS_MUTE:
267 /* Mute button always exists, but might be hidden */
268 if (g_value_get_boolean(value))
269 gtk_widget_show(GTK_WIDGET(priv->tbutton));
271 gtk_widget_hide(GTK_WIDGET(priv->tbutton));
273 case PROP_HILDON_FOCUSABLE:
274 g_object_set( G_OBJECT(priv->volumebar), "can-focus",
275 g_value_get_boolean(value), NULL );
277 case PROP_HILDON_LEVEL:
278 hildon_volumebar_set_level(HILDON_VOLUMEBAR(priv->volumebar),
279 g_value_get_double(value));
281 case PROP_HILDON_MUTE:
282 hildon_volumebar_set_mute(HILDON_VOLUMEBAR(priv->volumebar),
283 g_value_get_boolean(value));
286 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
293 hildon_volumebar_get_property(GObject * object,
294 guint prop_id, GValue * value,
297 HildonVolumebar *vb = HILDON_VOLUMEBAR(object);
298 HildonVolumebarPrivate *priv = HILDON_VOLUMEBAR_GET_PRIVATE(vb);
301 case PROP_HILDON_HAS_MUTE:
302 g_value_set_boolean(value, GTK_WIDGET_VISIBLE(priv->tbutton));
304 case PROP_HILDON_FOCUSABLE:
305 g_value_set_boolean(value, GTK_WIDGET_CAN_FOCUS(priv->volumebar));
307 case PROP_HILDON_LEVEL:
308 g_value_set_double(value, hildon_volumebar_get_level(vb));
310 case PROP_HILDON_MUTE:
311 g_value_set_boolean(value, hildon_volumebar_get_mute(vb));
314 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
320 * hildon_volumebar_level_change:
321 * @self: a #HildonVolumebar widget
323 * Emits "level_changed" signal to the given volume bar. This function
324 * is mainly used by derived classes.
327 hildon_volumebar_level_change(HildonVolumebar * self)
329 g_return_if_fail(HILDON_IS_VOLUMEBAR(self));
330 g_signal_emit_by_name(GTK_WIDGET(self), "level_changed");
334 * hildon_volumebar_set_level:
335 * @self: volume bar to change level on
338 * Sets new volume level for this #HildonVolumebar.
341 hildon_volumebar_set_level(HildonVolumebar * self, gdouble level)
343 HildonVolumebarPrivate *priv;
345 g_return_if_fail(HILDON_IS_VOLUMEBAR(self));
347 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
349 hildon_volumebar_range_set_level(priv->volumebar, level);
353 * hildon_volumebar_get_level:
354 * @self: volume bar to query level on
356 * Gets the volume level of this #HildonVolumebar.
358 * Returns: volume level or -1 on error
361 hildon_volumebar_get_level(HildonVolumebar * self)
363 HildonVolumebarPrivate *priv;
365 g_return_val_if_fail(HILDON_IS_VOLUMEBAR(self), -1);
367 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
369 return hildon_volumebar_range_get_level(priv->volumebar);
373 * hildon_volumebar_set_mute:
374 * @self: volume bar to work on
377 * Sets mute status for this #HildonVolumebar.
380 hildon_volumebar_set_mute(HildonVolumebar * self, gboolean mute)
382 HildonVolumebarPrivate *priv;
383 gboolean focusable = TRUE;
385 g_return_if_fail(HILDON_IS_VOLUMEBAR(self));
387 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
389 /* Slider should be insensitive when mute is on */
390 gtk_widget_set_sensitive(GTK_WIDGET(priv->volumebar), !mute);
392 focusable = GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (priv->volumebar));
396 /* Make mute button focusable since the slider isn't anymore */
397 g_object_set (G_OBJECT (priv->tbutton), "can-focus", TRUE, NULL);
398 gtk_widget_grab_focus (GTK_WIDGET(priv->tbutton));
403 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
405 /* Mute off grabs focus */
407 gtk_widget_grab_focus (GTK_WIDGET (self));
410 /* If volumebar is not focusable, focus the parent window instead */
411 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (self),
413 gtk_window_set_focus (GTK_WINDOW (win), NULL);
417 /* Update mute button state and redraw */
418 gtk_toggle_button_set_active(priv->tbutton, mute);
420 gtk_widget_queue_draw (GTK_WIDGET (self));
424 * hildon_volumebar_get_mute:
425 * @self: volume bar to query mute status
427 * Gets mute status of this #HildonVolumebar (ON/OFF).
429 * Returns: Mute status as #gboolean value.
432 hildon_volumebar_get_mute(HildonVolumebar * self)
434 HildonVolumebarPrivate *priv;
436 g_return_val_if_fail(HILDON_IS_VOLUMEBAR(self), TRUE);
438 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
440 return gtk_toggle_button_get_active(priv->tbutton);
444 * hildon_volumebar_get_adjustment
445 * @self : a #HildonVolumebar
447 * Gets the GtkAdjustment used in volume bar. This can be handy
448 * to give to hildon_appview_set_connected_adjustment which
449 * will allow changing the volume with increase / decrease
452 * This is a temporary solution until volume bar is restructured to
453 * be a child class of GtkRange.
455 * Returns: a #GtkAdjustment used by volume bar.
458 hildon_volumebar_get_adjustment (HildonVolumebar * self)
460 HildonVolumebarPrivate *priv;
462 g_return_val_if_fail(HILDON_IS_VOLUMEBAR(self), NULL);
464 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
466 return gtk_range_get_adjustment (GTK_RANGE (priv->volumebar));
470 mute_toggled (HildonVolumebar *self)
472 /* This looks like no-op, but it still does something meaningfull!
473 set_mute also updates the ui to match new state that
474 is already reported by get_mute */
475 hildon_volumebar_set_mute (self, hildon_volumebar_get_mute(self));
479 hildon_volumebar_key_press (GtkWidget * widget,
482 HildonVolumebarPrivate *priv;
484 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
486 /* Enter key toggles mute button (unless it is hidden) */
487 if (event->keyval == GDK_Return && GTK_WIDGET_VISIBLE(priv->tbutton)) {
488 gtk_toggle_button_set_active(priv->tbutton,
489 !hildon_volumebar_get_mute(HILDON_VOLUMEBAR(widget)));
493 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event);
496 /* Sends mute-toggled signal to widget, used as a callback in derived classes
497 Just keep this "protected" in order to avoid introducing new API. */
499 _hildon_volumebar_mute_toggled(HildonVolumebar * self)
501 g_return_if_fail(HILDON_IS_VOLUMEBAR(self));
502 g_signal_emit_by_name(self, "mute_toggled");