/usr/sbin/wall -a Brendan Gregg
Brendan Gregg, Fishworks engineer

Monday Mar 05, 2007

While Solaris has a fancy GNOME based desktop called JDS3, other desktop environments are available and work fine. FVWM2 is a fast alternative with a modest set of features, and is available on the Software Companion CD (which you may already have a copy of).

If you have installed fvwm2 from the companion CD and would like to try it, the easiest way is to enter a fail safe session from the login screen, then run the binary - /opt/sfw/bin/fvwm2. The proper way is to create config files under /etc/dt/config, so that the login screen provides FVWM as an option.

After getting fvwm2 running, I found my volume up/down/mute keys on this Sun type 7 keyboard didn't work. An internet search didn't find any solutions. To get these keys to work, I wrote a short C program to ioctl /dev/audioctl, and added some lines to the .fvwmrc file. I'm writing this quick blog entry to help the next person doing the same Internet search. If there is a better way to do this in Solaris already (like a shipped binary), I missed it!

This is the C program,

/* volumeset.c - set Sun's /dev/audio play volume */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/audioio.h>

void
usage(char *name)
{
        (void) printf("USAGE: %s [+|-]volume_percent\n", name);
        (void) printf("   eg,\n");
        (void) printf("       %s 100     # maximum volume\n", name);
        (void) printf("       %s +5      # plus 5 percent\n", name);
        exit(1);
}

int
main(int argc, char *argv[])
{
        audio_info_t ai;
        int fd, vol, mod, gain;

        if (argc < 2)
                usage(argv[0]);

        switch (argv[1][0]) {
                case '+':
                        mod = 1;
                        vol = atoi(&argv[1][1]);
                        break;
                case '-':
                        mod = -1;
                        vol = atoi(&argv[1][1]);
                        break;
                case '0'...'9':
                        mod = 0;
                        vol = atoi(argv[1]);
                        if (vol > 100 || vol < 0) {
                                (void) printf("ERROR: volume must be "
                                    "between 0 and 100.\n");
                                exit(4);
                        }
                        break;
                default:
                        usage(argv[0]);
        }

        if (mod != 0 && vol == 0)
                usage(argv[0]);

        if ((fd = open("/dev/audioctl", O_RDONLY)) == -1) {
                (void) perror("can't open /dev/audioctl");
                exit(2);
        }

        if (ioctl(fd, AUDIO_GETINFO, &ai) == -1) {
                (void) perror("fetching audio state failed");
                exit(3);
        }

        if (mod == 0)
                gain = (vol * 255) / 100;
        else
                gain = ai.play.gain + (mod * vol * 255) / 100;
        if (gain < 0)
                gain = 0;
        if (gain > 255)
                gain = 255;

        ai.play.gain = gain;
        ai.output_muted = gain == 0 ? 1 : 0;

        if (ioctl(fd, AUDIO_SETINFO, &ai) == -1) {
                (void) perror("setting audio state failed");
                exit(4);
        }

        (void) close(fd);

        return (0);
}
If you don't have Sun's C compiler installed, you can compile it using /usr/sfw/bin/gcc -o volumeset volumeset.c.

The following are the lines I added to ~/.fvwm/.fvwm2rc to bind the audio keys on the top left to the volumeset program (copied to /usr/local/bin); these bindings probably work for type 6 keyboards as well (haven't tried),

Key SunAudioMute A       A       Exec /usr/local/bin/volumeset 0
Key SunAudioLowerVolume A A      Exec /usr/local/bin/volumeset -15
Key SunAudioRaiseVolume A A      Exec /usr/local/bin/volumeset +15
The above lines bind the keys to mute the volume, decrease by 15% or increase by 15% (it may be better to make the mute behave as a toggle, rather than always mute). After restarting fvwm, my audio keys now work fine.
Comments:

One of the problems with man page documentation is that it often bogs down with details while offering no clues as to proper usage. For instance, no program should hard code "/dev/audio", instead using the value of the AUDIODEV environment variable. Similarly, the control device should be the same value with "ctl" appended. By the way, what do you use to make your screencasts? They are great!

Posted by Brian Utterback on March 06, 2007 at 08:17 AM PST #

G'Day Brian,

You are right - this should use AUDIODEV, and it is in both audio(7I) and audioplay(1). Normally I'd study these first, but at the time I wanted a quick fix for the fvwm volume keys!

While I have made a helpermonkey screencast in the past (and more planned), I don't know what happened to it. Maybe you saw it, maybe you are thinking of someone else. Anyhow, I used vnc2swf.py, from http://www.unixuser.org/~euske/vnc2swf/pyvnc2swf.html.

Posted by Brendan on March 06, 2007 at 10:48 AM PST #

Brendan, have you seen speckeysd(1M)? It's from CDE, but it may work with fvwm.

Posted by Boyd Adamson on March 06, 2007 at 09:45 PM PST #

how did you compile this with Sun's cc ? A select-case can use only a constant value, isn't it ? This wont fly with Sun's compiler: case '0'...'9': stefan

Posted by stefan parvu on April 26, 2007 at 02:40 AM PDT #

Boyd's right: speckeysd should sort you out.

Posted by Andre on April 27, 2007 at 10:07 AM PDT #

Post a Comment:
Comments are closed for this entry.