LCOV - code coverage report
Current view: top level - src/plugins/mpris - valent-mpris-impl.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 89.2 % 362 323
Test Date: 2024-11-16 20:34:14 Functions: 96.0 % 25 24
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 62.1 % 264 164

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-3.0-or-later
       2                 :             : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
       3                 :             : 
       4                 :             : #define G_LOG_DOMAIN "valent-mpris-impl"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <gio/gio.h>
       9                 :             : #include <valent.h>
      10                 :             : 
      11                 :             : #include "valent-mpris-impl.h"
      12                 :             : #include "valent-mpris-utils.h"
      13                 :             : 
      14                 :             : 
      15                 :             : struct _ValentMPRISImpl
      16                 :             : {
      17                 :             :   GObject               parent_instance;
      18                 :             : 
      19                 :             :   ValentMediaPlayer    *player;
      20                 :             :   GDBusConnection      *connection;
      21                 :             :   char                 *bus_name;
      22                 :             :   unsigned int          bus_name_id;
      23                 :             : 
      24                 :             :   GHashTable           *cache;
      25                 :             :   GHashTable           *pending;
      26                 :             :   unsigned int          flush_id;
      27                 :             : 
      28                 :             :   /* org.mpris.MediaPlayer2 */
      29                 :             :   unsigned int          application_id;
      30                 :             :   GDBusInterfaceVTable  application_vtable;
      31                 :             : 
      32                 :             :   /* org.mpris.MediaPlayer2.Player */
      33                 :             :   unsigned int          player_id;
      34                 :             :   GDBusInterfaceVTable  player_vtable;
      35                 :             : };
      36                 :             : 
      37   [ +  +  +  - ]:         368 : G_DEFINE_FINAL_TYPE (ValentMPRISImpl, valent_mpris_impl, G_TYPE_OBJECT)
      38                 :             : 
      39                 :             : 
      40                 :             : enum {
      41                 :             :   PROP_0,
      42                 :             :   PROP_PLAYER,
      43                 :             :   N_PROPERTIES
      44                 :             : };
      45                 :             : 
      46                 :             : static GParamSpec *properties[N_PROPERTIES] = { NULL, };
      47                 :             : 
      48                 :             : 
      49                 :             : /*
      50                 :             :  * org.mpris.MediaPlayer2
      51                 :             :  */
      52                 :             : static void
      53                 :           0 : application_method_call (GDBusConnection       *connection,
      54                 :             :                          const char            *sender,
      55                 :             :                          const char            *object_path,
      56                 :             :                          const char            *interface_name,
      57                 :             :                          const char            *method_name,
      58                 :             :                          GVariant              *parameters,
      59                 :             :                          GDBusMethodInvocation *invocation,
      60                 :             :                          gpointer               user_data)
      61                 :             : {
      62         [ #  # ]:           0 :   g_assert (VALENT_IS_MPRIS_IMPL (user_data));
      63         [ #  # ]:           0 :   g_assert (method_name != NULL);
      64                 :             : 
      65         [ #  # ]:           0 :   if (g_str_equal (method_name, "Raise"))
      66                 :             :     {
      67                 :           0 :       GApplication *application = g_application_get_default ();
      68                 :             : 
      69         [ #  # ]:           0 :       if (application != NULL)
      70                 :             :         {
      71                 :           0 :           g_action_group_activate_action (G_ACTION_GROUP (application),
      72                 :             :                                           "media-remote",
      73                 :             :                                           NULL);
      74                 :             :         }
      75                 :             :     }
      76                 :             : 
      77                 :             :   /* Silently ignore method calls */
      78                 :           0 :   g_dbus_method_invocation_return_value (invocation, NULL);
      79                 :           0 : }
      80                 :             : 
      81                 :             : static GVariant *
      82                 :          45 : application_get_property (GDBusConnection  *connection,
      83                 :             :                           const char       *sender,
      84                 :             :                           const char       *object_path,
      85                 :             :                           const char       *interface_name,
      86                 :             :                           const char       *property_name,
      87                 :             :                           GError          **error,
      88                 :             :                           gpointer          user_data)
      89                 :             : {
      90                 :          45 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (user_data);
      91                 :          45 :   GVariant *value = NULL;
      92                 :             : 
      93         [ +  - ]:          45 :   g_assert (VALENT_IS_MPRIS_IMPL (self));
      94         [ -  + ]:          45 :   g_assert (property_name != NULL);
      95                 :             : 
      96         [ -  + ]:          45 :   if ((value = g_hash_table_lookup (self->cache, property_name)) != NULL)
      97                 :           0 :     return g_variant_ref_sink (value);
      98                 :             : 
      99         [ +  + ]:          45 :   if (g_str_equal (property_name, "Identity"))
     100                 :           5 :     value = g_variant_new_string (valent_media_player_get_name (self->player));
     101         [ +  + ]:          40 :   else if (g_str_equal (property_name, "CanQuit"))
     102                 :           5 :     value = g_variant_new_boolean (FALSE);
     103         [ +  + ]:          35 :   else if (g_str_equal (property_name, "CanRaise"))
     104                 :           5 :     value = g_variant_new_boolean (TRUE);
     105         [ +  + ]:          30 :   else if (g_str_equal (property_name, "CanSetFullscreen"))
     106                 :           5 :     value = g_variant_new_boolean (FALSE);
     107         [ +  + ]:          25 :   else if (g_str_equal (property_name, "DesktopEntry"))
     108                 :           5 :     value = g_variant_new_string (APPLICATION_ID".desktop");
     109         [ +  + ]:          20 :   else if (g_str_equal (property_name, "Fullscreen") ||
     110         [ +  + ]:          15 :            g_str_equal (property_name, "HasTrackList"))
     111                 :          10 :     value = g_variant_new_boolean (FALSE);
     112         [ +  + ]:          10 :   else if (g_str_equal (property_name, "SupportedMimeTypes") ||
     113         [ +  - ]:           5 :            g_str_equal (property_name, "SupportedUriSchemes"))
     114                 :          10 :     value = g_variant_new_strv (NULL, 0);
     115                 :             : 
     116         [ +  - ]:          45 :   if (value != NULL)
     117                 :             :     {
     118                 :          90 :       g_hash_table_replace (self->cache,
     119                 :          45 :                             g_strdup (property_name),
     120         [ -  + ]:          45 :                             g_variant_ref_sink (value));
     121                 :             : 
     122                 :          45 :       return g_variant_ref_sink (value);
     123                 :             :     }
     124                 :             : 
     125                 :           0 :   g_set_error (error,
     126                 :             :                G_DBUS_ERROR,
     127                 :             :                G_DBUS_ERROR_UNKNOWN_PROPERTY,
     128                 :             :                "Unknown property \"%s\"", property_name);
     129                 :             : 
     130                 :           0 :   return NULL;
     131                 :             : }
     132                 :             : 
     133                 :             : /* LCOV_EXCL_START */
     134                 :             : static gboolean
     135                 :             : application_set_property (GDBusConnection  *connection,
     136                 :             :                           const char       *sender,
     137                 :             :                           const char       *object_path,
     138                 :             :                           const char       *interface_name,
     139                 :             :                           const char       *property_name,
     140                 :             :                           GVariant         *value,
     141                 :             :                           GError          **error,
     142                 :             :                           gpointer          user_data)
     143                 :             : {
     144                 :             :   /* Silently ignore property setters */
     145                 :             :   return TRUE;
     146                 :             : }
     147                 :             : /* LCOV_EXCL_STOP */
     148                 :             : 
     149                 :             : /*
     150                 :             :  * org.mpris.MediaPlayer2.Player
     151                 :             :  */
     152                 :             : static void
     153                 :          20 : player_method_call (GDBusConnection       *connection,
     154                 :             :                     const char            *sender,
     155                 :             :                     const char            *object_path,
     156                 :             :                     const char            *interface_name,
     157                 :             :                     const char            *method_name,
     158                 :             :                     GVariant              *parameters,
     159                 :             :                     GDBusMethodInvocation *invocation,
     160                 :             :                     gpointer               user_data)
     161                 :             : {
     162                 :          20 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (user_data);
     163                 :             : 
     164         [ +  - ]:          20 :   g_assert (VALENT_IS_MPRIS_IMPL (self));
     165         [ -  + ]:          20 :   g_assert (method_name != NULL);
     166                 :             : 
     167         [ +  + ]:          20 :   if (g_str_equal (method_name, "Next"))
     168                 :             :     {
     169                 :           3 :       valent_media_player_next (self->player);
     170                 :             :     }
     171         [ +  + ]:          17 :   else if (g_str_equal (method_name, "Pause"))
     172                 :             :     {
     173                 :           3 :       valent_media_player_pause (self->player);
     174                 :             :     }
     175         [ +  + ]:          14 :   else if (g_str_equal (method_name, "Play"))
     176                 :             :     {
     177                 :           3 :       valent_media_player_play (self->player);
     178                 :             :     }
     179         [ -  + ]:          11 :   else if (g_str_equal (method_name, "PlayPause"))
     180                 :             :     {
     181   [ #  #  #  #  :           0 :       valent_mpris_play_pause (self->player);
                   #  # ]
     182                 :             :     }
     183         [ +  + ]:          11 :   else if (g_str_equal (method_name, "Previous"))
     184                 :             :     {
     185                 :           3 :       valent_media_player_previous (self->player);
     186                 :             :     }
     187         [ +  + ]:           8 :   else if (g_str_equal (method_name, "Seek"))
     188                 :             :     {
     189                 :           3 :       int64_t offset_us;
     190                 :             : 
     191                 :             :       /* Convert microseconds to seconds */
     192                 :           3 :       g_variant_get (parameters, "(x)", &offset_us);
     193                 :           3 :       valent_media_player_seek (self->player, offset_us / G_TIME_SPAN_SECOND);
     194                 :             :     }
     195         [ +  + ]:           5 :   else if (g_str_equal (method_name, "SetPosition"))
     196                 :             :     {
     197                 :           2 :       int64_t position_us;
     198                 :             : 
     199                 :             :       /* Convert microseconds to seconds */
     200                 :           2 :       g_variant_get (parameters, "(&ox)", NULL, &position_us);
     201                 :           2 :       valent_media_player_set_position (self->player, position_us / G_TIME_SPAN_SECOND);
     202                 :             :     }
     203         [ +  - ]:           3 :   else if (g_str_equal (method_name, "Stop"))
     204                 :             :     {
     205                 :           3 :       valent_media_player_stop (self->player);
     206                 :             :     }
     207         [ #  # ]:           0 :   else if (g_str_equal (method_name, "OpenUri"))
     208                 :             :     {
     209                 :             :       /* Silently ignore method calls */
     210                 :             :     }
     211                 :             :   else
     212                 :             :     {
     213                 :           0 :       g_dbus_method_invocation_return_error (invocation,
     214                 :             :                                              G_DBUS_ERROR,
     215                 :             :                                              G_DBUS_ERROR_UNKNOWN_METHOD,
     216                 :             :                                              "Unknown method \"%s\"",
     217                 :             :                                              method_name);
     218                 :           0 :       return;
     219                 :             :     }
     220                 :             : 
     221                 :          20 :   g_dbus_method_invocation_return_value (invocation, NULL);
     222                 :             : }
     223                 :             : 
     224                 :             : static GVariant *
     225                 :          79 : player_get_property (GDBusConnection  *connection,
     226                 :             :                      const char       *sender,
     227                 :             :                      const char       *object_path,
     228                 :             :                      const char       *interface_name,
     229                 :             :                      const char       *property_name,
     230                 :             :                      GError          **error,
     231                 :             :                      gpointer          user_data)
     232                 :             : {
     233                 :          79 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (user_data);
     234                 :          79 :   ValentMediaActions flags = VALENT_MEDIA_ACTION_NONE;
     235                 :          79 :   GVariant *value;
     236                 :             : 
     237         [ +  - ]:          79 :   g_assert (VALENT_IS_MPRIS_IMPL (self));
     238         [ -  + ]:          79 :   g_assert (property_name != NULL);
     239                 :             : 
     240                 :             :   /* Check cache */
     241         [ -  + ]:          79 :   if ((value = g_hash_table_lookup (self->cache, property_name)) != NULL)
     242                 :           0 :     return g_variant_ref (value);
     243                 :             : 
     244                 :             :   /* The `Position` is not cached, because `PropertiesChanged` is not emitted */
     245         [ +  + ]:          79 :   if (g_str_equal (property_name, "Position"))
     246                 :             :     {
     247                 :           9 :       double position = valent_media_player_get_position (self->player);
     248                 :             : 
     249                 :             :       /* Convert seconds to microseconds */
     250                 :           9 :       return g_variant_new_int64 ((int64_t)(position * G_TIME_SPAN_SECOND));
     251                 :             :     }
     252                 :             : 
     253                 :             :   /* Load properties */
     254         [ +  + ]:          70 :   if (*property_name == 'C')
     255                 :          30 :     flags = valent_media_player_get_flags (self->player);
     256                 :             : 
     257         [ +  + ]:          70 :   if (g_str_equal (property_name, "CanControl"))
     258                 :             :     {
     259                 :           5 :       value = g_variant_new_boolean (flags != 0);
     260                 :             :     }
     261         [ +  + ]:          65 :   else if (g_str_equal (property_name, "CanGoNext"))
     262                 :             :     {
     263                 :           5 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_NEXT) != 0);
     264                 :             :     }
     265         [ +  + ]:          60 :   else if (g_str_equal (property_name, "CanGoPrevious"))
     266                 :             :     {
     267                 :           5 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_PREVIOUS) != 0);
     268                 :             :     }
     269         [ +  + ]:          55 :   else if (g_str_equal (property_name, "CanPlay"))
     270                 :             :     {
     271                 :           5 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_PLAY) != 0);
     272                 :             :     }
     273         [ +  + ]:          50 :   else if (g_str_equal (property_name, "CanPause"))
     274                 :             :     {
     275                 :           5 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_PAUSE) != 0);
     276                 :             :     }
     277         [ +  + ]:          45 :   else if (g_str_equal (property_name, "CanSeek"))
     278                 :             :     {
     279                 :           5 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_SEEK) != 0);
     280                 :             :     }
     281         [ +  + ]:          40 :   else if (g_str_equal (property_name, "Metadata"))
     282                 :             :     {
     283                 :           5 :       value = valent_media_player_get_metadata (self->player);
     284                 :             :     }
     285         [ +  + ]:          35 :   else if (g_str_equal (property_name, "LoopStatus"))
     286                 :             :     {
     287                 :           5 :       ValentMediaRepeat repeat = valent_media_player_get_repeat (self->player);
     288                 :             : 
     289                 :           5 :       value = g_variant_new_string (valent_mpris_repeat_to_string (repeat));
     290                 :             :     }
     291         [ +  + ]:          30 :   else if (g_str_equal (property_name, "Shuffle"))
     292                 :             :     {
     293                 :           5 :       gboolean shuffle = valent_media_player_get_shuffle (self->player);
     294                 :             : 
     295                 :           5 :       value = g_variant_new_boolean (shuffle);
     296                 :             :     }
     297         [ +  + ]:          25 :   else if (g_str_equal (property_name, "PlaybackStatus"))
     298                 :             :     {
     299                 :           5 :       ValentMediaState state = valent_media_player_get_state (self->player);
     300                 :             : 
     301                 :           5 :       value = g_variant_new_string (valent_mpris_state_to_string (state));
     302                 :             :     }
     303         [ +  + ]:          20 :   else if (g_str_equal (property_name, "Volume"))
     304                 :             :     {
     305                 :           5 :       double volume = valent_media_player_get_volume (self->player);
     306                 :             : 
     307                 :           5 :       value = g_variant_new_double (volume);
     308                 :             :     }
     309         [ +  + ]:          15 :   else if (g_str_equal (property_name, "Rate") ||
     310         [ +  + ]:          10 :            g_str_equal (property_name, "MaximumRate") ||
     311         [ +  - ]:           5 :            g_str_equal (property_name, "MinimumRate"))
     312                 :             :     {
     313                 :          15 :       value = g_variant_new_double (1.0);
     314                 :             :     }
     315                 :             : 
     316         [ +  - ]:          70 :   if (value != NULL)
     317                 :             :     {
     318                 :         140 :       g_hash_table_replace (self->cache,
     319                 :          70 :                             g_strdup (property_name),
     320         [ -  + ]:          70 :                             g_variant_take_ref (value));
     321                 :             : 
     322                 :          70 :       return g_variant_ref (value);
     323                 :             :     }
     324                 :             : 
     325                 :           0 :   g_set_error (error,
     326                 :             :                G_DBUS_ERROR,
     327                 :             :                G_DBUS_ERROR_UNKNOWN_PROPERTY,
     328                 :             :                "Unknown property \"%s\"",
     329                 :             :                property_name);
     330                 :             : 
     331                 :           0 :   return NULL;
     332                 :             : }
     333                 :             : 
     334                 :             : static gboolean
     335                 :           9 : player_set_property (GDBusConnection  *connection,
     336                 :             :                      const char       *sender,
     337                 :             :                      const char       *object_path,
     338                 :             :                      const char       *interface_name,
     339                 :             :                      const char       *property_name,
     340                 :             :                      GVariant         *value,
     341                 :             :                      GError          **error,
     342                 :             :                      gpointer          user_data)
     343                 :             : {
     344                 :           9 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (user_data);
     345                 :             : 
     346         [ +  - ]:           9 :   g_assert (VALENT_IS_MPRIS_IMPL (self));
     347         [ -  + ]:           9 :   g_assert (property_name != NULL);
     348                 :             : 
     349         [ +  + ]:           9 :   if (g_str_equal (property_name, "LoopStatus"))
     350                 :             :     {
     351                 :           3 :       const char *loop_status = g_variant_get_string (value, NULL);
     352                 :           3 :       ValentMediaRepeat repeat = valent_mpris_repeat_from_string (loop_status);
     353                 :             : 
     354                 :           3 :       valent_media_player_set_repeat (self->player, repeat);
     355                 :           3 :       return TRUE;
     356                 :             :     }
     357                 :             : 
     358         [ +  + ]:           6 :   if (g_str_equal (property_name, "Shuffle"))
     359                 :             :     {
     360                 :           3 :       gboolean shuffle = g_variant_get_boolean (value);
     361                 :             : 
     362                 :           3 :       valent_media_player_set_shuffle (self->player, shuffle);
     363                 :           3 :       return TRUE;
     364                 :             :     }
     365                 :             : 
     366         [ +  - ]:           3 :   if (g_str_equal (property_name, "Volume"))
     367                 :             :     {
     368                 :           3 :       double volume = g_variant_get_double (value);
     369                 :             : 
     370                 :           3 :       valent_media_player_set_volume (self->player, volume);
     371                 :           3 :       return TRUE;
     372                 :             :     }
     373                 :             : 
     374                 :             :   return TRUE;
     375                 :             : }
     376                 :             : 
     377                 :             : static gboolean
     378                 :          27 : valent_mpris_impl_flush (gpointer data)
     379                 :             : {
     380                 :          27 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (data);
     381                 :          54 :   g_autoptr (GError) error = NULL;
     382                 :          27 :   GVariant *parameters;
     383                 :          27 :   GVariantBuilder changed_props;
     384                 :          27 :   GVariantBuilder invalidated_props;
     385                 :          27 :   GHashTableIter iter;
     386                 :          27 :   GVariant *value;
     387                 :          27 :   char *name;
     388                 :             : 
     389         [ +  - ]:          27 :   g_assert (VALENT_IS_MPRIS_IMPL (self));
     390                 :             : 
     391         [ +  - ]:          27 :   if (self->connection != NULL)
     392                 :             :     {
     393                 :          27 :       g_variant_builder_init (&changed_props, G_VARIANT_TYPE_VARDICT);
     394                 :          27 :       g_variant_builder_init (&invalidated_props, G_VARIANT_TYPE_STRING_ARRAY);
     395                 :             : 
     396                 :          27 :       g_hash_table_iter_init (&iter, self->pending);
     397                 :             : 
     398         [ +  + ]:         166 :       while (g_hash_table_iter_next (&iter, (void**)&name, (void**)&value))
     399                 :             :         {
     400         [ +  - ]:         139 :           if (value)
     401                 :         139 :             g_variant_builder_add (&changed_props, "{sv}", name, value);
     402                 :             :           else
     403                 :           0 :             g_variant_builder_add (&invalidated_props, "s", name);
     404                 :             : 
     405                 :         139 :           g_hash_table_iter_remove (&iter);
     406                 :             :         }
     407                 :             : 
     408                 :          27 :       parameters = g_variant_new ("(s@a{sv}@as)",
     409                 :             :                                   "org.mpris.MediaPlayer2.Player",
     410                 :             :                                   g_variant_builder_end (&changed_props),
     411                 :             :                                   g_variant_builder_end (&invalidated_props));
     412                 :             : 
     413                 :          27 :       g_dbus_connection_emit_signal (self->connection,
     414                 :             :                                      NULL,
     415                 :             :                                      "/org/mpris/MediaPlayer2",
     416                 :             :                                      "org.freedesktop.DBus.Properties",
     417                 :             :                                      "PropertiesChanged",
     418                 :             :                                      parameters,
     419                 :             :                                      &error);
     420                 :             : 
     421         [ -  + ]:          27 :       if (error != NULL)
     422                 :           0 :         g_warning ("%s(): %s", G_STRFUNC, error->message);
     423                 :             :     }
     424                 :             : 
     425         [ +  - ]:          27 :   g_clear_handle_id (&self->flush_id, g_source_remove);
     426                 :             : 
     427         [ -  + ]:          27 :   return G_SOURCE_REMOVE;
     428                 :             : }
     429                 :             : 
     430                 :             : static void
     431                 :         150 : valent_mpris_impl_set_value (ValentMPRISImpl *self,
     432                 :             :                              const char      *name,
     433                 :             :                              GVariant        *value)
     434                 :             : {
     435         [ +  - ]:         150 :   g_assert (VALENT_IS_MPRIS_IMPL (self));
     436   [ +  -  -  + ]:         150 :   g_assert (name != NULL && *name != '\0');
     437         [ -  + ]:         150 :   g_assert (value != NULL);
     438                 :             : 
     439                 :         300 :   g_hash_table_replace (self->cache,
     440                 :         150 :                         g_strdup (name),
     441         [ -  + ]:         150 :                         g_variant_ref_sink (value));
     442                 :         300 :   g_hash_table_replace (self->pending,
     443                 :         150 :                         g_strdup (name),
     444         [ -  + ]:         150 :                         g_variant_ref_sink (value));
     445                 :             : 
     446         [ +  + ]:         150 :   if (self->flush_id == 0)
     447                 :          27 :     self->flush_id = g_idle_add (valent_mpris_impl_flush, self);
     448                 :         150 : }
     449                 :             : 
     450                 :             : static void
     451                 :           7 : valent_mpris_impl_propagate_seeked (ValentMPRISImpl *self,
     452                 :             :                                     int64_t          position)
     453                 :             : {
     454                 :           7 :   g_autoptr (GError) error = NULL;
     455                 :           7 :   gboolean ret;
     456                 :             : 
     457         [ -  + ]:           7 :   if (self->connection == NULL)
     458                 :           0 :     return;
     459                 :             : 
     460                 :           7 :   ret = g_dbus_connection_emit_signal (self->connection,
     461                 :             :                                        NULL,
     462                 :             :                                        "/org/mpris/MediaPlayer2",
     463                 :             :                                        "org.mpris.MediaPlayer2.Player",
     464                 :             :                                        "Seeked",
     465                 :             :                                        g_variant_new ("(x)", position),
     466                 :             :                                        &error);
     467                 :             : 
     468         [ -  + ]:           7 :   if (!ret)
     469                 :           0 :     g_warning ("%s(): %s", G_STRFUNC, error->message);
     470                 :             : }
     471                 :             : 
     472                 :             : static void
     473                 :          77 : valent_mpris_impl_propagate_notify (ValentMediaPlayer *player,
     474                 :             :                                     GParamSpec        *pspec,
     475                 :             :                                     ValentMPRISImpl   *self)
     476                 :             : {
     477                 :          77 :   const char *name = g_param_spec_get_name (pspec);
     478                 :          77 :   GVariant *value = NULL;
     479                 :             : 
     480         [ +  + ]:          77 :   if (g_str_equal (name, "flags"))
     481                 :             :     {
     482                 :          16 :       ValentMediaActions flags = valent_media_player_get_flags (self->player);
     483                 :             : 
     484                 :          16 :       value = g_variant_new_boolean (flags != 0);
     485                 :          16 :       valent_mpris_impl_set_value (self, "CanControl", value);
     486                 :          16 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_NEXT) != 0);
     487                 :          16 :       valent_mpris_impl_set_value (self, "CanGoNext", value);
     488                 :          16 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_PAUSE) != 0);
     489                 :          16 :       valent_mpris_impl_set_value (self, "CanPause", value);
     490                 :          16 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_PLAY) != 0);
     491                 :          16 :       valent_mpris_impl_set_value (self, "CanPlay", value);
     492                 :          16 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_PREVIOUS) != 0);
     493                 :          16 :       valent_mpris_impl_set_value (self, "CanGoPrevious", value);
     494                 :          16 :       value = g_variant_new_boolean ((flags & VALENT_MEDIA_ACTION_SEEK) != 0);
     495                 :          16 :       valent_mpris_impl_set_value (self, "CanSeek", value);
     496                 :             :     }
     497         [ +  + ]:          61 :   else if (g_str_equal (name, "metadata"))
     498                 :             :     {
     499                 :          19 :       value = valent_media_player_get_metadata (self->player);
     500                 :          19 :       valent_mpris_impl_set_value (self, "Metadata", value);
     501                 :          19 :       g_variant_unref (value);
     502                 :             :     }
     503         [ -  + ]:          42 :   else if (g_str_equal (name, "name"))
     504                 :             :     {
     505                 :           0 :       const char *identity = valent_media_player_get_name (self->player);
     506                 :             : 
     507                 :           0 :       value = g_variant_new_string (identity);
     508                 :           0 :       g_hash_table_replace (self->cache,
     509                 :           0 :                             g_strdup ("Identity"),
     510                 :           0 :                             g_variant_ref_sink (value));
     511                 :             :     }
     512         [ +  + ]:          42 :   else if (g_str_equal (name, "position"))
     513                 :             :     {
     514                 :           7 :       double position = valent_media_player_get_position (self->player);
     515                 :             : 
     516                 :             :       /* Convert seconds to microseconds */
     517                 :           7 :       value = g_variant_new_int64 ((int64_t)(position * G_TIME_SPAN_SECOND));
     518                 :          14 :       g_hash_table_replace (self->cache,
     519                 :           7 :                             g_strdup ("Position"),
     520                 :           7 :                             g_variant_ref_sink (value));
     521                 :             : 
     522                 :             :       /* Convert seconds to microseconds */
     523                 :           7 :       valent_mpris_impl_propagate_seeked (self, (int64_t)(position * G_TIME_SPAN_SECOND));
     524                 :             :     }
     525         [ +  + ]:          35 :   else if (g_str_equal (name, "repeat"))
     526                 :             :     {
     527                 :           3 :       ValentMediaRepeat repeat = valent_media_player_get_repeat (self->player);
     528                 :             : 
     529                 :           3 :       value = g_variant_new_string (valent_mpris_repeat_to_string (repeat));
     530                 :           3 :       valent_mpris_impl_set_value (self, "LoopStatus", value);
     531                 :             :     }
     532         [ +  + ]:          32 :   else if (g_str_equal (name, "shuffle"))
     533                 :             :     {
     534                 :           3 :       gboolean shuffle = valent_media_player_get_shuffle (self->player);
     535                 :             : 
     536                 :           3 :       value = g_variant_new_boolean (shuffle);
     537                 :           3 :       valent_mpris_impl_set_value (self, "Shuffle", value);
     538                 :             :     }
     539         [ +  + ]:          29 :   else if (g_str_equal (name, "state"))
     540                 :             :     {
     541                 :          26 :       ValentMediaState state = valent_media_player_get_state (self->player);
     542                 :             : 
     543                 :          26 :       value = g_variant_new_string (valent_mpris_state_to_string (state));
     544                 :          26 :       valent_mpris_impl_set_value (self, "PlaybackStatus", value);
     545                 :             :     }
     546         [ +  - ]:           3 :   else if (g_str_equal (name, "volume"))
     547                 :             :     {
     548                 :           3 :       double volume = valent_media_player_get_volume (self->player);
     549                 :             : 
     550                 :           3 :       value = g_variant_new_double (volume);
     551                 :           3 :       valent_mpris_impl_set_value (self, "Volume", value);
     552                 :             :     }
     553                 :          77 : }
     554                 :             : 
     555                 :             : /*
     556                 :             :  * GObject
     557                 :             :  */
     558                 :             : static void
     559                 :           5 : valent_mpris_impl_constructed (GObject *object)
     560                 :             : {
     561                 :           5 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (object);
     562                 :             : 
     563         [ +  - ]:           5 :   g_assert (VALENT_IS_MEDIA_PLAYER (self->player));
     564                 :             : 
     565                 :           5 :   g_signal_connect_object (self->player,
     566                 :             :                            "notify",
     567                 :             :                            G_CALLBACK (valent_mpris_impl_propagate_notify),
     568                 :             :                            self, 0);
     569                 :             : 
     570                 :           5 :   G_OBJECT_CLASS (valent_mpris_impl_parent_class)->constructed (object);
     571                 :           5 : }
     572                 :             : 
     573                 :             : static void
     574                 :           5 : valent_mpris_impl_dispose (GObject *object)
     575                 :             : {
     576                 :           5 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (object);
     577                 :             : 
     578                 :           5 :   g_signal_handlers_disconnect_by_data (self->player, self);
     579                 :           5 :   valent_mpris_impl_unexport (self);
     580                 :             : 
     581                 :           5 :   G_OBJECT_CLASS (valent_mpris_impl_parent_class)->dispose (object);
     582                 :           5 : }
     583                 :             : 
     584                 :             : static void
     585                 :           5 : valent_mpris_impl_finalize (GObject *object)
     586                 :             : {
     587                 :           5 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (object);
     588                 :             : 
     589         [ +  - ]:           5 :   g_clear_pointer (&self->bus_name, g_free);
     590         [ -  + ]:           5 :   g_clear_object (&self->connection);
     591         [ +  - ]:           5 :   g_clear_object (&self->player);
     592                 :             : 
     593         [ +  - ]:           5 :   g_clear_pointer (&self->cache, g_hash_table_unref);
     594         [ +  - ]:           5 :   g_clear_pointer (&self->pending, g_hash_table_unref);
     595                 :             : 
     596                 :           5 :   G_OBJECT_CLASS (valent_mpris_impl_parent_class)->finalize (object);
     597                 :           5 : }
     598                 :             : 
     599                 :             : static void
     600                 :           1 : valent_mpris_impl_get_property (GObject    *object,
     601                 :             :                                 guint       prop_id,
     602                 :             :                                 GValue     *value,
     603                 :             :                                 GParamSpec *pspec)
     604                 :             : {
     605                 :           1 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (object);
     606                 :             : 
     607         [ +  - ]:           1 :   switch (prop_id)
     608                 :             :     {
     609                 :           1 :     case PROP_PLAYER:
     610                 :           1 :       g_value_set_object (value, self->player);
     611                 :           1 :       break;
     612                 :             : 
     613                 :           0 :     default:
     614                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     615                 :             :     }
     616                 :           1 : }
     617                 :             : 
     618                 :             : static void
     619                 :           5 : valent_mpris_impl_set_property (GObject      *object,
     620                 :             :                                 guint         prop_id,
     621                 :             :                                 const GValue *value,
     622                 :             :                                 GParamSpec   *pspec)
     623                 :             : {
     624                 :           5 :   ValentMPRISImpl *self = VALENT_MPRIS_IMPL (object);
     625                 :             : 
     626         [ +  - ]:           5 :   switch (prop_id)
     627                 :             :     {
     628                 :           5 :     case PROP_PLAYER:
     629                 :           5 :       self->player = g_value_dup_object (value);
     630                 :           5 :       break;
     631                 :             : 
     632                 :           0 :     default:
     633                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     634                 :             :     }
     635                 :           5 : }
     636                 :             : 
     637                 :             : static void
     638                 :           2 : valent_mpris_impl_class_init (ValentMPRISImplClass *klass)
     639                 :             : {
     640                 :           2 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     641                 :             : 
     642                 :           2 :   object_class->constructed = valent_mpris_impl_constructed;
     643                 :           2 :   object_class->dispose = valent_mpris_impl_dispose;
     644                 :           2 :   object_class->finalize = valent_mpris_impl_finalize;
     645                 :           2 :   object_class->get_property = valent_mpris_impl_get_property;
     646                 :           2 :   object_class->set_property = valent_mpris_impl_set_property;
     647                 :             : 
     648                 :             :   /**
     649                 :             :    * ValentMprisDevice:player:
     650                 :             :    *
     651                 :             :    * The [class@Valent.MediaPlayer] being exported.
     652                 :             :    */
     653                 :           4 :   properties [PROP_PLAYER] =
     654                 :           2 :     g_param_spec_object ("player", NULL, NULL,
     655                 :             :                          VALENT_TYPE_MEDIA_PLAYER,
     656                 :             :                          (G_PARAM_READWRITE |
     657                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     658                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     659                 :             :                           G_PARAM_STATIC_STRINGS));
     660                 :             : 
     661                 :           2 :   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
     662                 :           2 : }
     663                 :             : 
     664                 :             : static void
     665                 :           5 : valent_mpris_impl_init (ValentMPRISImpl *self)
     666                 :             : {
     667                 :           5 :   self->application_vtable.method_call = application_method_call;
     668                 :           5 :   self->application_vtable.get_property = application_get_property;
     669                 :           5 :   self->application_vtable.set_property = application_set_property;
     670                 :             : 
     671                 :           5 :   self->player_vtable.method_call = player_method_call;
     672                 :           5 :   self->player_vtable.get_property = player_get_property;
     673                 :           5 :   self->player_vtable.set_property = player_set_property;
     674                 :             : 
     675                 :           5 :   self->bus_name = g_strdup (VALENT_MPRIS_DBUS_NAME);
     676                 :           5 :   self->cache = g_hash_table_new_full (g_str_hash,
     677                 :             :                                        g_str_equal,
     678                 :             :                                        g_free,
     679                 :             :                                        (GDestroyNotify)g_variant_unref);
     680                 :           5 :   self->pending = g_hash_table_new_full (g_str_hash,
     681                 :             :                                          g_str_equal,
     682                 :             :                                          g_free,
     683                 :             :                                          (GDestroyNotify)g_variant_unref);
     684                 :           5 : }
     685                 :             : 
     686                 :             : /**
     687                 :             :  * valent_mpris_impl_new:
     688                 :             :  * @player: a `ValentMediaPlayer`
     689                 :             :  *
     690                 :             :  * Get the `ValentMPRISImpl` instance.
     691                 :             :  *
     692                 :             :  * Returns: (transfer full) (nullable): a `ValentMPRISImpl`
     693                 :             :  */
     694                 :             : ValentMPRISImpl *
     695                 :           5 : valent_mpris_impl_new (ValentMediaPlayer *player)
     696                 :             : {
     697         [ +  - ]:           5 :   g_return_val_if_fail (VALENT_IS_MEDIA_PLAYER (player), NULL);
     698                 :             : 
     699                 :           5 :   return g_object_new (VALENT_TYPE_MPRIS_IMPL,
     700                 :             :                        "player", player,
     701                 :             :                        NULL);
     702                 :             : }
     703                 :             : 
     704                 :             : /**
     705                 :             :  * valent_media_player_impl_export:
     706                 :             :  * @impl: a `ValentMPRISImpl`
     707                 :             :  * @connection: a `GDBusConnection`
     708                 :             :  * @error:
     709                 :             :  *
     710                 :             :  * Impl @impl on @connection.
     711                 :             :  */
     712                 :             : gboolean
     713                 :           5 : valent_mpris_impl_export (ValentMPRISImpl  *impl,
     714                 :             :                           GDBusConnection  *connection,
     715                 :             :                           GError          **error)
     716                 :             : {
     717         [ +  - ]:           5 :   g_return_val_if_fail (VALENT_IS_MPRIS_IMPL (impl), FALSE);
     718   [ +  -  +  -  :           5 :   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
             -  +  -  - ]
     719   [ +  -  -  + ]:           5 :   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
     720                 :             : 
     721         [ -  + ]:           5 :   if (impl->connection == connection)
     722                 :             :     return TRUE;
     723                 :             : 
     724                 :             :   /* Unexport from any existing connection */
     725                 :           5 :   valent_mpris_impl_unexport (impl);
     726                 :           5 :   impl->connection = g_object_ref (connection);
     727                 :             : 
     728                 :             :   /* Register org.mpris.MediaPlayer2 interface */
     729         [ +  - ]:           5 :   if (impl->application_id == 0)
     730                 :             :     {
     731                 :          10 :       impl->application_id =
     732                 :           5 :         g_dbus_connection_register_object (impl->connection,
     733                 :             :                                            "/org/mpris/MediaPlayer2",
     734                 :             :                                            VALENT_MPRIS_APPLICATION_INFO,
     735                 :           5 :                                            &impl->application_vtable,
     736                 :             :                                            impl, NULL,
     737                 :             :                                            error);
     738                 :             : 
     739         [ -  + ]:           5 :       if (impl->application_id == 0)
     740                 :             :         {
     741                 :           0 :           valent_mpris_impl_unexport (impl);
     742                 :           0 :           return FALSE;
     743                 :             :         }
     744                 :             :     }
     745                 :             : 
     746                 :             :   /* Register org.mpris.MediaPlayer2.Player interface */
     747         [ +  - ]:           5 :   if (impl->player_id == 0)
     748                 :             :     {
     749                 :          10 :       impl->player_id =
     750                 :           5 :         g_dbus_connection_register_object (impl->connection,
     751                 :             :                                            "/org/mpris/MediaPlayer2",
     752                 :             :                                            VALENT_MPRIS_PLAYER_INFO,
     753                 :           5 :                                            &impl->player_vtable,
     754                 :             :                                            impl, NULL,
     755                 :             :                                            error);
     756                 :             : 
     757         [ -  + ]:           5 :       if (impl->player_id == 0)
     758                 :             :         {
     759                 :           0 :           valent_mpris_impl_unexport (impl);
     760                 :           0 :           return FALSE;
     761                 :             :         }
     762                 :             :     }
     763                 :             : 
     764                 :             :   /* Own a well-known name on the connection */
     765         [ -  + ]:           5 :   if (impl->bus_name_id == 0)
     766                 :             :     {
     767                 :           5 :       impl->bus_name_id =
     768                 :           5 :         g_bus_own_name_on_connection (impl->connection,
     769                 :           5 :                                       impl->bus_name,
     770                 :             :                                       G_BUS_NAME_OWNER_FLAGS_NONE,
     771                 :             :                                       NULL, // NameAcquired
     772                 :             :                                       NULL, // NameLost
     773                 :             :                                       NULL,
     774                 :             :                                       NULL);
     775                 :             :     }
     776                 :             : 
     777                 :             :   return TRUE;
     778                 :             : }
     779                 :             : 
     780                 :             : static void
     781                 :           5 : valent_mpris_impl_export_full_cb (GObject      *object,
     782                 :             :                                   GAsyncResult *result,
     783                 :             :                                   gpointer      user_data)
     784                 :             : {
     785                 :           5 :   g_autoptr (GTask) task = G_TASK (user_data);
     786                 :           5 :   ValentMPRISImpl *self = g_task_get_source_object (task);
     787   [ +  -  -  - ]:           5 :   g_autoptr (GDBusConnection) connection = NULL;
     788         [ -  - ]:           5 :   g_autoptr (GError) error = NULL;
     789                 :             : 
     790                 :           5 :   connection = g_dbus_connection_new_for_address_finish (result, &error);
     791                 :             : 
     792         [ -  + ]:           5 :   if (connection == NULL)
     793                 :           0 :     return g_task_return_error (task, g_steal_pointer (&error));
     794                 :             : 
     795         [ -  + ]:           5 :   if (!valent_mpris_impl_export (self, connection, &error))
     796                 :           0 :     return g_task_return_error (task, g_steal_pointer (&error));
     797                 :             : 
     798         [ -  + ]:           5 :   g_task_return_boolean (task, TRUE);
     799                 :             : }
     800                 :             : 
     801                 :             : /**
     802                 :             :  * valent_mpris_impl_export_full:
     803                 :             :  * @impl: a `ValentMPRISImpl`
     804                 :             :  * @bus_name: the well-known name to own
     805                 :             :  * @cancellable: (nullable): a `GCancellable`
     806                 :             :  * @callback: (scope async): a `GAsyncReadyCallback`
     807                 :             :  * @user_data: user supplied data
     808                 :             :  *
     809                 :             :  * Impl the test media player on the session bus.
     810                 :             :  */
     811                 :             : void
     812                 :           5 : valent_mpris_impl_export_full (ValentMPRISImpl     *impl,
     813                 :             :                                const char          *bus_name,
     814                 :             :                                GCancellable        *cancellable,
     815                 :             :                                GAsyncReadyCallback  callback,
     816                 :             :                                gpointer             user_data)
     817                 :             : {
     818                 :           5 :   g_autoptr (GTask) task = NULL;
     819         [ -  - ]:           5 :   g_autofree char *address = NULL;
     820                 :           5 :   g_autoptr (GError) error = NULL;
     821                 :             : 
     822         [ +  - ]:           5 :   g_return_if_fail (VALENT_IS_MPRIS_IMPL (impl));
     823         [ -  + ]:           5 :   g_return_if_fail (g_dbus_is_name (bus_name));
     824   [ +  +  +  -  :           5 :   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  +  -  - ]
     825                 :             : 
     826                 :           5 :   task = g_task_new (impl, cancellable, callback, user_data);
     827         [ +  - ]:           5 :   g_task_set_source_tag (task, valent_mpris_impl_export_full);
     828                 :             : 
     829                 :             :   /* Set the new bus name */
     830                 :           5 :   g_set_str (&impl->bus_name, bus_name);
     831                 :             : 
     832                 :             :   /* Set up a dedicated connection */
     833                 :           5 :   address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION,
     834                 :             :                                              cancellable,
     835                 :             :                                              &error);
     836                 :             : 
     837         [ -  + ]:           5 :   if (address == NULL)
     838                 :           0 :     return g_task_return_error (task, g_steal_pointer (&error));
     839                 :             : 
     840         [ -  + ]:           5 :   g_dbus_connection_new_for_address (address,
     841                 :             :                                      G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
     842                 :             :                                      G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
     843                 :             :                                      NULL,
     844                 :             :                                      cancellable,
     845                 :             :                                      (GAsyncReadyCallback)valent_mpris_impl_export_full_cb,
     846                 :             :                                      g_steal_pointer (&task));
     847                 :             : }
     848                 :             : 
     849                 :             : /**
     850                 :             :  * valent_mpris_impl_export_finish:
     851                 :             :  * @impl: a `ValentMPRISImpl`
     852                 :             :  * @cancellable: (nullable): a `GCancellable`
     853                 :             :  * @error: (nullable): a `GError`
     854                 :             :  *
     855                 :             :  * Finish an operation started by valent_mpris_impl_export_full().
     856                 :             :  *
     857                 :             :  * Returns: %TRUE if successful, or %FALSE with @error set
     858                 :             :  */
     859                 :             : gboolean
     860                 :           5 : valent_mpris_impl_export_finish (ValentMPRISImpl  *impl,
     861                 :             :                                  GAsyncResult     *result,
     862                 :             :                                  GError          **error)
     863                 :             : {
     864         [ +  - ]:           5 :   g_return_val_if_fail (VALENT_IS_MPRIS_IMPL (impl), FALSE);
     865         [ -  + ]:           5 :   g_return_val_if_fail (g_task_is_valid (result, impl), FALSE);
     866   [ +  -  -  + ]:           5 :   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
     867                 :             : 
     868                 :           5 :   return g_task_propagate_boolean (G_TASK (result), error);
     869                 :             : }
     870                 :             : 
     871                 :             : /**
     872                 :             :  * valent_mpris_player_impl_unexport:
     873                 :             :  * @impl: a `ValentMPRISImpl`
     874                 :             :  *
     875                 :             :  * Unexport the player.
     876                 :             :  */
     877                 :             : void
     878                 :          14 : valent_mpris_impl_unexport (ValentMPRISImpl *impl)
     879                 :             : {
     880         [ +  - ]:          14 :   g_return_if_fail (VALENT_IS_MPRIS_IMPL (impl));
     881                 :             : 
     882         [ -  + ]:          14 :   g_clear_handle_id (&impl->flush_id, g_source_remove);
     883         [ +  + ]:          14 :   g_clear_handle_id (&impl->bus_name_id, g_bus_unown_name);
     884                 :             : 
     885         [ +  + ]:          14 :   if (impl->player_id > 0)
     886                 :             :     {
     887                 :           5 :       g_dbus_connection_unregister_object (impl->connection,
     888                 :             :                                            impl->player_id);
     889                 :           5 :       impl->player_id = 0;
     890                 :             :     }
     891                 :             : 
     892         [ +  + ]:          14 :   if (impl->application_id > 0)
     893                 :             :     {
     894                 :           5 :       g_dbus_connection_unregister_object (impl->connection,
     895                 :             :                                            impl->application_id);
     896                 :           5 :       impl->application_id = 0;
     897                 :             :     }
     898                 :             : 
     899         [ +  + ]:          14 :   g_clear_object (&impl->connection);
     900                 :             : }
     901                 :             : 
        

Generated by: LCOV version 2.0-1