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.
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:mute:
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 (object),
459 g_value_get_double (value));
462 case PROP_HILDON_MUTE:
463 hildon_volumebar_set_mute (HILDON_VOLUMEBAR (object),
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;
568 gboolean volumebar_has_focus;
569 gboolean button_has_focus;
571 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
573 priv = HILDON_VOLUMEBAR_GET_PRIVATE (self);
576 volumebar_has_focus = GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->volumebar));
577 button_has_focus = GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (priv->tbutton));
579 /* Slider should be insensitive when mute is on */
580 gtk_widget_set_sensitive (GTK_WIDGET (priv->volumebar), !mute);
582 focusable = GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (priv->volumebar));
585 if (focusable && volumebar_has_focus) {
586 /* Make mute button focusable since the slider isn't anymore */
587 g_object_set (G_OBJECT (priv->tbutton), "can-focus", TRUE, NULL);
588 gtk_widget_grab_focus (GTK_WIDGET (priv->tbutton));
593 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
595 /* Mute off grabs focus */
596 if (focusable && button_has_focus){
597 gtk_widget_grab_focus (GTK_WIDGET (priv->volumebar));
601 /* Update mute button state and redraw */
602 gtk_toggle_button_set_active (priv->tbutton, mute);
604 /* FIXME I'm darn sure that's not really needed */
605 gtk_widget_queue_draw (GTK_WIDGET (self));
609 * hildon_volumebar_get_mute:
610 * @self: volume bar to query mute status
612 * Gets mute status of this #HildonVolumebar (ON/OFF).
614 * Returns: Mute status as #gboolean value.
617 hildon_volumebar_get_mute (HildonVolumebar *self)
619 HildonVolumebarPrivate *priv;
621 g_return_val_if_fail (HILDON_IS_VOLUMEBAR (self), TRUE);
623 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
626 return gtk_toggle_button_get_active (priv->tbutton);
630 * hildon_volumebar_get_adjustment
631 * @self : a #HildonVolumebar
633 * Gets the GtkAdjustment used in volume bar. This can be handy
634 * to pass to hildon_appview_set_connected_adjustment which
635 * will allow changing the volume with 'increase' / 'decrease'
638 * Returns: a #GtkAdjustment used by volume bar.
641 hildon_volumebar_get_adjustment (HildonVolumebar *self)
643 HildonVolumebarPrivate *priv;
645 g_return_val_if_fail(HILDON_IS_VOLUMEBAR(self), NULL);
647 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
650 return gtk_range_get_adjustment (GTK_RANGE (priv->volumebar));
654 mute_toggled (HildonVolumebar *self)
656 /* This looks like no-op, but it still does something meaningfull!
657 set_mute also updates the ui to match new state that
658 is already reported by get_mute */
660 hildon_volumebar_set_mute (self, hildon_volumebar_get_mute (self));
664 hildon_volumebar_key_press (GtkWidget *widget,
667 HildonVolumebarPrivate *priv;
669 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
670 g_assert (priv != NULL);
672 /* Enter key toggles mute button (unless it is hidden) */
673 if (event->keyval == GDK_Return && GTK_WIDGET_VISIBLE (priv->tbutton)) {
674 gtk_toggle_button_set_active (priv->tbutton,
675 ! hildon_volumebar_get_mute(HILDON_VOLUMEBAR(widget)));
680 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
684 * Sends mute-toggled signal to widget, used as a callback in derived classes.
687 hildon_volumebar_mute_toggled (HildonVolumebar * self)
689 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
690 /* FIXME Emit by id */
691 g_signal_emit_by_name (self, "mute_toggled");
695 hildon_volumebar_level_change (HildonVolumebar *self)
697 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
699 /* FIXME Use numerical val, id */
700 g_signal_emit_by_name (GTK_WIDGET (self), "level_changed");
704 * hildon_volumebar_set_range_insensitive_message:
705 * @widget: A @GtkWidget to assign the banner to
706 * @message: A message to display to the user
708 * Used to asign an insensitive message to the slider of the given volumebar.
709 * It simply calls hildon_helper_set_insensitive_message on the slider/range of
713 hildon_volumebar_set_range_insensitive_message (HildonVolumebar *widget,
714 const gchar *message)
716 g_return_if_fail (HILDON_IS_VOLUMEBAR (widget));
718 HildonVolumebarPrivate *priv;
719 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
721 hildon_helper_set_insensitive_message ((GtkWidget *) priv->volumebar, message);
725 * hildon_volumebar_set_range_insensitive_messagef:
726 * @widget: A @GtkWidget to assign the banner to
727 * @format : a printf-like format string
728 * @varargs : arguments for the format string
730 * A helper printf-like variant of hildon_helper_set_insensitive_message.
733 hildon_volumebar_set_range_insensitive_messagef (HildonVolumebar *widget,
737 g_return_if_fail (HILDON_IS_VOLUMEBAR (widget));
739 HildonVolumebarPrivate *priv;
740 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
745 va_start (args, format);
746 message = g_strdup_vprintf (format, args);
749 hildon_helper_set_insensitive_message ((GtkWidget *) priv->volumebar, message);