[SF#190]Workaround for style problem in shiki themes.
[lxde/lxpanel.git] / src / plugins / volume / volume.c
CommitLineData
4542c20d 1/**
e5035ac1
JH
2 * Copyright (c) 2006, 2008 LxDE Developers,
3 * see the file AUTHORS for details.
a99ee9e1
JH
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
31b80004
JH
20#include <gtk/gtk.h>
21#include <stdlib.h>
22#include <fcntl.h>
23#include <unistd.h>
24
f277dbb7 25#include <glib/gi18n.h>
31b80004
JH
26#include <gdk-pixbuf/gdk-pixbuf.h>
27
6958db5d 28#include "plugin.h"
31b80004
JH
29
30#include "dbg.h"
31
32#include "volume-impl.h"
33
34#include "volume_xpm.h"
35
36int mixer_fd;
37
e5035ac1
JH
38GtkSpinButton *vol_spin;
39static gdouble vol_before_mute;
40static gdouble curr_volume;
41static GtkWidget *curr_image;
42static gboolean skip_botton1_event;
43
31b80004 44typedef struct {
6958db5d 45 Panel *panel;
4542c20d 46 GtkWidget *dlg;
31b80004
JH
47} volume_t;
48
49static void
6958db5d 50volume_destructor(gpointer user_data)
31b80004 51{
6958db5d 52 volume_t *vol = (volume_t *) user_data;
4542c20d
HJYP
53
54 ENTER;
55 if (vol->dlg)
56 gtk_widget_destroy(vol->dlg);
4542c20d
HJYP
57 if (mixer_fd)
58 close(mixer_fd);
59 g_free(vol);
60 RET();
31b80004
JH
61}
62
6958db5d 63static void update_icon (GtkWidget *p, volume_t *vol)
31b80004 64{
e5035ac1
JH
65 GdkPixbuf *icon;
66 GtkWidget *image;
67 GtkIconTheme* theme;
68 GtkIconInfo* info;
6958db5d
AG
69 int icon_size;
70
71 theme = panel_get_icon_theme(vol->panel);
72 icon_size = panel_get_icon_size(vol->panel);
73
e5035ac1 74 if (curr_volume <= 0) {
6958db5d 75 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-mute", icon_size, 0 );
e5035ac1
JH
76 }
77 else if (curr_volume > 0 && curr_volume <= 50) {
6958db5d 78 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-min", icon_size, 0 );
e5035ac1
JH
79 }
80 else if (curr_volume > 50 && curr_volume <= 75) {
6958db5d 81 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-med", icon_size, 0 );
e5035ac1 82 }
6958db5d
AG
83 else /* curr_volume > 75 */ {
84 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-max", icon_size, 0 );
e5035ac1
JH
85 }
86
87 if (info ) {
88 icon = gdk_pixbuf_new_from_file_at_size(
89 gtk_icon_info_get_filename( info ),
6958db5d 90 icon_size, icon_size, NULL );
e5035ac1
JH
91 gtk_icon_info_free( info );
92 }
93 else {
94 icon = gdk_pixbuf_new_from_xpm_data((const char **) volume_xpm);
95 }
96
97
98
99 if (icon) {
100 if (curr_image) {
6958db5d 101 gtk_container_remove(GTK_CONTAINER(p), curr_image);
e5035ac1
JH
102 curr_image = NULL;
103 }
104 image = gtk_image_new_from_pixbuf(icon);
6958db5d 105 gtk_container_add(GTK_CONTAINER(p), image);
e5035ac1
JH
106
107 curr_image = image;
108 }
6958db5d 109 gtk_widget_show_all(p);
e5035ac1 110 return;
31b80004
JH
111}
112
6958db5d 113static void on_volume_focus (GtkWidget* dlg, GdkEventFocus *event, GtkWidget *p)
31b80004 114{
6958db5d
AG
115 volume_t *vol = lxpanel_plugin_get_data(p);
116
e5035ac1
JH
117 if (! vol_spin) return;
118 GtkAdjustment *vol_adjustment = gtk_spin_button_get_adjustment (vol_spin);
119 if (! vol_adjustment) return;
120 curr_volume = gtk_adjustment_get_value (vol_adjustment);
121
6958db5d 122 update_icon(p, vol);
e5035ac1
JH
123
124 /* FIXME: use smarter method */
125 gtk_widget_destroy( dlg );
126 vol->dlg = NULL;
127}
31b80004 128
6958db5d 129static void on_mouse_scroll (GtkWidget* widget, GdkEventScroll* evt, volume_t *vol)
e5035ac1 130{
e5035ac1 131 if ( ! vol->dlg ) {
cecb0eaa 132
e5035ac1 133 vol->dlg = create_volume_window();
6958db5d
AG
134 g_signal_connect( vol->dlg, "delete-event",
135 G_CALLBACK(on_volume_focus), widget );
cecb0eaa 136
e5035ac1
JH
137 }
138 else {
139 if (! vol_spin) return;
140 GtkAdjustment *vol_adjustment =
141 gtk_spin_button_get_adjustment (vol_spin);
142 if (! vol_adjustment) return;
143
144 curr_volume = gtk_adjustment_get_value (vol_adjustment);
145
146 if (evt->direction == GDK_SCROLL_UP) {
147 curr_volume += 2;
148 }
149 else /*if (evt->direction == GDK_SCROLL_DOWN)*/ {
150 curr_volume -= 2;
151 }
6958db5d 152 update_icon(widget, vol);
e5035ac1
JH
153 gtk_adjustment_set_value (vol_adjustment, curr_volume);
154 gtk_spin_button_set_adjustment(vol_spin, vol_adjustment);
155 skip_botton1_event = TRUE;
156 }
157}
158
6958db5d 159static gboolean on_button_press (GtkWidget* widget, GdkEventButton* evt, Panel* p)
e5035ac1 160{
6958db5d 161 volume_t *vol = lxpanel_plugin_get_data(widget);
e5035ac1
JH
162
163 /* for scroll correction */
164 if (skip_botton1_event) {
165 gtk_widget_destroy(vol->dlg);
166 vol->dlg = NULL;
167 skip_botton1_event = FALSE;
168 }
169
170 switch ( evt->button ) {
171 case 1: { /* Left click */
172 if ( ! vol->dlg ) {
173 vol->dlg = create_volume_window();
174
175 /* setting background to default */
6958db5d 176 gtk_widget_set_style(vol->dlg, panel_get_defstyle(p));
e5035ac1
JH
177
178 g_signal_connect( vol->dlg, "focus-out-event",
6958db5d 179 G_CALLBACK(on_volume_focus), widget );
e5035ac1
JH
180
181 gtk_window_present( GTK_WINDOW(vol->dlg) );
182 }
183 else {
184 /* update icon */
68f80334 185 if (! vol_spin) return FALSE;
e5035ac1
JH
186 GtkAdjustment *vol_adjustment =
187 gtk_spin_button_get_adjustment (vol_spin);
68f80334 188 if (! vol_adjustment) return FALSE;
e5035ac1 189 curr_volume = gtk_adjustment_get_value (vol_adjustment);
6958db5d 190 update_icon(widget, vol);
e5035ac1
JH
191
192 gtk_widget_destroy(vol->dlg);
193 vol->dlg = NULL;
194 }
195 break;
196 }
197
198 case 3: { /* right button */
6958db5d 199 lxpanel_plugin_button_press_event(widget, evt, p);
e5035ac1
JH
200 return TRUE;
201 }
202
203 case 2: { /* middle mouse button */
204 if ( ! vol->dlg ) {
205 vol->dlg = create_volume_window();
206 }
207
68f80334 208 if (! vol_spin) return FALSE;
e5035ac1
JH
209 GtkAdjustment *vol_adjustment =
210 gtk_spin_button_get_adjustment (vol_spin);
68f80334 211 if (! vol_adjustment) return FALSE;
e5035ac1
JH
212
213 curr_volume = gtk_adjustment_get_value (vol_adjustment);
214
215 if (curr_volume > 0) {
216 /* turning to mute */
217 vol_before_mute = curr_volume;
218 curr_volume = 0;
219 }
220 else {
221 curr_volume = vol_before_mute;
222 }
223
224 gtk_adjustment_set_value (vol_adjustment, curr_volume);
225 gtk_spin_button_set_adjustment(vol_spin, vol_adjustment);
226
6958db5d 227 update_icon(widget, vol);
e5035ac1
JH
228
229 gtk_widget_destroy( vol->dlg );
230 vol->dlg = NULL;
231 break;
232 }
233 default: /* never here */
234 break;
235 }
236 return FALSE;
31b80004
JH
237}
238
6958db5d 239static GtkWidget *volume_constructor(Panel *panel, config_setting_t *settings)
31b80004 240{
4542c20d 241 volume_t *vol;
6958db5d
AG
242 GtkWidget *p;
243 GtkAdjustment *vol_adjustment;
244
e5035ac1
JH
245 vol_before_mute = 1;
246 curr_volume = 0;
247 curr_image = NULL;
248 skip_botton1_event = FALSE;
4542c20d
HJYP
249
250 ENTER;
4542c20d
HJYP
251 /* check if OSS mixer device could be open */
252 mixer_fd = open ("/dev/mixer", O_RDWR, 0);
253 if (mixer_fd < 0) {
6958db5d
AG
254 RET(NULL);
255 }
256 /* try to obtain current volume */
257 p = create_volume_window(); /* use pointer */
258 if (! vol_spin)
259 goto _error;
260 vol_adjustment = gtk_spin_button_get_adjustment (vol_spin);
261 if (! vol_adjustment)
262 {
263_error:
264 gtk_widget_destroy(p);
265 RET(NULL);
4542c20d 266 }
e5035ac1 267 curr_volume = gtk_adjustment_get_value (vol_adjustment);
6958db5d
AG
268
269 vol = g_new0(volume_t, 1);
270 vol->dlg = p; /* it was reused */
271
272 p = gtk_event_box_new();
273 lxpanel_plugin_set_data(p, vol, volume_destructor);
274 vol->panel = panel;
275
276 gtk_widget_add_events(p, GDK_BUTTON_PRESS_MASK);
277 g_signal_connect(p, "scroll-event", G_CALLBACK(on_mouse_scroll), vol);
278 gtk_widget_set_size_request(p, panel_get_icon_size(panel), panel_get_icon_size(panel));
279
280 update_icon(p, vol);
281 gtk_widget_destroy( vol->dlg );
282 vol->dlg = NULL;
4542c20d 283
4542c20d 284 /* FIXME: display current level in tooltip. ex: "Volume Control: 80%" */
09fa171b 285 gtk_widget_set_tooltip_text(p, _("Volume control"));
31b80004 286
6958db5d 287 RET(p);
31b80004
JH
288}
289
6958db5d 290FM_DEFINE_MODULE(lxpanel_gtk, volume)
31b80004 291
6958db5d 292LXPanelPluginInit fm_module_init_lxpanel_gtk = {
3c3e9c9e 293 .name = N_("Volume Control"),
3c3e9c9e
HG
294 .description = "Display and control volume",
295
6958db5d
AG
296 .new_instance = volume_constructor,
297 .button_press_event = on_button_press
31b80004 298};