Enabling multithreaded compilation.
[debian/lxpanel.git] / src / plugins / volume / volume.c
CommitLineData
6cc5e1a6 1/**
10862fa6
DB
2 * Copyright (c) 2006, 2008 LxDE Developers,
3 * see the file AUTHORS for details.
6cc5e1a6
DB
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include <gtk/gtk.h>
21#include <stdlib.h>
22#include <fcntl.h>
23#include <unistd.h>
24
25#include <glib/gi18n.h>
26#include <gdk-pixbuf/gdk-pixbuf.h>
27
28#include "panel.h"
29#include "misc.h"
30#include "plugin.h"
31
32#include "dbg.h"
33
34#include "volume-impl.h"
35
36#include "volume_xpm.h"
37#undef const
38
39int mixer_fd;
40
10862fa6
DB
41GtkSpinButton *vol_spin;
42static gdouble vol_before_mute;
43static gdouble curr_volume;
44static GtkWidget *curr_image;
45static gboolean skip_botton1_event;
46
6cc5e1a6
DB
47typedef struct {
48 GtkWidget *mainw;
49 GtkWidget *dlg;
50 GtkTooltips* tooltips;
51} volume_t;
52
53static void
54volume_destructor(Plugin *p)
55{
56 volume_t *vol = (volume_t *) p->priv;
57
58 ENTER;
59 if (vol->dlg)
60 gtk_widget_destroy(vol->dlg);
61 g_object_unref( vol->tooltips );
62 gtk_widget_destroy(vol->mainw);
63 if (mixer_fd)
64 close(mixer_fd);
65 g_free(vol);
66 RET();
67}
68
10862fa6
DB
69static void update_icon (Plugin* p)
70{
71 volume_t *vol = (volume_t*) p->priv;
72
73 GdkPixbuf *icon;
74 GtkWidget *image;
75 GtkIconTheme* theme;
76 GtkIconInfo* info;
77
0f7f2ef3 78 theme = p->panel->icon_theme;
10862fa6
DB
79
80 if (curr_volume <= 0) {
1ea75322 81 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-mute", p->panel->icon_size, 0 );
10862fa6
DB
82 }
83 else if (curr_volume > 0 && curr_volume <= 50) {
1ea75322 84 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-min", p->panel->icon_size, 0 );
10862fa6
DB
85 }
86 else if (curr_volume > 50 && curr_volume <= 75) {
1ea75322 87 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-med", p->panel->icon_size, 0 );
10862fa6
DB
88 }
89 else if (curr_volume > 75) {
1ea75322 90 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-max", p->panel->icon_size, 0 );
10862fa6
DB
91 }
92
93 if (info ) {
94 icon = gdk_pixbuf_new_from_file_at_size(
95 gtk_icon_info_get_filename( info ),
1ea75322 96 p->panel->icon_size, p->panel->icon_size, NULL );
10862fa6
DB
97 gtk_icon_info_free( info );
98 }
99 else {
100 icon = gdk_pixbuf_new_from_xpm_data((const char **) volume_xpm);
101 }
102
103
104
105 if (icon) {
106 if (curr_image) {
107 gtk_container_remove(GTK_CONTAINER (vol->mainw),curr_image);
108 curr_image = NULL;
109 }
110 image = gtk_image_new_from_pixbuf(icon);
111 gtk_container_add (GTK_CONTAINER (vol->mainw), image);
112
113 curr_image = image;
114 }
115 gtk_widget_show_all(vol->mainw);
116 return;
117}
118
119static void on_volume_focus (GtkWidget* dlg, GdkEventFocus *event, Plugin* p)
120{
121 volume_t *vol = (volume_t*) p->priv;
122
123 if (! vol_spin) return;
124 GtkAdjustment *vol_adjustment = gtk_spin_button_get_adjustment (vol_spin);
125 if (! vol_adjustment) return;
126 curr_volume = gtk_adjustment_get_value (vol_adjustment);
127
128 update_icon(p);
129
130 /* FIXME: use smarter method */
131 gtk_widget_destroy( dlg );
132 vol->dlg = NULL;
133}
134
135static void on_mouse_scroll (GtkWidget* widget, GdkEventScroll* evt, Plugin* p)
6cc5e1a6 136{
10862fa6
DB
137 volume_t *vol = (volume_t*) p->priv;
138
139 if ( ! vol->dlg ) {
140
141 vol->dlg = create_volume_window();
142 g_signal_connect( vol->mainw, "delete-event",
143 G_CALLBACK(on_volume_focus), p );
144
145 }
146 else {
147 if (! vol_spin) return;
148 GtkAdjustment *vol_adjustment =
149 gtk_spin_button_get_adjustment (vol_spin);
150 if (! vol_adjustment) return;
151
152 curr_volume = gtk_adjustment_get_value (vol_adjustment);
153
154 if (evt->direction == GDK_SCROLL_UP) {
155 curr_volume += 2;
156 }
157 else /*if (evt->direction == GDK_SCROLL_DOWN)*/ {
158 curr_volume -= 2;
159 }
160 update_icon(p);
161 gtk_adjustment_set_value (vol_adjustment, curr_volume);
162 gtk_spin_button_set_adjustment(vol_spin, vol_adjustment);
163 skip_botton1_event = TRUE;
164 }
6cc5e1a6
DB
165}
166
1ea75322 167static gboolean on_button_press (GtkWidget* widget, GdkEventButton* evt, Plugin* p)
6cc5e1a6 168{
10862fa6 169 volume_t *vol = (volume_t*) p->priv;
6cc5e1a6 170
10862fa6
DB
171 /* for scroll correction */
172 if (skip_botton1_event) {
173 gtk_widget_destroy(vol->dlg);
174 vol->dlg = NULL;
175 skip_botton1_event = FALSE;
176 }
6cc5e1a6 177
10862fa6
DB
178 switch ( evt->button ) {
179 case 1: { /* Left click */
180 if ( ! vol->dlg ) {
181 vol->dlg = create_volume_window();
6cc5e1a6 182
10862fa6
DB
183 /* setting background to default */
184 gtk_widget_set_style(vol->dlg, p->panel->defstyle);
6cc5e1a6 185
10862fa6
DB
186 g_signal_connect( vol->dlg, "focus-out-event",
187 G_CALLBACK(on_volume_focus), p );
188
189 gtk_window_present( GTK_WINDOW(vol->dlg) );
190 }
191 else {
192 /* update icon */
193 if (! vol_spin) return;
194 GtkAdjustment *vol_adjustment =
195 gtk_spin_button_get_adjustment (vol_spin);
196 if (! vol_adjustment) return;
197 curr_volume = gtk_adjustment_get_value (vol_adjustment);
198 update_icon(p);
199
200 gtk_widget_destroy(vol->dlg);
201 vol->dlg = NULL;
202 }
203 break;
204 }
205
206 case 3: { /* right button */
207 GtkMenu* popup = lxpanel_get_panel_menu( p->panel, p, FALSE );
208 gtk_menu_popup( popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
209 return TRUE;
210 }
211
212 case 2: { /* middle mouse button */
213 if ( ! vol->dlg ) {
214 vol->dlg = create_volume_window();
215 }
216
217 if (! vol_spin) return;
218 GtkAdjustment *vol_adjustment =
219 gtk_spin_button_get_adjustment (vol_spin);
220 if (! vol_adjustment) return;
221
222 curr_volume = gtk_adjustment_get_value (vol_adjustment);
223
224 if (curr_volume > 0) {
225 /* turning to mute */
226 vol_before_mute = curr_volume;
227 curr_volume = 0;
228 }
229 else {
230 curr_volume = vol_before_mute;
231 }
232
233 gtk_adjustment_set_value (vol_adjustment, curr_volume);
234 gtk_spin_button_set_adjustment(vol_spin, vol_adjustment);
235
236 update_icon(p);
237
238 gtk_widget_destroy( vol->dlg );
239 vol->dlg = NULL;
240 break;
241 }
242 default: /* never here */
243 break;
244 }
245 return FALSE;
6cc5e1a6
DB
246}
247
10862fa6 248static int volume_constructor(Plugin *p, char **fp)
6cc5e1a6
DB
249{
250 volume_t *vol;
251 line s;
252 GdkPixbuf *icon;
253 GtkWidget *image;
254 GtkIconTheme* theme;
255 GtkIconInfo* info;
10862fa6
DB
256
257 vol_before_mute = 1;
258 curr_volume = 0;
259 curr_image = NULL;
260 skip_botton1_event = FALSE;
6cc5e1a6
DB
261
262 ENTER;
263 s.len = 256;
264 vol = g_new0(volume_t, 1);
265 g_return_val_if_fail(vol != NULL, 0);
266 p->priv = vol;
267
268 /* check if OSS mixer device could be open */
269 mixer_fd = open ("/dev/mixer", O_RDWR, 0);
270 if (mixer_fd < 0) {
271 RET(0);
272 }
273
274 vol->mainw = gtk_event_box_new();
275
6cc5e1a6
DB
276 gtk_widget_add_events( vol->mainw, GDK_BUTTON_PRESS_MASK );
277 g_signal_connect( vol->mainw, "button-press-event",
278 G_CALLBACK(on_button_press), p );
10862fa6
DB
279
280 g_signal_connect( vol->mainw, "scroll-event",
281 G_CALLBACK(on_mouse_scroll), p );
1ea75322 282 gtk_widget_set_size_request( vol->mainw, p->panel->icon_size, p->panel->icon_size );
6cc5e1a6 283
10862fa6
DB
284 /* obtain current volume */
285 vol->dlg = create_volume_window();
286 if (! vol_spin) return;
287 GtkAdjustment *vol_adjustment =
288 gtk_spin_button_get_adjustment (vol_spin);
289 if (! vol_adjustment) return;
290 curr_volume = gtk_adjustment_get_value (vol_adjustment);
291
292 update_icon(p);
293 gtk_widget_destroy( vol->dlg );
294 vol->dlg = NULL;
6cc5e1a6
DB
295
296 vol->tooltips = gtk_tooltips_new ();
6cc5e1a6 297 g_object_ref_sink( vol->tooltips );
6cc5e1a6
DB
298
299 /* FIXME: display current level in tooltip. ex: "Volume Control: 80%" */
300 gtk_tooltips_set_tip (vol->tooltips, vol->mainw, _("Volume control"), NULL);
301
302 p->pwid = vol->mainw;
303 RET(1);
304}
305
306
307PluginClass volume_plugin_class = {
1ea75322
DB
308
309 PLUGINCLASS_VERSIONING,
6cc5e1a6
DB
310
311 type : "volume",
312 name : N_("Volume Control"),
313 version: "1.0",
314 description : "Display and control volume",
315
316 constructor : volume_constructor,
317 destructor : volume_destructor,
318 config : NULL,
319 save : NULL
320};