~ctwm/ctwm/trunk

304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1
/*
2
 * These routines were extracted from the sound hack for olvwm3.3 by
463.1.29 by Matthew Fuller
Slightly improve history doc based on sound.txt.
3
 * Andrew "Ender" Scherpbier (turtle@sciences.sdsu.edu, Andrew@SDSU.Edu)
4
 * and modified by J.E. Sacco (jsacco @ssl.com) for tvtwm and twm.  They
5
 * were then slightly adapted for ctwm by Mark Boyns (boyns@sdsu.edu),
6
 * and have since been reworked more.
9 by Claude Lecommandeur
CTWM version 3.1
7
 */
8
395.1.1 by Matthew Fuller
Move ctwm.h to always be included first.
9
#include "ctwm.h"
10
9 by Claude Lecommandeur
CTWM version 3.1
11
#include <rplay.h>
12
#include <string.h>
13
#include <stdio.h>
136.1.14 by Richard Levitte
Add sound.h to declare the sound functions properly.
14
#include <ctype.h>
15
459.1.8 by Matthew Fuller
Start adding new definitions for magic events for the sound into a
16
#include "event_names.h"
136.1.14 by Richard Levitte
Add sound.h to declare the sound functions properly.
17
#include "sound.h"
9 by Claude Lecommandeur
CTWM version 3.1
18
459.1.7 by Matthew Fuller
Move rp to the heap, allowing us to get away from needing to know the
19
RPLAY **rp = NULL;
9 by Claude Lecommandeur
CTWM version 3.1
20
21
static int need_sound_init = 1;
463.1.9 by Matthew Fuller
Add a flag for when we set sounds in the config file, and refuse to
22
static int sound_from_config = 0;
9 by Claude Lecommandeur
CTWM version 3.1
23
static int sound_fd = 0;
24
static int sound_state = 1;
459.1.3 by Matthew Fuller
Use strncpy() when copying into hostname so we can't blow it out.
25
#define HOSTNAME_LEN 200
26
static char hostname[HOSTNAME_LEN];
9 by Claude Lecommandeur
CTWM version 3.1
27
143 by Richard Levitte
Comment on the trimming function and simplify it.
28
/*
29
 * Function to trim away spaces at the start and end of a string
30
 */
142 by Richard Levitte
Teach the sound file reader to trim spaces.
31
static char *
32
trim_spaces(char *str)
33
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
34
	if(str != NULL) {
35
		char *p = str + strlen(str);
36
		while(*str != '\0' && *str != '\r' && *str != '\n' && isspace(*str)) {
37
			str++;
38
		}
39
		/* Assume all line end characters are at the end */
40
		while(p > str && isspace(p[-1])) {
41
			p--;
42
		}
43
		*p = '\0';
44
	}
45
	return str;
142 by Richard Levitte
Teach the sound file reader to trim spaces.
46
}
47
9 by Claude Lecommandeur
CTWM version 3.1
48
/*
459.1.8 by Matthew Fuller
Start adding new definitions for magic events for the sound into a
49
 * Define stuff related to "magic" names.
50
 */
51
static const char *magic_events[] = {
52
	"Startup",
53
	"Shutdown",
54
};
55
#define NMAGICEVENTS (sizeof(magic_events) / sizeof(*magic_events))
56
57
static int
58
sound_magic_event_name2num(const char *name)
59
{
60
	int i;
61
62
	for(i = 0 ; i < NMAGICEVENTS ; i++) {
63
		if(strcasecmp(name, magic_events[i]) == 0) {
64
			/* We number these off the far end of the non-magic events */
65
			return event_names_size() + i;
66
		}
67
	}
68
69
	return -1;
70
}
71
72
459.1.10 by Matthew Fuller
Now we can define NEVENTS dynamically from out figured-up size rather
73
/*
74
 * Now we know how many events we need to store up info for
75
 */
76
#define NEVENTS (event_names_size() + NMAGICEVENTS)
77
78
459.1.8 by Matthew Fuller
Start adding new definitions for magic events for the sound into a
79
80
/*
463.1.2 by Matthew Fuller
Split up sound subsystem init from parsing the .ctwm-sounds file for
81
 * Initialize the subsystem and its necessary bits
9 by Claude Lecommandeur
CTWM version 3.1
82
 */
463.1.5 by Matthew Fuller
Export sound_init() and call it explicitly in main.
83
void
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
84
sound_init(void)
9 by Claude Lecommandeur
CTWM version 3.1
85
{
463.1.4 by Matthew Fuller
sound_init() now has nothing to do if sound is already init'd, so swap
86
	if(!need_sound_init) {
87
		return;
88
	}
89
90
	/* Can't happen */
91
	if(sound_fd != 0) {
92
		fprintf(stderr, "BUG: sound_fd not set but sound inited.\n");
93
		exit(1);
94
	}
95
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
96
	need_sound_init = 0;
463.1.4 by Matthew Fuller
sound_init() now has nothing to do if sound is already init'd, so swap
97
	if(hostname[0] == '\0') {
98
		strncpy(hostname, rplay_default_host(), HOSTNAME_LEN - 1);
99
		hostname[HOSTNAME_LEN - 1] = '\0'; /* JIC */
100
	}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
101
463.1.4 by Matthew Fuller
sound_init() now has nothing to do if sound is already init'd, so swap
102
	if((sound_fd = rplay_open(hostname)) < 0) {
103
		rplay_perror("create");
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
104
	}
105
106
	/*
459.1.7 by Matthew Fuller
Move rp to the heap, allowing us to get away from needing to know the
107
	 * Init rp if necessary
108
	 */
109
	if(rp == NULL) {
110
		if((rp = calloc(NEVENTS, sizeof(RPLAY *))) == NULL) {
111
			perror("calloc() rplay control");
112
			exit(1);
113
			/*
459.1.19 by Matthew Fuller
Don't need to XXX this, it's not so much a 'todo' as 'well...'.
114
			 * Should maybe just bomb out of sound stuff, but there's
459.1.7 by Matthew Fuller
Move rp to the heap, allowing us to get away from needing to know the
115
			 * currently no provision for that.  If malloc fails, we're
116
			 * pretty screwed anyway, so it's not much loss to just die.
117
			 */
118
		}
119
	}
463.1.2 by Matthew Fuller
Split up sound subsystem init from parsing the .ctwm-sounds file for
120
}
121
122
123
/*
463.1.10 by Matthew Fuller
Pull the list-clearing out of the file-reading func and ref it
124
 * Clear out any set sounds
125
 */
126
void
127
sound_clear_list(void)
128
{
129
	int i;
130
131
	/* JIC */
132
	if(rp == NULL) {
133
		return;
134
	}
135
136
	/*
137
	 * Destroy any old sounds
138
	 */
139
	for(i = 0; i < NEVENTS; i++) {
140
		if(rp[i] != NULL) {
141
			rplay_destroy(rp[i]);
142
		}
143
		rp[i] = NULL;
144
	}
145
}
146
147
148
/*
463.1.2 by Matthew Fuller
Split up sound subsystem init from parsing the .ctwm-sounds file for
149
 * [Re]load the sounds
150
 */
463.1.6 by Matthew Fuller
Export and load the list in the main func too. Remove the code in
151
void
463.1.2 by Matthew Fuller
Split up sound subsystem init from parsing the .ctwm-sounds file for
152
sound_load_list(void)
153
{
154
	FILE *fl;
155
	char *home;
156
	char *soundfile;
157
	char buffer[100];
459.1.7 by Matthew Fuller
Move rp to the heap, allowing us to get away from needing to know the
158
463.1.11 by Matthew Fuller
Adjust logic flow in reading .ctwm-sounds file so it doesn't clear
159
	/* Guard; shouldn't be possible */
463.1.3 by Matthew Fuller
Add a guard; this shouldn't happen.
160
	if(rp == NULL) {
161
		fprintf(stderr, "Tried to load sounds before subsystem inited.\n");
162
		exit(1);
163
	}
164
463.1.11 by Matthew Fuller
Adjust logic flow in reading .ctwm-sounds file so it doesn't clear
165
	/* Find the .ctwm-sounds file */
459.1.1 by Matthew Fuller
Use asprintf() instead of an unchecked fixed-length buffer for
166
	if((home = getenv("HOME")) == NULL) {
167
		home = "";
168
	}
169
	if(asprintf(&soundfile, "%s/.ctwm-sounds", home) < 0) {
170
		perror("Failed building path to sound file");
171
		return;
172
	}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
173
	fl = fopen(soundfile, "r");
459.1.1 by Matthew Fuller
Use asprintf() instead of an unchecked fixed-length buffer for
174
	free(soundfile);
463.1.9 by Matthew Fuller
Add a flag for when we set sounds in the config file, and refuse to
175
176
	/*
463.1.11 by Matthew Fuller
Adjust logic flow in reading .ctwm-sounds file so it doesn't clear
177
	 * If it was found, but we already have sound set from the config
178
	 * file, complain on stderr and then return.
463.1.9 by Matthew Fuller
Add a flag for when we set sounds in the config file, and refuse to
179
	 */
463.1.11 by Matthew Fuller
Adjust logic flow in reading .ctwm-sounds file so it doesn't clear
180
	if(fl != NULL && sound_from_config) {
463.1.9 by Matthew Fuller
Add a flag for when we set sounds in the config file, and refuse to
181
		fprintf(stderr, "RplaySounds set in ctwmrc, not reading "
463.1.33 by Matthew Fuller
make indent.
182
		        "~/.ctwm-sounds.\n");
463.1.9 by Matthew Fuller
Add a flag for when we set sounds in the config file, and refuse to
183
		fclose(fl);
184
		return;
185
	}
186
463.1.11 by Matthew Fuller
Adjust logic flow in reading .ctwm-sounds file so it doesn't clear
187
	/* Clear out the old list, whether we have new or not */
188
	sound_clear_list();
189
190
	/* If there wasn't a .ctwm-sounds file, we're done now */
191
	if(fl == NULL) {
192
		return;
193
	}
194
195
	/* Now go ahead and parse it in */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
196
	while(fgets(buffer, 100, fl) != NULL) {
459.1.5 by Matthew Fuller
Add a set_sound_event_name() function to take the event name (versus
197
		char *ename, *sndfile;
198
199
		ename = trim_spaces(strtok(buffer, ": \t"));
200
		if(ename == NULL || *ename == '#') {
201
			continue;
202
		}
203
204
		sndfile = trim_spaces(strtok(NULL, "\r\n"));
205
		if(sndfile == NULL || *sndfile == '#') {
206
			continue;
207
		}
208
463.1.14 by Matthew Fuller
Show warnings when parsing .ctwm-sounds too.
209
		if(set_sound_event_name(ename, sndfile) != 0) {
210
			fprintf(stderr, "Error adding sound for %s; maybe event "
463.1.33 by Matthew Fuller
make indent.
211
			        "name is invalid?\n", ename);
463.1.14 by Matthew Fuller
Show warnings when parsing .ctwm-sounds too.
212
		}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
213
	}
214
	fclose(fl);
9 by Claude Lecommandeur
CTWM version 3.1
215
}
216
217
218
/*
219
 * Play sound
220
 */
136.1.14 by Richard Levitte
Add sound.h to declare the sound functions properly.
221
void
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
222
play_sound(int snd)
9 by Claude Lecommandeur
CTWM version 3.1
223
{
459.1.17 by Matthew Fuller
Comment.
224
	/* Bounds */
459.1.15 by Matthew Fuller
Improve bounds checking.
225
	if(snd < 0 || snd >= NEVENTS) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
226
		return;
227
	}
459.1.17 by Matthew Fuller
Comment.
228
229
	/* Playing enabled */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
230
	if(sound_state == 0) {
231
		return;
232
	}
233
463.1.6 by Matthew Fuller
Export and load the list in the main func too. Remove the code in
234
	/* Better already be initted */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
235
	if(need_sound_init) {
463.1.6 by Matthew Fuller
Export and load the list in the main func too. Remove the code in
236
		fprintf(stderr, "BUG: play_sound() Sound should be initted already.\n");
237
		return;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
238
	}
239
459.1.17 by Matthew Fuller
Comment.
240
	/* Skip if this isn't a sound we have set */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
241
	if(rp[snd] == NULL) {
242
		return;
243
	}
459.1.17 by Matthew Fuller
Comment.
244
245
	/* And if all else fails, play it */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
246
	if(rplay(sound_fd, rp[snd]) < 0) {
459.1.2 by Matthew Fuller
Adjust text in this perror() to be less inaccurate.
247
		rplay_perror("rplay");
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
248
	}
9 by Claude Lecommandeur
CTWM version 3.1
249
}
250
136.1.14 by Richard Levitte
Add sound.h to declare the sound functions properly.
251
void
252
play_startup_sound(void)
9 by Claude Lecommandeur
CTWM version 3.1
253
{
459.1.9 by Matthew Fuller
Now we can use the function to lookup the id's for these, rather than
254
	play_sound(sound_magic_event_name2num("Startup"));
9 by Claude Lecommandeur
CTWM version 3.1
255
}
256
136.1.14 by Richard Levitte
Add sound.h to declare the sound functions properly.
257
void
258
play_exit_sound(void)
9 by Claude Lecommandeur
CTWM version 3.1
259
{
459.1.9 by Matthew Fuller
Now we can use the function to lookup the id's for these, rather than
260
	play_sound(sound_magic_event_name2num("Shutdown"));
9 by Claude Lecommandeur
CTWM version 3.1
261
}
262
463.1.9 by Matthew Fuller
Add a flag for when we set sounds in the config file, and refuse to
263
264
/*
265
 * Flag that we loaded sounds from the ctwmrc
266
 */
267
void
268
sound_set_from_config(void)
269
{
270
	sound_from_config = 1;
271
}
272
273
9 by Claude Lecommandeur
CTWM version 3.1
274
/*
275
 * Toggle the sound on/off
276
 */
136.1.14 by Richard Levitte
Add sound.h to declare the sound functions properly.
277
void
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
278
toggle_sound(void)
9 by Claude Lecommandeur
CTWM version 3.1
279
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
280
	sound_state ^= 1;
9 by Claude Lecommandeur
CTWM version 3.1
281
}
282
283
284
/*
285
 * Re-read the sounds mapping file
286
 */
136.1.14 by Richard Levitte
Add sound.h to declare the sound functions properly.
287
void
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
288
reread_sounds(void)
9 by Claude Lecommandeur
CTWM version 3.1
289
{
463.1.2 by Matthew Fuller
Split up sound subsystem init from parsing the .ctwm-sounds file for
290
	sound_load_list();
9 by Claude Lecommandeur
CTWM version 3.1
291
}
292
293
/*
294
 * Set the SoundHost and force the sound_fd to be re-opened.
295
 */
136.1.14 by Richard Levitte
Add sound.h to declare the sound functions properly.
296
void
297
set_sound_host(char *host)
9 by Claude Lecommandeur
CTWM version 3.1
298
{
459.1.3 by Matthew Fuller
Use strncpy() when copying into hostname so we can't blow it out.
299
	strncpy(hostname, host, HOSTNAME_LEN - 1);
300
	hostname[HOSTNAME_LEN - 1] = '\0'; /* JIC */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
301
	if(sound_fd != 0) {
9 by Claude Lecommandeur
CTWM version 3.1
302
		rplay_close(sound_fd);
303
	}
304
	sound_fd = 0;
305
}
306
459.1.4 by Matthew Fuller
Break out actually setting the sound for a given even into a separate
307
/*
308
 * Set the sound to play for a given event
309
 */
463.1.12 by Matthew Fuller
Make these setter funcs actually return info about whether they
310
int
459.1.5 by Matthew Fuller
Add a set_sound_event_name() function to take the event name (versus
311
set_sound_event_name(const char *ename, const char *soundfile)
312
{
313
	int i;
314
459.1.11 by Matthew Fuller
Update set_sound_event_name() to use our local magic lookup and new
315
	/* Find the index we'll use in rp[] for it */
316
	i = sound_magic_event_name2num(ename);
317
	if(i < 0) {
318
		i = event_num_by_name(ename);
319
	}
320
	if(i < 0) {
463.1.12 by Matthew Fuller
Make these setter funcs actually return info about whether they
321
		return -1;
459.1.11 by Matthew Fuller
Update set_sound_event_name() to use our local magic lookup and new
322
	}
323
324
	/* Gotcha */
463.1.34 by Matthew Fuller
Pass the set_sound_event() return straight through instead of ignoring
325
	return set_sound_event(i, soundfile);
459.1.5 by Matthew Fuller
Add a set_sound_event_name() function to take the event name (versus
326
}
327
463.1.12 by Matthew Fuller
Make these setter funcs actually return info about whether they
328
int
459.1.4 by Matthew Fuller
Break out actually setting the sound for a given even into a separate
329
set_sound_event(int snd, const char *soundfile)
330
{
459.1.16 by Matthew Fuller
Add a guard to be sure this doesn't get called too early.
331
	/* This shouldn't get called before things are initialized */
332
	if(rp == NULL) {
333
		fprintf(stderr, "%s(): internal error: called before initialized.\n", __func__);
334
		exit(1);
335
	}
336
459.1.4 by Matthew Fuller
Break out actually setting the sound for a given even into a separate
337
	/* Cleanup old if necessary */
338
	if(rp[snd] != NULL) {
339
		rplay_destroy(rp[snd]);
340
	}
341
342
	/* Setup new */
343
	rp[snd] = rplay_create(RPLAY_PLAY);
344
	if(rp[snd] == NULL) {
345
		rplay_perror("create");
463.1.12 by Matthew Fuller
Make these setter funcs actually return info about whether they
346
		return -1;
459.1.4 by Matthew Fuller
Break out actually setting the sound for a given even into a separate
347
	}
348
	if(rplay_set(rp[snd], RPLAY_INSERT, 0, RPLAY_SOUND, soundfile, NULL)
459.1.23 by Matthew Fuller
make indent.
349
	                < 0) {
459.1.4 by Matthew Fuller
Break out actually setting the sound for a given even into a separate
350
		rplay_perror("rplay");
351
	}
352
463.1.12 by Matthew Fuller
Make these setter funcs actually return info about whether they
353
	return 0;
459.1.4 by Matthew Fuller
Break out actually setting the sound for a given even into a separate
354
}