Adding upstream version 0.8.2.
[debian/lxpanel.git] / plugins / volume / volume.c
CommitLineData
0688b017
AG
1/*
2 * Copyright (C) 2006-2008 Jim Huang <jserv.tw@gmail.com>
3 * 2006-2008 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
4 * 2008 Frank ENDRES <frank_endres@yahoo.fr>
5 * 2009 Marty Jack <martyj19@comcast.net>
6 * 2014 Andriy Grytsenko <andrej@rep.kiev.ua>
7 *
8 * This file is a part of LXPanel project.
6cc5e1a6
DB
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
25#include <gtk/gtk.h>
26#include <stdlib.h>
27#include <fcntl.h>
28#include <unistd.h>
29
30#include <glib/gi18n.h>
31#include <gdk-pixbuf/gdk-pixbuf.h>
32
6cc5e1a6
DB
33#include "plugin.h"
34
35#include "dbg.h"
36
37#include "volume-impl.h"
38
39#include "volume_xpm.h"
6cc5e1a6
DB
40
41int mixer_fd;
42
7486d297
DB
43GtkSpinButton *vol_spin;
44static gdouble vol_before_mute;
45static gdouble curr_volume;
46static GtkWidget *curr_image;
47static gboolean skip_botton1_event;
48
6cc5e1a6 49typedef struct {
6b775dbb 50 LXPanel *panel;
6cc5e1a6 51 GtkWidget *dlg;
6cc5e1a6
DB
52} volume_t;
53
54static void
6b775dbb 55volume_destructor(gpointer user_data)
6cc5e1a6 56{
6b775dbb 57 volume_t *vol = (volume_t *) user_data;
6cc5e1a6
DB
58
59 ENTER;
60 if (vol->dlg)
61 gtk_widget_destroy(vol->dlg);
6cc5e1a6
DB
62 if (mixer_fd)
63 close(mixer_fd);
64 g_free(vol);
65 RET();
66}
67
6b775dbb 68static void update_icon (GtkWidget *p, volume_t *vol)
7486d297 69{
7486d297
DB
70 GdkPixbuf *icon;
71 GtkWidget *image;
72 GtkIconTheme* theme;
73 GtkIconInfo* info;
6b775dbb
AG
74 int icon_size;
75
76 theme = panel_get_icon_theme(vol->panel);
77 icon_size = panel_get_icon_size(vol->panel);
78
7486d297 79 if (curr_volume <= 0) {
6b775dbb 80 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-mute", icon_size, 0 );
7486d297
DB
81 }
82 else if (curr_volume > 0 && curr_volume <= 50) {
6b775dbb 83 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-min", icon_size, 0 );
7486d297
DB
84 }
85 else if (curr_volume > 50 && curr_volume <= 75) {
6b775dbb 86 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-med", icon_size, 0 );
7486d297 87 }
6b775dbb
AG
88 else /* curr_volume > 75 */ {
89 info = gtk_icon_theme_lookup_icon( theme, "stock_volume-max", icon_size, 0 );
7486d297
DB
90 }
91
92 if (info ) {
93 icon = gdk_pixbuf_new_from_file_at_size(
94 gtk_icon_info_get_filename( info ),
6b775dbb 95 icon_size, icon_size, NULL );
7486d297
DB
96 gtk_icon_info_free( info );
97 }
98 else {
99 icon = gdk_pixbuf_new_from_xpm_data((const char **) volume_xpm);
100 }
6b775dbb 101
7486d297 102 if (icon) {
6b775dbb
AG
103 if (curr_image) {
104 gtk_widget_destroy(curr_image);
7486d297
DB
105 curr_image = NULL;
106 }
107 image = gtk_image_new_from_pixbuf(icon);
6b775dbb
AG
108 gtk_container_add(GTK_CONTAINER(p), image);
109
7486d297
DB
110 curr_image = image;
111 }
6b775dbb 112 gtk_widget_show_all(p);
7486d297
DB
113 return;
114}
115
6b775dbb 116static void on_volume_focus (GtkWidget* dlg, GdkEventFocus *event, GtkWidget *p)
7486d297 117{
6b775dbb
AG
118 volume_t *vol = lxpanel_plugin_get_data(p);
119
7486d297
DB
120 if (! vol_spin) return;
121 GtkAdjustment *vol_adjustment = gtk_spin_button_get_adjustment (vol_spin);
122 if (! vol_adjustment) return;
123 curr_volume = gtk_adjustment_get_value (vol_adjustment);
6b775dbb
AG
124
125 update_icon(p, vol);
126
7486d297
DB
127 /* FIXME: use smarter method */
128 gtk_widget_destroy( dlg );
129 vol->dlg = NULL;
130}
131
6b775dbb 132static void on_mouse_scroll (GtkWidget* widget, GdkEventScroll* evt, volume_t *vol)
6cc5e1a6 133{
7486d297
DB
134 if ( ! vol->dlg ) {
135
136 vol->dlg = create_volume_window();
6b775dbb
AG
137 g_signal_connect( vol->dlg, "delete-event",
138 G_CALLBACK(on_volume_focus), widget );
7486d297
DB
139
140 }
141 else {
142 if (! vol_spin) return;
6b775dbb 143 GtkAdjustment *vol_adjustment =
7486d297
DB
144 gtk_spin_button_get_adjustment (vol_spin);
145 if (! vol_adjustment) return;
146
147 curr_volume = gtk_adjustment_get_value (vol_adjustment);
148
149 if (evt->direction == GDK_SCROLL_UP) {
150 curr_volume += 2;
151 }
152 else /*if (evt->direction == GDK_SCROLL_DOWN)*/ {
153 curr_volume -= 2;
154 }
6b775dbb 155 update_icon(widget, vol);
7486d297
DB
156 gtk_adjustment_set_value (vol_adjustment, curr_volume);
157 gtk_spin_button_set_adjustment(vol_spin, vol_adjustment);
158 skip_botton1_event = TRUE;
159 }
6cc5e1a6
DB
160}
161
6b775dbb 162static gboolean on_button_press (GtkWidget* widget, GdkEventButton* evt, LXPanel* p)
6cc5e1a6 163{
6b775dbb 164 volume_t *vol = lxpanel_plugin_get_data(widget);
6cc5e1a6 165
7486d297
DB
166 /* for scroll correction */
167 if (skip_botton1_event) {
168 gtk_widget_destroy(vol->dlg);
169 vol->dlg = NULL;
170 skip_botton1_event = FALSE;
171 }
6cc5e1a6 172
6b775dbb
AG
173 switch ( evt->button ) {
174 case 1: { /* Left click */
7486d297
DB
175 if ( ! vol->dlg ) {
176 vol->dlg = create_volume_window();
6cc5e1a6 177
7486d297 178 /* setting background to default */
6b775dbb 179 gtk_widget_set_style(vol->dlg, panel_get_defstyle(p));
6cc5e1a6 180
7486d297 181 g_signal_connect( vol->dlg, "focus-out-event",
6b775dbb 182 G_CALLBACK(on_volume_focus), widget );
7486d297
DB
183
184 gtk_window_present( GTK_WINDOW(vol->dlg) );
185 }
186 else {
187 /* update icon */
6b775dbb 188 if (! vol_spin) return FALSE;
7486d297
DB
189 GtkAdjustment *vol_adjustment =
190 gtk_spin_button_get_adjustment (vol_spin);
6b775dbb 191 if (! vol_adjustment) return FALSE;
7486d297 192 curr_volume = gtk_adjustment_get_value (vol_adjustment);
6b775dbb 193 update_icon(widget, vol);
7486d297
DB
194
195 gtk_widget_destroy(vol->dlg);
196 vol->dlg = NULL;
197 }
198 break;
199 }
200
7486d297
DB
201 case 2: { /* middle mouse button */
202 if ( ! vol->dlg ) {
203 vol->dlg = create_volume_window();
204 }
205
6b775dbb 206 if (! vol_spin) return FALSE;
7486d297
DB
207 GtkAdjustment *vol_adjustment =
208 gtk_spin_button_get_adjustment (vol_spin);
6b775dbb 209 if (! vol_adjustment) return FALSE;
7486d297
DB
210
211 curr_volume = gtk_adjustment_get_value (vol_adjustment);
212
213 if (curr_volume > 0) {
214 /* turning to mute */
215 vol_before_mute = curr_volume;
216 curr_volume = 0;
217 }
218 else {
219 curr_volume = vol_before_mute;
220 }
221
222 gtk_adjustment_set_value (vol_adjustment, curr_volume);
223 gtk_spin_button_set_adjustment(vol_spin, vol_adjustment);
224
6b775dbb 225 update_icon(widget, vol);
7486d297
DB
226
227 gtk_widget_destroy( vol->dlg );
228 vol->dlg = NULL;
229 break;
230 }
231 default: /* never here */
232 break;
233 }
234 return FALSE;
6cc5e1a6
DB
235}
236
6b775dbb 237static GtkWidget *volume_constructor(LXPanel *panel, config_setting_t *settings)
6cc5e1a6
DB
238{
239 volume_t *vol;
6b775dbb
AG
240 GtkWidget *p;
241 GtkAdjustment *vol_adjustment;
242
7486d297
DB
243 vol_before_mute = 1;
244 curr_volume = 0;
245 curr_image = NULL;
246 skip_botton1_event = FALSE;
6cc5e1a6
DB
247
248 ENTER;
6cc5e1a6
DB
249 /* check if OSS mixer device could be open */
250 mixer_fd = open ("/dev/mixer", O_RDWR, 0);
251 if (mixer_fd < 0) {
6b775dbb
AG
252 RET(NULL);
253 }
254 /* try to obtain current volume */
255 p = create_volume_window(); /* use pointer */
256 if (! vol_spin)
257 goto _error;
258 vol_adjustment = gtk_spin_button_get_adjustment (vol_spin);
259 if (! vol_adjustment)
260 {
261_error:
262 gtk_widget_destroy(p);
263 RET(NULL);
6cc5e1a6 264 }
7486d297 265 curr_volume = gtk_adjustment_get_value (vol_adjustment);
6cc5e1a6 266
6b775dbb
AG
267 vol = g_new0(volume_t, 1);
268 vol->dlg = p; /* it was reused */
6cc5e1a6 269
6b775dbb
AG
270 p = gtk_event_box_new();
271 lxpanel_plugin_set_data(p, vol, volume_destructor);
272 vol->panel = panel;
6cc5e1a6 273
6b775dbb
AG
274 g_signal_connect(p, "scroll-event", G_CALLBACK(on_mouse_scroll), vol);
275 gtk_widget_set_size_request(p, panel_get_icon_size(panel), panel_get_icon_size(panel));
6cc5e1a6 276
6b775dbb
AG
277 update_icon(p, vol);
278 gtk_widget_destroy( vol->dlg );
279 vol->dlg = NULL;
6cc5e1a6 280
6b775dbb
AG
281 /* FIXME: display current level in tooltip. ex: "Volume Control: 80%" */
282 gtk_widget_set_tooltip_text(p, _("Volume control"));
283
284 RET(p);
285}
2ba86315 286
6b775dbb 287FM_DEFINE_MODULE(lxpanel_gtk, volume)
6cc5e1a6 288
6b775dbb
AG
289LXPanelPluginInit fm_module_init_lxpanel_gtk = {
290 .name = N_("Volume Control"),
291 .description = "Display and control volume",
6cc5e1a6 292
6b775dbb
AG
293 .new_instance = volume_constructor,
294 .button_press_event = on_button_press
6cc5e1a6 295};