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 (void)
120 static GType volumebar_type = 0;
122 if (!volumebar_type) {
123 static const GTypeInfo volumebar_info = {
124 sizeof(HildonVolumebarClass),
125 NULL, /* base_init */
126 NULL, /* base_finalize */
127 (GClassInitFunc) hildon_volumebar_class_init,
128 NULL, /* class_finalize */
129 NULL, /* class_data */
130 sizeof(HildonVolumebar),
132 (GInstanceInitFunc) hildon_volumebar_init,
134 volumebar_type = g_type_register_static(GTK_TYPE_CONTAINER,
138 return volumebar_type;
142 hildon_volumebar_class_init (HildonVolumebarClass *volumebar_class)
144 GObjectClass *gobject_class = G_OBJECT_CLASS (volumebar_class);
145 GtkObjectClass *object_class = GTK_OBJECT_CLASS (volumebar_class);
146 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (volumebar_class);
147 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (volumebar_class);
149 parent_class = g_type_class_peek_parent (volumebar_class);
151 g_type_class_add_private (volumebar_class,
152 sizeof (HildonVolumebarPrivate));
154 /* Because we derived our widget from GtkContainer, we should also
155 * override forall method
157 volumebar_class->mute_toggled = mute_toggled;
158 container_class->forall = hildon_child_forall;
159 widget_class->size_allocate = hildon_volumebar_size_allocate;
160 widget_class->realize = hildon_volumebar_realize;
161 widget_class->unrealize = hildon_volumebar_unrealize;
162 widget_class->map = hildon_volumebar_map;
163 widget_class->unmap = hildon_volumebar_unmap;
164 widget_class->key_press_event = hildon_volumebar_key_press;
165 object_class->destroy = hildon_volumebar_destroy;
167 signals[MUTE_TOGGLED_SIGNAL] = g_signal_new ("mute_toggled",
173 (HildonVolumebarClass,
174 mute_toggled), NULL, NULL,
175 gtk_marshal_VOID__VOID,
178 signals[LEVEL_CHANGED_SIGNAL] = g_signal_new ("level_changed",
184 (HildonVolumebarClass,
185 level_changed), NULL,
187 gtk_marshal_VOID__VOID,
190 gobject_class->notify = hildon_volumebar_notify;
191 gobject_class->set_property = hildon_volumebar_set_property;
192 gobject_class->get_property = hildon_volumebar_get_property;
194 /*This kind of property could be usefull in the gtkcontainer*/
195 g_object_class_install_property (gobject_class,
196 PROP_HILDON_FOCUSABLE,
197 g_param_spec_boolean ("can-focus",
198 "The widget focusablility",
199 "The widget focusablility. TRUE is focusable",
201 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
203 g_object_class_install_property (gobject_class,
204 PROP_HILDON_HAS_MUTE,
205 g_param_spec_boolean ("has_mute",
206 "Show/Hide the mute button",
207 "Whether the mute button is visible. Default value: TRUE",
209 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
211 g_object_class_install_property (gobject_class,
213 g_param_spec_double ("level",
215 "Current volume level",
221 g_object_class_install_property (gobject_class,
223 g_param_spec_boolean ("mute",
225 "Whether volume is muted",
231 hildon_volumebar_init (HildonVolumebar *volumebar)
233 HildonVolumebarPrivate *priv;
235 priv = HILDON_VOLUMEBAR_GET_PRIVATE(volumebar);
238 /* Should set GTK_NO_WINDOW flag, because widget is derived from
240 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (volumebar), GTK_NO_WINDOW);
241 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (volumebar), GTK_CAN_FOCUS);
243 /* Initialize mute button */
244 priv->tbutton = GTK_TOGGLE_BUTTON (gtk_toggle_button_new ());
245 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
249 hildon_volumebar_size_allocate (GtkWidget *widget,
250 GtkAllocation *allocation)
252 HildonVolumebarPrivate *priv;
254 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
257 if (GTK_WIDGET_CLASS (parent_class)->size_allocate)
258 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
260 if (GTK_WIDGET_REALIZED (widget))
261 gdk_window_move_resize (priv->event_window,
262 allocation->x, allocation->y,
263 allocation->width, allocation->height);
267 hildon_volumebar_realize (GtkWidget *widget)
269 HildonVolumebarPrivate *priv;
270 GdkWindowAttr attributes;
271 gint attributes_mask;
273 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
276 GTK_WIDGET_CLASS (parent_class)->realize (widget);
278 attributes.window_type = GDK_WINDOW_CHILD;
279 attributes.x = widget->allocation.x;
280 attributes.y = widget->allocation.y;
281 attributes.width = widget->allocation.width;
282 attributes.height = widget->allocation.height;
283 attributes.wclass = GDK_INPUT_ONLY;
284 attributes.event_mask = GDK_BUTTON_PRESS_MASK;
286 attributes_mask = GDK_WA_X | GDK_WA_Y;
288 priv->event_window = gdk_window_new (widget->window,
289 &attributes, attributes_mask);
291 gdk_window_set_user_data (priv->event_window, widget);
295 hildon_volumebar_unrealize (GtkWidget *widget)
297 HildonVolumebarPrivate *priv;
299 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
302 if (priv->event_window) {
303 gdk_window_set_user_data (priv->event_window, NULL);
304 gdk_window_destroy (priv->event_window);
305 priv->event_window = NULL;
308 GTK_WIDGET_CLASS (parent_class)->unrealize(widget);
312 hildon_volumebar_map (GtkWidget *widget)
314 HildonVolumebarPrivate *priv;
316 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
319 GTK_WIDGET_CLASS (parent_class)->map (widget);
321 /* the event window must be on top of all other widget windows, so show it
323 if (! GTK_WIDGET_SENSITIVE (widget))
324 gdk_window_show (priv->event_window);
328 hildon_volumebar_unmap (GtkWidget *widget)
330 HildonVolumebarPrivate *priv;
332 priv = HILDON_VOLUMEBAR_GET_PRIVATE (widget);
335 gdk_window_hide (priv->event_window);
337 GTK_WIDGET_CLASS (parent_class)->unmap(widget);
341 hildon_child_forall (GtkContainer *container,
342 gboolean include_internals,
343 GtkCallback callback,
344 gpointer callback_data)
346 HildonVolumebarPrivate *priv;
348 priv = HILDON_VOLUMEBAR_GET_PRIVATE (container);
349 g_assert (callback != NULL);
352 /* No external children */
353 if (! include_internals)
356 /* Execute callback for both internals */
357 (*callback) (GTK_WIDGET (priv->tbutton), callback_data);
358 (*callback) (GTK_WIDGET (priv->volumebar), callback_data);
362 hildon_volumebar_notify (GObject *self,
365 HildonVolumebarPrivate *priv;
367 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
370 if (GTK_WIDGET_MAPPED (self)) {
371 /* show/hide the event window on sensitivity change */
372 if (g_str_equal (param->name, "sensitive")) {
373 if (GTK_WIDGET_SENSITIVE (self))
374 gdk_window_hide (priv->event_window);
376 gdk_window_show (priv->event_window);
380 if (G_OBJECT_CLASS(parent_class)->notify)
381 G_OBJECT_CLASS(parent_class)->notify (self, param);
385 hildon_volumebar_destroy (GtkObject *self)
387 HildonVolumebarPrivate *priv;
389 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
393 gtk_widget_unparent (GTK_WIDGET (priv->tbutton));
394 priv->tbutton = NULL;
396 if (priv->volumebar) {
397 gtk_widget_unparent (GTK_WIDGET (priv->volumebar));
398 priv->volumebar = NULL;
401 if (GTK_OBJECT_CLASS (parent_class)->destroy)
402 GTK_OBJECT_CLASS (parent_class)->destroy (self);
406 hildon_volumebar_set_property (GObject *object,
411 HildonVolumebarPrivate *priv;
413 priv = HILDON_VOLUMEBAR_GET_PRIVATE(object);
418 case PROP_HILDON_HAS_MUTE:
419 /* Mute button always exists but might be hidden */
420 if (g_value_get_boolean (value))
421 gtk_widget_show (GTK_WIDGET (priv->tbutton));
423 gtk_widget_hide (GTK_WIDGET (priv->tbutton));
426 case PROP_HILDON_FOCUSABLE:
427 g_object_set (G_OBJECT (priv->volumebar), "can-focus",
428 g_value_get_boolean (value), NULL );
431 case PROP_HILDON_LEVEL:
432 hildon_volumebar_set_level (HILDON_VOLUMEBAR (priv->volumebar),
433 g_value_get_double (value));
436 case PROP_HILDON_MUTE:
437 hildon_volumebar_set_mute (HILDON_VOLUMEBAR (priv->volumebar),
438 g_value_get_boolean (value));
442 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
449 hildon_volumebar_get_property (GObject *object,
454 HildonVolumebarPrivate *priv;
457 priv = HILDON_VOLUMEBAR_GET_PRIVATE(object);
460 vb = HILDON_VOLUMEBAR (object);
464 case PROP_HILDON_HAS_MUTE:
465 g_value_set_boolean (value, GTK_WIDGET_VISIBLE (priv->tbutton));
468 case PROP_HILDON_FOCUSABLE:
469 g_value_set_boolean (value, GTK_WIDGET_CAN_FOCUS (priv->volumebar));
472 case PROP_HILDON_LEVEL:
473 g_value_set_double (value, hildon_volumebar_get_level (vb));
476 case PROP_HILDON_MUTE:
477 g_value_set_boolean (value, hildon_volumebar_get_mute (vb));
481 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
488 * hildon_volumebar_set_level:
489 * @self: volume bar to change level on
492 * Sets new volume level for this #HildonVolumebar.
495 hildon_volumebar_set_level (HildonVolumebar *self,
498 HildonVolumebarPrivate *priv;
500 g_return_if_fail(HILDON_IS_VOLUMEBAR (self));
502 priv = HILDON_VOLUMEBAR_GET_PRIVATE (self);
505 hildon_volumebar_range_set_level (priv->volumebar, level);
509 * hildon_volumebar_get_level:
510 * @self: volume bar to query level on
512 * Gets the volume level of this #HildonVolumebar.
514 * Returns: volume level or -1 on error
517 hildon_volumebar_get_level (HildonVolumebar *self)
519 HildonVolumebarPrivate *priv;
521 g_return_val_if_fail(HILDON_IS_VOLUMEBAR (self), -1);
523 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
526 return hildon_volumebar_range_get_level (priv->volumebar);
530 * hildon_volumebar_set_mute:
531 * @self: volume bar to work on
534 * Sets mute status for this #HildonVolumebar.
537 hildon_volumebar_set_mute (HildonVolumebar *self,
540 HildonVolumebarPrivate *priv;
541 gboolean focusable = TRUE;
543 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
545 priv = HILDON_VOLUMEBAR_GET_PRIVATE (self);
548 /* Slider should be insensitive when mute is on */
549 gtk_widget_set_sensitive (GTK_WIDGET (priv->volumebar), !mute);
551 focusable = GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (priv->volumebar));
555 /* Make mute button focusable since the slider isn't anymore */
556 g_object_set (G_OBJECT (priv->tbutton), "can-focus", TRUE, NULL);
557 gtk_widget_grab_focus (GTK_WIDGET (priv->tbutton));
562 g_object_set (G_OBJECT (priv->tbutton), "can-focus", FALSE, NULL);
564 /* Mute off grabs focus */
566 gtk_widget_grab_focus (GTK_WIDGET (self));
569 /* If volumebar is not focusable, focus the parent window instead */
570 GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (self),
572 gtk_window_set_focus (GTK_WINDOW (win), NULL);
576 /* Update mute button state and redraw */
577 gtk_toggle_button_set_active (priv->tbutton, mute);
579 /* FIXME I'm darn sure that's not really needed */
580 gtk_widget_queue_draw (GTK_WIDGET (self));
584 * hildon_volumebar_get_mute:
585 * @self: volume bar to query mute status
587 * Gets mute status of this #HildonVolumebar (ON/OFF).
589 * Returns: Mute status as #gboolean value.
592 hildon_volumebar_get_mute (HildonVolumebar *self)
594 HildonVolumebarPrivate *priv;
596 g_return_val_if_fail (HILDON_IS_VOLUMEBAR (self), TRUE);
598 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
601 return gtk_toggle_button_get_active (priv->tbutton);
605 * hildon_volumebar_get_adjustment
606 * @self : a #HildonVolumebar
608 * Gets the GtkAdjustment used in volume bar. This can be handy
609 * to pass to hildon_appview_set_connected_adjustment which
610 * will allow changing the volume with 'increase' / 'decrease'
613 * Returns: a #GtkAdjustment used by volume bar.
616 hildon_volumebar_get_adjustment (HildonVolumebar *self)
618 HildonVolumebarPrivate *priv;
620 g_return_val_if_fail(HILDON_IS_VOLUMEBAR(self), NULL);
622 priv = HILDON_VOLUMEBAR_GET_PRIVATE(self);
625 return gtk_range_get_adjustment (GTK_RANGE (priv->volumebar));
629 mute_toggled (HildonVolumebar *self)
631 /* This looks like no-op, but it still does something meaningfull!
632 set_mute also updates the ui to match new state that
633 is already reported by get_mute */
635 hildon_volumebar_set_mute (self, hildon_volumebar_get_mute (self));
639 hildon_volumebar_key_press (GtkWidget *widget,
642 HildonVolumebarPrivate *priv;
644 priv = HILDON_VOLUMEBAR_GET_PRIVATE(widget);
645 g_assert (priv != NULL);
647 /* Enter key toggles mute button (unless it is hidden) */
648 if (event->keyval == GDK_Return && GTK_WIDGET_VISIBLE (priv->tbutton)) {
649 gtk_toggle_button_set_active (priv->tbutton,
650 ! hildon_volumebar_get_mute(HILDON_VOLUMEBAR(widget)));
655 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
659 * Sends mute-toggled signal to widget, used as a callback in derived classes.
662 hildon_volumebar_mute_toggled (HildonVolumebar * self)
664 g_return_if_fail(HILDON_IS_VOLUMEBAR(self));
665 /* FIXME Emit by id */
666 g_signal_emit_by_name(self, "mute_toggled");
670 hildon_volumebar_level_change (HildonVolumebar *self)
672 g_return_if_fail (HILDON_IS_VOLUMEBAR (self));
674 /* FIXME Use numerical val, id */
675 g_signal_emit_by_name (GTK_WIDGET(self), "level_changed");