2 * This file is a part of hildon
4 * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
6 * Contact: Rodrigo Novo <rodrigo.novo@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 (at your option) 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.
36 * #HildonVolumebar has been deprecated since Hildon 2.2 and should not
37 * be used in newly written code. See
38 * <link linkend="hildon-migrating-volume-bar">Migrating Volume Bars</link>
39 * section to know how to migrate this deprecated widget.
44 #undef HILDON_DISABLE_DEPRECATED
50 #include <gdk/gdkkeysyms.h>
52 #include "hildon-volumebar.h"
53 #include "hildon-volumebar-range.h"
54 #include "hildon-volumebar-private.h"
56 static GtkContainerClass* parent_class;
59 hildon_volumebar_class_init (HildonVolumebarClass* volumebar_class);
62 hildon_volumebar_init (HildonVolumebar* volumebar);
65 hildon_child_forall (GtkContainer * container,
66 gboolean include_internals,
68 gpointer callback_data);
71 hildon_volumebar_destroy (GtkObject *self);
74 hildon_volumebar_set_property (GObject* object,
80 hildon_volumebar_get_property (GObject * object,
86 mute_toggled (HildonVolumebar *self);
89 hildon_volumebar_key_press (GtkWidget* widget,
93 hildon_volumebar_size_allocate (GtkWidget *widget,
94 GtkAllocation *allocation);
97 hildon_volumebar_realize (GtkWidget *widget);
100 hildon_volumebar_unrealize (GtkWidget *widget);
103 hildon_volumebar_map (GtkWidget *widget);
106 hildon_volumebar_unmap (GtkWidget *widget);
109 hildon_volumebar_grab_focus (GtkWidget *widget);
112 hildon_volumebar_focus (GtkWidget *widget,
113 GtkDirectionType direction);
116 hildon_volumebar_notify (GObject *self, GParamSpec *param);
121 LEVEL_CHANGED_SIGNAL,
127 PROP_HILDON_HAS_MUTE,
132 static guint signals [LAST_SIGNAL] = { 0 };
135 * hildon_volumebar_get_type:
137 * Initializes and returns the type of a hildon volumebar.
139 * Returns: GType of #HildonVolumebar
142 hildon_volumebar_get_type (void)
144 static GType volumebar_type = 0;
146 if (!volumebar_type) {
147 static const GTypeInfo volumebar_info = {
148 sizeof(HildonVolumebarClass),
149 NULL, /* base_init */
150 NULL, /* base_finalize */
151 (GClassInitFunc) hildon_volumebar_class_init,
152 NULL, /* class_finalize */
153 NULL, /* class_data */
154 sizeof(HildonVolumebar),
156 (GInstanceInitFunc) hildon_volumebar_init,
158 volumebar_type = g_type_register_static(GTK_TYPE_CONTAINER,
162 return volumebar_type;
166 hildon_volumebar_class_init (HildonVolumebarClass *volumebar_class)
168 GObjectClass *gobject_class = G_OBJECT_CLASS (volumebar_class);
169 GtkObjectClass *object_class = GTK_OBJECT_CLASS (volumebar_class);
170 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (volumebar_class);
171 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (volumebar_class);
173 parent_class = g_type_class_peek_parent (volumebar_class);
175 g_type_class_add_private (volumebar_class,
176 sizeof (HildonVolumebarPrivate));
178 /* Because we derived our widget from GtkContainer, we should also
179 * override forall method
181 volumebar_class->mute_toggled = mute_toggled;
182 container_class->forall = hildon_child_forall;
183 widget_class->size_allocate = hildon_volumebar_size_allocate;
184 widget_class->realize = hildon_volumebar_realize;
185 widget_class->unrealize = hildon_volumebar_unrealize;
186 widget_class->map = hildon_volumebar_map;
187 widget_class->unmap = hildon_volumebar_unmap;
188 widget_class->grab_focus = hildon_volumebar_grab_focus;
189 widget_class->focus = hildon_volumebar_focus;
190 widget_class->key_press_event = hildon_volumebar_key_press;
191 object_class->destroy = hildon_volumebar_destroy;
193 signals[MUTE_TOGGLED_SIGNAL] = g_signal_new ("mute_toggled",
199 (HildonVolumebarClass,
200 mute_toggled), NULL, NULL,
201 g_cclosure_marshal_VOID__VOID,
204 signals[LEVEL_CHANGED_SIGNAL] = g_signal_new ("level_changed",
210 (HildonVolumebarClass,
211 level_changed), NULL,
213 g_cclosure_marshal_VOID__VOID,
216 gobject_class->notify = hildon_volumebar_notify;
217 gobject_class->set_property = hildon_volumebar_set_property;
218 gobject_class->get_property = hildon_volumebar_get_property;
221 * HildonVolumebar:has-mute:
223 * Whether the mute button is visibile.
225 g_object_class_install_property (gobject_class,
226 PROP_HILDON_HAS_MUTE,
227 g_param_spec_boolean ("has_mute",
228 "Show/Hide the mute button",
229 "Whether the mute button is visible. Default value: TRUE",
231 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
234 * HildonVolumebar:level:
236 * Current volume level.
238 g_object_class_install_property (gobject_class,
240 g_param_spec_double ("level",
242 "Current volume level",
249 * HildonVolumebar:mute:
251 * Whether volume is muted.
253 g_object_class_install_property (gobject_class,
255 g_param_spec_boolean ("mute",
257 "Whether volume is muted",
263 hildon_volumebar_init (HildonVolumebar *volumebar)
265 HildonVolumebarPrivate *priv;
267 priv = HILDON_VOLUMEBAR_GET_PRIVATE(volumebar);
270 /* Should set GTK_NO_WINDOW flag, because widget is derived from
272 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (volumebar), GTK_NO_WINDOW);
273 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (volumebar), GTK_CAN_FOCUS);
275 /* Initialize mute button */
276 priv->tbutton = GTK_TOGGLE_BUTTON (gtk_toggle_button_new ());
277 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
281 hildon_volumebar_size_allocate (GtkWidget *widget,
282 GtkAllocation *allocation)
284 HildonVolumebarPrivate *priv;
286 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
289 if (GTK_WIDGET_CLASS (parent_class)->size_allocate)
290 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
292 if (GTK_WIDGET_REALIZED (widget))
293 gdk_window_move_resize (priv->event_window,
294 allocation->x, allocation->y,
295 allocation->width, allocation->height);
299 hildon_volumebar_realize (GtkWidget *widget)
301 HildonVolumebarPrivate *priv;
302 GdkWindowAttr attributes;
303 gint attributes_mask;
305 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
308 GTK_WIDGET_CLASS (parent_class)->realize (widget);
310 attributes.window_type = GDK_WINDOW_CHILD;
311 attributes.x = widget->allocation.x;
312 attributes.y = widget->allocation.y;
313 attributes.width = widget->allocation.width;
314 attributes.height = widget->allocation.height;
315 attributes.wclass = GDK_INPUT_ONLY;
316 attributes.event_mask = GDK_BUTTON_PRESS_MASK;
318 attributes_mask = GDK_WA_X | GDK_WA_Y;
320 priv->event_window = gdk_window_new (widget->window,
321 &attributes, attributes_mask);
323 gdk_window_set_user_data (priv->event_window, widget);
327 hildon_volumebar_unrealize (GtkWidget *widget)
329 HildonVolumebarPrivate *priv;
331 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
334 if (priv->event_window) {
335 gdk_window_set_user_data (priv->event_window, NULL);
336 gdk_window_destroy (priv->event_window);
337 priv->event_window = NULL;
340 GTK_WIDGET_CLASS (parent_class)->unrealize(widget);
344 hildon_volumebar_map (GtkWidget *widget)
346 HildonVolumebarPrivate *priv;
348 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
351 GTK_WIDGET_CLASS (parent_class)->map (widget);
353 /* the event window must be on top of all other widget windows, so show it
355 if (! GTK_WIDGET_SENSITIVE (widget))
356 gdk_window_show (priv->event_window);
360 hildon_volumebar_unmap (GtkWidget *widget)
362 HildonVolumebarPrivate *priv;
364 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
367 gdk_window_hide (priv->event_window);
369 GTK_WIDGET_CLASS (parent_class)->unmap(widget);
373 hildon_volumebar_grab_focus (GtkWidget *widget)
375 HildonVolumebarPrivate *priv;
377 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
380 if (GTK_WIDGET_CAN_FOCUS (widget)) {
381 if (gtk_toggle_button_get_active (priv->tbutton))
382 gtk_widget_grab_focus (GTK_WIDGET (priv->tbutton));
384 gtk_widget_grab_focus (GTK_WIDGET (priv->volumebar));
389 hildon_volumebar_focus (GtkWidget *widget,
390 GtkDirectionType direction)
392 HildonVolumebarPrivate *priv;
393 GtkOrientation orientation;
396 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
399 orientation = GTK_RANGE (priv->volumebar)->orientation;
401 has_focus = (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->volumebar)) ||
402 GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->tbutton)));
407 case GTK_DIR_TAB_FORWARD:
408 case GTK_DIR_TAB_BACKWARD:
409 if (has_focus && orientation == GTK_ORIENTATION_HORIZONTAL)
415 if (has_focus && orientation == GTK_ORIENTATION_VERTICAL)
423 return GTK_WIDGET_CLASS (parent_class)->focus (widget, direction);
427 hildon_child_forall (GtkContainer *container,
428 gboolean include_internals,
429 GtkCallback callback,
430 gpointer callback_data)
432 HildonVolumebarPrivate *priv;
434 priv = HILDON_VOLUMEBAR_GET_PRIVATE (container);
435 g_assert (callback != NULL);
438 /* No external children */
439 if (! include_internals)
442 /* Execute callback for both internals */
443 (*callback) (GTK_WIDGET (priv->tbutton), callback_data);
444 (*callback) (GTK_WIDGET (priv->volumebar), callback_data);
448 hildon_volumebar_notify (GObject *self,
451 HildonVolumebarPrivate *priv;
453 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
456 if (g_str_equal (param->name, "can-focus")) {
457 /* call set_mute() because that updates the widget's UI state */
458 hildon_volumebar_set_mute (HILDON_VOLUMEBAR (self),
459 hildon_volumebar_get_mute (HILDON_VOLUMEBAR (self)));
462 if (GTK_WIDGET_MAPPED (self)) {
463 /* show/hide the event window on sensitivity change */
464 if (g_str_equal (param->name, "sensitive")) {
465 if (GTK_WIDGET_SENSITIVE (self))
466 gdk_window_hide (priv->event_window);
468 gdk_window_show (priv->event_window);
472 if (G_OBJECT_CLASS(parent_class)->notify)
473 G_OBJECT_CLASS(parent_class)->notify (self, param);
477 hildon_volumebar_destroy (GtkObject *self)
479 HildonVolumebarPrivate *priv;
481 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
485 gtk_widget_unparent (GTK_WIDGET (priv->tbutton));
486 priv->tbutton = NULL;
488 if (priv->volumebar) {
489 gtk_widget_unparent (GTK_WIDGET (priv->volumebar));
490 priv->volumebar = NULL;
493 if (GTK_OBJECT_CLASS (parent_class)->destroy)
494 GTK_OBJECT_CLASS (parent_class)->destroy (self);
498 hildon_volumebar_set_property (GObject *object,
503 HildonVolumebarPrivate *priv;
505 priv = HILDON_VOLUMEBAR_GET_PRIVATE(object);
510 case PROP_HILDON_HAS_MUTE:
511 /* Mute button always exists but might be hidden */
512 if (g_value_get_boolean (value))
513 gtk_widget_show (GTK_WIDGET (priv->tbutton));
515 gtk_widget_hide (GTK_WIDGET (priv->tbutton));
518 case PROP_HILDON_LEVEL:
519 hildon_volumebar_set_level (HILDON_VOLUMEBAR (object),
520 g_value_get_double (value));
523 case PROP_HILDON_MUTE:
524 hildon_volumebar_set_mute (HILDON_VOLUMEBAR (object),
525 g_value_get_boolean (value));
529 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
536 hildon_volumebar_get_property (GObject *object,
541 HildonVolumebarPrivate *priv;
544 priv = HILDON_VOLUMEBAR_GET_PRIVATE(object);
547 vb = HILDON_VOLUMEBAR (object);
551 case PROP_HILDON_HAS_MUTE:
552 g_value_set_boolean (value, GTK_WIDGET_VISIBLE (priv->tbutton));
555 case PROP_HILDON_LEVEL:
556 g_value_set_double (value, hildon_volumebar_get_level (vb));
559 case PROP_HILDON_MUTE:
560 g_value_set_boolean (value, hildon_volumebar_get_mute (vb));
564 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
571 * hildon_volumebar_set_level:
572 * @self: volume bar to change level on
575 * Sets new volume level for this #HildonVolumebar.
578 hildon_volumebar_set_level (HildonVolumebar *self,
581 HildonVolumebarPrivate *priv;
583 g_return_if_fail(HILDON_IS_VOLUMEBAR (self));
585 priv = HILDON_VOLUMEBAR_GET_PRIVATE (self);
588 hildon_volumebar_range_set_level (priv->volumebar, level);
592 * hildon_volumebar_get_level:
593 * @self: volume bar to query level on
595 * Gets the volume level of this #HildonVolumebar.
597 * Returns: volume level or -1 on error
600 hildon_volumebar_get_level (HildonVolumebar *self)
602 HildonVolumebarPrivate *priv;
604 g_return_val_if_fail(HILDON_IS_VOLUMEBAR (self), -1);
606 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
609 return hildon_volumebar_range_get_level (priv->volumebar);
613 * hildon_volumebar_set_mute:
614 * @self: volume bar to work on
617 * Sets mute status for this #HildonVolumebar.
620 hildon_volumebar_set_mute (HildonVolumebar *self,
623 HildonVolumebarPrivate *priv;
626 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
628 priv = HILDON_VOLUMEBAR_GET_PRIVATE (self);
631 has_focus = (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->volumebar)) ||
632 GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->tbutton)));
634 /* Slider should be insensitive when mute is on */
635 gtk_widget_set_sensitive (GTK_WIDGET (priv->volumebar), !mute);
638 /* Make mute button focusable since the slider isn't anymore */
639 g_object_set (G_OBJECT (priv->tbutton), "can-focus", TRUE, NULL);
642 gtk_widget_grab_focus (GTK_WIDGET (priv->tbutton));
646 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
649 gtk_widget_grab_focus (GTK_WIDGET (priv->volumebar));
652 /* Update mute button state and redraw */
653 gtk_toggle_button_set_active (priv->tbutton, mute);
657 * hildon_volumebar_get_mute:
658 * @self: volume bar to query mute status
660 * Gets mute status of this #HildonVolumebar (ON/OFF).
662 * Returns: Mute status as #gboolean value.
665 hildon_volumebar_get_mute (HildonVolumebar *self)
667 HildonVolumebarPrivate *priv;
669 g_return_val_if_fail (HILDON_IS_VOLUMEBAR (self), TRUE);
671 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
674 return gtk_toggle_button_get_active (priv->tbutton);
678 * hildon_volumebar_get_adjustment
679 * @self : a #HildonVolumebar
681 * Gets the GtkAdjustment used in volume bar. This can be handy
682 * to pass to hildon_appview_set_connected_adjustment which
683 * will allow changing the volume with 'increase' / 'decrease'
686 * Returns: a #GtkAdjustment used by volume bar.
689 hildon_volumebar_get_adjustment (HildonVolumebar *self)
691 HildonVolumebarPrivate *priv;
693 g_return_val_if_fail(HILDON_IS_VOLUMEBAR(self), NULL);
695 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
698 return gtk_range_get_adjustment (GTK_RANGE (priv->volumebar));
702 mute_toggled (HildonVolumebar *self)
704 /* This looks like no-op, but it still does something meaningfull!
705 set_mute also updates the ui to match new state that
706 is already reported by get_mute */
708 hildon_volumebar_set_mute (self, hildon_volumebar_get_mute (self));
712 hildon_volumebar_key_press (GtkWidget *widget,
715 HildonVolumebarPrivate *priv;
717 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
718 g_assert (priv != NULL);
720 /* Enter key toggles mute button (unless it is hidden) */
721 if (event->keyval == GDK_Return && GTK_WIDGET_VISIBLE (priv->tbutton)) {
722 gtk_toggle_button_set_active (priv->tbutton,
723 ! hildon_volumebar_get_mute(HILDON_VOLUMEBAR(widget)));
728 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
732 * Sends mute-toggled signal to widget, used as a callback in derived classes.
735 hildon_volumebar_mute_toggled (HildonVolumebar * self)
737 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
738 /* FIXME Emit by id */
739 g_signal_emit_by_name (self, "mute_toggled");
743 hildon_volumebar_level_change (HildonVolumebar *self)
745 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
747 /* FIXME Use numerical val, id */
748 g_signal_emit_by_name (GTK_WIDGET (self), "level_changed");
752 * hildon_volumebar_set_range_insensitive_message:
753 * @widget: A @GtkWidget to assign the banner to
754 * @message: A message to display to the user
756 * Used to asign an insensitive message to the slider of the given volumebar.
757 * It simply calls hildon_helper_set_insensitive_message on the slider/range of
760 * Deprecated: As of hildon 2.2, it is strongly discouraged to use insensitive messages.
763 hildon_volumebar_set_range_insensitive_message (HildonVolumebar *widget,
764 const gchar *message)
766 g_return_if_fail (HILDON_IS_VOLUMEBAR (widget));
768 HildonVolumebarPrivate *priv;
769 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
771 hildon_helper_set_insensitive_message ((GtkWidget *) priv->volumebar, message);
775 * hildon_volumebar_set_range_insensitive_messagef:
776 * @widget: A @GtkWidget to assign the banner to
777 * @format : a printf-like format string
778 * @varargs : arguments for the format string
780 * A helper printf-like variant of hildon_helper_set_insensitive_message.
782 * Deprecated: As of hildon 2.2, it is strongly discouraged to use insensitive messages.
785 hildon_volumebar_set_range_insensitive_messagef (HildonVolumebar *widget,
789 g_return_if_fail (HILDON_IS_VOLUMEBAR (widget));
791 HildonVolumebarPrivate *priv;
792 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
797 va_start (args, format);
798 message = g_strdup_vprintf (format, args);
801 hildon_helper_set_insensitive_message ((GtkWidget *) priv->volumebar, message);