fvwm1/modules/FvwmAudio/FvwmAudio.c
2019-08-26 23:33:33 +01:00

504 lines
10 KiB
C

/*
* Copyright (C) 1994 Mark Boyns (boyns@sdsu.edu) and
* Mark Scott (mscott@mcd.mot.com)
*
* FvwmAudio version 1.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* ChangeLog
* Fixed FvwmAudio to reflect the changes made to the module protocol.
* Szijarto Szabolcs <saby@sch.bme.hu> provided FvwmSound code that used
$HOSTDISPLAY for the rplay host. The code has been added to FvwmAudio.
* Fixed bugs reported by beta testers, thanks!
* Builtin rplay support has been added to FvwmAudio. This support is
enabled when FvwmAudio is compiled with HAVE_RPLAY defined and when
FvwmAudioPlayCmd is set to builtin-rplay. I guess it's safe to say
that FvwmSound is now obsolete. -- Mark Boyns 5/7/94
* FvwmAudio is based heavily on an Fvwm module "FvwmSound" by Mark Boyns
and the real credit for this really goes to him for the concept.
I just stripped out the "rplay" library dependencies to allow generic
audio play command support.
*/
/*
* This module is based on FvwmModuleDebugger which has the following
* copyright:
*
* This module, and the entire ModuleDebugger program, and the concept for
* interfacing this module to the Window Manager, are all original work
* by Robert Nation
*
* Copyright 1994, Robert Nation. No guarantees or warantees or anything
* are provided or implied in any way whatsoever. Use this program at your
* own risk. Permission to use this program for any purpose is given,
* as long as the copyright is kept intact.
*/
/*
* fvwm includes:
*/
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include "../../configure.h"
#include "../../fvwm/module.h"
#include "../../version.h"
#include "../../libs/fvwmlib.h"
/*
* rplay includes:
*/
#ifdef HAVE_RPLAY
#include <rplay.h>
#endif
#define BUILTIN_STARTUP MAX_MESSAGES
#define BUILTIN_SHUTDOWN MAX_MESSAGES+1
#define BUILTIN_UNKNOWN MAX_MESSAGES+2
#define MAX_BUILTIN 3
#define BUFSIZE 512
/* globals */
char *MyName;
int fd_width;
int fd[2];
char audio_play_cmd_line[BUFSIZE], audio_play_dir[BUFSIZE];
time_t audio_delay = 0; /* seconds */
#ifdef HAVE_RPLAY
int rplay_fd = -1;
#endif
/* prototypes */
void Loop(int *);
void process_message(unsigned long,unsigned long *);
void DeadPipe(int);
void config(char *);
void done(int);
int audio_play(short);
/* define the message table */
char *messages[MAX_MESSAGES+MAX_BUILTIN] =
{
"toggle_paging",
"new_page",
"new_desk",
"add_window",
"raise_window",
"lower_window",
"configure_window",
"focus_change",
"destroy_window",
"iconify",
"deiconify",
"window_name",
"icon_name",
"res_class",
"res_name",
"end_windowlist",
"icon_location",
"map",
/* add builtins here */
"startup",
"shutdown",
"unknown",
};
/* define the sound table */
char *sound_table[MAX_MESSAGES+MAX_BUILTIN];
#ifdef HAVE_RPLAY
/* define the rplay table */
RPLAY *rplay_table[MAX_MESSAGES+MAX_BUILTIN];
#endif
main(int argc, char **argv)
{
char *temp, *s;
if ((argc != 6)&&(argc != 7))
{
fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",
MyName, VERSION);
exit(1);
}
/* Save our program name - for error messages */
temp = argv[0];
s=strrchr(argv[0], '/');
if (s != NULL)
temp = s + 1;
MyName = safemalloc(strlen(temp)+2);
strcpy(MyName,"*");
strcat(MyName, temp);
/* Dead pipe == Fvwm died */
signal (SIGPIPE, DeadPipe);
fd[0] = atoi(argv[1]);
fd[1] = atoi(argv[2]);
audio_play_dir[0] = '\0';
audio_play_cmd_line[0] = '\0';
/*
* Read the sound configuration.
*/
config(argv[3]);
/*
* Play the startup sound.
*/
audio_play(BUILTIN_STARTUP);
SendText(fd,"Nop",0);
Loop(fd);
}
/***********************************************************************
*
* Procedure:
* config - read the sound configuration file.
*
***********************************************************************/
void config(char *config_file)
{
FILE *fp;
char buf[BUFSIZE];
char *message;
char *sound;
char *p;
int i, found;
#ifdef HAVE_RPLAY
char host[128];
int volume = RPLAY_DEFAULT_VOLUME;
int priority = RPLAY_DEFAULT_PRIORITY;
#endif
fp = fopen(config_file, "r");
if (fp == NULL)
{
done(1);
}
/*
* Intialize all the sounds.
*/
for (i = 0; i < MAX_MESSAGES+MAX_BUILTIN; i++) {
sound_table[i] = NULL;
#ifdef HAVE_RPLAY
rplay_table[i] = NULL;
#endif
}
#ifdef HAVE_RPLAY
strcpy(host, rplay_default_host());
#endif
while (fgets(buf, sizeof(buf), fp))
{
buf[strlen(buf)-1] = '\0';
if (buf[0] != '*')
{
continue;
}
/*
* Search for *FvwmAudio.
*/
if (mystrncasecmp(buf, MyName, strlen(MyName)) == 0)
{
p = strtok(buf, " \t");
if (mystrcasecmp(p, "*FvwmAudioPlayCmd") == 0) {
p = strtok(NULL, "\n"); /* allow parameters */
if (p && *p) {
strcpy(audio_play_cmd_line, p);
}
}
else if (mystrcasecmp(p, "*FvwmAudioDir") == 0) {
p = strtok(NULL, " \t");
if (p && *p) {
strcpy(audio_play_dir, p);
}
}
else if (mystrcasecmp(p, "*FvwmAudioDelay") == 0) {
p = strtok(NULL, " \t");
if (p && *p) {
audio_delay = atoi(p);
}
}
#ifdef HAVE_RPLAY
/*
* Check for rplay configuration options.
*/
else if (mystrcasecmp(p, "*FvwmAudioRplayHost") == 0)
{
p = strtok(NULL, " \t");
if (p && *p)
{
/*
* Check for environment variables like $HOSTDISPLAY.
*/
if (*p == '$')
{
char *c1, *c2;
c2 = host;
for (c1 = (char *)getenv(p+1); *c1 && (*c1 != ':'); c1++)
{
*c2++ = *c1;
}
*c2 = '\0';
}
else
{
strcpy(host, p);
}
}
}
else if (mystrcasecmp(p, "*FvwmAudioRplayVolume") == 0)
{
p = strtok(NULL, " \t");
if (p && *p) {
volume = atoi(p);
}
}
else if (mystrcasecmp(p, "*FvwmAudioRplayPriority") == 0)
{
p = strtok(NULL, " \t");
if (p && *p) {
priority = atoi(p);
}
}
#endif
/*
* *FvwmAudio <message_type> <audio_file>
*/
else {
message = strtok(NULL, " \t");
sound = strtok(NULL, " \t");
if (!message || !*message || !sound || !*sound)
{
continue;
}
found = 0;
for (i = 0; !found && i < MAX_MESSAGES+MAX_BUILTIN; i++)
{
if (mystrcasecmp(message, messages[i]) == 0) {
#ifdef HAVE_RPLAY
rplay_table[i] = rplay_create(RPLAY_PLAY);
rplay_set(rplay_table[i], RPLAY_APPEND,
RPLAY_SOUND, sound,
RPLAY_PRIORITY, priority,
RPLAY_VOLUME, volume,
NULL);
#endif
sound_table[i]=safemalloc(strlen(sound)+1);
strcpy(sound_table[i],sound);
found++;
}
}
}
}
}
fclose(fp);
#ifdef HAVE_RPLAY
/*
* Builtin rplay support is enabled when FvwmAudioPlayCmd == builtin-rplay.
*/
if (mystrcasecmp(audio_play_cmd_line, "builtin-rplay") == 0)
{
rplay_fd = rplay_open(host);
if (rplay_fd < 0)
{
rplay_perror("rplay_open");
done(1);
}
}
#endif
}
/***********************************************************************
*
* Procedure:
* Loop - wait for data to process
*
***********************************************************************/
void Loop(int *fd)
{
unsigned long header[3], *body;
char *cbody;
int body_length,count,count2=0, total;
time_t now, last_time = 0;
unsigned long code;
while (1)
{
if ((count = read(fd[1],header,3*sizeof(unsigned long))) > 0)
{
/*
* Ignore messages that occur during the delay
* period.
*/
now = time(0);
if (now < (last_time + audio_delay))
{
continue;
}
last_time = now;
if(header[0] == START_FLAG)
{
body_length = header[2]-3;
body = (unsigned long *)
safemalloc(body_length * sizeof(unsigned long));
cbody = (char *)body;
total = 0;
while(total < body_length*sizeof(unsigned long))
{
if((count2=read(fd[1],&cbody[total],
body_length*sizeof(unsigned long)-total)) >0)
total += count2;
else if(count2 < 0)
DeadPipe(0);
}
/*
* code will equal the number of shifts in the
* base-2 header[1] number. Could use log here
* but this should be fast enough.
*/
code = -1;
while (header[1])
{
code++;
header[1] >>= 1;
}
/*
* Play the sound.
*/
if (code >= 0 && code < MAX_MESSAGES)
{
audio_play(code);
}
else
{
audio_play(BUILTIN_UNKNOWN);
}
free(body);
}
}
if(count <= 0)
DeadPipe(1);
}
}
/***********************************************************************
*
* Procedure:
* SIGPIPE handler - SIGPIPE means fvwm is dying
*
***********************************************************************/
void DeadPipe(int nonsense)
{
done(0);
}
/***********************************************************************
*
* Procedure:
* done - common exit point for FvwmAudio.
*
***********************************************************************/
void done(int n)
{
audio_play(BUILTIN_SHUTDOWN);
exit(n);
}
/***********************************************************************
*
* Procedure:
*
* audio_play - actually plays sound from lookup table
*
**********************************************************************/
int audio_play(short sound)
{
static char buf[BUFSIZE];
#ifdef HAVE_RPLAY
if (rplay_fd != -1)
{
if (rplay_table[sound])
{
if (rplay(rplay_fd, rplay_table[sound]) < 0)
{
rplay_perror("rplay");
}
}
return 0;
}
#endif
if (sound_table[sound])
{
memset(buf,NULL,BUFSIZE);
/*
* Don't use audio_play_dir if it's NULL or if the sound file
* is an absolute pathname.
*/
if (audio_play_dir[0] == '\0' || sound_table[sound][0] == '/')
{
sprintf(buf,"%s %s", audio_play_cmd_line, sound_table[sound]);
}
else
{
sprintf(buf,"%s %s/%s", audio_play_cmd_line, audio_play_dir,
sound_table[sound]);
}
return system(buf);
}
return 1;
}