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#include "gtkprivate.h"
36
37
38/**
39 * GtkVolumeButton:
40 *
41 * `GtkVolumeButton` is a `GtkScaleButton` subclass tailored for
42 * volume control.
43 *
44 * ![An example GtkVolumeButton](volumebutton.png)
45 */
46
47typedef struct _GtkVolumeButtonClass GtkVolumeButtonClass;
48
49struct _GtkVolumeButtonClass
50{
51 GtkScaleButtonClass parent_class;
52};
53
54#define EPSILON (1e-10)
55
56static const char * const icons[] =
57{
58 "audio-volume-muted",
59 "audio-volume-high",
60 "audio-volume-low",
61 "audio-volume-medium",
62 NULL
63};
64
65static const char * const icons_symbolic[] =
66{
67 "audio-volume-muted-symbolic",
68 "audio-volume-high-symbolic",
69 "audio-volume-low-symbolic",
70 "audio-volume-medium-symbolic",
71 NULL
72};
73
74enum
75{
76 PROP_0,
77 PROP_SYMBOLIC
78};
79
80static gboolean cb_query_tooltip (GtkWidget *button,
81 int x,
82 int y,
83 gboolean keyboard_mode,
84 GtkTooltip *tooltip,
85 gpointer user_data);
86static void cb_value_changed (GtkVolumeButton *button,
87 double value,
88 gpointer user_data);
89
90G_DEFINE_TYPE (GtkVolumeButton, gtk_volume_button, GTK_TYPE_SCALE_BUTTON)
91
92static gboolean
93get_symbolic (GtkScaleButton *button)
94{
95 char **icon_list;
96 gboolean ret;
97
98 g_object_get (object: button, first_property_name: "icons", &icon_list, NULL);
99 if (icon_list != NULL &&
100 icon_list[0] != NULL &&
101 g_str_equal (v1: icon_list[0], v2: icons_symbolic[0]))
102 ret = TRUE;
103 else
104 ret = FALSE;
105 g_strfreev (str_array: icon_list);
106
107 return ret;
108}
109
110static void
111gtk_volume_button_set_property (GObject *object,
112 guint prop_id,
113 const GValue *value,
114 GParamSpec *pspec)
115{
116 GtkScaleButton *button = GTK_SCALE_BUTTON (object);
117
118 switch (prop_id)
119 {
120 case PROP_SYMBOLIC:
121 if (get_symbolic (button) != g_value_get_boolean (value))
122 {
123 if (g_value_get_boolean (value))
124 gtk_scale_button_set_icons (button, icons: (const char **) icons_symbolic);
125 else
126 gtk_scale_button_set_icons (button, icons: (const char **) icons);
127 g_object_notify_by_pspec (object, pspec);
128 }
129 break;
130 default:
131 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
132 break;
133 }
134}
135
136static void
137gtk_volume_button_get_property (GObject *object,
138 guint prop_id,
139 GValue *value,
140 GParamSpec *pspec)
141{
142 switch (prop_id)
143 {
144 case PROP_SYMBOLIC:
145 g_value_set_boolean (value, v_boolean: get_symbolic (GTK_SCALE_BUTTON (object)));
146 break;
147 default:
148 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
149 break;
150 }
151}
152
153static void
154gtk_volume_button_class_init (GtkVolumeButtonClass *klass)
155{
156 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
157 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
158
159 gobject_class->set_property = gtk_volume_button_set_property;
160 gobject_class->get_property = gtk_volume_button_get_property;
161
162 /**
163 * GtkVolumeButton:use-symbolic:
164 *
165 * Whether to use symbolic icons as the icons.
166 *
167 * Note that if the symbolic icons are not available in your installed
168 * theme, then the normal (potentially colorful) icons will be used.
169 */
170 g_object_class_install_property (oclass: gobject_class,
171 property_id: PROP_SYMBOLIC,
172 pspec: g_param_spec_boolean (name: "use-symbolic",
173 P_("Use symbolic icons"),
174 P_("Whether to use symbolic icons"),
175 TRUE,
176 GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY));
177
178 /* Bind class to template
179 */
180 gtk_widget_class_set_template_from_resource (widget_class, resource_name: "/org/gtk/libgtk/ui/gtkvolumebutton.ui");
181 gtk_widget_class_bind_template_callback (widget_class, cb_query_tooltip);
182 gtk_widget_class_bind_template_callback (widget_class, cb_value_changed);
183}
184
185static void
186gtk_volume_button_init (GtkVolumeButton *button)
187{
188 GtkWidget *widget = GTK_WIDGET (button);
189
190 gtk_widget_init_template (widget);
191}
192
193/**
194 * gtk_volume_button_new:
195 *
196 * Creates a `GtkVolumeButton`.
197 *
198 * The button has a range between 0.0 and 1.0, with a stepping of 0.02.
199 * Volume values can be obtained and modified using the functions from
200 * [class@Gtk.ScaleButton].
201 *
202 * Returns: a new `GtkVolumeButton`
203 */
204GtkWidget *
205gtk_volume_button_new (void)
206{
207 GObject *button;
208 button = g_object_new (GTK_TYPE_VOLUME_BUTTON, NULL);
209 return GTK_WIDGET (button);
210}
211
212static gboolean
213cb_query_tooltip (GtkWidget *button,
214 int x,
215 int y,
216 gboolean keyboard_mode,
217 GtkTooltip *tooltip,
218 gpointer user_data)
219{
220 GtkScaleButton *scale_button = GTK_SCALE_BUTTON (button);
221 GtkAdjustment *adjustment;
222 double val;
223 char *str;
224
225 adjustment = gtk_scale_button_get_adjustment (button: scale_button);
226 val = gtk_scale_button_get_value (button: scale_button);
227
228 if (val < (gtk_adjustment_get_lower (adjustment) + EPSILON))
229 {
230 str = g_strdup (_("Muted"));
231 }
232 else if (val >= (gtk_adjustment_get_upper (adjustment) - EPSILON))
233 {
234 str = g_strdup (_("Full Volume"));
235 }
236 else
237 {
238 int percent;
239
240 percent = (int) (100. * val / (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment)) + .5);
241
242 /* Translators: this is the percentage of the current volume,
243 * as used in the tooltip, eg. "49 %".
244 * Translate the "%d" to "%Id" if you want to use localised digits,
245 * or otherwise translate the "%d" to "%d".
246 */
247 str = g_strdup_printf (C_("volume percentage", "%d %%"), percent);
248 }
249
250 gtk_tooltip_set_text (tooltip, text: str);
251 g_free (mem: str);
252
253 return TRUE;
254}
255
256static void
257cb_value_changed (GtkVolumeButton *button, double value, gpointer user_data)
258{
259 gtk_widget_trigger_tooltip_query (GTK_WIDGET (button));
260}
261

source code of gtk/gtk/gtkvolumebutton.c