1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2007 Red Hat, Inc.
3 *
4 * Authors:
5 * - Bastien Nocera <bnocera@redhat.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /*
22 * Modified by the GTK+ Team and others 2007. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26 */
27
28 #include "config.h"
29
30 #include "gtkvolumebutton.h"
31
32 #include "gtkadjustment.h"
33 #include "gtkintl.h"
34 #include "gtktooltip.h"
35
36
37 /**
38 * SECTION:gtkvolumebutton
39 * @Short_description: A button which pops up a volume control
40 * @Title: GtkVolumeButton
41 *
42 * #GtkVolumeButton is a subclass of #GtkScaleButton that has
43 * been tailored for use as a volume control widget with suitable
44 * icons, tooltips and accessible labels.
45 */
46
47 #define EPSILON (1e-10)
48
49 static const gchar * const icons[] =
50 {
51 "audio-volume-muted",
52 "audio-volume-high",
53 "audio-volume-low",
54 "audio-volume-medium",
55 NULL
56 };
57
58 static const gchar * const icons_symbolic[] =
59 {
60 "audio-volume-muted-symbolic",
61 "audio-volume-high-symbolic",
62 "audio-volume-low-symbolic",
63 "audio-volume-medium-symbolic",
64 NULL
65 };
66
67 enum
68 {
69 PROP_0,
70 PROP_SYMBOLIC
71 };
72
73 static gboolean cb_query_tooltip (GtkWidget *button,
74 gint x,
75 gint y,
76 gboolean keyboard_mode,
77 GtkTooltip *tooltip,
78 gpointer user_data);
79 static void cb_value_changed (GtkVolumeButton *button,
80 gdouble value,
81 gpointer user_data);
82
G_DEFINE_TYPE(GtkVolumeButton,gtk_volume_button,GTK_TYPE_SCALE_BUTTON)83 G_DEFINE_TYPE (GtkVolumeButton, gtk_volume_button, GTK_TYPE_SCALE_BUTTON)
84
85 static gboolean
86 get_symbolic (GtkScaleButton *button)
87 {
88 gchar **icon_list;
89 gboolean ret;
90
91 g_object_get (button, "icons", &icon_list, NULL);
92 if (icon_list != NULL &&
93 icon_list[0] != NULL &&
94 g_str_equal (icon_list[0], icons_symbolic[0]))
95 ret = TRUE;
96 else
97 ret = FALSE;
98 g_strfreev (icon_list);
99
100 return ret;
101 }
102
103 static void
gtk_volume_button_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)104 gtk_volume_button_set_property (GObject *object,
105 guint prop_id,
106 const GValue *value,
107 GParamSpec *pspec)
108 {
109 GtkScaleButton *button = GTK_SCALE_BUTTON (object);
110
111 switch (prop_id)
112 {
113 case PROP_SYMBOLIC:
114 if (get_symbolic (button) != g_value_get_boolean (value))
115 {
116 if (g_value_get_boolean (value))
117 gtk_scale_button_set_icons (button, (const char **) icons_symbolic);
118 else
119 gtk_scale_button_set_icons (button, (const char **) icons);
120 g_object_notify_by_pspec (object, pspec);
121 }
122 break;
123 default:
124 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
125 break;
126 }
127 }
128
129 static void
gtk_volume_button_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)130 gtk_volume_button_get_property (GObject *object,
131 guint prop_id,
132 GValue *value,
133 GParamSpec *pspec)
134 {
135 switch (prop_id)
136 {
137 case PROP_SYMBOLIC:
138 g_value_set_boolean (value, get_symbolic (GTK_SCALE_BUTTON (object)));
139 break;
140 default:
141 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
142 break;
143 }
144 }
145
146 static void
gtk_volume_button_class_init(GtkVolumeButtonClass * klass)147 gtk_volume_button_class_init (GtkVolumeButtonClass *klass)
148 {
149 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
150 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
151
152 gobject_class->set_property = gtk_volume_button_set_property;
153 gobject_class->get_property = gtk_volume_button_get_property;
154
155 /**
156 * GtkVolumeButton:use-symbolic:
157 *
158 * Whether to use symbolic icons as the icons. Note that
159 * if the symbolic icons are not available in your installed
160 * theme, then the normal (potentially colorful) icons will
161 * be used.
162 *
163 * Since: 3.0
164 */
165 g_object_class_install_property (gobject_class,
166 PROP_SYMBOLIC,
167 g_param_spec_boolean ("use-symbolic",
168 P_("Use symbolic icons"),
169 P_("Whether to use symbolic icons"),
170 TRUE,
171 G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY));
172
173 /* Bind class to template
174 */
175 gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkvolumebutton.ui");
176 gtk_widget_class_bind_template_callback (widget_class, cb_query_tooltip);
177 gtk_widget_class_bind_template_callback (widget_class, cb_value_changed);
178 }
179
180 static void
gtk_volume_button_init(GtkVolumeButton * button)181 gtk_volume_button_init (GtkVolumeButton *button)
182 {
183 GtkWidget *widget = GTK_WIDGET (button);
184
185 gtk_widget_init_template (widget);
186
187 /* The atk action description is not supported by GtkBuilder */
188 atk_action_set_description (ATK_ACTION (gtk_widget_get_accessible (GTK_WIDGET (widget))),
189 1, _("Adjusts the volume"));
190 }
191
192 /**
193 * gtk_volume_button_new:
194 *
195 * Creates a #GtkVolumeButton, with a range between 0.0 and 1.0, with
196 * a stepping of 0.02. Volume values can be obtained and modified using
197 * the functions from #GtkScaleButton.
198 *
199 * Returns: a new #GtkVolumeButton
200 *
201 * Since: 2.12
202 */
203 GtkWidget *
gtk_volume_button_new(void)204 gtk_volume_button_new (void)
205 {
206 GObject *button;
207 button = g_object_new (GTK_TYPE_VOLUME_BUTTON, NULL);
208 return GTK_WIDGET (button);
209 }
210
211 static gboolean
cb_query_tooltip(GtkWidget * button,gint x,gint y,gboolean keyboard_mode,GtkTooltip * tooltip,gpointer user_data)212 cb_query_tooltip (GtkWidget *button,
213 gint x,
214 gint y,
215 gboolean keyboard_mode,
216 GtkTooltip *tooltip,
217 gpointer user_data)
218 {
219 GtkScaleButton *scale_button = GTK_SCALE_BUTTON (button);
220 GtkAdjustment *adjustment;
221 gdouble val;
222 char *str;
223 AtkImage *image;
224
225 image = ATK_IMAGE (gtk_widget_get_accessible (button));
226
227 adjustment = gtk_scale_button_get_adjustment (scale_button);
228 val = gtk_scale_button_get_value (scale_button);
229
230 if (val < (gtk_adjustment_get_lower (adjustment) + EPSILON))
231 {
232 str = g_strdup (_("Muted"));
233 }
234 else if (val >= (gtk_adjustment_get_upper (adjustment) - EPSILON))
235 {
236 str = g_strdup (_("Full Volume"));
237 }
238 else
239 {
240 int percent;
241
242 percent = (int) (100. * val / (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment)) + .5);
243
244 /* Translators: this is the percentage of the current volume,
245 * as used in the tooltip, eg. "49 %".
246 * Translate the "%d" to "%Id" if you want to use localised digits,
247 * or otherwise translate the "%d" to "%d".
248 */
249 str = g_strdup_printf (C_("volume percentage", "%d %%"), percent);
250 }
251
252 gtk_tooltip_set_text (tooltip, str);
253 atk_image_set_image_description (image, str);
254 g_free (str);
255
256 return TRUE;
257 }
258
259 static void
cb_value_changed(GtkVolumeButton * button,gdouble value,gpointer user_data)260 cb_value_changed (GtkVolumeButton *button, gdouble value, gpointer user_data)
261 {
262 gtk_widget_trigger_tooltip_query (GTK_WIDGET (button));
263 }
264