1 /* WMix 3.0 -- a mixer using the OSS mixer API.
2 * Copyright (C) 2000, 2001 timecop@japan.co.jp
3 * Mixer code in version 3.0 based on mixer api library by
4 * Daniel Richard G. <skunk@mit.edu>, which in turn was based on
5 * the mixer code in WMix 2.x releases.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program 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
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include <X11/Xutil.h>
33 #include <X11/extensions/Xrandr.h>
35 #include "include/common.h"
36 #include "include/mixer.h"
37 #include "include/misc.h"
38 #include "include/ui_x.h"
39 #include "include/mmkeys.h"
40 #include "include/config.h"
41 #include "include/mixer-oss.h"
42 #include "include/mixer-alsa.h"
44 void (*mixer_init
)(const char *mixer_device
,
46 const char *exclude
[]);
47 bool (*mixer_is_changed
)(void);
48 int (*mixer_get_channel_count
)(void);
49 int (*mixer_get_channel
)(void);
50 const char *(*mixer_get_channel_name
)(void);
51 const char *(*mixer_get_short_name
)(void);
52 void (*mixer_set_channel
)(int channel
);
53 void (*mixer_set_channel_rel
)(int delta_channel
);
54 float (*mixer_get_volume
)(void);
55 void (*mixer_set_volume
)(float volume
);
56 void (*mixer_set_volume_rel
)(float delta_volume
);
57 float (*mixer_get_balance
)(void);
58 void (*mixer_set_balance
)(float balance
);
59 void (*mixer_set_balance_rel
)(float delta_balance
);
60 void (*mixer_toggle_mute
)(void);
61 void (*mixer_toggle_rec
)(void);
62 bool (*mixer_is_muted
)(void);
63 bool (*mixer_is_stereo
)(void);
64 bool (*mixer_is_rec
)(void);
65 bool (*mixer_can_rec
)(void);
66 bool (*is_exclude
)(const char *short_name
,
67 const char *exclude
[]);
68 void (*mixer_tick
)(void);
70 static Display
*display
;
71 static bool button_pressed
= false;
72 static bool slider_pressed
= false;
73 static double prev_button_press_time
= 0.0;
75 static float display_height
;
76 static float display_width
;
77 static int mouse_drag_home_x
;
78 static int mouse_drag_home_y
;
82 static void signal_catch(int sig
);
83 static void button_press_event(XButtonEvent
*event
);
84 static void button_release_event(XButtonEvent
*event
);
85 static int key_press_event(XKeyEvent
*event
);
86 static void motion_event(XMotionEvent
*event
);
87 static void choose_api(int api
);
90 int main(int argc
, char **argv
)
93 int rr_event_base
, rr_error_base
;
97 parse_cli_options(argc
, argv
);
99 config_set_defaults();
100 choose_api(config
.api
);
102 mixer_init(config
.mixer_device
, config
.verbose
, (const char **)config
.exclude_channel
);
103 mixer_set_channel(0);
105 display
= XOpenDisplay(config
.display_name
);
106 if (display
== NULL
) {
109 if (config
.display_name
) {
110 name
= config
.display_name
;
112 name
= getenv("DISPLAY");
114 fprintf(stderr
, "wmix:error: Unable to open display, variable $DISPLAY not set\n");
118 fprintf(stderr
, "wmix:error: Unable to open display \"%s\"\n", name
);
122 have_randr
= XRRQueryExtension(display
, &rr_event_base
, &rr_error_base
);
124 int rr_mask
= RRScreenChangeNotifyMask
;
125 XRRSelectInput(display
,
126 RootWindow(display
, DefaultScreen(display
)),
130 display_width
= (float)DisplayWidth(display
, DefaultScreen(display
)) / 4.0;
131 display_height
= (float)DisplayHeight(display
, DefaultScreen(display
)) / 2.0;
133 dockapp_init(display
, have_randr
);
134 new_window("wmix", 64, 64, argc
, argv
);
138 mmkey_install(display
);
142 blit_string("wmix " VERSION
);
143 scroll_text(3, 4, 57, true);
146 /* add click regions */
147 add_region(1, 37, 36, 25, 25); /* knob */
148 add_region(2, 4, 42, 27, 15); /* balancer */
149 add_region(3, 2, 26, 7, 10); /* previous channel */
150 add_region(4, 10, 26, 7, 10); /* next channel */
151 add_region(5, 39, 14, 20, 7); /* mute toggle */
152 add_region(6, 4, 14, 13, 7); /* rec toggle */
153 add_region(10, 3, 4, 56, 7); /* re-scroll current channel name */
155 /* setup up/down signal handler */
157 signal(SIGUSR1
, (void *) signal_catch
);
158 signal(SIGUSR2
, (void *) signal_catch
);
161 if (button_pressed
|| slider_pressed
|| (XPending(display
) > 0)) {
162 XNextEvent(display
, &event
);
163 switch (event
.type
) {
165 if (key_press_event(&event
.xkey
))
172 button_press_event(&event
.xbutton
);
176 button_release_event(&event
.xbutton
);
180 /* process cursor change, or drag events */
181 motion_event(&event
.xmotion
);
185 /* go back to standard cursor */
186 if ((!button_pressed
) && (!slider_pressed
))
187 set_cursor(NORMAL_CURSOR
);
190 XCloseDisplay(display
);
194 if (event
.type
== rr_event_base
+ RRScreenChangeNotify
) {
195 XRRUpdateConfiguration(&event
);
205 scroll_text(3, 4, 57, false);
206 /* rescroll message after some delay */
207 if (idle_loop
++ > 256) {
208 scroll_text(3, 4, 57, true);
211 /* get rid of OSD after a few seconds of idle */
212 if ((idle_loop
> 15) && osd_mapped() && !button_pressed
) {
216 if (mixer_is_changed())
223 static void signal_catch(int sig
)
227 mixer_set_volume_rel(config
.scrollstep
);
231 update_osd(mixer_get_volume(), false);
236 mixer_set_volume_rel(-config
.scrollstep
);
240 update_osd(mixer_get_volume(), false);
247 static void choose_api(int api
)
250 mixer_init
= &mixer_alsa_init
;
251 mixer_is_changed
= &mixer_alsa_is_changed
;
252 mixer_get_channel_count
= mixer_alsa_get_channel_count
;
253 mixer_get_channel
= mixer_alsa_get_channel
;
254 mixer_get_channel_name
= mixer_alsa_get_channel_name
;
255 mixer_get_short_name
= mixer_alsa_get_short_name
;
256 mixer_set_channel
= mixer_alsa_set_channel
;
257 mixer_set_channel_rel
= mixer_alsa_set_channel_rel
;
258 mixer_get_volume
= mixer_alsa_get_volume
;
259 mixer_set_volume
= mixer_alsa_set_volume
;
260 mixer_set_volume_rel
= mixer_alsa_set_volume_rel
;
261 mixer_get_balance
= mixer_alsa_get_balance
;
262 mixer_set_balance
= mixer_alsa_set_balance
;
263 mixer_set_balance_rel
= mixer_alsa_set_balance_rel
;
264 mixer_toggle_mute
= mixer_alsa_toggle_mute
;
265 mixer_toggle_rec
= mixer_alsa_toggle_rec
;
266 mixer_is_muted
= mixer_alsa_is_muted
;
267 mixer_is_stereo
= mixer_alsa_is_stereo
;
268 mixer_is_rec
= mixer_alsa_is_rec
;
269 mixer_can_rec
= mixer_alsa_can_rec
;
270 mixer_tick
= mixer_alsa_tick
;
271 } else if (api
== 1) {
272 mixer_init
= &mixer_oss_init
;
273 mixer_is_changed
= &mixer_oss_is_changed
;
274 mixer_get_channel_count
= mixer_oss_get_channel_count
;
275 mixer_get_channel
= mixer_oss_get_channel
;
276 mixer_get_channel_name
= mixer_oss_get_channel_name
;
277 mixer_get_short_name
= mixer_oss_get_short_name
;
278 mixer_set_channel
= mixer_oss_set_channel
;
279 mixer_set_channel_rel
= mixer_oss_set_channel_rel
;
280 mixer_get_volume
= mixer_oss_get_volume
;
281 mixer_set_volume
= mixer_oss_set_volume
;
282 mixer_set_volume_rel
= mixer_oss_set_volume_rel
;
283 mixer_get_balance
= mixer_oss_get_balance
;
284 mixer_set_balance
= mixer_oss_set_balance
;
285 mixer_set_balance_rel
= mixer_oss_set_balance_rel
;
286 mixer_toggle_mute
= mixer_oss_toggle_mute
;
287 mixer_toggle_rec
= mixer_oss_toggle_rec
;
288 mixer_is_muted
= mixer_oss_is_muted
;
289 mixer_is_stereo
= mixer_oss_is_stereo
;
290 mixer_is_rec
= mixer_oss_is_rec
;
291 mixer_can_rec
= mixer_oss_can_rec
;
296 static void button_press_event(XButtonEvent
*event
)
298 double button_press_time
= get_current_time();
301 bool double_click
= false;
303 /* handle wheel scrolling to adjust volume */
304 if (config
.mousewheel
) {
305 if (event
->button
== config
.wheel_button_up
) {
306 mixer_set_volume_rel(config
.scrollstep
);
310 update_osd(mixer_get_volume(), false);
314 if (event
->button
== config
.wheel_button_down
) {
315 mixer_set_volume_rel(-config
.scrollstep
);
319 update_osd(mixer_get_volume(), false);
325 if ((button_press_time
- prev_button_press_time
) <= 0.5) {
327 prev_button_press_time
= 0.0;
329 prev_button_press_time
= button_press_time
;
331 switch (check_region(x
, y
)) {
332 case 1: /* on knob */
333 button_pressed
= true;
334 slider_pressed
= false;
335 mouse_drag_home_x
= x
;
336 mouse_drag_home_y
= y
;
342 case 2: /* on slider */
343 button_pressed
= false;
344 slider_pressed
= true;
345 mouse_drag_home_x
= x
;
346 mouse_drag_home_y
= y
;
348 mixer_set_balance(0.0);
352 case 3: /* previous channel */
353 mixer_set_channel_rel(-1);
354 blit_string(config
.scrolltext
? mixer_get_channel_name() : mixer_get_short_name());
355 scroll_text(3, 4, 57, true);
360 case 4: /* next channel */
361 mixer_set_channel_rel(1);
362 blit_string(config
.scrolltext
? mixer_get_channel_name() : mixer_get_short_name());
363 scroll_text(3, 4, 57, true);
368 case 5: /* toggle mute */
372 case 6: /* toggle rec */
377 scroll_text(3, 4, 57, true);
380 printf("unknown region pressed\n");
385 static int key_press_event(XKeyEvent
*event
)
387 if (event
->keycode
== mmkeys
.raise_volume
) {
388 mixer_set_volume_rel(config
.scrollstep
);
392 update_osd(mixer_get_volume(), false);
396 if (event
->keycode
== mmkeys
.lower_volume
) {
397 mixer_set_volume_rel(-config
.scrollstep
);
401 update_osd(mixer_get_volume(), false);
405 if (event
->keycode
== mmkeys
.mute
) {
411 /* Ignore other keys */
415 static void button_release_event(XButtonEvent
*event
)
421 region
= check_region(x
, y
);
424 set_cursor(HAND_CURSOR
);
426 button_pressed
= false;
427 slider_pressed
= false;
430 static void motion_event(XMotionEvent
*event
)
436 if ((x
== mouse_drag_home_x
) && (y
== mouse_drag_home_y
))
439 region
= check_region(x
, y
);
441 if (button_pressed
) {
442 if (y
!= mouse_drag_home_y
) {
445 set_cursor(NULL_CURSOR
);
447 delta
= (float)(mouse_drag_home_y
- y
) / display_height
;
452 update_osd(mixer_get_volume(), false);
454 XWarpPointer(display
, None
, event
->window
, x
, y
, 0, 0,
455 mouse_drag_home_x
, mouse_drag_home_y
);
459 if (slider_pressed
) {
460 if (x
!= mouse_drag_home_x
) {
463 set_cursor(NULL_CURSOR
);
465 delta
= (float)(x
- mouse_drag_home_x
) / display_width
;
468 XWarpPointer(display
, None
, event
->window
, x
, y
, 0, 0,
469 mouse_drag_home_x
, mouse_drag_home_y
);
474 set_cursor(HAND_CURSOR
);
475 else if (region
== 2)
476 set_cursor(BAR_CURSOR
);
478 set_cursor(NORMAL_CURSOR
);