xenocara/app/fvwm/modules/FvwmEvent/FvwmEvent.c

520 lines
12 KiB
C

/*#define DEBUG
*
* Copyright (C) 1994 Mark Boyns (boyns@sdsu.edu) and
* Mark Scott (mscott@mcd.mot.com)
* 1996-1998 Albrecht Kadlec (albrecht@auto.tuwien.ac.at)
*
* FvwmEvent version 1.0
*
* 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
* renamed & cleaned up so that FvwmEvent (TaDa !!) is a general event
handler module.
-- 21.04.98 Albrecht Kadlec (albrecht@auto.tuwien.ac.at)
* changed parsing to use new library functions
* merged bug fix from Christophe MARTIN <cmartin@ipnl.in2p3.fr>
- FvwmAudio doesn't read messages it is not interrested in,
thus desynchronize,
- keep time stamp even if no sound is played
- minimize malloc/free
mark boyns ok-ed this patch, I reviewed it and put out those ugly
#defines for RESYNC and READ_BODY by reordering the control structures
-- Albrecht Kadlec (albrecht@auto.tuwien.ac.at)
* made FvwmAudio insensitive to its name -> can be symlinked.
corrected some error message deficiencies, code for quoted 'sound'
parameters shamelessly stolen from FvwmButtons/parse.c (with minimal
adjustments)
FvwmAudio now supports rsynth's say command:
*FvwmAudioPlayCmd say
*FvwmAudio add_window "add window"
*FvwmAudio raise_window 'raise window'
-- 08/07/96 Albrecht Kadlec (albrecht@auto.tuwien.ac.at)
* 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.
*/
#include "config.h"
#include "../../fvwm/module.h"
#include "fvwmlib.h"
/*
* fvwm includes:
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <unistd.h>
#include <ctype.h>
/*
* rplay includes:
*/
#ifdef HAVE_RPLAY
#include <rplay.h>
#undef M_ERROR /* Solaris fix */
#endif
#include "ModParse.h"
#ifdef DEBUG
#define INFO(x) fprintf(stderr,x)
#else
#define INFO(x)
#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 MyNameLen;
int fd[2];
char cmd_line[BUFSIZE]="";
time_t audio_delay = 0, /* seconds */
last_time = 0,
now;
#ifdef HAVE_RPLAY
int rplay_fd = -1;
#endif
/* prototypes */
int execute_event(short);
void config(void);
void DeadPipe(int) __attribute__((__noreturn__));
static RETSIGTYPE TerminateHandler(int);
/* define the event table */
char *events[MAX_MESSAGES+MAX_BUILTIN] =
{
"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",
"error",
"config_info",
"end_config_info",
"icon_file",
"default_icon",
"string",
#ifdef M_BELL
"beep",
#endif
#ifdef M_TOGGLEPAGE
"togglepage",
#endif
"mini_icon",
"windowshade",
"dewindowshade",
"locksonsend",
"sendconfig",
/* add builtins here */
"startup",
"shutdown",
"unknown"
};
/* define the action table */
char *action_table[MAX_MESSAGES+MAX_BUILTIN];
#ifdef HAVE_RPLAY
/* define the rplay table */
RPLAY *rplay_table[MAX_MESSAGES+MAX_BUILTIN];
#endif
static volatile sig_atomic_t isTerminated = False;
int main(int argc, char **argv)
{
char *s;
unsigned long header[HEADER_SIZE], body[MAX_BODY_SIZE];
int total, remaining, count, event;
INFO("--- started ----\n");
/* Save our program name - for error events */
if ((s=strrchr(argv[0], '/'))) /* strip path */
s++;
else /* no slash */
s = argv[0];
MyNameLen=strlen(s)+1; /* account for '*' */
MyName = safemalloc(MyNameLen+1); /* account for \0 */
*MyName='*';
strcpy(MyName+1, s); /* append name */
if ((argc != 6)&&(argc != 7)) /* Now MyName is defined */
{
fprintf(stderr,"%s Version "VERSION" should only be executed by fvwm!\n",
MyName+1);
exit(1);
}
INFO("--- installing signal server\n");
#ifdef HAVE_SIGACTION
{
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
# ifdef SA_INTERRUPT
sigact.sa_flags = SA_INTERRUPT;
# else
sigact.sa_flags = 0;
# endif
sigact.sa_handler = TerminateHandler;
sigaction(SIGPIPE,&sigact,NULL); /* Dead pipe == Fvwm died */
sigaction(SIGTERM,&sigact,NULL); /* "polite" termination signal */
}
#else
/* We don't have sigaction(), so fall back to less robust methods. */
signal(SIGPIPE, TerminateHandler);
signal(SIGTERM, TerminateHandler);
#endif
fd[0] = atoi(argv[1]);
fd[1] = atoi(argv[2]);
INFO("--- configuring\n");
config(); /* configure events */
execute_event(BUILTIN_STARTUP); /* Startup event */
SendText(fd,"Nop",0); /* what for ? */
/* main loop */
INFO("--- waiting\n");
while ( !isTerminated )
{
if ((count = read(fd[1],header,
HEADER_SIZE*sizeof(unsigned long))) <= 0)
exit(0);
/* if this read is interrrupted EINTR, the wrong event is triggered !!! */
if( header[0] != START_FLAG )
continue; /* should find something better for resyncing */
/* Ignore events that occur during the delay period. */
now = time(0);
/* junk the event body */
total=0;
remaining = (header[2] - HEADER_SIZE) * sizeof(unsigned long);
while (remaining)
{
if((count=read(fd[1],&body[total],remaining)) < 0)
exit(0);
remaining -= count;
total +=count;
}
if (now < last_time + audio_delay)
continue; /* quash event */
/*
* event will equal the number of shifts in the
* base-2 header[1] number. Could use log here
* but this should be fast enough.
*/
event = -1;
while (header[1])
{
event++;
header[1] >>= 1;
}
if (event < 0 || event >= MAX_MESSAGES)
event=BUILTIN_UNKNOWN;
execute_event(event); /* execute action */
} /* while */
execute_event(BUILTIN_SHUTDOWN);
return 0;
}
/***********************************************************************
*
* Procedure:
*
* execute_event - actually executes the actions from lookup table
*
**********************************************************************/
int execute_event(short event)
{
static char buf[BUFSIZE];
#ifdef HAVE_RPLAY
if (rplay_fd != -1) /* this is the sign that rplay is used */
{
if (rplay_table[event])
if (rplay(rplay_fd, rplay_table[event]) >= 0)
last_time = now;
else
rplay_perror("rplay");
return 0;
} else /* avoid invalid second execute */
#endif
if (action_table[event])
{
sprintf(buf,"%s %s", cmd_line, action_table[event]);
#if 1
INFO(buf);
INFO("\n");
SendText(fd,buf,0); /* let fvwm2 execute the function */
last_time = now;
#else
if( ! ( ret = system(buf))) /* directly execute external program */
last_time = now;
return ret;
#endif
}
return 1;
}
/***********************************************************************
*
* Procedure:
* config - read the configuration file.
*
***********************************************************************/
char *table[]=
{
"Cmd",
"Delay"
#ifdef HAVE_RPLAY
,
"RplayHost",
"RplayPriority",
"RplayVolume"
#endif
}; /* define entries here, if this list becomes unsorted, use LFindToken */
void config(void)
{
char *buf, *event, *action, *p, *q, **e;
int i, found;
#ifdef HAVE_RPLAY
int volume = RPLAY_DEFAULT_VOLUME,
priority = RPLAY_DEFAULT_PRIORITY;
char host[128];
strcpy(host, rplay_default_host());
#endif
/* Intialize all the actions */
for (i = 0; i < MAX_MESSAGES+MAX_BUILTIN; i++)
{
action_table[i] = NULL;
#ifdef HAVE_RPLAY
rplay_table[i] = NULL;
#endif
}
while (GetConfigLine(fd,&buf), buf != NULL)
{
if (buf[strlen(buf)-1] == '\n') { /* if line ends with newline */
buf[strlen(buf)-1] = '\0'; /* strip off \n */
}
/* Search for MyName (normally *FvwmAudio) */
if (strncasecmp(buf, MyName, MyNameLen) == 0)
{
p = buf+MyNameLen;
INFO(buf);
INFO("\n");
if ((e= FindToken(p,table,char *))) /* config option ? */
{
p+=strlen(*e); /* skip matched token */
q=GetArgument(&p);
if (!q)
{
fprintf(stderr,"%s: %s%s needs a parameter\n",
MyName+1, MyName+1,*e);
continue;
}
switch (e - (char**)table)
{
case 0: if (q) strcpy(cmd_line, q); /* Cmd */
else *cmd_line='\0';
INFO("cmd_line = ->");
INFO(cmd_line);
INFO("<-\n");
break;
case 1: audio_delay = atoi(q); break; /* Delay */
#ifdef HAVE_RPLAY
case 2: if (*q == '$') /* RPlayHost */
{ /* Check for $HOSTDISPLAY */
char *c1= (char *)getenv(q+1), *c2= host;
while (c1 && *c1 != ':')
*c2++ = *c1++;
*c2 = '\0';
}
else
strcpy(host, q);
break;
case 3: priority = atoi(q); break; /* RplayPriority */
case 4: volume = atoi(q); break; /* RplayVolume */
#endif
}
}
else /* test for isspace(*p) ??? */
{
event = GetArgument(&p);
action = GetArgument(&p);
INFO(event);
INFO(" ");
INFO(action);
INFO("\n");
if (!event || !*event || !action || !*action)
{
fprintf(stderr,"%s: incomplete event definition %s\n",
MyName+1, buf);
continue;
}
for (found = 0,i = 0; !found && i < MAX_MESSAGES+MAX_BUILTIN;
i++)
{
INFO(events[i]);
INFO("\n");
if (MatchToken(event, events[i]))
{
#ifdef HAVE_RPLAY
rplay_table[i] = rplay_create(RPLAY_PLAY);
rplay_set(rplay_table[i], RPLAY_APPEND,
RPLAY_SOUND, action,
RPLAY_PRIORITY, priority,
RPLAY_VOLUME, volume,
NULL);
#endif
action_table[i]=action;
found=1;
INFO("found\n");
}
}
if (!found) fprintf(stderr,"%s: unknown event type: %s\n",
MyName+1, event);
}
}
/*else INFO("NO CONFIG\n");*/
}
#ifdef HAVE_RPLAY
/*
* Builtin rplay support is enabled when FvwmAudioPlayCmd == builtin-rplay.
*/
if (strcasecmp(cmd_line, "builtin-rplay") == 0)
if ((rplay_fd = rplay_open(host)) < 0)
{
rplay_perror("rplay_open");
exit(1);
}
#endif
}
/***********************************************************************
*
* Procedure:
* SIGPIPE handler - SIGPIPE means fvwm is dying
*
***********************************************************************/
static RETSIGTYPE
TerminateHandler(int nonsense)
{
isTerminated = True;
}
/***********************************************************************
*
* Procedure:
* Externally callable procedure to quit
*
***********************************************************************/
void DeadPipe(int flag)
{
execute_event(BUILTIN_SHUTDOWN);
exit(flag);
}