Blame plugins/media-keys/mpris-controller.c

Packit 9ca0cf
/*
Packit 9ca0cf
 * Copyright © 2013 Intel Corporation.
Packit 9ca0cf
 *
Packit 9ca0cf
 * This program is free software; you can redistribute it and/or modify it
Packit 9ca0cf
 * under the terms and conditions of the GNU Lesser General Public License,
Packit 9ca0cf
 * version 2.1, as published by the Free Software Foundation.
Packit 9ca0cf
 *
Packit 9ca0cf
 * This program is distributed in the hope it will be useful, but WITHOUT ANY
Packit 9ca0cf
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
Packit 9ca0cf
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
Packit 9ca0cf
 * details.
Packit 9ca0cf
 *
Packit 9ca0cf
 * You should have received a copy of the GNU Lesser General Public License
Packit 9ca0cf
 * along with this program; if not, see <http://www.gnu.org/licenses>
Packit 9ca0cf
 *
Packit 9ca0cf
 * Author: Michael Wood <michael.g.wood@intel.com>
Packit 9ca0cf
 */
Packit 9ca0cf
Packit 9ca0cf
#include "mpris-controller.h"
Packit 9ca0cf
#include "bus-watch-namespace.h"
Packit 9ca0cf
#include <gio/gio.h>
Packit 9ca0cf
Packit 9ca0cf
G_DEFINE_TYPE (MprisController, mpris_controller, G_TYPE_OBJECT)
Packit 9ca0cf
Packit 9ca0cf
#define CONTROLLER_PRIVATE(o) \
Packit 9ca0cf
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), MPRIS_TYPE_CONTROLLER, MprisControllerPrivate))
Packit 9ca0cf
Packit 9ca0cf
enum {
Packit 9ca0cf
  PROP_0,
Packit 9ca0cf
  PROP_HAS_ACTIVE_PLAYER
Packit 9ca0cf
};
Packit 9ca0cf
Packit 9ca0cf
struct _MprisControllerPrivate
Packit 9ca0cf
{
Packit 9ca0cf
  GCancellable *cancellable;
Packit 9ca0cf
  GDBusProxy *mpris_client_proxy;
Packit 9ca0cf
  guint namespace_watcher_id;
Packit 9ca0cf
  GSList *other_players;
Packit 9ca0cf
  gboolean connecting;
Packit 9ca0cf
};
Packit 9ca0cf
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
mpris_controller_dispose (GObject *object)
Packit 9ca0cf
{
Packit 9ca0cf
  MprisControllerPrivate *priv = MPRIS_CONTROLLER (object)->priv;
Packit 9ca0cf
Packit 9ca0cf
  g_clear_object (&priv->cancellable);
Packit 9ca0cf
  g_clear_object (&priv->mpris_client_proxy);
Packit 9ca0cf
Packit 9ca0cf
  if (priv->namespace_watcher_id)
Packit 9ca0cf
    {
Packit 9ca0cf
      bus_unwatch_namespace (priv->namespace_watcher_id);
Packit 9ca0cf
      priv->namespace_watcher_id = 0;
Packit 9ca0cf
    }
Packit 9ca0cf
Packit 9ca0cf
  if (priv->other_players)
Packit 9ca0cf
    {
Packit 9ca0cf
      g_slist_free_full (priv->other_players, g_free);
Packit 9ca0cf
      priv->other_players = NULL;
Packit 9ca0cf
    }
Packit 9ca0cf
Packit 9ca0cf
  G_OBJECT_CLASS (mpris_controller_parent_class)->dispose (object);
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
mpris_proxy_call_done (GObject      *object,
Packit 9ca0cf
                       GAsyncResult *res,
Packit 9ca0cf
                       gpointer      user_data)
Packit 9ca0cf
{
Packit 9ca0cf
  GError *error = NULL;
Packit 9ca0cf
  GVariant *ret;
Packit 9ca0cf
Packit 9ca0cf
  if (!(ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), res, &error)))
Packit 9ca0cf
    {
Packit 9ca0cf
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
Packit 9ca0cf
        g_warning ("Error calling method %s", error->message);
Packit 9ca0cf
      g_clear_error (&error);
Packit 9ca0cf
      return;
Packit 9ca0cf
    }
Packit 9ca0cf
  g_variant_unref (ret);
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
gboolean
Packit 9ca0cf
mpris_controller_key (MprisController *self, const gchar *key)
Packit 9ca0cf
{
Packit 9ca0cf
  MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv;
Packit 9ca0cf
Packit 9ca0cf
  if (!priv->mpris_client_proxy)
Packit 9ca0cf
    return FALSE;
Packit 9ca0cf
Packit 9ca0cf
  if (g_strcmp0 (key, "Play") == 0)
Packit 9ca0cf
    key = "PlayPause";
Packit 9ca0cf
Packit 9ca0cf
  g_debug ("calling %s over dbus to mpris client %s",
Packit 9ca0cf
           key, g_dbus_proxy_get_name (priv->mpris_client_proxy));
Packit 9ca0cf
  g_dbus_proxy_call (priv->mpris_client_proxy,
Packit 9ca0cf
                     key, NULL, 0, -1, priv->cancellable,
Packit 9ca0cf
                     mpris_proxy_call_done,
Packit 9ca0cf
                     NULL);
Packit 9ca0cf
  return TRUE;
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
mpris_proxy_ready_cb (GObject      *object,
Packit 9ca0cf
                      GAsyncResult *res,
Packit 9ca0cf
                      gpointer      user_data)
Packit 9ca0cf
{
Packit 9ca0cf
  MprisControllerPrivate *priv;
Packit 9ca0cf
  GError *error = NULL;
Packit 9ca0cf
  GDBusProxy *proxy;
Packit 9ca0cf
Packit 9ca0cf
  proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
Packit 9ca0cf
Packit 9ca0cf
  if (!proxy)
Packit 9ca0cf
    {
Packit 9ca0cf
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
Packit 9ca0cf
        g_warning ("Error connecting to mpris interface %s", error->message);
Packit 9ca0cf
      g_clear_error (&error);
Packit 9ca0cf
      return;
Packit 9ca0cf
    }
Packit 9ca0cf
Packit 9ca0cf
  priv = MPRIS_CONTROLLER (user_data)->priv;
Packit 9ca0cf
  priv->mpris_client_proxy = proxy;
Packit 9ca0cf
  priv->connecting = FALSE;
Packit 9ca0cf
Packit 9ca0cf
  g_object_notify (user_data, "has-active-player");
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
start_mpris_proxy (MprisController *self, const gchar *name)
Packit 9ca0cf
{
Packit 9ca0cf
  MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv;
Packit 9ca0cf
Packit 9ca0cf
  g_debug ("Creating proxy for for %s", name);
Packit 9ca0cf
  g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
Packit 9ca0cf
                            0,
Packit 9ca0cf
                            NULL,
Packit 9ca0cf
                            name,
Packit 9ca0cf
                            "/org/mpris/MediaPlayer2",
Packit 9ca0cf
                            "org.mpris.MediaPlayer2.Player",
Packit 9ca0cf
                            priv->cancellable,
Packit 9ca0cf
                            mpris_proxy_ready_cb,
Packit 9ca0cf
                            self);
Packit 9ca0cf
  priv->connecting = TRUE;
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
mpris_player_appeared (GDBusConnection *connection,
Packit 9ca0cf
                       const gchar     *name,
Packit 9ca0cf
                       const gchar     *name_owner,
Packit 9ca0cf
                       gpointer         user_data)
Packit 9ca0cf
{
Packit 9ca0cf
  MprisController *self = user_data;
Packit 9ca0cf
  MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv;
Packit 9ca0cf
Packit 9ca0cf
  if (priv->mpris_client_proxy == NULL && !priv->connecting)
Packit 9ca0cf
    start_mpris_proxy (self, name);
Packit 9ca0cf
  else
Packit 9ca0cf
    self->priv->other_players = g_slist_prepend (self->priv->other_players, g_strdup (name));
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
mpris_player_vanished (GDBusConnection *connection,
Packit 9ca0cf
                       const gchar     *name,
Packit 9ca0cf
                       gpointer         user_data)
Packit 9ca0cf
{
Packit 9ca0cf
  MprisController *self = user_data;
Packit 9ca0cf
  MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv;
Packit 9ca0cf
Packit 9ca0cf
  if (priv->mpris_client_proxy &&
Packit 9ca0cf
      g_strcmp0 (name, g_dbus_proxy_get_name (priv->mpris_client_proxy)) == 0)
Packit 9ca0cf
    {
Packit 9ca0cf
      g_clear_object (&priv->mpris_client_proxy);
Packit 9ca0cf
      g_object_notify (user_data, "has-active-player");
Packit 9ca0cf
Packit 9ca0cf
      /* take the next one if there's one */
Packit 9ca0cf
      if (self->priv->other_players && !priv->connecting)
Packit 9ca0cf
        {
Packit 9ca0cf
          GSList *first;
Packit 9ca0cf
          gchar *name;
Packit 9ca0cf
Packit 9ca0cf
          first = self->priv->other_players;
Packit 9ca0cf
          name = first->data;
Packit 9ca0cf
Packit 9ca0cf
          start_mpris_proxy (self, name);
Packit 9ca0cf
Packit 9ca0cf
          self->priv->other_players = self->priv->other_players->next;
Packit 9ca0cf
          g_free (name);
Packit 9ca0cf
          g_slist_free_1 (first);
Packit 9ca0cf
        }
Packit 9ca0cf
    }
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
mpris_controller_constructed (GObject *object)
Packit 9ca0cf
{
Packit 9ca0cf
  MprisControllerPrivate *priv = MPRIS_CONTROLLER (object)->priv;
Packit 9ca0cf
Packit 9ca0cf
  priv->namespace_watcher_id = bus_watch_namespace (G_BUS_TYPE_SESSION,
Packit 9ca0cf
                                                    "org.mpris.MediaPlayer2",
Packit 9ca0cf
                                                    mpris_player_appeared,
Packit 9ca0cf
                                                    mpris_player_vanished,
Packit 9ca0cf
                                                    MPRIS_CONTROLLER (object),
Packit 9ca0cf
                                                    NULL);
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
mpris_controller_get_property (GObject    *object,
Packit 9ca0cf
                               guint       prop_id,
Packit 9ca0cf
                               GValue     *value,
Packit 9ca0cf
                               GParamSpec *pspec)
Packit 9ca0cf
{
Packit 9ca0cf
  MprisController *self = MPRIS_CONTROLLER (object);
Packit 9ca0cf
Packit 9ca0cf
  switch (prop_id) {
Packit 9ca0cf
  case PROP_HAS_ACTIVE_PLAYER:
Packit 9ca0cf
    g_value_set_boolean (value,
Packit 9ca0cf
                         mpris_controller_get_has_active_player (self));
Packit 9ca0cf
    break;
Packit 9ca0cf
  default:
Packit 9ca0cf
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 9ca0cf
    break;
Packit 9ca0cf
  }
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
mpris_controller_class_init (MprisControllerClass *klass)
Packit 9ca0cf
{
Packit 9ca0cf
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit 9ca0cf
Packit 9ca0cf
  g_type_class_add_private (klass, sizeof (MprisControllerPrivate));
Packit 9ca0cf
Packit 9ca0cf
  object_class->constructed = mpris_controller_constructed;
Packit 9ca0cf
  object_class->dispose = mpris_controller_dispose;
Packit 9ca0cf
  object_class->get_property = mpris_controller_get_property;
Packit 9ca0cf
Packit 9ca0cf
  g_object_class_install_property (object_class,
Packit 9ca0cf
                                   PROP_HAS_ACTIVE_PLAYER,
Packit 9ca0cf
                                   g_param_spec_boolean ("has-active-player",
Packit 9ca0cf
                                                         NULL,
Packit 9ca0cf
                                                         NULL,
Packit 9ca0cf
                                                         FALSE,
Packit 9ca0cf
                                                         G_PARAM_READABLE));
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
static void
Packit 9ca0cf
mpris_controller_init (MprisController *self)
Packit 9ca0cf
{
Packit 9ca0cf
  self->priv = CONTROLLER_PRIVATE (self);
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
gboolean
Packit 9ca0cf
mpris_controller_get_has_active_player (MprisController *controller)
Packit 9ca0cf
{
Packit 9ca0cf
  g_return_val_if_fail (MPRIS_IS_CONTROLLER (controller), FALSE);
Packit 9ca0cf
Packit 9ca0cf
  return (controller->priv->mpris_client_proxy != NULL);
Packit 9ca0cf
}
Packit 9ca0cf
Packit 9ca0cf
MprisController *
Packit 9ca0cf
mpris_controller_new (void)
Packit 9ca0cf
{
Packit 9ca0cf
  return g_object_new (MPRIS_TYPE_CONTROLLER, NULL);
Packit 9ca0cf
}