]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-sound-manager.c
Change Finnish translation team web page to l10n.gnome.org
[empathy.git] / libempathy-gtk / empathy-sound-manager.c
index 459016db1b3915b08bcaa9ef7de93830e63ba530..3453e8f2cd176218185b27a33f4e9f15ca2365ac 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * empathy-sound-manager.c - Various sound related utility functions.
- * Copyright (C) 2009 Collabora Ltd.
+ * Copyright (C) 2009-2010 Collabora Ltd.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <config.h>
-
+#include "config.h"
 #include "empathy-sound-manager.h"
 
-#include <canberra-gtk.h>
 #include <glib/gi18n-lib.h>
-#include <gtk/gtk.h>
+
+#include "empathy-gsettings.h"
+#include "empathy-presence-manager.h"
+#include "empathy-utils.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
-#include <libempathy/empathy-debug.h>
-#include <libempathy/empathy-gsettings.h>
-#include <libempathy/empathy-utils.h>
+#include "empathy-debug.h"
 
 typedef struct {
   EmpathySound sound_id;
@@ -42,6 +41,7 @@ typedef struct {
   gint sound_id;
   guint play_interval;
   guint replay_timeout_id;
+  EmpathySoundManager *self;
 } EmpathyRepeatableSound;
 
 /* NOTE: these entries MUST be in the same order than EmpathySound enum */
@@ -68,84 +68,197 @@ static EmpathySoundEntry sound_entries[LAST_EMPATHY_SOUND] = {
     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;
+G_DEFINE_TYPE (EmpathySoundManager, empathy_sound_manager, G_TYPE_OBJECT)
+
+struct _EmpathySoundManagerPrivate
+{
+  /* A hash table containing currently repeating sounds. The format is the
+   * following:
+   * Key: An EmpathySound
+   * Value : The EmpathyRepeatableSound associated with that EmpathySound. */
+  GHashTable *repeating_sounds;
+  GSettings *gsettings_sound;
+};
+
+static void
+empathy_sound_manager_dispose (GObject *object)
+{
+  EmpathySoundManager *self = (EmpathySoundManager *) object;
+
+  tp_clear_pointer (&self->priv->repeating_sounds, g_hash_table_unref);
+  tp_clear_object (&self->priv->gsettings_sound);
+
+  G_OBJECT_CLASS (empathy_sound_manager_parent_class)->dispose (object);
+}
+
+static void
+empathy_sound_manager_class_init (EmpathySoundManagerClass *cls)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (cls);
+
+  object_class->dispose = empathy_sound_manager_dispose;
+
+  g_type_class_add_private (cls, sizeof (EmpathySoundManagerPrivate));
+}
+
+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 (repeatable_sound->self->priv->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);
+
+  if (repeatable_sound->widget != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (repeatable_sound->widget,
+          empathy_sound_widget_destroyed_cb, repeatable_sound);
+    }
+
+  g_object_unref (repeatable_sound->self);
+
+  g_slice_free (EmpathyRepeatableSound, repeatable_sound);
+}
+
+static void
+empathy_sound_manager_init (EmpathySoundManager *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+      EMPATHY_TYPE_SOUND_MANAGER, EmpathySoundManagerPrivate);
+
+  self->priv->repeating_sounds = g_hash_table_new_full (NULL, NULL,
+      NULL, repeating_sounds_item_delete);
+
+  self->priv->gsettings_sound = g_settings_new (EMPATHY_PREFS_SOUNDS_SCHEMA);
+}
+
+EmpathySoundManager *
+empathy_sound_manager_dup_singleton (void)
+{
+  static EmpathySoundManager *manager = NULL;
+
+  if (G_LIKELY (manager != NULL))
+      return g_object_ref (manager);
+
+  manager = g_object_new (EMPATHY_TYPE_SOUND_MANAGER, NULL);
+
+  g_object_add_weak_pointer (G_OBJECT (manager), (gpointer *) &manager);
+  return manager;
+}
 
 static gboolean
-empathy_sound_pref_is_enabled (EmpathySound sound_id)
+empathy_check_available_state (void)
+{
+  TpConnectionPresenceType most_available_requested_presence;
+  TpAccountManager *am;
+  GList *accounts;
+
+  /* We cannot use tp_account_manager_get_most_available_presence() or
+   * empathy_presence_manager_get_state() because it is the requested presence
+   * that matters, not the current presence.
+   * See https://bugzilla.gnome.org/show_bug.cgi?id=704454 */
+  most_available_requested_presence = TP_CONNECTION_PRESENCE_TYPE_UNSET;
+  am = tp_account_manager_dup ();
+  accounts = tp_account_manager_dup_valid_accounts (am);
+  while (accounts != NULL)
+    {
+      TpAccount *account = accounts->data;
+      TpConnectionPresenceType requested_presence;
+
+      requested_presence = tp_account_get_requested_presence (account,
+          NULL, NULL);
+
+      if (tp_connection_presence_type_cmp_availability (requested_presence,
+              most_available_requested_presence) > 0)
+        most_available_requested_presence = requested_presence;
+
+      g_object_unref (account);
+      accounts = g_list_delete_link (accounts, accounts);
+    }
+
+  g_object_unref (am);
+
+  if (most_available_requested_presence != TP_CONNECTION_PRESENCE_TYPE_AVAILABLE &&
+    most_available_requested_presence != TP_CONNECTION_PRESENCE_TYPE_UNSET)
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+empathy_sound_pref_is_enabled (EmpathySoundManager *self,
+    EmpathySound sound_id)
 {
   EmpathySoundEntry *entry;
-  GSettings *gsettings = g_settings_new (EMPATHY_PREFS_SOUNDS_SCHEMA);
-  gboolean res;
 
   entry = &(sound_entries[sound_id]);
   g_return_val_if_fail (entry->sound_id == sound_id, FALSE);
 
   if (entry->key == NULL)
-    {
-      res = TRUE;
-      goto finally;
-    }
-
-  res = g_settings_get_boolean (gsettings, EMPATHY_PREFS_SOUNDS_ENABLED);
+    return TRUE;
 
-  if (!res)
-    goto finally;
+  if (! g_settings_get_boolean (self->priv->gsettings_sound,
+      EMPATHY_PREFS_SOUNDS_ENABLED))
+    return FALSE;
 
   if (!empathy_check_available_state ())
     {
-      if (g_settings_get_boolean (gsettings,
+      if (g_settings_get_boolean (self->priv->gsettings_sound,
             EMPATHY_PREFS_SOUNDS_DISABLED_AWAY))
-        {
-          res = FALSE;
-          goto finally;
-        }
+        return FALSE;
     }
 
-  res = g_settings_get_boolean (gsettings, entry->key);
-
-finally:
-  g_object_unref (gsettings);
-
-  return res;
+  return g_settings_get_boolean (self->priv->gsettings_sound, entry->key);
 }
 
 /**
- * empathy_sound_stop:
+ * empathy_sound_manager_stop:
+ * @self: a #EmpathySoundManager
  * @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)
+empathy_sound_manager_stop (EmpathySoundManager *self,
+    EmpathySound sound_id)
 {
   EmpathySoundEntry *entry;
+  EmpathyRepeatableSound *repeatable_sound;
 
   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)
+  repeatable_sound = g_hash_table_lookup (self->priv->repeating_sounds,
+      GINT_TO_POINTER (sound_id));
+  if (repeatable_sound != 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)
         {
-          /* 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;
-            }
+          g_hash_table_remove (self->priv->repeating_sounds,
+              GINT_TO_POINTER (sound_id));
+          return;
         }
     }
 
@@ -180,8 +293,11 @@ empathy_sound_play_internal (GtkWidget *widget, EmpathySound sound_id,
           gettext (entry->event_ca_description)) < 0)
     goto failed;
 
-  if (ca_gtk_proplist_set_for_widget (p, widget) < 0)
-    goto failed;
+  if (widget != NULL)
+    {
+      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);
@@ -198,7 +314,8 @@ failed:
 }
 
 /**
- * empathy_sound_play_full:
+ * empathy_sound_manager_play_full:
+ * @self: a #EmpathySoundManager
  * @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
@@ -219,41 +336,47 @@ failed:
  *               otherwise.
  */
 gboolean
-empathy_sound_play_full (GtkWidget *widget, EmpathySound sound_id,
-  ca_finish_callback_t callback, gpointer user_data)
+empathy_sound_manager_play_full (EmpathySoundManager *self,
+    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 (widget == NULL || GTK_IS_WIDGET (widget), FALSE);
   g_return_val_if_fail (sound_id < LAST_EMPATHY_SOUND, FALSE);
 
-  if (!empathy_sound_pref_is_enabled (sound_id))
+  if (!empathy_sound_pref_is_enabled (self, 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)
+  if (g_hash_table_lookup (self->priv->repeating_sounds,
+        GINT_TO_POINTER (sound_id)) != NULL)
     return FALSE;
 
   return empathy_sound_play_internal (widget, sound_id, callback, user_data);
 }
 
 /**
- * empathy_sound_play:
+ * empathy_sound_manager_play:
+ * @self: a #EmpathySoundManager
  * @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.'
+ * Plays a sound. See %empathy_sound_manager_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)
+empathy_sound_manager_play (EmpathySoundManager *self,
+    GtkWidget *widget,
+    EmpathySound sound_id)
 {
-  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+  g_return_val_if_fail (widget == NULL || 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);
+  return empathy_sound_manager_play_full (self, widget, sound_id, NULL, NULL);
 }
 
 static void playing_finished_cb (ca_context *c, guint id, int error_code,
@@ -273,7 +396,7 @@ playing_timeout_cb (gpointer data)
   if (!playing)
     {
       DEBUG ("Failed to replay sound, stop repeating");
-      g_hash_table_remove (repeating_sounds,
+      g_hash_table_remove (repeatable_sound->self->priv->repeating_sounds,
           GINT_TO_POINTER (repeatable_sound->sound_id));
     }
 
@@ -289,7 +412,7 @@ playing_finished_cb (ca_context *c, guint id, int error_code,
   if (error_code != CA_SUCCESS)
     {
       DEBUG ("Error: %s", ca_strerror (error_code));
-      g_hash_table_remove (repeating_sounds,
+      g_hash_table_remove (repeatable_sound->self->priv->repeating_sounds,
           GINT_TO_POINTER (repeatable_sound->sound_id));
       return;
     }
@@ -298,37 +421,9 @@ playing_finished_cb (ca_context *c, guint id, int error_code,
       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:
+ * empathy_sound_manager_start_playing:
+ * @self: a #EmpathySoundManager
  * @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
@@ -342,24 +437,21 @@ repeating_sounds_item_delete (gpointer data)
  * Return value: %TRUE if the sound has successfully started playing.
  */
 gboolean
-empathy_sound_start_playing (GtkWidget *widget, EmpathySound sound_id,
+empathy_sound_manager_start_playing (EmpathySoundManager *self,
+    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 (widget == NULL || GTK_IS_WIDGET (widget), FALSE);
   g_return_val_if_fail (sound_id < LAST_EMPATHY_SOUND, FALSE);
 
-  if (!empathy_sound_pref_is_enabled (sound_id))
+  if (!empathy_sound_pref_is_enabled (self, 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,
+  if (g_hash_table_lookup (self->priv->repeating_sounds,
                GINT_TO_POINTER (sound_id)) != NULL)
     {
       /* The sound is already playing in loop. No need to continue. */
@@ -371,19 +463,24 @@ empathy_sound_start_playing (GtkWidget *widget, EmpathySound sound_id,
   repeatable_sound->sound_id = sound_id;
   repeatable_sound->play_interval = timeout_before_replay;
   repeatable_sound->replay_timeout_id = 0;
+  repeatable_sound->self = g_object_ref (self);
 
-  g_hash_table_insert (repeating_sounds, GINT_TO_POINTER (sound_id),
+  g_hash_table_insert (self->priv->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);
+  if (widget != NULL)
+    {
+      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));
+      g_hash_table_remove (self->priv->repeating_sounds,
+          GINT_TO_POINTER (sound_id));
 
   return playing;
 }