3 * Copyright (C) 1994 Mark Boyns (boyns@sdsu.edu) and
4 * Mark Scott (mscott@mcd.mot.com)
5 * 1996-1998 Albrecht Kadlec (albrecht@auto.tuwien.ac.at)
7 * FvwmEvent version 1.0
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 * This module is based on FvwmModuleDebugger which has the following
28 * This module, and the entire ModuleDebugger program, and the concept for
29 * interfacing this module to the Window Manager, are all original work
32 * Copyright 1994, Robert Nation. No guarantees or warantees or anything
33 * are provided or implied in any way whatsoever. Use this program at your
34 * own risk. Permission to use this program for any purpose is given,
35 * as long as the copyright is kept intact.
38 /* ---------------------------- included header files ----------------------- */
46 #include "libs/Fplay.h"
48 #include "libs/Module.h"
49 #include "libs/fvwmlib.h"
50 #include "libs/Parse.h"
51 #include "libs/Strings.h"
59 #include "libs/ftime.h"
62 /* ---------------------------- local definitions --------------------------- */
64 #define BUILTIN_STARTUP 0
65 #define BUILTIN_SHUTDOWN 1
66 #define BUILTIN_UNKNOWN 2
68 #define MAX_RPLAY_HOSTNAME_LEN MAX_MODULE_INPUT_TEXT_LEN
69 #define SYNC_MASK_M (M_DESTROY_WINDOW | M_LOWER_WINDOW | \
70 M_RESTACK | M_CONFIGURE_WINDOW)
71 #define SYNC_MASK_MX (M_EXTENDED_MSG)
73 /* ---------------------------- local macros -------------------------------- */
75 /* ---------------------------- imports ------------------------------------- */
77 /* ---------------------------- included code files ------------------------- */
79 /* ---------------------------- local types --------------------------------- */
92 /* ---------------------------- forward declarations ------------------------ */
94 void execute_event(event_entry
*, short, unsigned long*);
96 RETSIGTYPE
DeadPipe(int);
97 static RETSIGTYPE
TerminateHandler(int);
99 /* ---------------------------- local variables ----------------------------- */
101 /* ---------------------------- exported variables (globals) ---------------- */
104 static int MyNameLen
;
106 static char *cmd_line
= NULL
;
107 static time_t audio_delay
= 0; /* seconds */
108 static time_t last_time
= 0;
110 static time_t start_audio_delay
= 0;
111 /* don't tag on the windowID by default */
112 static Bool PassID
= False
;
113 static Bool audio_compat
= False
;
114 static char *audio_play_dir
= NULL
;
116 #define ARG_NO_WINID 1024 /* just a large number */
118 #define EVENT_ENTRY(name,action_arg) { name, action_arg, {NULL} }
119 static event_entry message_event_table
[] =
121 EVENT_ENTRY( "new_page", -1 ),
122 EVENT_ENTRY( "new_desk", 0 | ARG_NO_WINID
),
123 EVENT_ENTRY( "old_add_window", 0 ),
124 EVENT_ENTRY( "raise_window", 0 ),
125 EVENT_ENTRY( "lower_window", 0 ),
126 EVENT_ENTRY( "old_configure_window", 0 ),
127 EVENT_ENTRY( "focus_change", 0 ),
128 EVENT_ENTRY( "destroy_window", 0 ),
129 EVENT_ENTRY( "iconify", 0 ),
130 EVENT_ENTRY( "deiconify", 0 ),
131 EVENT_ENTRY( "window_name", 0 ),
132 EVENT_ENTRY( "icon_name", 0 ),
133 EVENT_ENTRY( "res_class", 0 ),
134 EVENT_ENTRY( "res_name", 0 ),
135 EVENT_ENTRY( "end_windowlist", -1 ),
136 EVENT_ENTRY( "icon_location", 0 ),
137 EVENT_ENTRY( "map", 0 ),
138 EVENT_ENTRY( "error", -1 ),
139 EVENT_ENTRY( "config_info", -1 ),
140 EVENT_ENTRY( "end_config_info", -1 ),
141 EVENT_ENTRY( "icon_file", 0 ),
142 EVENT_ENTRY( "default_icon", -1 ),
143 EVENT_ENTRY( "string", -1 ),
144 EVENT_ENTRY( "mini_icon", 0 ),
145 EVENT_ENTRY( "windowshade", 0 ),
146 EVENT_ENTRY( "dewindowshade", 0 ),
147 EVENT_ENTRY( "visible_name", 0 ),
148 EVENT_ENTRY( "sendconfig", -1 ),
149 EVENT_ENTRY( "restack", -1 ),
150 EVENT_ENTRY( "add_window", 0 ),
151 EVENT_ENTRY( "configure_window", 0 ),
154 static event_entry extended_message_event_table
[] =
156 EVENT_ENTRY( "visible_icon_name", 0 ),
157 EVENT_ENTRY( "enter_window", 0 ),
158 EVENT_ENTRY( "leave_window", 0 ),
159 EVENT_ENTRY( "property_change", 0),
160 EVENT_ENTRY( "reply", 0), /* FvwmEvent will never receive MX_REPLY */
163 static event_entry builtin_event_table
[] =
165 EVENT_ENTRY( "startup", -1 ),
166 EVENT_ENTRY( "shutdown", -1 ),
167 EVENT_ENTRY( "unknown", -1),
172 /* These are some events described in the man page, which does not exist in
174 static event_entry future_event_table
[] =
177 EVENT_ENTRY( "beep", -1 ),
180 EVENT_ENTRY( "toggle_paging", -1 ),
186 static event_entry
* event_tables
[] =
189 extended_message_event_table
,
196 static int rplay_fd
= -1;
197 static unsigned int m_selected
= 0;
198 static unsigned int mx_selected
= 0;
199 static unsigned int m_sync
= 0;
200 static unsigned int mx_sync
= 0;
203 static volatile sig_atomic_t isTerminated
= False
;
205 /* ---------------------------- local functions ----------------------------- */
207 void unlock_event(unsigned long evtype
)
211 if (evtype
& M_EXTENDED_MSG
)
221 SendUnlockNotification(fd
);
227 int main(int argc
, char **argv
)
230 unsigned long header
[FvwmPacketHeaderSize
];
231 unsigned long body
[FvwmPacketBodyMaxSize
];
232 int total
, remaining
, count
, event
;
235 cmd_line
= (char *)safemalloc(1);
237 /* Save our program name - for error events */
238 if ((s
=strrchr(argv
[0], '/')))
250 if (strcmp(argv
[6], "-audio") == 0)
261 /* account for '*' */
262 MyNameLen
=strlen(s
)+1;
264 MyName
= safemalloc(MyNameLen
+1);
268 if (StrEquals("FvwmAudio", s
))
270 /* catch the FvwmAudio alias */
274 /* Now MyName is defined */
275 if ((argc
!= 6)&&(argc
!= 7))
277 fprintf(stderr
, "%s Version "VERSION
" should only be "
278 "executed by fvwm!\n", MyName
+1);
282 #ifdef HAVE_SIGACTION
284 struct sigaction sigact
;
286 sigemptyset(&sigact
.sa_mask
);
288 sigact
.sa_flags
= SA_INTERRUPT
;
292 sigact
.sa_handler
= TerminateHandler
;
294 /* Dead pipe == Fvwm died */
295 sigaction(SIGPIPE
,&sigact
,NULL
);
296 /* "polite" termination signal */
297 sigaction(SIGTERM
,&sigact
,NULL
);
300 /* We don't have sigaction(), so fall back to less robust methods. */
301 signal(SIGPIPE
, TerminateHandler
);
302 signal(SIGTERM
, TerminateHandler
);
305 fd
[0] = atoi(argv
[1]);
306 fd
[1] = atoi(argv
[2]);
308 /* configure events */
311 execute_event(builtin_event_table
, BUILTIN_STARTUP
, NULL
);
312 if (start_audio_delay
)
316 /* tell fvwm we're running */
317 SetMessageMask(fd
, m_selected
);
318 SetMessageMask(fd
, mx_selected
| M_EXTENDED_MSG
);
319 m_sync
= (m_selected
& SYNC_MASK_M
);
320 mx_sync
= (mx_selected
& SYNC_MASK_M
) | M_EXTENDED_MSG
;
321 /* migo (19-Aug-2000): synchronize on M_DESTROY_WINDOW
322 * dv (6-Jul-2002: synchronize on a number of events that can hide or
323 * destroy a window */
326 SetSyncMask(fd
, m_sync
);
328 if (mx_sync
!= M_EXTENDED_MSG
)
330 SetSyncMask(fd
, mx_sync
);
332 mx_sync
&= ~M_EXTENDED_MSG
;
333 SendFinishedStartupNotification(fd
);
336 while (!isTerminated
)
338 unsigned long msg_bit
;
339 event_entry
*event_table
;
341 if ((count
= read(fd
[1], header
, FvwmPacketHeaderSize_byte
)) <=
347 /* if this read is interrrupted EINTR, the wrong event is
350 if (header
[0] != START_FLAG
)
352 /* should find something better for resyncing */
353 unlock_event(header
[1]);
357 /* Ignore events that occur during the delay period. */
360 /* junk the event body */
362 remaining
= (header
[2] - FvwmPacketHeaderSize
) *
363 sizeof(unsigned long);
366 if ((count
=read(fd
[1],&body
[total
],remaining
)) < 0)
369 unlock_event(header
[1]);
376 if (now
< last_time
+ audio_delay
+ start_audio_delay
)
379 unlock_event(header
[1]);
384 start_audio_delay
= 0;
387 /* event will equal the number of shifts in the base-2
388 * header[1] number. Could use log here but this should be
392 is_extended_msg
= (msg_bit
& M_EXTENDED_MSG
);
393 msg_bit
&= ~M_EXTENDED_MSG
;
401 (event
>= MAX_MESSAGES
&& !is_extended_msg
) ||
402 (event
>= MAX_EXTENDED_MESSAGES
&& is_extended_msg
))
404 event_table
= builtin_event_table
;
405 event
= BUILTIN_UNKNOWN
;
407 else if (is_extended_msg
)
409 event_table
= extended_message_event_table
;
413 event_table
= message_event_table
;
415 execute_event(event_table
, event
, body
);
416 unlock_event(header
[1]);
418 execute_event(builtin_event_table
, BUILTIN_SHUTDOWN
, NULL
);
428 * execute_event - actually executes the actions from lookup table
431 void execute_event(event_entry
*event_table
, short event
, unsigned long *body
)
433 /* this is the sign that rplay is used */
434 if (rplay_fd
!= -1 && event_table
[event
].action
.rplay
!= NULL
)
436 if (Fplay(rplay_fd
, event_table
[event
].action
.rplay
) >= 0)
442 Fplay_perror("rplay");
447 if (event_table
[event
].action
.action
!= NULL
)
453 action
= event_table
[event
].action
.action
;
454 len
= strlen(cmd_line
) + strlen(action
) + 32;
457 len
+= strlen(audio_play_dir
);
459 buf
= (char *)safemalloc(len
);
462 /* Don't use audio_play_dir if it's NULL or if
463 * the sound file is an absolute pathname. */
464 if (!audio_play_dir
|| audio_play_dir
[0] == '\0' ||
467 sprintf(buf
,"%s %s", cmd_line
, action
);
471 sprintf(buf
,"%s %s/%s &", cmd_line
,
472 audio_play_dir
, action
);
481 int action_arg
= event_table
[event
].action_arg
;
484 if (action_arg
!= -1 && !(action_arg
& ARG_NO_WINID
))
486 fw
= body
[action_arg
];
489 if (PassID
&& action_arg
!= -1)
491 if (action_arg
& ARG_NO_WINID
)
493 action_arg
&= ~ARG_NO_WINID
;
494 sprintf(buf
, "%s %s %ld", cmd_line
,
495 action
, body
[action_arg
]);
499 sprintf(buf
, "%s %s 0x%lx", cmd_line
,
500 action
, body
[action_arg
]);
505 sprintf(buf
,"%s %s", cmd_line
, action
);
507 /* let fvwm execute the function */
508 SendText(fd
, buf
, fw
);
523 * config - read the configuration file.
527 static int volume
= FPLAY_DEFAULT_VOLUME
;
528 static int priority
= FPLAY_DEFAULT_PRIORITY
;
529 void handle_config_line(char *buf
, char **phost
)
550 }; /* define entries here, if this list becomes unsorted, use FindToken */
554 /* config option ? */
555 if ((e
= FindToken(p
, table
, char *)))
557 /* skip matched token */
559 token
= PeekToken(p
, &p
);
560 switch (e
- (char**)table
)
568 "%s: PlayCmd supported only when"
569 " invoked as FvwmAudio\n", MyName
+1);
581 cmd_line
= safestrdup(token
);
585 cmd_line
= safestrdup("");
593 audio_delay
= atoi(token
);
602 "%s: Dir supported only when invoked as"
603 " FvwmAudio\n", MyName
+1);
610 free(audio_play_dir
);
612 audio_play_dir
= safestrdup(token
);
628 if (token
&& (*token
== '$'))
630 /* Check for $HOSTDISPLAY */
631 char *c1
= (char *)getenv(token
+ 1);
635 *phost
= safestrdup(c1
);
637 while (c1
&& *c1
!= ':')
646 *phost
= safestrdup(token
);
654 priority
= atoi(token
);
662 volume
= atoi(token
);
670 start_audio_delay
= atoi(token
);
678 event_entry
**event_table
;
680 /* test for isspace(*p) ??? */
681 p
= GetNextSimpleOption(p
, &event
);
682 p
= GetNextSimpleOption(p
, &action
);
683 if (!event
|| !*event
|| !action
|| !*action
)
693 fprintf(stderr
, "%s: incomplete event definition %s\n",
697 event_table
= event_tables
;
699 while(found
== 0 && *event_table
!= NULL
)
701 event_entry
*loop_event
;
703 for (loop_event
= *event_table
, i
= 0;
704 found
== 0 && loop_event
->name
!= NULL
;
707 if (MatchToken(event
, loop_event
->name
))
709 if (loop_event
->action
.action
!= NULL
)
711 free(loop_event
->action
.action
);
713 loop_event
->action
.action
= action
;
715 if (*event_table
== message_event_table
)
717 m_selected
|= (1 << i
);
721 extended_message_event_table
)
723 mx_selected
|= (1 << i
);
731 fprintf(stderr
, "%s: unknown event type: %s\n",
754 host
= safestrdup(Fplay_default_host());
757 /* get config lines with my name */
758 InitGetConfigLine(fd
,MyName
);
759 while (GetConfigLine(fd
,&buf
), buf
!= NULL
&& *buf
!= 0)
761 if (buf
[strlen(buf
)-1] == '\n')
763 /* if line ends with newline, strip it off */
764 buf
[strlen(buf
)-1] = '\0';
767 /* Search for MyName (normally *FvwmEvent) */
768 if (strncasecmp(buf
, MyName
, MyNameLen
) == 0)
770 handle_config_line(buf
, &host
);
774 /* Builtin rplay support is enabled when
775 * FvwmAudioPlayCmd == builtin-rplay. */
776 if (USE_FPLAY
&& StrEquals(cmd_line
, "builtin-rplay"))
778 event_entry
**event_table
;
780 if ((rplay_fd
= Fplay_open(host
)) < 0)
782 Fplay_perror("rplay_open");
785 /* change actions to rplay objects */
786 event_table
= event_tables
;
787 while(*event_table
!= NULL
)
789 event_entry
*loop_event
;
790 for (loop_event
= *event_table
;
791 loop_event
->name
!= NULL
; loop_event
++)
793 if (loop_event
->action
.action
!= NULL
)
796 tmp_action
= loop_event
->action
.action
;
797 loop_event
->action
.rplay
=
801 loop_event
->action
.rplay
,
803 FPLAY_SOUND
, tmp_action
,
804 FPLAY_PRIORITY
, priority
,
805 FPLAY_VOLUME
, volume
, NULL
);
819 * SIGPIPE handler - SIGPIPE means fvwm is dying
823 TerminateHandler(int nonsense
)
833 * Externally callable procedure to quit
836 RETSIGTYPE
DeadPipe(int flag
)
838 execute_event(builtin_event_table
, BUILTIN_SHUTDOWN
, NULL
);