Mercurial > pidgin
annotate src/gtksound.c @ 11261:b53606580f68
[gaim-migrate @ 13439]
Patch #1226486 from Levi Bard
Fixes bug #1224178
If you change the topic in a chat room and that topic change is rejected, the
topic field is wrong -- it shows the new topic even thought it didn't get set.
This patch resets the GUI's topic immediately when you hit enter. Then, if the
topic change is successful, the server will echo the topic change back to us
and we'll update the GUI to the new topic.
The only question is, does the server always echo the topic back to us? From the
core's point of view, I'm ready to assume yes. It's the case for both IRC and
Jabber*. If someone could test changing a topic in SILC or Zephyr, that'd be
great. If servers using those protocols do not echo the topic back, the prpl
will have to fake it as appropriate.
* I didn't actually test on Jabber, but Nathan said the server will echo the
topic change back. If it's broken, let me know.
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Sun, 14 Aug 2005 06:55:57 +0000 |
parents | bb0d7b719af2 |
children | 448ebda0f7ec |
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 | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
39 #include "debug.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
40 #include "notify.h" |
5684 | 41 #include "prefs.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
42 #include "sound.h" |
7465 | 43 #include "util.h" |
5684 | 44 |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
45 #include "gtksound.h" |
5684 | 46 |
47 struct gaim_sound_event { | |
48 char *label; | |
49 char *pref; | |
50 char *def; | |
51 }; | |
52 | |
10074 | 53 #define PLAY_SOUND_TIMEOUT 15000 |
5684 | 54 |
10320 | 55 static guint mute_login_sounds_timeout = 0; |
5684 | 56 static gboolean mute_login_sounds = FALSE; |
6199 | 57 static gboolean sound_initialized = FALSE; |
5684 | 58 |
59 static struct gaim_sound_event sounds[GAIM_NUM_SOUNDS] = { | |
10158 | 60 {N_("Buddy logs in"), "login", "login.wav"}, |
61 {N_("Buddy logs out"), "logout", "logout.wav"}, | |
5684 | 62 {N_("Message received"), "im_recv", "receive.wav"}, |
63 {N_("Message received begins conversation"), "first_im_recv", "receive.wav"}, | |
64 {N_("Message sent"), "send_im", "send.wav"}, | |
10158 | 65 {N_("Person enters chat"), "join_chat", "login.wav"}, |
66 {N_("Person leaves chat"), "left_chat", "logout.wav"}, | |
5684 | 67 {N_("You talk in chat"), "send_chat_msg", "send.wav"}, |
68 {N_("Others talk in chat"), "chat_msg_recv", "receive.wav"}, | |
69 /* this isn't a terminator, it's the buddy pounce default sound event ;-) */ | |
10158 | 70 {NULL, "pounce_default", "alert.wav"}, |
71 {N_("Someone says your name in chat"), "nick_said", "alert.wav"} | |
5684 | 72 }; |
73 | |
74 #ifdef USE_AO | |
75 static int ao_driver = -1; | |
76 #endif /* USE_AO */ | |
77 | |
10320 | 78 static gboolean |
79 mute_login_sounds_cb(gpointer data) | |
80 { | |
81 mute_login_sounds = FALSE; | |
82 mute_login_sounds_timeout = 0; | |
83 return FALSE; | |
84 } | |
85 | |
86 /* | |
87 * We mute sounds for the 10 seconds after you log in so that | |
88 * you don't get flooded with sounds when the blist shows all | |
89 * your buddies logging in. | |
90 */ | |
91 static void | |
92 account_signon_cb(GaimConnection *gc, gpointer data) | |
93 { | |
94 if (mute_login_sounds_timeout != 0) | |
95 g_source_remove(mute_login_sounds_timeout); | |
96 mute_login_sounds = TRUE; | |
97 mute_login_sounds_timeout = gaim_timeout_add(10000, mute_login_sounds_cb, NULL); | |
98 } | |
99 | |
10322 | 100 static void |
101 _pref_sound_method_changed(const char *name, GaimPrefType type, | |
102 gpointer val, gpointer data) { | |
103 if(type != GAIM_PREF_STRING || strcmp(name, "/gaim/gtk/sound/method")) | |
104 return; | |
105 | |
106 sound_initialized = TRUE; | |
107 | |
108 #ifdef USE_AO | |
109 ao_driver = -1; | |
110 | |
111 if(!strcmp(val, "esd")) | |
112 ao_driver = ao_driver_id("esd"); | |
113 else if(!strcmp(val, "arts")) | |
114 ao_driver = ao_driver_id("arts"); | |
11082 | 115 else if(!strcmp(val, "nas")) |
116 ao_driver = ao_driver_id("nas"); | |
10322 | 117 else if(!strcmp(val, "automatic")) |
118 ao_driver = ao_default_driver_id(); | |
119 | |
120 if(ao_driver != -1) { | |
121 ao_info *info = ao_driver_info(ao_driver); | |
122 gaim_debug_info("sound", | |
123 "Sound output driver loaded: %s\n", info->name); | |
124 } | |
125 #endif /* USE_AO */ | |
126 } | |
127 | |
128 const char * | |
129 gaim_gtk_sound_get_event_option(GaimSoundEventID event) | |
130 { | |
131 if(event >= GAIM_NUM_SOUNDS) | |
132 return 0; | |
133 | |
134 return sounds[event].pref; | |
135 } | |
136 | |
137 char * | |
138 gaim_gtk_sound_get_event_label(GaimSoundEventID event) | |
139 { | |
140 if(event >= GAIM_NUM_SOUNDS) | |
141 return NULL; | |
142 | |
143 return sounds[event].label; | |
144 } | |
145 | |
146 void * | |
147 gaim_gtk_sound_get_handle() | |
148 { | |
149 static int handle; | |
150 | |
151 return &handle; | |
152 } | |
153 | |
154 static void | |
155 gaim_gtk_sound_init(void) | |
5684 | 156 { |
10320 | 157 void *gtk_sound_handle = gaim_gtk_sound_get_handle(); |
158 | |
159 gaim_signal_connect(gaim_connections_get_handle(), "signed-on", | |
160 gtk_sound_handle, GAIM_CALLBACK(account_signon_cb), | |
161 NULL); | |
162 | |
5684 | 163 gaim_prefs_add_none("/gaim/gtk/sound"); |
164 gaim_prefs_add_none("/gaim/gtk/sound/enabled"); | |
165 gaim_prefs_add_none("/gaim/gtk/sound/file"); | |
166 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/login", TRUE); | |
167 gaim_prefs_add_string("/gaim/gtk/sound/file/login", ""); | |
168 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/logout", TRUE); | |
169 gaim_prefs_add_string("/gaim/gtk/sound/file/logout", ""); | |
170 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/im_recv", TRUE); | |
171 gaim_prefs_add_string("/gaim/gtk/sound/file/im_recv", ""); | |
172 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/first_im_recv", FALSE); | |
173 gaim_prefs_add_string("/gaim/gtk/sound/file/first_im_recv", ""); | |
174 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/send_im", TRUE); | |
175 gaim_prefs_add_string("/gaim/gtk/sound/file/send_im", ""); | |
176 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/join_chat", FALSE); | |
177 gaim_prefs_add_string("/gaim/gtk/sound/file/join_chat", ""); | |
178 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/left_chat", FALSE); | |
179 gaim_prefs_add_string("/gaim/gtk/sound/file/left_chat", ""); | |
180 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/send_chat_msg", FALSE); | |
181 gaim_prefs_add_string("/gaim/gtk/sound/file/send_chat_msg", ""); | |
182 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/chat_msg_recv", FALSE); | |
183 gaim_prefs_add_string("/gaim/gtk/sound/file/chat_msg_recv", ""); | |
184 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/nick_said", FALSE); | |
185 gaim_prefs_add_string("/gaim/gtk/sound/file/nick_said", ""); | |
7460
3973a09525b3
[gaim-migrate @ 8073]
Christian Hammond <chipx86@chipx86.com>
parents:
7035
diff
changeset
|
186 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/pounce_default", TRUE); |
3973a09525b3
[gaim-migrate @ 8073]
Christian Hammond <chipx86@chipx86.com>
parents:
7035
diff
changeset
|
187 gaim_prefs_add_string("/gaim/gtk/sound/file/pounce_default", ""); |
8633 | 188 gaim_prefs_add_bool("/gaim/gtk/sound/conv_focus", TRUE); |
10074 | 189 gaim_prefs_add_bool("/gaim/gtk/sound/mute", FALSE); |
5684 | 190 gaim_prefs_add_string("/gaim/gtk/sound/command", ""); |
191 gaim_prefs_add_string("/gaim/gtk/sound/method", "automatic"); | |
192 | |
193 #ifdef USE_AO | |
10322 | 194 gaim_debug_info("sound", "Initializing sound output drivers.\n"); |
5684 | 195 ao_initialize(); |
196 #endif /* USE_AO */ | |
197 | |
10087 | 198 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
|
199 _pref_sound_method_changed, NULL); |
5684 | 200 } |
201 | |
10322 | 202 static void |
203 gaim_gtk_sound_uninit(void) | |
5684 | 204 { |
205 #ifdef USE_AO | |
206 ao_shutdown(); | |
207 #endif | |
6199 | 208 sound_initialized = FALSE; |
5684 | 209 } |
210 | |
11082 | 211 #if defined(USE_AO) |
10322 | 212 static gboolean |
213 expire_old_child(gpointer data) | |
10074 | 214 { |
215 int ret; | |
216 pid_t pid = GPOINTER_TO_INT(data); | |
217 | |
218 ret = waitpid(pid, NULL, WNOHANG | WUNTRACED); | |
219 | |
220 if(ret == 0) { | |
221 if(kill(pid, SIGKILL) < 0) | |
10322 | 222 gaim_debug_error("gtksound", "Killing process %d failed (%s)\n", |
223 pid, strerror(errno)); | |
10074 | 224 } |
225 | |
226 return FALSE; /* do not run again */ | |
227 } | |
228 #endif | |
229 | |
10322 | 230 static void |
231 gaim_gtk_sound_play_file(const char *filename) | |
5684 | 232 { |
233 const char *method; | |
11082 | 234 #if defined(USE_AO) |
5684 | 235 pid_t pid; |
236 #ifdef USE_AO | |
237 AFfilehandle file; | |
238 #endif | |
239 #endif | |
240 | |
6199 | 241 if (!sound_initialized) |
242 gaim_prefs_trigger_callback("/gaim/gtk/sound/method"); | |
243 | |
10074 | 244 if (gaim_prefs_get_bool("/gaim/gtk/sound/mute")) |
5684 | 245 return; |
246 | |
247 method = gaim_prefs_get_string("/gaim/gtk/sound/method"); | |
248 | |
10074 | 249 if (!strcmp(method, "none")) { |
250 return; | |
251 } else if (!strcmp(method, "beep")) { | |
5684 | 252 gdk_beep(); |
253 return; | |
254 } | |
255 | |
256 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { | |
257 char *tmp = g_strdup_printf(_("Unable to play sound because the chosen file (%s) does not exist."), filename); | |
258 gaim_notify_error(NULL, NULL, tmp, NULL); | |
259 g_free(tmp); | |
260 return; | |
261 } | |
262 | |
263 #ifndef _WIN32 | |
264 if (!strcmp(method, "custom")) { | |
265 const char *sound_cmd; | |
266 char *command; | |
267 GError *error = NULL; | |
268 | |
269 sound_cmd = gaim_prefs_get_string("/gaim/gtk/sound/command"); | |
270 | |
271 if (!sound_cmd || *sound_cmd == '\0') { | |
272 gaim_notify_error(NULL, NULL, | |
273 _("Unable to play sound because the " | |
274 "'Command' sound method has been chosen, " | |
275 "but no command has been set."), NULL); | |
276 return; | |
277 } | |
278 | |
7464 | 279 if(strstr(sound_cmd, "%s")) |
280 command = gaim_strreplace(sound_cmd, "%s", filename); | |
281 else | |
282 command = g_strdup_printf("%s %s", sound_cmd, filename); | |
5684 | 283 |
284 if(!g_spawn_command_line_async(command, &error)) { | |
285 char *tmp = g_strdup_printf(_("Unable to play sound because the configured sound command could not be launched: %s"), error->message); | |
286 gaim_notify_error(NULL, NULL, tmp, NULL); | |
287 g_free(tmp); | |
288 g_error_free(error); | |
289 } | |
290 | |
291 g_free(command); | |
292 return; | |
293 } | |
11082 | 294 #if defined(USE_AO) |
5684 | 295 pid = fork(); |
296 if (pid < 0) | |
297 return; | |
298 else if (pid == 0) { | |
299 #ifdef USE_AO | |
300 file = afOpenFile(filename, "rb", NULL); | |
301 if(file) { | |
302 ao_device *device; | |
303 ao_sample_format format; | |
304 int in_fmt; | |
305 int bytes_per_frame; | |
306 | |
307 format.rate = afGetRate(file, AF_DEFAULT_TRACK); | |
308 format.channels = afGetChannels(file, AF_DEFAULT_TRACK); | |
309 afGetSampleFormat(file, AF_DEFAULT_TRACK, &in_fmt, | |
310 &format.bits); | |
311 | |
312 /* XXX: libao doesn't seem to like 8-bit sounds, so we'll | |
313 * let libaudiofile make them a bit better for us */ | |
314 if(format.bits == 8) | |
315 format.bits = 16; | |
316 | |
317 afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, | |
318 AF_SAMPFMT_TWOSCOMP, format.bits); | |
319 | |
320 #if __BYTE_ORDER == __BIG_ENDIAN | |
321 format.byte_format = AO_FMT_BIG; | |
322 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
323 AF_BYTEORDER_BIGENDIAN); | |
324 #elif __BYTE_ORDER == __LITTLE_ENDIAN | |
325 format.byte_format = AO_FMT_LITTLE; | |
326 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
327 AF_BYTEORDER_LITTLEENDIAN); | |
328 #endif | |
329 | |
330 bytes_per_frame = format.bits * format.channels / 8; | |
331 | |
332 device = ao_open_live(ao_driver, &format, NULL); | |
333 | |
334 if(device) { | |
335 int frames_read; | |
336 char buf[4096]; | |
337 int buf_frames = sizeof(buf) / bytes_per_frame; | |
338 | |
339 while((frames_read = afReadFrames(file, AF_DEFAULT_TRACK, | |
340 buf, buf_frames))) { | |
341 if(!ao_play(device, buf, frames_read * bytes_per_frame)) | |
342 break; | |
343 } | |
344 ao_close(device); | |
345 } | |
346 afCloseFile(file); | |
347 } | |
348 ao_shutdown(); | |
349 #endif /* USE_AO */ | |
350 _exit(0); | |
10074 | 351 } else { |
352 gaim_timeout_add(PLAY_SOUND_TIMEOUT, expire_old_child, GINT_TO_POINTER(pid)); | |
5684 | 353 } |
11082 | 354 #else /* USE_AO */ |
5684 | 355 gdk_beep(); |
356 return; | |
11082 | 357 #endif /* USE_AO */ |
5684 | 358 #else /* _WIN32 */ |
10322 | 359 gaim_debug_info("sound", "Playing %s\n", filename); |
5684 | 360 |
10922
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
361 if (G_WIN32_HAVE_WIDECHAR_API ()) { |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
362 wchar_t *wc_filename = g_utf8_to_utf16(filename, |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
363 -1, NULL, NULL, NULL); |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
364 if (!PlaySoundW(wc_filename, NULL, SND_ASYNC | SND_FILENAME)) |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
365 gaim_debug(GAIM_DEBUG_ERROR, "sound", "Error playing sound.\n"); |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
366 g_free(wc_filename); |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
367 } else { |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
368 char *l_filename = g_locale_from_utf8(filename, |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
369 -1, NULL, NULL, NULL); |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
370 if (!PlaySoundA(l_filename, NULL, SND_ASYNC | SND_FILENAME)) |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
371 gaim_debug(GAIM_DEBUG_ERROR, "sound", "Error playing sound.\n"); |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
372 g_free(l_filename); |
68083504217c
[gaim-migrate @ 12691]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10322
diff
changeset
|
373 } |
5684 | 374 #endif /* _WIN32 */ |
375 } | |
376 | |
10322 | 377 static void |
378 gaim_gtk_sound_play_event(GaimSoundEventID event) | |
5684 | 379 { |
380 char *enable_pref; | |
381 char *file_pref; | |
382 | |
383 if ((event == GAIM_SOUND_BUDDY_ARRIVE) && mute_login_sounds) | |
384 return; | |
385 | |
386 if (event >= GAIM_NUM_SOUNDS) { | |
10322 | 387 gaim_debug_error("sound", "got request for unknown sound: %d\n", event); |
5684 | 388 return; |
389 } | |
390 | |
391 enable_pref = g_strdup_printf("/gaim/gtk/sound/enabled/%s", | |
392 sounds[event].pref); | |
393 file_pref = g_strdup_printf("/gaim/gtk/sound/file/%s", sounds[event].pref); | |
394 | |
395 /* check NULL for sounds that don't have an option, ie buddy pounce */ | |
396 if (gaim_prefs_get_bool(enable_pref)) { | |
397 char *filename = g_strdup(gaim_prefs_get_string(file_pref)); | |
398 if(!filename || !strlen(filename)) { | |
399 if(filename) g_free(filename); | |
400 filename = g_build_filename(DATADIR, "sounds", "gaim", sounds[event].def, NULL); | |
401 } | |
402 | |
403 gaim_sound_play_file(filename); | |
404 g_free(filename); | |
405 } | |
406 | |
407 g_free(enable_pref); | |
408 g_free(file_pref); | |
409 } | |
410 | |
411 static GaimSoundUiOps sound_ui_ops = | |
412 { | |
413 gaim_gtk_sound_init, | |
10322 | 414 gaim_gtk_sound_uninit, |
5684 | 415 gaim_gtk_sound_play_file, |
416 gaim_gtk_sound_play_event | |
417 }; | |
418 | |
7035
feb3d21a7794
[gaim-migrate @ 7598]
Christian Hammond <chipx86@chipx86.com>
parents:
6778
diff
changeset
|
419 GaimSoundUiOps * |
feb3d21a7794
[gaim-migrate @ 7598]
Christian Hammond <chipx86@chipx86.com>
parents:
6778
diff
changeset
|
420 gaim_gtk_sound_get_ui_ops(void) |
5684 | 421 { |
422 return &sound_ui_ops; | |
423 } |