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 | |
47 | typedef struct _GtkVolumeButtonClass GtkVolumeButtonClass; |
48 | |
49 | struct _GtkVolumeButtonClass |
50 | { |
51 | GtkScaleButtonClass parent_class; |
52 | }; |
53 | |
54 | #define EPSILON (1e-10) |
55 | |
56 | static 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 | |
65 | static 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 | |
74 | enum |
75 | { |
76 | PROP_0, |
77 | PROP_SYMBOLIC |
78 | }; |
79 | |
80 | static gboolean cb_query_tooltip (GtkWidget *button, |
81 | int x, |
82 | int y, |
83 | gboolean keyboard_mode, |
84 | GtkTooltip *tooltip, |
85 | gpointer user_data); |
86 | static void cb_value_changed (GtkVolumeButton *button, |
87 | double value, |
88 | gpointer user_data); |
89 | |
90 | G_DEFINE_TYPE (GtkVolumeButton, gtk_volume_button, GTK_TYPE_SCALE_BUTTON) |
91 | |
92 | static gboolean |
93 | get_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 | |
110 | static void |
111 | gtk_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 | |
136 | static void |
137 | gtk_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 | |
153 | static void |
154 | gtk_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 | |
185 | static void |
186 | gtk_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 | */ |
204 | GtkWidget * |
205 | gtk_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 | |
212 | static gboolean |
213 | cb_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 | |
256 | static void |
257 | cb_value_changed (GtkVolumeButton *button, double value, gpointer user_data) |
258 | { |
259 | gtk_widget_trigger_tooltip_query (GTK_WIDGET (button)); |
260 | } |
261 | |