Mercurial > pidgin.yaz
annotate src/gtksound.c @ 10311:b7566fc34c6c
[gaim-migrate @ 11505]
Hitting the enter key when you're cursor is in the alias field of the
Add Chat dialog now activates the dialogs default action.
Closes bug 1075200 and patch 1078079. Thanks to Andrew Hart for
taking a stab at this and wounding, but not killing. Killing is wrong!
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Fri, 03 Dec 2004 04:02:10 +0000 |
parents | ec140184437b |
children | 61852117568f |
rev | line source |
---|---|
5684 | 1 /* |
10297
ec140184437b
[gaim-migrate @ 11480]
Luke Schierer <lschiere@pidgin.im>
parents:
10158
diff
changeset
|
2 * @file gtksound.h GTK+ Sound |
ec140184437b
[gaim-migrate @ 11480]
Luke Schierer <lschiere@pidgin.im>
parents:
10158
diff
changeset
|
3 * @ingroup gtkui |
ec140184437b
[gaim-migrate @ 11480]
Luke Schierer <lschiere@pidgin.im>
parents:
10158
diff
changeset
|
4 * |
5684 | 5 * gaim |
6 * | |
8046 | 7 * Gaim is the legal property of its developers, whose names are too numerous |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
5684 | 10 * |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 * | |
25 */ | |
9791 | 26 #include "internal.h" |
27 #include "gtkgaim.h" | |
5684 | 28 |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
29 #ifdef _WIN32 |
5684 | 30 #include <windows.h> |
31 #include <mmsystem.h> | |
32 #endif | |
33 | |
34 #ifdef USE_AO | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
35 # include <ao/ao.h> |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
36 # include <audiofile.h> |
5684 | 37 #endif /* USE_AO */ |
38 | |
39 #ifdef USE_NAS_AUDIO | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
40 # include <audio/audiolib.h> |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
41 # include <audio/soundlib.h> |
5684 | 42 #endif /* USE_NAS_AUDIO */ |
43 | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
44 #include "debug.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
45 #include "notify.h" |
5684 | 46 #include "prefs.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
47 #include "sound.h" |
7465 | 48 #include "util.h" |
5684 | 49 |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
50 #include "gtksound.h" |
5684 | 51 |
52 | |
53 struct gaim_sound_event { | |
54 char *label; | |
55 char *pref; | |
56 char *def; | |
57 }; | |
58 | |
10074 | 59 #define PLAY_SOUND_TIMEOUT 15000 |
5684 | 60 |
61 static gboolean mute_login_sounds = FALSE; | |
6199 | 62 static gboolean sound_initialized = FALSE; |
5684 | 63 |
64 static struct gaim_sound_event sounds[GAIM_NUM_SOUNDS] = { | |
10158 | 65 {N_("Buddy logs in"), "login", "login.wav"}, |
66 {N_("Buddy logs out"), "logout", "logout.wav"}, | |
5684 | 67 {N_("Message received"), "im_recv", "receive.wav"}, |
68 {N_("Message received begins conversation"), "first_im_recv", "receive.wav"}, | |
69 {N_("Message sent"), "send_im", "send.wav"}, | |
10158 | 70 {N_("Person enters chat"), "join_chat", "login.wav"}, |
71 {N_("Person leaves chat"), "left_chat", "logout.wav"}, | |
5684 | 72 {N_("You talk in chat"), "send_chat_msg", "send.wav"}, |
73 {N_("Others talk in chat"), "chat_msg_recv", "receive.wav"}, | |
74 /* this isn't a terminator, it's the buddy pounce default sound event ;-) */ | |
10158 | 75 {NULL, "pounce_default", "alert.wav"}, |
76 {N_("Someone says your name in chat"), "nick_said", "alert.wav"} | |
5684 | 77 }; |
78 | |
79 #ifdef USE_AO | |
80 static int ao_driver = -1; | |
81 #endif /* USE_AO */ | |
82 | |
5794
5e93fc46d1af
[gaim-migrate @ 6219]
Christian Hammond <chipx86@chipx86.com>
parents:
5684
diff
changeset
|
83 static void _pref_sound_method_changed(const char *name, GaimPrefType type, |
5684 | 84 gpointer val, gpointer data); |
85 | |
86 static void gaim_gtk_sound_init(void) | |
87 { | |
88 gaim_prefs_add_none("/gaim/gtk/sound"); | |
89 gaim_prefs_add_none("/gaim/gtk/sound/enabled"); | |
90 gaim_prefs_add_none("/gaim/gtk/sound/file"); | |
91 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/login", TRUE); | |
92 gaim_prefs_add_string("/gaim/gtk/sound/file/login", ""); | |
93 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/logout", TRUE); | |
94 gaim_prefs_add_string("/gaim/gtk/sound/file/logout", ""); | |
95 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/im_recv", TRUE); | |
96 gaim_prefs_add_string("/gaim/gtk/sound/file/im_recv", ""); | |
97 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/first_im_recv", FALSE); | |
98 gaim_prefs_add_string("/gaim/gtk/sound/file/first_im_recv", ""); | |
99 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/send_im", TRUE); | |
100 gaim_prefs_add_string("/gaim/gtk/sound/file/send_im", ""); | |
101 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/join_chat", FALSE); | |
102 gaim_prefs_add_string("/gaim/gtk/sound/file/join_chat", ""); | |
103 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/left_chat", FALSE); | |
104 gaim_prefs_add_string("/gaim/gtk/sound/file/left_chat", ""); | |
105 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/send_chat_msg", FALSE); | |
106 gaim_prefs_add_string("/gaim/gtk/sound/file/send_chat_msg", ""); | |
107 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/chat_msg_recv", FALSE); | |
108 gaim_prefs_add_string("/gaim/gtk/sound/file/chat_msg_recv", ""); | |
109 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/nick_said", FALSE); | |
110 gaim_prefs_add_string("/gaim/gtk/sound/file/nick_said", ""); | |
7460
3973a09525b3
[gaim-migrate @ 8073]
Christian Hammond <chipx86@chipx86.com>
parents:
7035
diff
changeset
|
111 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/pounce_default", TRUE); |
3973a09525b3
[gaim-migrate @ 8073]
Christian Hammond <chipx86@chipx86.com>
parents:
7035
diff
changeset
|
112 gaim_prefs_add_string("/gaim/gtk/sound/file/pounce_default", ""); |
8633 | 113 gaim_prefs_add_bool("/gaim/gtk/sound/conv_focus", TRUE); |
10074 | 114 gaim_prefs_add_bool("/gaim/gtk/sound/mute", FALSE); |
5684 | 115 gaim_prefs_add_string("/gaim/gtk/sound/command", ""); |
116 gaim_prefs_add_string("/gaim/gtk/sound/method", "automatic"); | |
117 | |
118 #ifdef USE_AO | |
119 gaim_debug(GAIM_DEBUG_INFO, "sound", | |
120 "Initializing sound output drivers.\n"); | |
121 ao_initialize(); | |
122 #endif /* USE_AO */ | |
123 | |
10087 | 124 gaim_prefs_connect_callback(gaim_gtk_sound_get_handle(), "/gaim/gtk/sound/method", |
5794
5e93fc46d1af
[gaim-migrate @ 6219]
Christian Hammond <chipx86@chipx86.com>
parents:
5684
diff
changeset
|
125 _pref_sound_method_changed, NULL); |
5684 | 126 } |
127 | |
128 | |
129 static void gaim_gtk_sound_shutdown(void) | |
130 { | |
131 #ifdef USE_AO | |
132 ao_shutdown(); | |
133 #endif | |
6199 | 134 sound_initialized = FALSE; |
5684 | 135 } |
136 | |
10074 | 137 #if defined(USE_NAS_AUDIO) || defined(USE_AO) |
138 gboolean expire_old_child(gpointer data) | |
139 { | |
140 int ret; | |
141 pid_t pid = GPOINTER_TO_INT(data); | |
142 | |
143 ret = waitpid(pid, NULL, WNOHANG | WUNTRACED); | |
144 | |
145 if(ret == 0) { | |
146 if(kill(pid, SIGKILL) < 0) | |
147 gaim_debug_error("gtksound", "Killing process %d failed (%s)\n", pid, strerror(errno)); | |
148 } | |
149 | |
150 return FALSE; /* do not run again */ | |
151 } | |
152 #endif | |
153 | |
5684 | 154 static void gaim_gtk_sound_play_file(const char *filename) |
155 { | |
156 const char *method; | |
157 #if defined(USE_NAS_AUDIO) || defined(USE_AO) | |
158 pid_t pid; | |
159 #ifdef USE_AO | |
160 AFfilehandle file; | |
161 #endif | |
162 #endif | |
163 | |
6199 | 164 if (!sound_initialized) |
165 gaim_prefs_trigger_callback("/gaim/gtk/sound/method"); | |
166 | |
10074 | 167 if (gaim_prefs_get_bool("/gaim/gtk/sound/mute")) |
5684 | 168 return; |
169 | |
170 method = gaim_prefs_get_string("/gaim/gtk/sound/method"); | |
171 | |
10074 | 172 if (!strcmp(method, "none")) { |
173 return; | |
174 } else if (!strcmp(method, "beep")) { | |
5684 | 175 gdk_beep(); |
176 return; | |
177 } | |
178 | |
179 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { | |
180 char *tmp = g_strdup_printf(_("Unable to play sound because the chosen file (%s) does not exist."), filename); | |
181 gaim_notify_error(NULL, NULL, tmp, NULL); | |
182 g_free(tmp); | |
183 return; | |
184 } | |
185 | |
186 #ifndef _WIN32 | |
187 if (!strcmp(method, "custom")) { | |
188 const char *sound_cmd; | |
189 char *command; | |
190 GError *error = NULL; | |
191 | |
192 sound_cmd = gaim_prefs_get_string("/gaim/gtk/sound/command"); | |
193 | |
194 if (!sound_cmd || *sound_cmd == '\0') { | |
195 gaim_notify_error(NULL, NULL, | |
196 _("Unable to play sound because the " | |
197 "'Command' sound method has been chosen, " | |
198 "but no command has been set."), NULL); | |
199 return; | |
200 } | |
201 | |
7464 | 202 if(strstr(sound_cmd, "%s")) |
203 command = gaim_strreplace(sound_cmd, "%s", filename); | |
204 else | |
205 command = g_strdup_printf("%s %s", sound_cmd, filename); | |
5684 | 206 |
207 if(!g_spawn_command_line_async(command, &error)) { | |
208 char *tmp = g_strdup_printf(_("Unable to play sound because the configured sound command could not be launched: %s"), error->message); | |
209 gaim_notify_error(NULL, NULL, tmp, NULL); | |
210 g_free(tmp); | |
211 g_error_free(error); | |
212 } | |
213 | |
214 g_free(command); | |
215 return; | |
216 } | |
217 #if defined(USE_NAS_AUDIO) || defined(USE_AO) | |
218 pid = fork(); | |
219 if (pid < 0) | |
220 return; | |
221 else if (pid == 0) { | |
222 #ifdef USE_NAS_AUDIO | |
223 if (!strcmp(method, "nas")) { | |
224 if (play_file_nas(filename)) | |
225 _exit(0); | |
226 } | |
227 #endif /* USE_NAS_AUDIO */ | |
228 | |
229 #ifdef USE_AO | |
230 file = afOpenFile(filename, "rb", NULL); | |
231 if(file) { | |
232 ao_device *device; | |
233 ao_sample_format format; | |
234 int in_fmt; | |
235 int bytes_per_frame; | |
236 | |
237 format.rate = afGetRate(file, AF_DEFAULT_TRACK); | |
238 format.channels = afGetChannels(file, AF_DEFAULT_TRACK); | |
239 afGetSampleFormat(file, AF_DEFAULT_TRACK, &in_fmt, | |
240 &format.bits); | |
241 | |
242 /* XXX: libao doesn't seem to like 8-bit sounds, so we'll | |
243 * let libaudiofile make them a bit better for us */ | |
244 if(format.bits == 8) | |
245 format.bits = 16; | |
246 | |
247 afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, | |
248 AF_SAMPFMT_TWOSCOMP, format.bits); | |
249 | |
250 #if __BYTE_ORDER == __BIG_ENDIAN | |
251 format.byte_format = AO_FMT_BIG; | |
252 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
253 AF_BYTEORDER_BIGENDIAN); | |
254 #elif __BYTE_ORDER == __LITTLE_ENDIAN | |
255 format.byte_format = AO_FMT_LITTLE; | |
256 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
257 AF_BYTEORDER_LITTLEENDIAN); | |
258 #endif | |
259 | |
260 bytes_per_frame = format.bits * format.channels / 8; | |
261 | |
262 device = ao_open_live(ao_driver, &format, NULL); | |
263 | |
264 if(device) { | |
265 int frames_read; | |
266 char buf[4096]; | |
267 int buf_frames = sizeof(buf) / bytes_per_frame; | |
268 | |
269 while((frames_read = afReadFrames(file, AF_DEFAULT_TRACK, | |
270 buf, buf_frames))) { | |
271 if(!ao_play(device, buf, frames_read * bytes_per_frame)) | |
272 break; | |
273 } | |
274 ao_close(device); | |
275 } | |
276 afCloseFile(file); | |
277 } | |
278 ao_shutdown(); | |
279 #endif /* USE_AO */ | |
280 _exit(0); | |
10074 | 281 } else { |
282 gaim_timeout_add(PLAY_SOUND_TIMEOUT, expire_old_child, GINT_TO_POINTER(pid)); | |
5684 | 283 } |
284 #else /* USE_NAS_AUDIO || USE_AO */ | |
285 gdk_beep(); | |
286 return; | |
287 #endif /* USE_NAS_AUDIO || USE_AO */ | |
288 #else /* _WIN32 */ | |
289 gaim_debug(GAIM_DEBUG_INFO, "sound", "Playing %s\n", filename); | |
290 | |
291 if (!PlaySound(filename, 0, SND_ASYNC | SND_FILENAME)) | |
292 gaim_debug(GAIM_DEBUG_ERROR, "sound", "Error playing sound.\n"); | |
293 #endif /* _WIN32 */ | |
294 } | |
295 | |
296 static void gaim_gtk_sound_play_event(GaimSoundEventID event) | |
297 { | |
298 char *enable_pref; | |
299 char *file_pref; | |
300 | |
301 if ((event == GAIM_SOUND_BUDDY_ARRIVE) && mute_login_sounds) | |
302 return; | |
303 | |
304 if (event >= GAIM_NUM_SOUNDS) { | |
305 gaim_debug(GAIM_DEBUG_MISC, "sound", | |
306 "got request for unknown sound: %d\n", event); | |
307 return; | |
308 } | |
309 | |
310 enable_pref = g_strdup_printf("/gaim/gtk/sound/enabled/%s", | |
311 sounds[event].pref); | |
312 file_pref = g_strdup_printf("/gaim/gtk/sound/file/%s", sounds[event].pref); | |
313 | |
314 /* check NULL for sounds that don't have an option, ie buddy pounce */ | |
315 if (gaim_prefs_get_bool(enable_pref)) { | |
316 char *filename = g_strdup(gaim_prefs_get_string(file_pref)); | |
317 if(!filename || !strlen(filename)) { | |
318 if(filename) g_free(filename); | |
319 filename = g_build_filename(DATADIR, "sounds", "gaim", sounds[event].def, NULL); | |
320 } | |
321 | |
322 gaim_sound_play_file(filename); | |
323 g_free(filename); | |
324 } | |
325 | |
326 g_free(enable_pref); | |
327 g_free(file_pref); | |
328 } | |
329 | |
330 static GaimSoundUiOps sound_ui_ops = | |
331 { | |
332 gaim_gtk_sound_init, | |
333 gaim_gtk_sound_shutdown, | |
334 gaim_gtk_sound_play_file, | |
335 gaim_gtk_sound_play_event | |
336 }; | |
337 | |
7035
feb3d21a7794
[gaim-migrate @ 7598]
Christian Hammond <chipx86@chipx86.com>
parents:
6778
diff
changeset
|
338 GaimSoundUiOps * |
feb3d21a7794
[gaim-migrate @ 7598]
Christian Hammond <chipx86@chipx86.com>
parents:
6778
diff
changeset
|
339 gaim_gtk_sound_get_ui_ops(void) |
5684 | 340 { |
341 return &sound_ui_ops; | |
342 } | |
343 | |
344 | |
5794
5e93fc46d1af
[gaim-migrate @ 6219]
Christian Hammond <chipx86@chipx86.com>
parents:
5684
diff
changeset
|
345 static void _pref_sound_method_changed(const char *name, GaimPrefType type, |
5684 | 346 gpointer val, gpointer data) { |
6778 | 347 if(type != GAIM_PREF_STRING || strcmp(name, "/gaim/gtk/sound/method")) |
348 return; | |
349 | |
6199 | 350 sound_initialized = TRUE; |
351 | |
5684 | 352 #ifdef USE_AO |
353 ao_driver = -1; | |
354 | |
355 if(!strcmp(val, "esd")) | |
356 ao_driver = ao_driver_id("esd"); | |
357 else if(!strcmp(val, "arts")) | |
358 ao_driver = ao_driver_id("arts"); | |
359 else if(!strcmp(val, "automatic")) | |
360 ao_driver = ao_default_driver_id(); | |
361 | |
362 if(ao_driver != -1) { | |
363 ao_info *info = ao_driver_info(ao_driver); | |
364 gaim_debug(GAIM_DEBUG_INFO, "sound", | |
365 "Sound output driver loaded: %s\n", info->name); | |
366 } | |
367 #endif /* USE_AO */ | |
368 #ifdef USE_NAS | |
369 if (!strcmp(val, "nas")) | |
370 gaim_debug(GAIM_DEBUG_INFO, "sound", | |
371 "Sound output driver loaded: NAS output\n"); | |
372 #endif /* USE_NAS */ | |
373 } | |
374 | |
375 #ifdef USE_NAS_AUDIO | |
376 static gboolean play_file_nas(const char *filename) | |
377 { | |
378 AuServer *nas_serv; | |
379 gboolean ret = FALSE; | |
380 | |
381 if((nas_serv = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL))) { | |
382 ret = AuSoundPlaySynchronousFromFile(nas_serv, filename, 100); | |
383 AuCloseServer(nas_serv); | |
384 } | |
385 | |
386 return ret; | |
387 } | |
388 | |
389 #endif /* USE_NAS_AUDIO */ | |
390 | |
391 void gaim_gtk_sound_set_login_mute(gboolean mute) | |
392 { | |
393 mute_login_sounds = mute; | |
394 } | |
395 | |
396 const char *gaim_gtk_sound_get_event_option(GaimSoundEventID event) | |
397 { | |
398 if(event >= GAIM_NUM_SOUNDS) | |
399 return 0; | |
400 | |
401 return sounds[event].pref; | |
402 } | |
403 | |
404 char *gaim_gtk_sound_get_event_label(GaimSoundEventID event) | |
405 { | |
406 if(event >= GAIM_NUM_SOUNDS) | |
407 return NULL; | |
408 | |
409 return sounds[event].label; | |
410 } | |
10087 | 411 |
412 void *gaim_gtk_sound_get_handle() | |
413 { | |
414 static int handle; | |
415 | |
416 return &handle; | |
417 } |