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

Generated by: LCOV version 2.0-1