Backports src/mpris from upstream v0.22 to fix mpris integration diff --git a/src/mpris/celluloid-mpris-base.c b/src/mpris/celluloid-mpris-base.c index 223f571..c44a63e 100644 --- a/src/mpris/celluloid-mpris-base.c +++ b/src/mpris/celluloid-mpris-base.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 gnome-mpv + * Copyright (c) 2015-2019, 2021 gnome-mpv * * This file is part of Celluloid. * @@ -42,6 +42,7 @@ struct _CelluloidMprisBase { CelluloidMprisModule parent; CelluloidController *controller; + GHashTable *readonly_table; guint reg_id; }; @@ -230,6 +231,7 @@ method_handler( GDBusConnection *connection, gpointer data ) { CelluloidMprisBase *base = data; + gboolean unknown_method = FALSE; if(g_strcmp0(method_name, "Raise") == 0) { @@ -240,9 +242,25 @@ method_handler( GDBusConnection *connection, { celluloid_controller_quit(base->controller); } + else + { + unknown_method = TRUE; + } - g_dbus_method_invocation_return_value - (invocation, g_variant_new("()", NULL)); + if(unknown_method) + { + g_dbus_method_invocation_return_error + ( invocation, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_UNKNOWN_METHOD, + "Attempted to call unknown method \"%s\"", + method_name ); + } + else + { + g_dbus_method_invocation_return_value + (invocation, g_variant_new("()", NULL)); + } } static GVariant * @@ -254,9 +272,24 @@ get_prop_handler( GDBusConnection *connection, GError **error, gpointer data ) { + CelluloidMprisBase *base = CELLULOID_MPRIS_BASE(data); + CelluloidMprisModule *module = CELLULOID_MPRIS_MODULE(data); GVariant *value = NULL; - celluloid_mpris_module_get_properties(data, property_name, &value, NULL); + if(!g_hash_table_contains(base->readonly_table, property_name)) + { + g_set_error + ( error, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_UNKNOWN_PROPERTY, + "Failed to get value of unknown property \"%s\"", + property_name ); + } + else + { + celluloid_mpris_module_get_properties + (module, property_name, &value, NULL); + } return value?g_variant_ref(value):NULL; } @@ -271,22 +304,39 @@ set_prop_handler( GDBusConnection *connection, GError **error, gpointer data ) { - CelluloidMprisBase *base = data; + CelluloidMprisBase *base = CELLULOID_MPRIS_BASE(data); + gboolean result = TRUE; - if(g_strcmp0(property_name, "Fullscreen") == 0) + if(!g_hash_table_contains(base->readonly_table, property_name)) + { + result = FALSE; + + g_set_error + ( error, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_UNKNOWN_PROPERTY, + "Failed to set value of unknown property \"%s\"", + property_name ); + } + else if(GPOINTER_TO_INT(g_hash_table_lookup(base->readonly_table, property_name))) + { + result = FALSE; + + g_set_error + ( error, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_SET_READONLY, + "Attempted to set value of readonly property \"%s\"", + property_name ); + } + else if(g_strcmp0(property_name, "Fullscreen") == 0) { CelluloidView *view = celluloid_controller_get_view(base->controller); celluloid_view_set_fullscreen(view, g_variant_get_boolean(value)); } - else - { - celluloid_mpris_module_set_properties( data, - property_name, value, - NULL ); - } - return TRUE; /* This function should always succeed */ + return result; } static void @@ -360,8 +410,39 @@ celluloid_mpris_base_class_init(CelluloidMprisBaseClass *klass) static void celluloid_mpris_base_init(CelluloidMprisBase *base) { - base->controller = NULL; - base->reg_id = 0; + const struct + { + const gchar *name; + gboolean readonly; + } + properties[] = + { + {"CanQuit", TRUE}, + {"Fullscreen", FALSE}, + {"CanSetFullscreen", TRUE}, + {"CanRaise", TRUE}, + {"HasTrackList", TRUE}, + {"Identity", TRUE}, + {"DesktopEntry", TRUE}, + {"SupportedUriSchemes", TRUE}, + {"SupportedMimeTypes", TRUE}, + {NULL, FALSE} + }; + + base->controller = + NULL; + base->readonly_table = + g_hash_table_new_full(g_str_hash, g_int_equal, g_free, NULL); + base->reg_id = + 0; + + for(gint i = 0; properties[i].name; i++) + { + g_hash_table_replace + ( base->readonly_table, + g_strdup(properties[i].name), + GINT_TO_POINTER(properties[i].readonly) ); + } } CelluloidMprisModule * diff --git a/src/mpris/celluloid-mpris-module.c b/src/mpris/celluloid-mpris-module.c index 677c8a0..358516c 100644 --- a/src/mpris/celluloid-mpris-module.c +++ b/src/mpris/celluloid-mpris-module.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 gnome-mpv + * Copyright (c) 2017-2019, 2021 gnome-mpv * * This file is part of Celluloid. * @@ -83,9 +83,8 @@ set_property( GObject *object, { CelluloidMprisModulePrivate *priv; - priv = G_TYPE_INSTANCE_GET_PRIVATE( object, - CELLULOID_TYPE_MPRIS_MODULE, - CelluloidMprisModulePrivate ); + priv = celluloid_mpris_module_get_instance_private + (CELLULOID_MPRIS_MODULE(object)); switch(property_id) { @@ -111,9 +110,8 @@ get_property( GObject *object, { CelluloidMprisModulePrivate *priv; - priv = G_TYPE_INSTANCE_GET_PRIVATE( object, - CELLULOID_TYPE_MPRIS_MODULE, - CelluloidMprisModulePrivate ); + priv = celluloid_mpris_module_get_instance_private + (CELLULOID_MPRIS_MODULE(object)); switch(property_id) { @@ -136,9 +134,8 @@ dispose(GObject *object) { CelluloidMprisModulePrivate *priv; - priv = G_TYPE_INSTANCE_GET_PRIVATE( object, - CELLULOID_TYPE_MPRIS_MODULE, - CelluloidMprisModulePrivate ); + priv = celluloid_mpris_module_get_instance_private + (CELLULOID_MPRIS_MODULE(object)); g_hash_table_unref(priv->prop_table); @@ -150,9 +147,8 @@ finalize(GObject *object) { CelluloidMprisModulePrivate *priv; - priv = G_TYPE_INSTANCE_GET_PRIVATE( object, - CELLULOID_TYPE_MPRIS_MODULE, - CelluloidMprisModulePrivate ); + priv = celluloid_mpris_module_get_instance_private + (CELLULOID_MPRIS_MODULE(object)); g_slist_foreach(priv->signal_ids, (GFunc)disconnect_signal, NULL); g_slist_free_full(priv->signal_ids, g_free); @@ -197,9 +193,7 @@ celluloid_mpris_module_init(CelluloidMprisModule *module) { CelluloidMprisModulePrivate *priv; - priv = G_TYPE_INSTANCE_GET_PRIVATE( module, - CELLULOID_TYPE_MPRIS_MODULE, - CelluloidMprisModulePrivate ); + priv = celluloid_mpris_module_get_instance_private(module); priv->conn = NULL; priv->iface = NULL; @@ -222,9 +216,7 @@ celluloid_mpris_module_connect_signal( CelluloidMprisModule *module, CelluloidMprisModulePrivate *priv; CelluloidSignalHandlerInfo *info; - priv = G_TYPE_INSTANCE_GET_PRIVATE( module, - CELLULOID_TYPE_MPRIS_MODULE, - CelluloidMprisModulePrivate ); + priv = celluloid_mpris_module_get_instance_private(module); info = g_malloc(sizeof(CelluloidSignalHandlerInfo)); info->instance = instance; @@ -241,9 +233,7 @@ celluloid_mpris_module_get_properties(CelluloidMprisModule *module, ...) gchar *name; GVariant **value_ptr; - priv = G_TYPE_INSTANCE_GET_PRIVATE( module, - CELLULOID_TYPE_MPRIS_MODULE, - CelluloidMprisModulePrivate ); + priv = celluloid_mpris_module_get_instance_private(module); va_start(arg, module); @@ -255,6 +245,8 @@ celluloid_mpris_module_get_properties(CelluloidMprisModule *module, ...) { *value_ptr = g_hash_table_lookup(priv->prop_table, name); } + + va_end(arg); } void @@ -271,9 +263,7 @@ celluloid_mpris_module_set_properties_full( CelluloidMprisModule *module, const gchar *elem_type_string; GVariant *sig_args; - priv = G_TYPE_INSTANCE_GET_PRIVATE( module, - CELLULOID_TYPE_MPRIS_MODULE, - CelluloidMprisModulePrivate ); + priv = celluloid_mpris_module_get_instance_private(module); builder_type_string = send_new_value?"a{sv}":"as"; elem_type_string = builder_type_string+1; @@ -296,6 +286,8 @@ celluloid_mpris_module_set_properties_full( CelluloidMprisModule *module, g_variant_builder_add(&builder, elem_type_string, name, value); } + va_end(arg); + sig_args = g_variant_new( "(sa{sv}as)", priv->iface->name, send_new_value?&builder:NULL, diff --git a/src/mpris/celluloid-mpris-player.c b/src/mpris/celluloid-mpris-player.c index cd276d0..a3a52cf 100644 --- a/src/mpris/celluloid-mpris-player.c +++ b/src/mpris/celluloid-mpris-player.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 gnome-mpv + * Copyright (c) 2015-2019, 2021 gnome-mpv * * This file is part of Celluloid. * @@ -42,6 +42,7 @@ struct _CelluloidMprisPlayer { CelluloidMprisModule parent; CelluloidController *controller; + GHashTable *readonly_table; guint reg_id; }; @@ -402,30 +403,34 @@ method_handler( GDBusConnection *connection, CelluloidMprisPlayer *player = data; CelluloidModel *model = celluloid_controller_get_model (player->controller); + gboolean unknown_method = FALSE; if(g_strcmp0(method_name, "Next") == 0) { - celluloid_model_key_press(model, "NEXT"); + celluloid_model_next_playlist_entry(model); } else if(g_strcmp0(method_name, "Previous") == 0) { - celluloid_model_key_press(model, "PREV"); + celluloid_model_previous_playlist_entry(model); } else if(g_strcmp0(method_name, "Pause") == 0) { - celluloid_model_key_press(model, "PAUSE"); + celluloid_model_pause(model); } else if(g_strcmp0(method_name, "PlayPause") == 0) { - celluloid_model_key_press(model, "PLAYPAUSE"); + gboolean pause = FALSE; + + g_object_get(model, "pause", &pause, NULL); + g_object_set(model, "pause", !pause, NULL); } else if(g_strcmp0(method_name, "Stop") == 0) { - celluloid_model_key_press(model, "STOP"); + celluloid_model_stop(model); } else if(g_strcmp0(method_name, "Play") == 0) { - celluloid_model_key_press(model, "PLAY"); + celluloid_model_play(model); } else if(g_strcmp0(method_name, "Seek") == 0) { @@ -459,9 +464,25 @@ method_handler( GDBusConnection *connection, g_variant_get(parameters, "(&s)", &uri); celluloid_model_load_file(model, uri, FALSE); } + else + { + unknown_method = TRUE; + } - g_dbus_method_invocation_return_value - (invocation, g_variant_new("()", NULL)); + if(unknown_method) + { + g_dbus_method_invocation_return_error + ( invocation, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_UNKNOWN_METHOD, + "Attempted to call unknown method \"%s\"", + method_name ); + } + else + { + g_dbus_method_invocation_return_value + (invocation, g_variant_new("()", NULL)); + } } static GVariant * @@ -473,10 +494,20 @@ get_prop_handler( GDBusConnection *connection, GError **error, gpointer data ) { - CelluloidMprisPlayer *player = data; - GVariant *value; + CelluloidMprisPlayer *player = CELLULOID_MPRIS_PLAYER(data); + CelluloidMprisModule *module = CELLULOID_MPRIS_MODULE(data); + GVariant *value = NULL; - if(g_strcmp0(property_name, "Position") == 0) + if(!g_hash_table_contains(player->readonly_table, property_name)) + { + g_set_error + ( error, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_UNKNOWN_PROPERTY, + "Failed to get value of unknown property \"%s\"", + property_name ); + } + else if(g_strcmp0(property_name, "Position") == 0) { CelluloidModel *model; gdouble position; @@ -488,7 +519,7 @@ get_prop_handler( GDBusConnection *connection, else { celluloid_mpris_module_get_properties - ( CELLULOID_MPRIS_MODULE(data), + ( module, property_name, &value, NULL ); } @@ -506,11 +537,32 @@ set_prop_handler( GDBusConnection *connection, GError **error, gpointer data ) { - CelluloidMprisPlayer *player = data; + CelluloidMprisPlayer *player = CELLULOID_MPRIS_PLAYER(data); CelluloidModel *model = celluloid_controller_get_model (player->controller); + gboolean result = TRUE; - if(g_strcmp0(property_name, "LoopStatus") == 0) + if(!g_hash_table_contains(player->readonly_table, property_name)) + { + result = FALSE; + + g_set_error + ( error, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_UNKNOWN_PROPERTY, + "Failed to set value of unknown property \"%s\"", + property_name ); + } + else if(GPOINTER_TO_INT(g_hash_table_lookup(player->readonly_table, property_name))) + { + g_set_error + ( error, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_SET_READONLY, + "Attempted to set value of readonly property \"%s\"", + property_name ); + } + else if(g_strcmp0(property_name, "LoopStatus") == 0) { const gchar *loop = g_variant_get_string(value, NULL); const gchar *loop_file = g_strcmp0(loop, "Track") == 0 ? @@ -536,11 +588,7 @@ set_prop_handler( GDBusConnection *connection, NULL ); } - celluloid_mpris_module_set_properties( CELLULOID_MPRIS_MODULE(data), - property_name, value, - NULL ); - - return TRUE; /* This function should always succeed */ + return result; } static void @@ -840,8 +888,43 @@ celluloid_mpris_player_class_init(CelluloidMprisPlayerClass *klass) static void celluloid_mpris_player_init(CelluloidMprisPlayer *player) { - player->controller = NULL; - player->reg_id = 0; + const struct + { + const gchar *name; + gboolean readonly; + } + properties[] = + { + {"PlaybackStatus", TRUE}, + {"LoopStatus", FALSE}, + {"Rate", FALSE}, + {"Metadata", TRUE}, + {"Volume", FALSE}, + {"MinimumRate", TRUE}, + {"MaximumRate", TRUE}, + {"CanGoNext", TRUE}, + {"CanGoPrevious", TRUE}, + {"CanPlay", TRUE}, + {"CanPause", TRUE}, + {"CanSeek", TRUE}, + {"CanControl", TRUE}, + {NULL, FALSE} + }; + + player->controller = + NULL; + player->readonly_table = + g_hash_table_new_full(g_str_hash, g_int_equal, g_free, NULL); + player->reg_id = + 0; + + for(gint i = 0; properties[i].name; i++) + { + g_hash_table_replace + ( player->readonly_table, + g_strdup(properties[i].name), + GINT_TO_POINTER(properties[i].readonly) ); + } } CelluloidMprisModule * diff --git a/src/mpris/celluloid-mpris-track-list.c b/src/mpris/celluloid-mpris-track-list.c index 7b5d8c5..7784ad2 100644 --- a/src/mpris/celluloid-mpris-track-list.c +++ b/src/mpris/celluloid-mpris-track-list.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 gnome-mpv + * Copyright (c) 2017-2019, 2021 gnome-mpv * * This file is part of Celluloid. * @@ -19,6 +19,7 @@ #include "celluloid-mpris-track-list.h" #include "celluloid-mpris-gdbus.h" +#include "celluloid-mpris.h" #include "celluloid-common.h" #include "celluloid-def.h" @@ -35,6 +36,7 @@ struct _CelluloidMprisTrackList { CelluloidMprisModule parent; CelluloidController *controller; + GHashTable *readonly_table; guint reg_id; }; @@ -226,6 +228,7 @@ method_handler( GDBusConnection *connection, CelluloidMprisTrackList *track_list = data; CelluloidModel *model = celluloid_controller_get_model (track_list->controller); + gboolean unknown_method = FALSE; GVariant *return_value = NULL; if(g_strcmp0(method_name, "GetTracksMetadata") == 0) @@ -283,12 +286,22 @@ method_handler( GDBusConnection *connection, } else { - g_critical("Attempted to call unknown method: %s", method_name); - - return_value = g_variant_new("()", NULL); + unknown_method = TRUE; } - g_dbus_method_invocation_return_value(invocation, return_value); + if(unknown_method) + { + g_dbus_method_invocation_return_error + ( invocation, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_UNKNOWN_METHOD, + "Attempted to call unknown method \"%s\"", + method_name ); + } + else + { + g_dbus_method_invocation_return_value(invocation, return_value); + } } static GVariant * @@ -300,15 +313,25 @@ get_prop_handler( GDBusConnection *connection, GError **error, gpointer data ) { + CelluloidMprisTrackList *track_list = CELLULOID_MPRIS_TRACK_LIST(data); + CelluloidMprisModule *module = CELLULOID_MPRIS_MODULE(data); GVariant *value = NULL; - celluloid_mpris_module_get_properties( CELLULOID_MPRIS_MODULE(data), - property_name, &value, - NULL ); + if(!g_hash_table_contains(track_list->readonly_table, property_name)) + { + g_set_error + ( error, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_UNKNOWN_PROPERTY, + "Failed to get value of unknown property \"%s\"", + property_name ); + } + else + { + celluloid_mpris_module_get_properties + (module, property_name, &value, NULL); + } - /* Call g_variant_ref() to prevent the value of the property in the - * properties table from being freed. - */ return value?g_variant_ref(value):NULL; } @@ -322,10 +345,26 @@ set_prop_handler( GDBusConnection *connection, GError **error, gpointer data ) { - g_warning( "Attempted to set property %s in " - "org.mpris.MediaPlayer2.TrackList, but the interface " - "only has read-only properties.", - property_name ); + CelluloidMprisTrackList *track_list = CELLULOID_MPRIS_TRACK_LIST(data); + + if(!g_hash_table_contains(track_list->readonly_table, property_name)) + { + g_set_error + ( error, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_UNKNOWN_PROPERTY, + "Failed to set value of unknown property \"%s\"", + property_name ); + } + else if(GPOINTER_TO_INT(g_hash_table_lookup(track_list->readonly_table, property_name))) + { + g_set_error + ( error, + CELLULOID_MPRIS_ERROR, + CELLULOID_MPRIS_ERROR_SET_READONLY, + "Attempted to set value of readonly property \"%s\"", + property_name ); + } /* Always fail since the interface only has read-only properties */ return FALSE; @@ -576,8 +615,32 @@ celluloid_mpris_track_list_class_init(CelluloidMprisTrackListClass *klass) static void celluloid_mpris_track_list_init(CelluloidMprisTrackList *track_list) { - track_list->controller = NULL; - track_list->reg_id = 0; + const struct + { + const gchar *name; + gboolean readonly; + } + properties[] = + { + {"Tracks", TRUE}, + {"Fullscreen", TRUE}, + {NULL, FALSE} + }; + + track_list->controller = + NULL; + track_list->readonly_table = + g_hash_table_new_full(g_str_hash, g_int_equal, g_free, NULL); + track_list->reg_id = + 0; + + for(gint i = 0; properties[i].name; i++) + { + g_hash_table_replace + ( track_list->readonly_table, + g_strdup(properties[i].name), + GINT_TO_POINTER(properties[i].readonly) ); + } } CelluloidMprisModule * diff --git a/src/mpris/celluloid-mpris.c b/src/mpris/celluloid-mpris.c index 053aa4c..5d14065 100644 --- a/src/mpris/celluloid-mpris.c +++ b/src/mpris/celluloid-mpris.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 gnome-mpv + * Copyright (c) 2015-2019, 2021 gnome-mpv * * This file is part of Celluloid. * @@ -55,6 +55,8 @@ struct _CelluloidMprisClass G_DEFINE_TYPE(CelluloidMpris, celluloid_mpris, G_TYPE_OBJECT) +G_DEFINE_QUARK(celluloid-mpris-error-quark, celluloid_mpris_error) + static void constructed(GObject *object); @@ -73,11 +75,6 @@ get_property( GObject *object, GValue *value, GParamSpec *pspec ); -static void -name_acquired_handler( GDBusConnection *connection, - const gchar *name, - gpointer data ); - static void name_lost_handler( GDBusConnection *connection, const gchar *name, @@ -119,12 +116,23 @@ constructed(GObject *object) gchar *name = g_strdup_printf (MPRIS_BUS_NAME ".instance-%u", window_id); + self->session_bus_conn = conn; + self->base = celluloid_mpris_base_new + (self->controller, conn); + self->player = celluloid_mpris_player_new + (self->controller, conn); + self->track_list = celluloid_mpris_track_list_new + (self->controller, conn); + + celluloid_mpris_module_register(self->base); + celluloid_mpris_module_register(self->player); + celluloid_mpris_module_register(self->track_list); + self->name_id = g_bus_own_name_on_connection ( conn, name, G_BUS_NAME_OWNER_FLAGS_NONE, - (GBusNameAcquiredCallback) - name_acquired_handler, + NULL, (GBusNameLostCallback) name_lost_handler, self, @@ -197,26 +205,6 @@ get_property( GObject *object, } -static void -name_acquired_handler( GDBusConnection *connection, - const gchar *name, - gpointer data ) -{ - CelluloidMpris *self = data; - - self->session_bus_conn = connection; - self->base = celluloid_mpris_base_new - (self->controller, connection); - self->player = celluloid_mpris_player_new - (self->controller, connection); - self->track_list = celluloid_mpris_track_list_new - (self->controller, connection); - - celluloid_mpris_module_register(self->base); - celluloid_mpris_module_register(self->player); - celluloid_mpris_module_register(self->track_list); -} - static void name_lost_handler( GDBusConnection *connection, const gchar *name, diff --git a/src/mpris/celluloid-mpris.h b/src/mpris/celluloid-mpris.h index 3ac9d57..6618f4b 100644 --- a/src/mpris/celluloid-mpris.h +++ b/src/mpris/celluloid-mpris.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 gnome-mpv + * Copyright (c) 2015-2019, 2021 gnome-mpv * * This file is part of Celluloid. * @@ -31,6 +31,19 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(CelluloidMpris, celluloid_mpris, CELLULOID, MPRIS, GObject) +#define CELLULOID_MPRIS_ERROR celluloid_mpris_error_quark() + +enum +{ + CELLULOID_MPRIS_ERROR_UNKNOWN_METHOD, + CELLULOID_MPRIS_ERROR_UNKNOWN_PROPERTY, + CELLULOID_MPRIS_ERROR_SET_READONLY, + CELLULOID_MPRIS_ERROR_FAILED +}; + +GQuark +celluloid_mpris_error_quark(void); + GVariant * celluloid_mpris_build_g_variant_string_array(const gchar** list);