From 53050e14aadcd76d454a5236454e3d44f63f0ddd Mon Sep 17 00:00:00 2001 From: Jonathan Tellier Date: Fri, 26 Jun 2009 14:05:43 +0200 Subject: Move sound related functions to its own module. --- libempathy-gtk/Makefile.am | 2 + libempathy-gtk/empathy-sound.c | 385 ++++++++++++++++++++++++++++++++++++++ libempathy-gtk/empathy-sound.h | 56 ++++++ libempathy-gtk/empathy-ui-utils.c | 139 +------------- libempathy-gtk/empathy-ui-utils.h | 26 --- 5 files changed, 444 insertions(+), 164 deletions(-) create mode 100644 libempathy-gtk/empathy-sound.c create mode 100644 libempathy-gtk/empathy-sound.h (limited to 'libempathy-gtk') diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am index c38a96f23..10931012a 100644 --- a/libempathy-gtk/Makefile.am +++ b/libempathy-gtk/Makefile.am @@ -54,6 +54,7 @@ libempathy_gtk_handwritten_source = \ empathy-presence-chooser.c \ empathy-profile-chooser.c \ empathy-smiley-manager.c \ + empathy-sound.c \ empathy-spell.c \ empathy-status-preset-dialog.c \ empathy-theme-boxes.c \ @@ -113,6 +114,7 @@ libempathy_gtk_headers = \ empathy-presence-chooser.h \ empathy-profile-chooser.h \ empathy-smiley-manager.h \ + empathy-sound.h \ empathy-spell.h \ empathy-status-preset-dialog.h \ empathy-theme-boxes.h \ diff --git a/libempathy-gtk/empathy-sound.c b/libempathy-gtk/empathy-sound.c new file mode 100644 index 000000000..d97f72bef --- /dev/null +++ b/libempathy-gtk/empathy-sound.c @@ -0,0 +1,385 @@ +/* + * empathy-sound.c - Various sound related utility functions. + * Copyright (C) 2009 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "empathy-sound.h" + +#include +#include +#include + +#define DEBUG_FLAG EMPATHY_DEBUG_OTHER +#include +#include + +#include "empathy-conf.h" + +typedef struct { + EmpathySound sound_id; + const char * event_ca_id; + const char * event_ca_description; + const char * gconf_key; +} EmpathySoundEntry; + +typedef struct { + GtkWidget *widget; + gint sound_id; + guint play_interval; + guint replay_timeout_id; +} EmpathyRepeatableSound; + +/* NOTE: these entries MUST be in the same order than EmpathySound enum */ +static EmpathySoundEntry sound_entries[LAST_EMPATHY_SOUND] = { + { EMPATHY_SOUND_MESSAGE_INCOMING, "message-new-instant", + N_("Received an instant message"), EMPATHY_PREFS_SOUNDS_INCOMING_MESSAGE } , + { EMPATHY_SOUND_MESSAGE_OUTGOING, "message-sent-instant", + N_("Sent an instant message"), EMPATHY_PREFS_SOUNDS_OUTGOING_MESSAGE } , + { EMPATHY_SOUND_CONVERSATION_NEW, "message-new-instant", + N_("Incoming chat request"), EMPATHY_PREFS_SOUNDS_NEW_CONVERSATION }, + { EMPATHY_SOUND_CONTACT_CONNECTED, "service-login", + N_("Contact connected"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGIN }, + { EMPATHY_SOUND_CONTACT_DISCONNECTED, "service-logout", + N_("Contact disconnected"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGOUT }, + { EMPATHY_SOUND_ACCOUNT_CONNECTED, "service-login", + N_("Connected to server"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGIN }, + { EMPATHY_SOUND_ACCOUNT_DISCONNECTED, "service-logout", + N_("Disconnected from server"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGOUT }, + { EMPATHY_SOUND_PHONE_INCOMING, "phone-incoming-call", + N_("Incoming voice call"), NULL }, + { EMPATHY_SOUND_PHONE_OUTGOING, "phone-outgoing-calling", + N_("Outgoing voice call"), NULL }, + { EMPATHY_SOUND_PHONE_HANGUP, "phone-hangup", + N_("Voice call ended"), NULL }, +}; + +/* An hash table containing currently repeating sounds. The format is the + * following: + * Key: An EmpathySound + * Value : The EmpathyRepeatableSound associated with that EmpathySound. */ +static GHashTable *repeating_sounds; + +static gboolean +empathy_sound_pref_is_enabled (EmpathySound sound_id) +{ + EmpathySoundEntry *entry; + EmpathyConf *conf; + gboolean res; + + entry = &(sound_entries[sound_id]); + g_return_val_if_fail (entry->sound_id == sound_id, FALSE); + + if (entry->gconf_key == NULL) + return TRUE; + + conf = empathy_conf_get (); + res = FALSE; + + empathy_conf_get_bool (conf, EMPATHY_PREFS_SOUNDS_ENABLED, &res); + + if (!res) + return FALSE; + + if (!empathy_check_available_state ()) + { + empathy_conf_get_bool (conf, EMPATHY_PREFS_SOUNDS_DISABLED_AWAY, &res); + + if (res) + return FALSE; + } + + empathy_conf_get_bool (conf, entry->gconf_key, &res); + + return res; +} + +/** + * empathy_sound_stop: + * @sound_id: The #EmpathySound to stop playing. + * + * Stop playing a sound. If it has been stated in loop with + * empathy_sound_start_playing(), it will also stop replaying. + */ +void +empathy_sound_stop (EmpathySound sound_id) +{ + EmpathySoundEntry *entry; + + g_return_if_fail (sound_id < LAST_EMPATHY_SOUND); + + entry = &(sound_entries[sound_id]); + g_return_if_fail (entry->sound_id == sound_id); + + if (repeating_sounds != NULL) + { + EmpathyRepeatableSound *repeatable_sound; + + repeatable_sound = g_hash_table_lookup (repeating_sounds, + GINT_TO_POINTER (sound_id)); + if (repeatable_sound != NULL) + { + /* The sound must be stopped... If it is waiting for replay, remove + * it from hash table to cancel. Otherwise we'll cancel the sound + * being played. */ + if (repeatable_sound->replay_timeout_id != 0) + { + g_hash_table_remove (repeating_sounds, GINT_TO_POINTER (sound_id)); + return; + } + } + } + + ca_context_cancel (ca_gtk_context_get (), entry->sound_id); +} + +static gboolean +empathy_sound_play_internal (GtkWidget *widget, EmpathySound sound_id, + ca_finish_callback_t callback, gpointer user_data) +{ + EmpathySoundEntry *entry; + ca_context *c; + ca_proplist *p = NULL; + + entry = &(sound_entries[sound_id]); + g_return_val_if_fail (entry->sound_id == sound_id, FALSE); + + c = ca_gtk_context_get (); + ca_context_cancel (c, entry->sound_id); + + DEBUG ("Play sound \"%s\" (%s)", + entry->event_ca_id, + entry->event_ca_description); + + if (ca_proplist_create (&p) < 0) + goto failed; + + if (ca_proplist_sets (p, CA_PROP_EVENT_ID, entry->event_ca_id) < 0) + goto failed; + + if (ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION, + gettext (entry->event_ca_id)) < 0) + goto failed; + + if (ca_gtk_proplist_set_for_widget (p, widget) < 0) + goto failed; + + ca_context_play_full (ca_gtk_context_get (), entry->sound_id, p, callback, + user_data); + + ca_proplist_destroy (p); + + return TRUE; + +failed: + if (p != NULL) + ca_proplist_destroy (p); + + return FALSE; +} + +/** + * empathy_sound_play_full: + * @widget: The #GtkWidget from which the sound is originating. + * @sound_id: The #EmpathySound to play. + * @callback: The #ca_finish_callback_t function that will be called when the + * sound has stopped playing. + * @user_data: user data to pass to the function. + * + * Plays a sound. + * + * Returns %TRUE if the sound has successfully started playing, otherwise + * returning %FALSE and @callback won't be called. + * + * This function returns %FALSE if the sound is already playing in loop using + * %empathy_sound_start_playing. + * + * This function returns %FALSE if the sound is disabled in empathy preferences. + * + * Return value: %TRUE if the sound has successfully started playing, %FALSE + * otherwise. + */ +gboolean +empathy_sound_play_full (GtkWidget *widget, EmpathySound sound_id, + ca_finish_callback_t callback, gpointer user_data) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (sound_id < LAST_EMPATHY_SOUND, FALSE); + + if (!empathy_sound_pref_is_enabled (sound_id)) + return FALSE; + + /* The sound might already be playing repeatedly. If it's the case, we + * immediadely return since there's no need to make it play again */ + if (repeating_sounds != NULL && + g_hash_table_lookup (repeating_sounds, GINT_TO_POINTER (sound_id)) != NULL) + return FALSE; + + return empathy_sound_play_internal (widget, sound_id, callback, user_data); +} + +/** + * empathy_sound_play: + * @widget: The #GtkWidget from which the sound is originating. + * @sound_id: The #EmpathySound to play. + * + * Plays a sound. See %empathy_sound_play_full for details.' + * + * Return value: %TRUE if the sound has successfully started playing, %FALSE + * otherwise. + */ +gboolean +empathy_sound_play (GtkWidget *widget, EmpathySound sound_id) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (sound_id < LAST_EMPATHY_SOUND, FALSE); + + return empathy_sound_play_full (widget, sound_id, NULL, NULL); +} + +static void playing_finished_cb (ca_context *c, guint id, int error_code, + gpointer user_data); + +static gboolean +playing_timeout_cb (gpointer data) +{ + EmpathyRepeatableSound *repeatable_sound = data; + gboolean playing; + + repeatable_sound->replay_timeout_id = 0; + + playing = empathy_sound_play_internal (repeatable_sound->widget, + repeatable_sound->sound_id, playing_finished_cb, data); + + if (!playing) + { + DEBUG ("Failed to replay sound, stop repeating"); + g_hash_table_remove (repeating_sounds, + GINT_TO_POINTER (repeatable_sound->sound_id)); + } + + return FALSE; +} + +static void +playing_finished_cb (ca_context *c, guint id, int error_code, + gpointer user_data) +{ + EmpathyRepeatableSound *repeatable_sound = user_data; + + if (error_code != CA_SUCCESS) + { + DEBUG ("Error: %s", ca_strerror (error_code)); + g_hash_table_remove (repeating_sounds, + GINT_TO_POINTER (repeatable_sound->sound_id)); + return; + } + + repeatable_sound->replay_timeout_id = g_timeout_add ( + repeatable_sound->play_interval, playing_timeout_cb, user_data); +} + +static void +empathy_sound_widget_destroyed_cb (GtkWidget *widget, gpointer user_data) +{ + EmpathyRepeatableSound *repeatable_sound = user_data; + + /* The sound must be stopped... If it is waiting for replay, remove + * it from hash table to cancel. Otherwise playing_finished_cb will be + * called with an error. */ + if (repeatable_sound->replay_timeout_id != 0) + { + g_hash_table_remove (repeating_sounds, + GINT_TO_POINTER (repeatable_sound->sound_id)); + } +} + +static void +repeating_sounds_item_delete (gpointer data) +{ + EmpathyRepeatableSound *repeatable_sound = data; + + if (repeatable_sound->replay_timeout_id != 0) + g_source_remove (repeatable_sound->replay_timeout_id); + + g_signal_handlers_disconnect_by_func (repeatable_sound->widget, + empathy_sound_widget_destroyed_cb, repeatable_sound); + + g_slice_free (EmpathyRepeatableSound, repeatable_sound); +} + +/** + * empathy_sound_start_playing: + * @widget: The #GtkWidget from which the sound is originating. + * @sound_id: The #EmpathySound to play. + * @timeout_before_replay: The amount of time, in milliseconds, between two + * consecutive play. + * + * Start playing a sound in loop. To stop the sound, call empathy_call_stop () + * by passing it the same @sound_id. Note that if you start playing a sound + * multiple times, you'll have to call %empathy_sound_stop the same number of + * times. + * + * Return value: %TRUE if the sound has successfully started playing. + */ +gboolean +empathy_sound_start_playing (GtkWidget *widget, EmpathySound sound_id, + guint timeout_before_replay) +{ + EmpathyRepeatableSound *repeatable_sound; + gboolean playing = FALSE; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + g_return_val_if_fail (sound_id < LAST_EMPATHY_SOUND, FALSE); + + if (!empathy_sound_pref_is_enabled (sound_id)) + return FALSE; + + if (repeating_sounds == NULL) + { + repeating_sounds = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, repeating_sounds_item_delete); + } + else if (g_hash_table_lookup (repeating_sounds, + GINT_TO_POINTER (sound_id)) != NULL) + { + /* The sound is already playing in loop. No need to continue. */ + return FALSE; + } + + repeatable_sound = g_slice_new0 (EmpathyRepeatableSound); + repeatable_sound->widget = widget; + repeatable_sound->sound_id = sound_id; + repeatable_sound->play_interval = timeout_before_replay; + repeatable_sound->replay_timeout_id = 0; + + g_hash_table_insert (repeating_sounds, GINT_TO_POINTER (sound_id), + repeatable_sound); + + g_signal_connect (G_OBJECT (widget), "destroy", + G_CALLBACK (empathy_sound_widget_destroyed_cb), + repeatable_sound); + + playing = empathy_sound_play_internal (widget, sound_id, playing_finished_cb, + repeatable_sound); + + if (!playing) + g_hash_table_remove (repeating_sounds, GINT_TO_POINTER (sound_id)); + + return playing; +} diff --git a/libempathy-gtk/empathy-sound.h b/libempathy-gtk/empathy-sound.h new file mode 100644 index 000000000..f65f6260e --- /dev/null +++ b/libempathy-gtk/empathy-sound.h @@ -0,0 +1,56 @@ +/* + * empathy-sound.h - Various sound related utility functions. + * Copyright (C) 2009 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef __EMPATHY_SOUND_H__ +#define __EMPATHY_SOUND_H__ + +#include + +#include + +G_BEGIN_DECLS + +/* NOTE: Keep this sync with sound_entries in empathy-sound.c */ +typedef enum { + EMPATHY_SOUND_MESSAGE_INCOMING = 0, + EMPATHY_SOUND_MESSAGE_OUTGOING, + EMPATHY_SOUND_CONVERSATION_NEW, + EMPATHY_SOUND_CONTACT_CONNECTED, + EMPATHY_SOUND_CONTACT_DISCONNECTED, + EMPATHY_SOUND_ACCOUNT_CONNECTED, + EMPATHY_SOUND_ACCOUNT_DISCONNECTED, + EMPATHY_SOUND_PHONE_INCOMING, + EMPATHY_SOUND_PHONE_OUTGOING, + EMPATHY_SOUND_PHONE_HANGUP, + LAST_EMPATHY_SOUND, +} EmpathySound; + +gboolean empathy_sound_play (GtkWidget *widget, EmpathySound sound_id); +void empathy_sound_stop (EmpathySound sound_id); + +gboolean empathy_sound_start_playing (GtkWidget *widget, EmpathySound sound_id, + guint timeout_before_replay); + +gboolean empathy_sound_play_full (GtkWidget *widget, EmpathySound sound_id, + ca_finish_callback_t callback, gpointer user_data); + +G_END_DECLS + +#endif /* #ifndef __EMPATHY_SOUND_H__*/ diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index 902bcb3e6..ffe81a352 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -37,7 +37,6 @@ #include #include #include -#include #include @@ -1540,140 +1539,4 @@ empathy_receive_file_with_file_chooser (EmpathyFTHandler *handler) G_CALLBACK (file_manager_receive_file_response_cb), handler); gtk_widget_show (widget); -} - -typedef struct { - EmpathySound sound_id; - const char * event_ca_id; - const char * event_ca_description; - const char * gconf_key; -} EmpathySoundEntry; - -/* NOTE: these entries MUST be in the same order than EmpathySound enum */ -static EmpathySoundEntry sound_entries[LAST_EMPATHY_SOUND] = { - { EMPATHY_SOUND_MESSAGE_INCOMING, "message-new-instant", - N_("Received an instant message"), EMPATHY_PREFS_SOUNDS_INCOMING_MESSAGE } , - { EMPATHY_SOUND_MESSAGE_OUTGOING, "message-sent-instant", - N_("Sent an instant message"), EMPATHY_PREFS_SOUNDS_OUTGOING_MESSAGE } , - { EMPATHY_SOUND_CONVERSATION_NEW, "message-new-instant", - N_("Incoming chat request"), EMPATHY_PREFS_SOUNDS_NEW_CONVERSATION }, - { EMPATHY_SOUND_CONTACT_CONNECTED, "service-login", - N_("Contact connected"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGIN }, - { EMPATHY_SOUND_CONTACT_DISCONNECTED, "service-logout", - N_("Contact disconnected"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGOUT }, - { EMPATHY_SOUND_ACCOUNT_CONNECTED, "service-login", - N_("Connected to server"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGIN }, - { EMPATHY_SOUND_ACCOUNT_DISCONNECTED, "service-logout", - N_("Disconnected from server"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGOUT }, - { EMPATHY_SOUND_PHONE_INCOMING, "phone-incoming-call", - N_("Incoming voice call"), NULL }, - { EMPATHY_SOUND_PHONE_OUTGOING, "phone-outgoing-calling", - N_("Outgoing voice call"), NULL }, - { EMPATHY_SOUND_PHONE_HANGUP, "phone-hangup", - N_("Voice call ended"), NULL }, -}; - - -static gboolean -empathy_sound_pref_is_enabled (const char *key) -{ - EmpathyConf *conf; - gboolean res; - - conf = empathy_conf_get (); - res = FALSE; - - empathy_conf_get_bool (conf, EMPATHY_PREFS_SOUNDS_ENABLED, &res); - - if (!res) { - return FALSE; - } - - if (!empathy_check_available_state ()) { - empathy_conf_get_bool (conf, EMPATHY_PREFS_SOUNDS_DISABLED_AWAY, - &res); - if (res) { - return FALSE; - } - } - - empathy_conf_get_bool (conf, key, &res); - - return res; -} - -void -empathy_sound_stop (EmpathySound sound_id) -{ - EmpathySoundEntry *entry; - - g_return_if_fail (sound_id < LAST_EMPATHY_SOUND); - - entry = &(sound_entries[sound_id]); - g_return_if_fail (entry->sound_id == sound_id); - - ca_context_cancel (ca_gtk_context_get (), entry->sound_id); -} - - -gboolean -empathy_sound_play_full (GtkWidget *widget, EmpathySound sound_id, - ca_finish_callback_t callback, gpointer user_data) -{ - EmpathySoundEntry *entry; - gboolean should_play = TRUE; - ca_proplist *p = NULL; - ca_context *c; - - g_return_val_if_fail (sound_id < LAST_EMPATHY_SOUND, FALSE); - - entry = &(sound_entries[sound_id]); - g_return_val_if_fail (entry->sound_id == sound_id, FALSE); - - if (entry->gconf_key != NULL) { - should_play = empathy_sound_pref_is_enabled (entry->gconf_key); - } - - if (!should_play) - return FALSE; - - c = ca_gtk_context_get (); - ca_context_cancel (c, entry->sound_id); - - DEBUG ("Play sound \"%s\" (%s)", - entry->event_ca_id, - entry->event_ca_description); - - if (ca_proplist_create (&p) < 0) - goto failed; - - if (ca_proplist_sets (p, CA_PROP_EVENT_ID, entry->event_ca_id) < 0) - goto failed; - - if (ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION, - gettext (entry->event_ca_id)) < 0) - goto failed; - - if (ca_gtk_proplist_set_for_widget (p, widget) < 0) - goto failed; - - ca_context_play_full (ca_gtk_context_get (), entry->sound_id, - p, callback, user_data); - - ca_proplist_destroy (p); - - return TRUE; - -failed: - if (p != NULL) - ca_proplist_destroy (p); - - return FALSE; -} - -void -empathy_sound_play (GtkWidget *widget, EmpathySound sound_id) -{ - empathy_sound_play_full (widget, sound_id, NULL, NULL); -} - +} \ No newline at end of file diff --git a/libempathy-gtk/empathy-ui-utils.h b/libempathy-gtk/empathy-ui-utils.h index 60d48f3c4..4c1384602 100644 --- a/libempathy-gtk/empathy-ui-utils.h +++ b/libempathy-gtk/empathy-ui-utils.h @@ -34,8 +34,6 @@ #include -#include - #include #include @@ -46,21 +44,6 @@ G_BEGIN_DECLS -/* NOTE: Keep this sync with sound_entries in empathy-ui-utils.c */ -typedef enum { - EMPATHY_SOUND_MESSAGE_INCOMING = 0, - EMPATHY_SOUND_MESSAGE_OUTGOING, - EMPATHY_SOUND_CONVERSATION_NEW, - EMPATHY_SOUND_CONTACT_CONNECTED, - EMPATHY_SOUND_CONTACT_DISCONNECTED, - EMPATHY_SOUND_ACCOUNT_CONNECTED, - EMPATHY_SOUND_ACCOUNT_DISCONNECTED, - EMPATHY_SOUND_PHONE_INCOMING, - EMPATHY_SOUND_PHONE_OUTGOING, - EMPATHY_SOUND_PHONE_HANGUP, - LAST_EMPATHY_SOUND, -} EmpathySound; - void empathy_gtk_init (void); GRegex * empathy_uri_regex_dup_singleton (void); @@ -129,15 +112,6 @@ GtkWidget * empathy_link_button_new (const gchar *url, void empathy_send_file_with_file_chooser (EmpathyContact *contact); void empathy_receive_file_with_file_chooser (EmpathyFTHandler *handler); -/* Sounds */ -void empathy_sound_play (GtkWidget *widget, - EmpathySound sound_id); -gboolean empathy_sound_play_full (GtkWidget *widget, - EmpathySound sound_id, - ca_finish_callback_t callback, - gpointer user_data); -void empathy_sound_stop (EmpathySound sound_id); - G_END_DECLS #endif /* __EMPATHY_UI_UTILS_H__ */ -- cgit v1.2.3