2 * This file is a part of hildon
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
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.
39 #include "hildon-volumebar.h"
41 #include <gdk/gdkkeysyms.h>
42 #include "hildon-volumebar-range.h"
43 #include "hildon-volumebar-private.h"
45 static GtkContainerClass* parent_class;
48 hildon_volumebar_class_init (HildonVolumebarClass* volumebar_class);
51 hildon_volumebar_init (HildonVolumebar* volumebar);
54 hildon_child_forall (GtkContainer * container,
55 gboolean include_internals,
57 gpointer callback_data);
60 hildon_volumebar_destroy (GtkObject *self);
63 hildon_volumebar_set_property (GObject* object,
69 hildon_volumebar_get_property (GObject * object,
75 mute_toggled (HildonVolumebar *self);
78 hildon_volumebar_key_press (GtkWidget* widget,
82 hildon_volumebar_size_allocate (GtkWidget *widget,
83 GtkAllocation *allocation);
86 hildon_volumebar_realize (GtkWidget *widget);
89 hildon_volumebar_unrealize (GtkWidget *widget);
92 hildon_volumebar_map (GtkWidget *widget);
95 hildon_volumebar_unmap (GtkWidget *widget);
98 hildon_volumebar_notify (GObject *self, GParamSpec *param);
103 LEVEL_CHANGED_SIGNAL,
109 PROP_HILDON_HAS_MUTE,
110 PROP_HILDON_FOCUSABLE,
115 static guint signals [LAST_SIGNAL] = { 0 };
118 * hildon_volumebar_get_type:
120 * Initializes and returns the type of a hildon volumebar.
122 * @Returns: GType of #HildonVolumebar
125 hildon_volumebar_get_type (void)
127 static GType volumebar_type = 0;
129 if (!volumebar_type) {
130 static const GTypeInfo volumebar_info = {
131 sizeof(HildonVolumebarClass),
132 NULL, /* base_init */
133 NULL, /* base_finalize */
134 (GClassInitFunc) hildon_volumebar_class_init,
135 NULL, /* class_finalize */
136 NULL, /* class_data */
137 sizeof(HildonVolumebar),
139 (GInstanceInitFunc) hildon_volumebar_init,
141 volumebar_type = g_type_register_static(GTK_TYPE_CONTAINER,
145 return volumebar_type;
149 hildon_volumebar_class_init (HildonVolumebarClass *volumebar_class)
151 GObjectClass *gobject_class = G_OBJECT_CLASS (volumebar_class);
152 GtkObjectClass *object_class = GTK_OBJECT_CLASS (volumebar_class);
153 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (volumebar_class);
154 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (volumebar_class);
156 parent_class = g_type_class_peek_parent (volumebar_class);
158 g_type_class_add_private (volumebar_class,
159 sizeof (HildonVolumebarPrivate));
161 /* Because we derived our widget from GtkContainer, we should also
162 * override forall method
164 volumebar_class->mute_toggled = mute_toggled;
165 container_class->forall = hildon_child_forall;
166 widget_class->size_allocate = hildon_volumebar_size_allocate;
167 widget_class->realize = hildon_volumebar_realize;
168 widget_class->unrealize = hildon_volumebar_unrealize;
169 widget_class->map = hildon_volumebar_map;
170 widget_class->unmap = hildon_volumebar_unmap;
171 widget_class->key_press_event = hildon_volumebar_key_press;
172 object_class->destroy = hildon_volumebar_destroy;
174 signals[MUTE_TOGGLED_SIGNAL] = g_signal_new ("mute_toggled",
180 (HildonVolumebarClass,
181 mute_toggled), NULL, NULL,
182 gtk_marshal_VOID__VOID,
185 signals[LEVEL_CHANGED_SIGNAL] = g_signal_new ("level_changed",
191 (HildonVolumebarClass,
192 level_changed), NULL,
194 gtk_marshal_VOID__VOID,
197 gobject_class->notify = hildon_volumebar_notify;
198 gobject_class->set_property = hildon_volumebar_set_property;
199 gobject_class->get_property = hildon_volumebar_get_property;
202 * HildonVolumebar:can-focus:
204 * The widget focusability.
206 g_object_class_install_property (gobject_class,
207 PROP_HILDON_FOCUSABLE,
208 g_param_spec_boolean ("can-focus",
209 "The widget focusablility",
210 "The widget focusablility. TRUE is focusable",
212 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
215 * HildonVolumebar:has-mute:
217 * Whether the mute button is visibile.
219 g_object_class_install_property (gobject_class,
220 PROP_HILDON_HAS_MUTE,
221 g_param_spec_boolean ("has_mute",
222 "Show/Hide the mute button",
223 "Whether the mute button is visible. Default value: TRUE",
225 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
228 * HildonVolumebar:level:
230 * Current volume level.
232 g_object_class_install_property (gobject_class,
234 g_param_spec_double ("level",
236 "Current volume level",
243 * HildonVolumebar:can-focus:
245 * Whether volume is muted.
247 g_object_class_install_property (gobject_class,
249 g_param_spec_boolean ("mute",
251 "Whether volume is muted",
257 hildon_volumebar_init (HildonVolumebar *volumebar)
259 HildonVolumebarPrivate *priv;
261 priv = HILDON_VOLUMEBAR_GET_PRIVATE(volumebar);
264 /* Should set GTK_NO_WINDOW flag, because widget is derived from
266 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (volumebar), GTK_NO_WINDOW);
267 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (volumebar), GTK_CAN_FOCUS);
269 /* Initialize mute button */
270 priv->tbutton = GTK_TOGGLE_BUTTON (gtk_toggle_button_new ());
271 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
275 hildon_volumebar_size_allocate (GtkWidget *widget,
276 GtkAllocation *allocation)
278 HildonVolumebarPrivate *priv;
280 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
283 if (GTK_WIDGET_CLASS (parent_class)->size_allocate)
284 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
286 if (GTK_WIDGET_REALIZED (widget))
287 gdk_window_move_resize (priv->event_window,
288 allocation->x, allocation->y,
289 allocation->width, allocation->height);
293 hildon_volumebar_realize (GtkWidget *widget)
295 HildonVolumebarPrivate *priv;
296 GdkWindowAttr attributes;
297 gint attributes_mask;
299 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
302 GTK_WIDGET_CLASS (parent_class)->realize (widget);
304 attributes.window_type = GDK_WINDOW_CHILD;
305 attributes.x = widget->allocation.x;
306 attributes.y = widget->allocation.y;
307 attributes.width = widget->allocation.width;
308 attributes.height = widget->allocation.height;
309 attributes.wclass = GDK_INPUT_ONLY;
310 attributes.event_mask = GDK_BUTTON_PRESS_MASK;
312 attributes_mask = GDK_WA_X | GDK_WA_Y;
314 priv->event_window = gdk_window_new (widget->window,
315 &attributes, attributes_mask);
317 gdk_window_set_user_data (priv->event_window, widget);
321 hildon_volumebar_unrealize (GtkWidget *widget)
323 HildonVolumebarPrivate *priv;
325 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
328 if (priv->event_window) {
329 gdk_window_set_user_data (priv->event_window, NULL);
330 gdk_window_destroy (priv->event_window);
331 priv->event_window = NULL;
334 GTK_WIDGET_CLASS (parent_class)->unrealize(widget);
338 hildon_volumebar_map (GtkWidget *widget)
340 HildonVolumebarPrivate *priv;
342 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
345 GTK_WIDGET_CLASS (parent_class)->map (widget);
347 /* the event window must be on top of all other widget windows, so show it
349 if (! GTK_WIDGET_SENSITIVE (widget))
350 gdk_window_show (priv->event_window);
354 hildon_volumebar_unmap (GtkWidget *widget)
356 HildonVolumebarPrivate *priv;
358 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
361 gdk_window_hide (priv->event_window);
363 GTK_WIDGET_CLASS (parent_class)->unmap(widget);
367 hildon_child_forall (GtkContainer *container,
368 gboolean include_internals,
369 GtkCallback callback,
370 gpointer callback_data)
372 HildonVolumebarPrivate *priv;
374 priv = HILDON_VOLUMEBAR_GET_PRIVATE (container);
375 g_assert (callback != NULL);
378 /* No external children */
379 if (! include_internals)
382 /* Execute callback for both internals */
383 (*callback) (GTK_WIDGET (priv->tbutton), callback_data);
384 (*callback) (GTK_WIDGET (priv->volumebar), callback_data);
388 hildon_volumebar_notify (GObject *self,
391 HildonVolumebarPrivate *priv;
393 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
396 if (GTK_WIDGET_MAPPED (self)) {
397 /* show/hide the event window on sensitivity change */
398 if (g_str_equal (param->name, "sensitive")) {
399 if (GTK_WIDGET_SENSITIVE (self))
400 gdk_window_hide (priv->event_window);
402 gdk_window_show (priv->event_window);
406 if (G_OBJECT_CLASS(parent_class)->notify)
407 G_OBJECT_CLASS(parent_class)->notify (self, param);
411 hildon_volumebar_destroy (GtkObject *self)
413 HildonVolumebarPrivate *priv;
415 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
419 gtk_widget_unparent (GTK_WIDGET (priv->tbutton));
420 priv->tbutton = NULL;
422 if (priv->volumebar) {
423 gtk_widget_unparent (GTK_WIDGET (priv->volumebar));
424 priv->volumebar = NULL;
427 if (GTK_OBJECT_CLASS (parent_class)->destroy)
428 GTK_OBJECT_CLASS (parent_class)->destroy (self);
432 hildon_volumebar_set_property (GObject *object,
437 HildonVolumebarPrivate *priv;
439 priv = HILDON_VOLUMEBAR_GET_PRIVATE(object);
444 case PROP_HILDON_HAS_MUTE:
445 /* Mute button always exists but might be hidden */
446 if (g_value_get_boolean (value))
447 gtk_widget_show (GTK_WIDGET (priv->tbutton));
449 gtk_widget_hide (GTK_WIDGET (priv->tbutton));
452 case PROP_HILDON_FOCUSABLE:
453 g_object_set (G_OBJECT (priv->volumebar), "can-focus",
454 g_value_get_boolean (value), NULL );
457 case PROP_HILDON_LEVEL:
458 hildon_volumebar_set_level (HILDON_VOLUMEBAR (priv->volumebar),
459 g_value_get_double (value));
462 case PROP_HILDON_MUTE:
463 hildon_volumebar_set_mute (HILDON_VOLUMEBAR (priv->volumebar),
464 g_value_get_boolean (value));
468 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
475 hildon_volumebar_get_property (GObject *object,
480 HildonVolumebarPrivate *priv;
483 priv = HILDON_VOLUMEBAR_GET_PRIVATE(object);
486 vb = HILDON_VOLUMEBAR (object);
490 case PROP_HILDON_HAS_MUTE:
491 g_value_set_boolean (value, GTK_WIDGET_VISIBLE (priv->tbutton));
494 case PROP_HILDON_FOCUSABLE:
495 g_value_set_boolean (value, GTK_WIDGET_CAN_FOCUS (priv->volumebar));
498 case PROP_HILDON_LEVEL:
499 g_value_set_double (value, hildon_volumebar_get_level (vb));
502 case PROP_HILDON_MUTE:
503 g_value_set_boolean (value, hildon_volumebar_get_mute (vb));
507 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
514 * hildon_volumebar_set_level:
515 * @self: volume bar to change level on
518 * Sets new volume level for this #HildonVolumebar.
521 hildon_volumebar_set_level (HildonVolumebar *self,
524 HildonVolumebarPrivate *priv;
526 g_return_if_fail(HILDON_IS_VOLUMEBAR (self));
528 priv = HILDON_VOLUMEBAR_GET_PRIVATE (self);
531 hildon_volumebar_range_set_level (priv->volumebar, level);
535 * hildon_volumebar_get_level:
536 * @self: volume bar to query level on
538 * Gets the volume level of this #HildonVolumebar.
540 * Returns: volume level or -1 on error
543 hildon_volumebar_get_level (HildonVolumebar *self)
545 HildonVolumebarPrivate *priv;
547 g_return_val_if_fail(HILDON_IS_VOLUMEBAR (self), -1);
549 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
552 return hildon_volumebar_range_get_level (priv->volumebar);
556 * hildon_volumebar_set_mute:
557 * @self: volume bar to work on
560 * Sets mute status for this #HildonVolumebar.
563 hildon_volumebar_set_mute (HildonVolumebar *self,
566 HildonVolumebarPrivate *priv;
567 gboolean focusable = TRUE;
569 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
571 priv = HILDON_VOLUMEBAR_GET_PRIVATE (self);
574 /* Slider should be insensitive when mute is on */
575 gtk_widget_set_sensitive (GTK_WIDGET (priv->volumebar), !mute);
577 focusable = GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (priv->volumebar));
581 /* Make mute button focusable since the slider isn't anymore */
582 g_object_set (G_OBJECT (priv->tbutton), "can-focus", TRUE, NULL);
583 gtk_widget_grab_focus (GTK_WIDGET (priv->tbutton));
588 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
590 /* Mute off grabs focus */
592 gtk_widget_grab_focus (GTK_WIDGET (self));
595 /* If volumebar is not focusable, focus the parent window instead */
596 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (self),
598 gtk_window_set_focus (GTK_WINDOW (win), NULL);
602 /* Update mute button state and redraw */
603 gtk_toggle_button_set_active (priv->tbutton, mute);
605 /* FIXME I'm darn sure that's not really needed */
606 gtk_widget_queue_draw (GTK_WIDGET (self));
610 * hildon_volumebar_get_mute:
611 * @self: volume bar to query mute status
613 * Gets mute status of this #HildonVolumebar (ON/OFF).
615 * Returns: Mute status as #gboolean value.
618 hildon_volumebar_get_mute (HildonVolumebar *self)
620 HildonVolumebarPrivate *priv;
622 g_return_val_if_fail (HILDON_IS_VOLUMEBAR (self), TRUE);
624 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
627 return gtk_toggle_button_get_active (priv->tbutton);
631 * hildon_volumebar_get_adjustment
632 * @self : a #HildonVolumebar
634 * Gets the GtkAdjustment used in volume bar. This can be handy
635 * to pass to hildon_appview_set_connected_adjustment which
636 * will allow changing the volume with 'increase' / 'decrease'
639 * Returns: a #GtkAdjustment used by volume bar.
642 hildon_volumebar_get_adjustment (HildonVolumebar *self)
644 HildonVolumebarPrivate *priv;
646 g_return_val_if_fail(HILDON_IS_VOLUMEBAR(self), NULL);
648 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
651 return gtk_range_get_adjustment (GTK_RANGE (priv->volumebar));
655 mute_toggled (HildonVolumebar *self)
657 /* This looks like no-op, but it still does something meaningfull!
658 set_mute also updates the ui to match new state that
659 is already reported by get_mute */
661 hildon_volumebar_set_mute (self, hildon_volumebar_get_mute (self));
665 hildon_volumebar_key_press (GtkWidget *widget,
668 HildonVolumebarPrivate *priv;
670 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
671 g_assert (priv != NULL);
673 /* Enter key toggles mute button (unless it is hidden) */
674 if (event->keyval == GDK_Return && GTK_WIDGET_VISIBLE (priv->tbutton)) {
675 gtk_toggle_button_set_active (priv->tbutton,
676 ! hildon_volumebar_get_mute(HILDON_VOLUMEBAR(widget)));
681 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
685 * Sends mute-toggled signal to widget, used as a callback in derived classes.
688 hildon_volumebar_mute_toggled (HildonVolumebar * self)
690 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
691 /* FIXME Emit by id */
692 g_signal_emit_by_name (self, "mute_toggled");
696 hildon_volumebar_level_change (HildonVolumebar *self)
698 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
700 /* FIXME Use numerical val, id */
701 g_signal_emit_by_name (GTK_WIDGET (self), "level_changed");