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
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.
35 #undef HILDON_DISABLE_DEPRECATED
41 #include <gdk/gdkkeysyms.h>
43 #include "hildon-volumebar.h"
44 #include "hildon-volumebar-range.h"
45 #include "hildon-volumebar-private.h"
47 static GtkContainerClass* parent_class;
50 hildon_volumebar_class_init (HildonVolumebarClass* volumebar_class);
53 hildon_volumebar_init (HildonVolumebar* volumebar);
56 hildon_child_forall (GtkContainer * container,
57 gboolean include_internals,
59 gpointer callback_data);
62 hildon_volumebar_destroy (GtkObject *self);
65 hildon_volumebar_set_property (GObject* object,
71 hildon_volumebar_get_property (GObject * object,
77 mute_toggled (HildonVolumebar *self);
80 hildon_volumebar_key_press (GtkWidget* widget,
84 hildon_volumebar_size_allocate (GtkWidget *widget,
85 GtkAllocation *allocation);
88 hildon_volumebar_realize (GtkWidget *widget);
91 hildon_volumebar_unrealize (GtkWidget *widget);
94 hildon_volumebar_map (GtkWidget *widget);
97 hildon_volumebar_unmap (GtkWidget *widget);
100 hildon_volumebar_grab_focus (GtkWidget *widget);
103 hildon_volumebar_focus (GtkWidget *widget,
104 GtkDirectionType direction);
107 hildon_volumebar_notify (GObject *self, GParamSpec *param);
112 LEVEL_CHANGED_SIGNAL,
118 PROP_HILDON_HAS_MUTE,
123 static guint signals [LAST_SIGNAL] = { 0 };
126 * hildon_volumebar_get_type:
128 * Initializes and returns the type of a hildon volumebar.
130 * @Returns: GType of #HildonVolumebar
133 hildon_volumebar_get_type (void)
135 static GType volumebar_type = 0;
137 if (!volumebar_type) {
138 static const GTypeInfo volumebar_info = {
139 sizeof(HildonVolumebarClass),
140 NULL, /* base_init */
141 NULL, /* base_finalize */
142 (GClassInitFunc) hildon_volumebar_class_init,
143 NULL, /* class_finalize */
144 NULL, /* class_data */
145 sizeof(HildonVolumebar),
147 (GInstanceInitFunc) hildon_volumebar_init,
149 volumebar_type = g_type_register_static(GTK_TYPE_CONTAINER,
153 return volumebar_type;
157 hildon_volumebar_class_init (HildonVolumebarClass *volumebar_class)
159 GObjectClass *gobject_class = G_OBJECT_CLASS (volumebar_class);
160 GtkObjectClass *object_class = GTK_OBJECT_CLASS (volumebar_class);
161 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (volumebar_class);
162 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (volumebar_class);
164 parent_class = g_type_class_peek_parent (volumebar_class);
166 g_type_class_add_private (volumebar_class,
167 sizeof (HildonVolumebarPrivate));
169 /* Because we derived our widget from GtkContainer, we should also
170 * override forall method
172 volumebar_class->mute_toggled = mute_toggled;
173 container_class->forall = hildon_child_forall;
174 widget_class->size_allocate = hildon_volumebar_size_allocate;
175 widget_class->realize = hildon_volumebar_realize;
176 widget_class->unrealize = hildon_volumebar_unrealize;
177 widget_class->map = hildon_volumebar_map;
178 widget_class->unmap = hildon_volumebar_unmap;
179 widget_class->grab_focus = hildon_volumebar_grab_focus;
180 widget_class->focus = hildon_volumebar_focus;
181 widget_class->key_press_event = hildon_volumebar_key_press;
182 object_class->destroy = hildon_volumebar_destroy;
184 signals[MUTE_TOGGLED_SIGNAL] = g_signal_new ("mute_toggled",
190 (HildonVolumebarClass,
191 mute_toggled), NULL, NULL,
192 gtk_marshal_VOID__VOID,
195 signals[LEVEL_CHANGED_SIGNAL] = g_signal_new ("level_changed",
201 (HildonVolumebarClass,
202 level_changed), NULL,
204 gtk_marshal_VOID__VOID,
207 gobject_class->notify = hildon_volumebar_notify;
208 gobject_class->set_property = hildon_volumebar_set_property;
209 gobject_class->get_property = hildon_volumebar_get_property;
212 * HildonVolumebar:has-mute:
214 * Whether the mute button is visibile.
216 g_object_class_install_property (gobject_class,
217 PROP_HILDON_HAS_MUTE,
218 g_param_spec_boolean ("has_mute",
219 "Show/Hide the mute button",
220 "Whether the mute button is visible. Default value: TRUE",
222 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
225 * HildonVolumebar:level:
227 * Current volume level.
229 g_object_class_install_property (gobject_class,
231 g_param_spec_double ("level",
233 "Current volume level",
240 * HildonVolumebar:mute:
242 * Whether volume is muted.
244 g_object_class_install_property (gobject_class,
246 g_param_spec_boolean ("mute",
248 "Whether volume is muted",
254 hildon_volumebar_init (HildonVolumebar *volumebar)
256 HildonVolumebarPrivate *priv;
258 priv = HILDON_VOLUMEBAR_GET_PRIVATE(volumebar);
261 /* Should set GTK_NO_WINDOW flag, because widget is derived from
263 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (volumebar), GTK_NO_WINDOW);
264 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (volumebar), GTK_CAN_FOCUS);
266 /* Initialize mute button */
267 priv->tbutton = GTK_TOGGLE_BUTTON (gtk_toggle_button_new ());
268 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
272 hildon_volumebar_size_allocate (GtkWidget *widget,
273 GtkAllocation *allocation)
275 HildonVolumebarPrivate *priv;
277 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
280 if (GTK_WIDGET_CLASS (parent_class)->size_allocate)
281 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
283 if (GTK_WIDGET_REALIZED (widget))
284 gdk_window_move_resize (priv->event_window,
285 allocation->x, allocation->y,
286 allocation->width, allocation->height);
290 hildon_volumebar_realize (GtkWidget *widget)
292 HildonVolumebarPrivate *priv;
293 GdkWindowAttr attributes;
294 gint attributes_mask;
296 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
299 GTK_WIDGET_CLASS (parent_class)->realize (widget);
301 attributes.window_type = GDK_WINDOW_CHILD;
302 attributes.x = widget->allocation.x;
303 attributes.y = widget->allocation.y;
304 attributes.width = widget->allocation.width;
305 attributes.height = widget->allocation.height;
306 attributes.wclass = GDK_INPUT_ONLY;
307 attributes.event_mask = GDK_BUTTON_PRESS_MASK;
309 attributes_mask = GDK_WA_X | GDK_WA_Y;
311 priv->event_window = gdk_window_new (widget->window,
312 &attributes, attributes_mask);
314 gdk_window_set_user_data (priv->event_window, widget);
318 hildon_volumebar_unrealize (GtkWidget *widget)
320 HildonVolumebarPrivate *priv;
322 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
325 if (priv->event_window) {
326 gdk_window_set_user_data (priv->event_window, NULL);
327 gdk_window_destroy (priv->event_window);
328 priv->event_window = NULL;
331 GTK_WIDGET_CLASS (parent_class)->unrealize(widget);
335 hildon_volumebar_map (GtkWidget *widget)
337 HildonVolumebarPrivate *priv;
339 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
342 GTK_WIDGET_CLASS (parent_class)->map (widget);
344 /* the event window must be on top of all other widget windows, so show it
346 if (! GTK_WIDGET_SENSITIVE (widget))
347 gdk_window_show (priv->event_window);
351 hildon_volumebar_unmap (GtkWidget *widget)
353 HildonVolumebarPrivate *priv;
355 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
358 gdk_window_hide (priv->event_window);
360 GTK_WIDGET_CLASS (parent_class)->unmap(widget);
364 hildon_volumebar_grab_focus (GtkWidget *widget)
366 HildonVolumebarPrivate *priv;
368 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
371 if (GTK_WIDGET_CAN_FOCUS (widget)) {
372 if (gtk_toggle_button_get_active (priv->tbutton))
373 gtk_widget_grab_focus (GTK_WIDGET (priv->tbutton));
375 gtk_widget_grab_focus (GTK_WIDGET (priv->volumebar));
380 hildon_volumebar_focus (GtkWidget *widget,
381 GtkDirectionType direction)
383 HildonVolumebarPrivate *priv;
384 GtkOrientation orientation;
387 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
390 orientation = GTK_RANGE (priv->volumebar)->orientation;
392 has_focus = (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->volumebar)) ||
393 GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->tbutton)));
398 case GTK_DIR_TAB_FORWARD:
399 case GTK_DIR_TAB_BACKWARD:
400 if (has_focus && orientation == GTK_ORIENTATION_HORIZONTAL)
406 if (has_focus && orientation == GTK_ORIENTATION_VERTICAL)
414 return GTK_WIDGET_CLASS (parent_class)->focus (widget, direction);
418 hildon_child_forall (GtkContainer *container,
419 gboolean include_internals,
420 GtkCallback callback,
421 gpointer callback_data)
423 HildonVolumebarPrivate *priv;
425 priv = HILDON_VOLUMEBAR_GET_PRIVATE (container);
426 g_assert (callback != NULL);
429 /* No external children */
430 if (! include_internals)
433 /* Execute callback for both internals */
434 (*callback) (GTK_WIDGET (priv->tbutton), callback_data);
435 (*callback) (GTK_WIDGET (priv->volumebar), callback_data);
439 hildon_volumebar_notify (GObject *self,
442 HildonVolumebarPrivate *priv;
444 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
447 if (g_str_equal (param->name, "can-focus")) {
448 /* call set_mute() because that updates the widget's UI state */
449 hildon_volumebar_set_mute (HILDON_VOLUMEBAR (self),
450 hildon_volumebar_get_mute (HILDON_VOLUMEBAR (self)));
453 if (GTK_WIDGET_MAPPED (self)) {
454 /* show/hide the event window on sensitivity change */
455 if (g_str_equal (param->name, "sensitive")) {
456 if (GTK_WIDGET_SENSITIVE (self))
457 gdk_window_hide (priv->event_window);
459 gdk_window_show (priv->event_window);
463 if (G_OBJECT_CLASS(parent_class)->notify)
464 G_OBJECT_CLASS(parent_class)->notify (self, param);
468 hildon_volumebar_destroy (GtkObject *self)
470 HildonVolumebarPrivate *priv;
472 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
476 gtk_widget_unparent (GTK_WIDGET (priv->tbutton));
477 priv->tbutton = NULL;
479 if (priv->volumebar) {
480 gtk_widget_unparent (GTK_WIDGET (priv->volumebar));
481 priv->volumebar = NULL;
484 if (GTK_OBJECT_CLASS (parent_class)->destroy)
485 GTK_OBJECT_CLASS (parent_class)->destroy (self);
489 hildon_volumebar_set_property (GObject *object,
494 HildonVolumebarPrivate *priv;
496 priv = HILDON_VOLUMEBAR_GET_PRIVATE(object);
501 case PROP_HILDON_HAS_MUTE:
502 /* Mute button always exists but might be hidden */
503 if (g_value_get_boolean (value))
504 gtk_widget_show (GTK_WIDGET (priv->tbutton));
506 gtk_widget_hide (GTK_WIDGET (priv->tbutton));
509 case PROP_HILDON_LEVEL:
510 hildon_volumebar_set_level (HILDON_VOLUMEBAR (object),
511 g_value_get_double (value));
514 case PROP_HILDON_MUTE:
515 hildon_volumebar_set_mute (HILDON_VOLUMEBAR (object),
516 g_value_get_boolean (value));
520 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
527 hildon_volumebar_get_property (GObject *object,
532 HildonVolumebarPrivate *priv;
535 priv = HILDON_VOLUMEBAR_GET_PRIVATE(object);
538 vb = HILDON_VOLUMEBAR (object);
542 case PROP_HILDON_HAS_MUTE:
543 g_value_set_boolean (value, GTK_WIDGET_VISIBLE (priv->tbutton));
546 case PROP_HILDON_LEVEL:
547 g_value_set_double (value, hildon_volumebar_get_level (vb));
550 case PROP_HILDON_MUTE:
551 g_value_set_boolean (value, hildon_volumebar_get_mute (vb));
555 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
562 * hildon_volumebar_set_level:
563 * @self: volume bar to change level on
566 * Sets new volume level for this #HildonVolumebar.
569 hildon_volumebar_set_level (HildonVolumebar *self,
572 HildonVolumebarPrivate *priv;
574 g_return_if_fail(HILDON_IS_VOLUMEBAR (self));
576 priv = HILDON_VOLUMEBAR_GET_PRIVATE (self);
579 hildon_volumebar_range_set_level (priv->volumebar, level);
583 * hildon_volumebar_get_level:
584 * @self: volume bar to query level on
586 * Gets the volume level of this #HildonVolumebar.
588 * Returns: volume level or -1 on error
591 hildon_volumebar_get_level (HildonVolumebar *self)
593 HildonVolumebarPrivate *priv;
595 g_return_val_if_fail(HILDON_IS_VOLUMEBAR (self), -1);
597 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
600 return hildon_volumebar_range_get_level (priv->volumebar);
604 * hildon_volumebar_set_mute:
605 * @self: volume bar to work on
608 * Sets mute status for this #HildonVolumebar.
611 hildon_volumebar_set_mute (HildonVolumebar *self,
614 HildonVolumebarPrivate *priv;
617 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
619 priv = HILDON_VOLUMEBAR_GET_PRIVATE (self);
622 has_focus = (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->volumebar)) ||
623 GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->tbutton)));
625 /* Slider should be insensitive when mute is on */
626 gtk_widget_set_sensitive (GTK_WIDGET (priv->volumebar), !mute);
629 /* Make mute button focusable since the slider isn't anymore */
630 g_object_set (G_OBJECT (priv->tbutton), "can-focus", TRUE, NULL);
633 gtk_widget_grab_focus (GTK_WIDGET (priv->tbutton));
637 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
640 gtk_widget_grab_focus (GTK_WIDGET (priv->volumebar));
643 /* Update mute button state and redraw */
644 gtk_toggle_button_set_active (priv->tbutton, mute);
648 * hildon_volumebar_get_mute:
649 * @self: volume bar to query mute status
651 * Gets mute status of this #HildonVolumebar (ON/OFF).
653 * Returns: Mute status as #gboolean value.
656 hildon_volumebar_get_mute (HildonVolumebar *self)
658 HildonVolumebarPrivate *priv;
660 g_return_val_if_fail (HILDON_IS_VOLUMEBAR (self), TRUE);
662 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
665 return gtk_toggle_button_get_active (priv->tbutton);
669 * hildon_volumebar_get_adjustment
670 * @self : a #HildonVolumebar
672 * Gets the GtkAdjustment used in volume bar. This can be handy
673 * to pass to hildon_appview_set_connected_adjustment which
674 * will allow changing the volume with 'increase' / 'decrease'
677 * Returns: a #GtkAdjustment used by volume bar.
680 hildon_volumebar_get_adjustment (HildonVolumebar *self)
682 HildonVolumebarPrivate *priv;
684 g_return_val_if_fail(HILDON_IS_VOLUMEBAR(self), NULL);
686 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
689 return gtk_range_get_adjustment (GTK_RANGE (priv->volumebar));
693 mute_toggled (HildonVolumebar *self)
695 /* This looks like no-op, but it still does something meaningfull!
696 set_mute also updates the ui to match new state that
697 is already reported by get_mute */
699 hildon_volumebar_set_mute (self, hildon_volumebar_get_mute (self));
703 hildon_volumebar_key_press (GtkWidget *widget,
706 HildonVolumebarPrivate *priv;
708 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
709 g_assert (priv != NULL);
711 /* Enter key toggles mute button (unless it is hidden) */
712 if (event->keyval == GDK_Return && GTK_WIDGET_VISIBLE (priv->tbutton)) {
713 gtk_toggle_button_set_active (priv->tbutton,
714 ! hildon_volumebar_get_mute(HILDON_VOLUMEBAR(widget)));
719 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
723 * Sends mute-toggled signal to widget, used as a callback in derived classes.
726 hildon_volumebar_mute_toggled (HildonVolumebar * self)
728 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
729 /* FIXME Emit by id */
730 g_signal_emit_by_name (self, "mute_toggled");
734 hildon_volumebar_level_change (HildonVolumebar *self)
736 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
738 /* FIXME Use numerical val, id */
739 g_signal_emit_by_name (GTK_WIDGET (self), "level_changed");
743 * hildon_volumebar_set_range_insensitive_message:
744 * @widget: A @GtkWidget to assign the banner to
745 * @message: A message to display to the user
747 * Used to asign an insensitive message to the slider of the given volumebar.
748 * It simply calls hildon_helper_set_insensitive_message on the slider/range of
751 * Deprecated: As of hildon 2.2, it is strongly discouraged to use insensitive messages.
754 hildon_volumebar_set_range_insensitive_message (HildonVolumebar *widget,
755 const gchar *message)
757 g_return_if_fail (HILDON_IS_VOLUMEBAR (widget));
759 HildonVolumebarPrivate *priv;
760 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
762 hildon_helper_set_insensitive_message ((GtkWidget *) priv->volumebar, message);
766 * hildon_volumebar_set_range_insensitive_messagef:
767 * @widget: A @GtkWidget to assign the banner to
768 * @format : a printf-like format string
769 * @varargs : arguments for the format string
771 * A helper printf-like variant of hildon_helper_set_insensitive_message.
773 * Deprecated: As of hildon 2.2, it is strongly discouraged to use insensitive messages.
776 hildon_volumebar_set_range_insensitive_messagef (HildonVolumebar *widget,
780 g_return_if_fail (HILDON_IS_VOLUMEBAR (widget));
782 HildonVolumebarPrivate *priv;
783 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
788 va_start (args, format);
789 message = g_strdup_vprintf (format, args);
792 hildon_helper_set_insensitive_message ((GtkWidget *) priv->volumebar, message);