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"
45 static Display
*display
;
46 static bool button_pressed
= false;
47 static bool slider_pressed
= false;
48 static double prev_button_press_time
= 0.0;
50 static float display_height
;
51 static float display_width
;
52 static int mouse_drag_home_x
;
53 static int mouse_drag_home_y
;
57 static void signal_catch(int sig
);
58 static void button_press_event(XButtonEvent
*event
);
59 static void button_release_event(XButtonEvent
*event
);
60 static int key_press_event(XKeyEvent
*event
);
61 static void motion_event(XMotionEvent
*event
);
62 static void choose_api(int api
);
65 int main(int argc
, char **argv
)
68 int rr_event_base
, rr_error_base
;
72 parse_cli_options(argc
, argv
);
74 config_set_defaults();
75 choose_api(config
.api
);
77 mixer_init(config
.mixer_device
, config
.verbose
, (const char **)config
.exclude_channel
);
80 display
= XOpenDisplay(config
.display_name
);
81 if (display
== NULL
) {
84 if (config
.display_name
) {
85 name
= config
.display_name
;
87 name
= getenv("DISPLAY");
89 fprintf(stderr
, "wmix:error: Unable to open display, variable $DISPLAY not set\n");
93 fprintf(stderr
, "wmix:error: Unable to open display \"%s\"\n", name
);
97 have_randr
= XRRQueryExtension(display
, &rr_event_base
, &rr_error_base
);
99 int rr_mask
= RRScreenChangeNotifyMask
;
100 XRRSelectInput(display
,
101 RootWindow(display
, DefaultScreen(display
)),
105 display_width
= (float)DisplayWidth(display
, DefaultScreen(display
)) / 4.0;
106 display_height
= (float)DisplayHeight(display
, DefaultScreen(display
)) / 2.0;
108 dockapp_init(display
, have_randr
);
109 new_window("wmix", 64, 64);
113 mmkey_install(display
);
117 blit_string("wmix " VERSION
);
118 scroll_text(3, 4, 57, true);
121 /* add click regions */
122 add_region(1, 37, 36, 25, 25); /* knob */
123 add_region(2, 4, 42, 27, 15); /* balancer */
124 add_region(3, 2, 26, 7, 10); /* previous channel */
125 add_region(4, 10, 26, 7, 10); /* next channel */
126 add_region(5, 39, 14, 20, 7); /* mute toggle */
127 add_region(6, 4, 14, 13, 7); /* rec toggle */
128 add_region(10, 3, 4, 56, 7); /* re-scroll current channel name */
130 /* setup up/down signal handler */
132 signal(SIGUSR1
, (void *) signal_catch
);
133 signal(SIGUSR2
, (void *) signal_catch
);
136 if (button_pressed
|| slider_pressed
|| (XPending(display
) > 0)) {
137 XNextEvent(display
, &event
);
138 switch (event
.type
) {
140 if (key_press_event(&event
.xkey
))
147 button_press_event(&event
.xbutton
);
151 button_release_event(&event
.xbutton
);
155 /* process cursor change, or drag events */
156 motion_event(&event
.xmotion
);
160 /* go back to standard cursor */
161 if ((!button_pressed
) && (!slider_pressed
))
162 set_cursor(NORMAL_CURSOR
);
165 XCloseDisplay(display
);
169 if (event
.type
== rr_event_base
+ RRScreenChangeNotify
) {
170 XRRUpdateConfiguration(&event
);
180 scroll_text(3, 4, 57, false);
181 /* rescroll message after some delay */
182 if (idle_loop
++ > 256) {
183 scroll_text(3, 4, 57, true);
186 /* get rid of OSD after a few seconds of idle */
187 if ((idle_loop
> 15) && osd_mapped() && !button_pressed
) {
191 if (mixer_is_changed())
198 static void signal_catch(int sig
)
202 mixer_set_volume_rel(config
.scrollstep
);
206 update_osd(mixer_get_volume(), false);
211 mixer_set_volume_rel(-config
.scrollstep
);
215 update_osd(mixer_get_volume(), false);
222 static void choose_api(int api
)
225 mixer_init
= &mixer_alsa_init
;
226 mixer_is_changed
= &mixer_alsa_is_changed
;
227 mixer_get_channel_count
= mixer_alsa_get_channel_count
;
228 mixer_get_channel
= mixer_alsa_get_channel
;
229 mixer_get_channel_name
= mixer_alsa_get_channel_name
;
230 mixer_get_short_name
= mixer_alsa_get_short_name
;
231 mixer_set_channel
= mixer_alsa_set_channel
;
232 mixer_set_channel_rel
= mixer_alsa_set_channel_rel
;
233 mixer_get_volume
= mixer_alsa_get_volume
;
234 mixer_set_volume
= mixer_alsa_set_volume
;
235 mixer_set_volume_rel
= mixer_alsa_set_volume_rel
;
236 mixer_get_balance
= mixer_alsa_get_balance
;
237 mixer_set_balance
= mixer_alsa_set_balance
;
238 mixer_set_balance_rel
= mixer_alsa_set_balance_rel
;
239 mixer_toggle_mute
= mixer_alsa_toggle_mute
;
240 mixer_toggle_rec
= mixer_alsa_toggle_rec
;
241 mixer_is_muted
= mixer_alsa_is_muted
;
242 mixer_is_stereo
= mixer_alsa_is_stereo
;
243 mixer_is_rec
= mixer_alsa_is_rec
;
244 mixer_can_rec
= mixer_alsa_can_rec
;
245 mixer_tick
= mixer_alsa_tick
;
246 } else if (api
== 1) {
247 mixer_init
= &mixer_oss_init
;
248 mixer_is_changed
= &mixer_oss_is_changed
;
249 mixer_get_channel_count
= mixer_oss_get_channel_count
;
250 mixer_get_channel
= mixer_oss_get_channel
;
251 mixer_get_channel_name
= mixer_oss_get_channel_name
;
252 mixer_get_short_name
= mixer_oss_get_short_name
;
253 mixer_set_channel
= mixer_oss_set_channel
;
254 mixer_set_channel_rel
= mixer_oss_set_channel_rel
;
255 mixer_get_volume
= mixer_oss_get_volume
;
256 mixer_set_volume
= mixer_oss_set_volume
;
257 mixer_set_volume_rel
= mixer_oss_set_volume_rel
;
258 mixer_get_balance
= mixer_oss_get_balance
;
259 mixer_set_balance
= mixer_oss_set_balance
;
260 mixer_set_balance_rel
= mixer_oss_set_balance_rel
;
261 mixer_toggle_mute
= mixer_oss_toggle_mute
;
262 mixer_toggle_rec
= mixer_oss_toggle_rec
;
263 mixer_is_muted
= mixer_oss_is_muted
;
264 mixer_is_stereo
= mixer_oss_is_stereo
;
265 mixer_is_rec
= mixer_oss_is_rec
;
266 mixer_can_rec
= mixer_oss_can_rec
;
271 static void button_press_event(XButtonEvent
*event
)
273 double button_press_time
= get_current_time();
276 bool double_click
= false;
278 /* handle wheel scrolling to adjust volume */
279 if (config
.mousewheel
) {
280 if (event
->button
== config
.wheel_button_up
) {
281 mixer_set_volume_rel(config
.scrollstep
);
285 update_osd(mixer_get_volume(), false);
289 if (event
->button
== config
.wheel_button_down
) {
290 mixer_set_volume_rel(-config
.scrollstep
);
294 update_osd(mixer_get_volume(), false);
300 if ((button_press_time
- prev_button_press_time
) <= 0.5) {
302 prev_button_press_time
= 0.0;
304 prev_button_press_time
= button_press_time
;
306 switch (check_region(x
, y
)) {
307 case 1: /* on knob */
308 button_pressed
= true;
309 slider_pressed
= false;
310 mouse_drag_home_x
= x
;
311 mouse_drag_home_y
= y
;
317 case 2: /* on slider */
318 button_pressed
= false;
319 slider_pressed
= true;
320 mouse_drag_home_x
= x
;
321 mouse_drag_home_y
= y
;
323 mixer_set_balance(0.0);
327 case 3: /* previous channel */
328 mixer_set_channel_rel(-1);
329 blit_string(config
.scrolltext
? mixer_get_channel_name() : mixer_get_short_name());
330 scroll_text(3, 4, 57, true);
335 case 4: /* next channel */
336 mixer_set_channel_rel(1);
337 blit_string(config
.scrolltext
? mixer_get_channel_name() : mixer_get_short_name());
338 scroll_text(3, 4, 57, true);
343 case 5: /* toggle mute */
347 case 6: /* toggle rec */
352 scroll_text(3, 4, 57, true);
355 printf("unknown region pressed\n");
360 static int key_press_event(XKeyEvent
*event
)
362 if (event
->keycode
== mmkeys
.raise_volume
) {
363 mixer_set_volume_rel(config
.scrollstep
);
367 update_osd(mixer_get_volume(), false);
371 if (event
->keycode
== mmkeys
.lower_volume
) {
372 mixer_set_volume_rel(-config
.scrollstep
);
376 update_osd(mixer_get_volume(), false);
380 if (event
->keycode
== mmkeys
.mute
) {
386 /* Ignore other keys */
390 static void button_release_event(XButtonEvent
*event
)
396 region
= check_region(x
, y
);
399 set_cursor(HAND_CURSOR
);
401 button_pressed
= false;
402 slider_pressed
= false;
405 static void motion_event(XMotionEvent
*event
)
411 if ((x
== mouse_drag_home_x
) && (y
== mouse_drag_home_y
))
414 region
= check_region(x
, y
);
416 if (button_pressed
) {
417 if (y
!= mouse_drag_home_y
) {
420 set_cursor(NULL_CURSOR
);
422 delta
= (float)(mouse_drag_home_y
- y
) / display_height
;
427 update_osd(mixer_get_volume(), false);
429 XWarpPointer(display
, None
, event
->window
, x
, y
, 0, 0,
430 mouse_drag_home_x
, mouse_drag_home_y
);
434 if (slider_pressed
) {
435 if (x
!= mouse_drag_home_x
) {
438 set_cursor(NULL_CURSOR
);
440 delta
= (float)(x
- mouse_drag_home_x
) / display_width
;
443 XWarpPointer(display
, None
, event
->window
, x
, y
, 0, 0,
444 mouse_drag_home_x
, mouse_drag_home_y
);
449 set_cursor(HAND_CURSOR
);
450 else if (region
== 2)
451 set_cursor(BAR_CURSOR
);
453 set_cursor(NORMAL_CURSOR
);