From a3002b148c67760bf064f9600ef31c7549511d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Fernandes?= Date: Fri, 5 Aug 2022 19:40:17 +0100 Subject: libnautilus-extension: Introduce model-based properties extensions This is meant to replace the existing GtkWidget-based solution. Part of https://gitlab.gnome.org/GNOME/nautilus/-/issues/2365 --- libnautilus-extension/meson.build | 6 + libnautilus-extension/nautilus-extension.h | 3 + libnautilus-extension/nautilus-properties-item.c | 149 ++++++++++++++++++ libnautilus-extension/nautilus-properties-item.h | 61 ++++++++ .../nautilus-properties-model-provider.c | 29 ++++ .../nautilus-properties-model-provider.h | 66 ++++++++ libnautilus-extension/nautilus-properties-model.c | 167 +++++++++++++++++++++ libnautilus-extension/nautilus-properties-model.h | 71 +++++++++ 8 files changed, 552 insertions(+) create mode 100644 libnautilus-extension/nautilus-properties-item.c create mode 100644 libnautilus-extension/nautilus-properties-item.h create mode 100644 libnautilus-extension/nautilus-properties-model-provider.c create mode 100644 libnautilus-extension/nautilus-properties-model-provider.h create mode 100644 libnautilus-extension/nautilus-properties-model.c create mode 100644 libnautilus-extension/nautilus-properties-model.h (limited to 'libnautilus-extension') diff --git a/libnautilus-extension/meson.build b/libnautilus-extension/meson.build index 8450873de..27f21a5b5 100644 --- a/libnautilus-extension/meson.build +++ b/libnautilus-extension/meson.build @@ -7,6 +7,9 @@ libnautilus_extension_headers = [ 'nautilus-info-provider.h', 'nautilus-location-widget-provider.h', 'nautilus-menu-provider.h', + 'nautilus-properties-model-provider.h', + 'nautilus-properties-model.h', + 'nautilus-properties-item.h', 'nautilus-property-page-provider.h', 'nautilus-property-page.h', 'nautilus-menu.h' @@ -42,6 +45,9 @@ libnautilus_extension_sources = [ 'nautilus-location-widget-provider.c', 'nautilus-menu-item.c', 'nautilus-menu-provider.c', + 'nautilus-properties-model-provider.c', + 'nautilus-properties-model.c', + 'nautilus-properties-item.c', 'nautilus-property-page-provider.c', 'nautilus-property-page.c', 'nautilus-menu.c' diff --git a/libnautilus-extension/nautilus-extension.h b/libnautilus-extension/nautilus-extension.h index 894322eb9..af3f67837 100644 --- a/libnautilus-extension/nautilus-extension.h +++ b/libnautilus-extension/nautilus-extension.h @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/libnautilus-extension/nautilus-properties-item.c b/libnautilus-extension/nautilus-properties-item.c new file mode 100644 index 000000000..8731274a4 --- /dev/null +++ b/libnautilus-extension/nautilus-properties-item.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2022 António Fernandes + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include "nautilus-properties-item.h" + +enum +{ + PROP_0, + PROP_NAME, + PROP_VALUE, + LAST_PROP +}; + +struct _NautilusPropertiesItem +{ + GObject parent_instance; + + char *name; + char *value; +}; + +G_DEFINE_TYPE (NautilusPropertiesItem, nautilus_properties_item, G_TYPE_OBJECT) + +NautilusPropertiesItem * +nautilus_properties_item_new (const char *name, + const char *value) +{ + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + return g_object_new (NAUTILUS_TYPE_PROPERTIES_ITEM, + "name", name, + "value", value, + NULL); +} + +static void +nautilus_properties_item_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + NautilusPropertiesItem *self = NAUTILUS_PROPERTIES_ITEM (object); + + switch (param_id) + { + case PROP_NAME: + { + g_value_set_string (value, self->name); + } + break; + + case PROP_VALUE: + { + g_value_set_string (value, self->value); + } + break; + + default: + { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + } + break; + } +} + +static void +nautilus_properties_item_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + NautilusPropertiesItem *self = NAUTILUS_PROPERTIES_ITEM (object); + + switch (param_id) + { + case PROP_NAME: + { + g_free (self->name); + self->name = g_value_dup_string (value); + } + break; + + case PROP_VALUE: + { + g_free (self->value); + self->value = g_value_dup_string (value); + } + break; + + default: + { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + } + break; + } +} + +static void +nautilus_properties_item_finalize (GObject *object) +{ + NautilusPropertiesItem *self = NAUTILUS_PROPERTIES_ITEM (object); + + g_free (self->name); + g_free (self->value); + + G_OBJECT_CLASS (nautilus_properties_item_parent_class)->finalize (object); +} + +static void +nautilus_properties_item_init (NautilusPropertiesItem *self) +{ +} + +static void +nautilus_properties_item_class_init (NautilusPropertiesItemClass *class) +{ + GParamSpec *pspec; + + G_OBJECT_CLASS (class)->finalize = nautilus_properties_item_finalize; + G_OBJECT_CLASS (class)->get_property = nautilus_properties_item_get_property; + G_OBJECT_CLASS (class)->set_property = nautilus_properties_item_set_property; + + pspec = g_param_spec_string ("name", "", "", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (G_OBJECT_CLASS (class), PROP_NAME, pspec); + + pspec = g_param_spec_string ("value", "", "", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (G_OBJECT_CLASS (class), PROP_VALUE, pspec); +} + +const char * +nautilus_properties_item_get_name (NautilusPropertiesItem *self) +{ + return self->name; +} + +const char * +nautilus_properties_item_get_value (NautilusPropertiesItem *self) +{ + return self->value; +} diff --git a/libnautilus-extension/nautilus-properties-item.h b/libnautilus-extension/nautilus-properties-item.h new file mode 100644 index 000000000..5191816cd --- /dev/null +++ b/libnautilus-extension/nautilus-properties-item.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 António Fernandes + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#if !defined (NAUTILUS_EXTENSION_H) && !defined (NAUTILUS_COMPILATION) +#warning "Only should be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_PROPERTIES_ITEM (nautilus_properties_item_get_type ()) + +G_DECLARE_FINAL_TYPE (NautilusPropertiesItem, + nautilus_properties_item, + NAUTILUS, PROPERTIES_ITEM, + GObject) + +/** + * SECTION:nautilus-properties-item + * @name: NautilusPropertiesItem + * @value: Properties item descriptor object + * + * #NautilusPropertiesItem is an object that describes a name & value pair in + * file properties. Extensions can provide #NautilusPropertiesItem objects in + * models provided by #NautilusPropertiesModel. + */ + +/** + * nautilus_properties_item_new: + * @name: the user-visible name for the properties item. + * @model: the user-visible value for the properties item. + * + * Returns: (transfer full): a new #NautilusPropertiesItem + */ +NautilusPropertiesItem *nautilus_properties_item_new (const char *name, + const char *value); + +/** + * nautilus_properties_item_get_name: + * @item: the properties item + * + * Returns: (transfer none): the name of this #NautilusPropertiesItem + */ +const char *nautilus_properties_item_get_name (NautilusPropertiesItem *self); + +/** + * nautilus_properties_item_get_value: + * @item: the properties item + * + * Returns: (transfer none): the value of this #NautilusPropertiesItem + */ +const char * nautilus_properties_item_get_value (NautilusPropertiesItem *self); + + +G_END_DECLS diff --git a/libnautilus-extension/nautilus-properties-model-provider.c b/libnautilus-extension/nautilus-properties-model-provider.c new file mode 100644 index 000000000..4ade1105c --- /dev/null +++ b/libnautilus-extension/nautilus-properties-model-provider.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 The GNOME project contributors + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "nautilus-properties-model-provider.h" + +G_DEFINE_INTERFACE (NautilusPropertiesModelProvider, nautilus_properties_model_provider, G_TYPE_OBJECT) + +static void +nautilus_properties_model_provider_default_init (NautilusPropertiesModelProviderInterface *klass) +{ +} + +GList * +nautilus_properties_model_provider_get_models (NautilusPropertiesModelProvider *self, + GList *files) +{ + NautilusPropertiesModelProviderInterface *iface; + + g_return_val_if_fail (NAUTILUS_IS_PROPERTIES_MODEL_PROVIDER (self), NULL); + + iface = NAUTILUS_PROPERTIES_MODEL_PROVIDER_GET_IFACE (self); + + g_return_val_if_fail (iface->get_models != NULL, NULL); + + return iface->get_models (self, files); +} diff --git a/libnautilus-extension/nautilus-properties-model-provider.h b/libnautilus-extension/nautilus-properties-model-provider.h new file mode 100644 index 000000000..6caebd113 --- /dev/null +++ b/libnautilus-extension/nautilus-properties-model-provider.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 The GNOME project contributors + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#if !defined (NAUTILUS_EXTENSION_H) && !defined (NAUTILUS_COMPILATION) +#warning "Only should be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_PROPERTIES_MODEL_PROVIDER (nautilus_properties_model_provider_get_type ()) + +G_DECLARE_INTERFACE (NautilusPropertiesModelProvider, + nautilus_properties_model_provider, + NAUTILUS, PROPERTIES_MODEL_PROVIDER, + GObject) + +/** + * SECTION:nautilus-properties-model-provider + * @title: NautilusPropertiesModelProvider + * @short_description: Interface to provide additional properties + * + * #NautilusPropertiesModelProvider allows extension to provide additional + * information for the file properties. + */ + +/** + * NautilusPropertiesModelProviderInterface: + * @g_iface: The parent interface. + * @get_models: Returns a #GList of #NautilusPropertiesModel. + * See nautilus_properties_model_provider_get_models() for details. + * + * Interface for extensions to provide additional properties. + */ +struct _NautilusPropertiesModelProviderInterface +{ + GTypeInterface g_iface; + + GList *(*get_models) (NautilusPropertiesModelProvider *provider, + GList *files); +}; + +/** + * nautilus_properties_model_provider_get_models: + * @provider: a #NautilusPropertiesModelProvider + * @files: (element-type NautilusFileInfo): a #GList of #NautilusFileInfo + * + * This function is called by the application when it wants properties models + * from the extension. + * + * This function is called in the main thread before the Properties are shown, + * so it should return quickly. The models can be populated and updated + * asynchronously. + * + * Returns: (nullable) (element-type NautilusPropertyModel) (transfer full): A #GList of allocated #NautilusPropertiesModel models. + */ +GList *nautilus_properties_model_provider_get_models (NautilusPropertiesModelProvider *provider, + GList *files); + +G_END_DECLS diff --git a/libnautilus-extension/nautilus-properties-model.c b/libnautilus-extension/nautilus-properties-model.c new file mode 100644 index 000000000..b222ae047 --- /dev/null +++ b/libnautilus-extension/nautilus-properties-model.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2022 The GNOME project contributors + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include "nautilus-properties-model.h" +#include "nautilus-properties-item.h" + +enum +{ + PROP_0, + PROP_TITLE, + PROP_MODEL, + LAST_PROP +}; + +struct _NautilusPropertiesModel +{ + GObject parent_instance; + + char *title; + GListModel *model; +}; + +G_DEFINE_TYPE (NautilusPropertiesModel, nautilus_properties_model, G_TYPE_OBJECT) + +NautilusPropertiesModel * +nautilus_properties_model_new (const char *title, + GListModel *model) +{ + g_return_val_if_fail (title != NULL, NULL); + g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL); + g_return_val_if_fail (g_list_model_get_item_type (model) == NAUTILUS_TYPE_PROPERTIES_ITEM, NULL); + + return g_object_new (NAUTILUS_TYPE_PROPERTIES_MODEL, + "title", title, + "model", model, + NULL); +} + +static void +nautilus_properties_model_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + NautilusPropertiesModel *self = NAUTILUS_PROPERTIES_MODEL (object); + + switch (param_id) + { + case PROP_TITLE: + { + g_value_set_string (value, self->title); + } + break; + + case PROP_MODEL: + { + g_value_set_object (value, self->model); + } + break; + + default: + { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + } + break; + } +} + +static void +nautilus_properties_model_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + NautilusPropertiesModel *self = NAUTILUS_PROPERTIES_MODEL (object); + + switch (param_id) + { + case PROP_TITLE: + { + g_free (self->title); + self->title = g_value_dup_string (value); + } + break; + + case PROP_MODEL: + { + g_set_object (&self->model, g_value_get_object (value)); + } + break; + + default: + { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + } + break; + } +} + +static void +nautilus_properties_model_dispose (GObject *object) +{ + NautilusPropertiesModel *self = NAUTILUS_PROPERTIES_MODEL (object); + + g_clear_object (&self->model); + + G_OBJECT_CLASS (nautilus_properties_model_parent_class)->dispose (object); +} + +static void +nautilus_properties_model_finalize (GObject *object) +{ + NautilusPropertiesModel *self = NAUTILUS_PROPERTIES_MODEL (object); + + g_free (self->title); + + G_OBJECT_CLASS (nautilus_properties_model_parent_class)->finalize (object); +} + +static void +nautilus_properties_model_init (NautilusPropertiesModel *self) +{ +} + +static void +nautilus_properties_model_class_init (NautilusPropertiesModelClass *class) +{ + GParamSpec *pspec; + + G_OBJECT_CLASS (class)->finalize = nautilus_properties_model_finalize; + G_OBJECT_CLASS (class)->dispose = nautilus_properties_model_dispose; + G_OBJECT_CLASS (class)->get_property = nautilus_properties_model_get_property; + G_OBJECT_CLASS (class)->set_property = nautilus_properties_model_set_property; + + pspec = g_param_spec_string ("title", "", "", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (G_OBJECT_CLASS (class), PROP_TITLE, pspec); + + pspec = g_param_spec_object ("model", "", "", + G_TYPE_LIST_MODEL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (G_OBJECT_CLASS (class), PROP_MODEL, pspec); +} + +const char * +nautilus_properties_model_get_title (NautilusPropertiesModel *self) +{ + return self->title; +} + +void +nautilus_properties_model_set_title (NautilusPropertiesModel *self, + const char *title) +{ + g_object_set (self, "title", title, NULL); +} + +GListModel * +nautilus_properties_model_get_model (NautilusPropertiesModel *self) +{ + return self->model; +} diff --git a/libnautilus-extension/nautilus-properties-model.h b/libnautilus-extension/nautilus-properties-model.h new file mode 100644 index 000000000..3b60ba928 --- /dev/null +++ b/libnautilus-extension/nautilus-properties-model.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 The GNOME project contributors + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#if !defined (NAUTILUS_EXTENSION_H) && !defined (NAUTILUS_COMPILATION) +#warning "Only should be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define NAUTILUS_TYPE_PROPERTIES_MODEL (nautilus_properties_model_get_type ()) + +G_DECLARE_FINAL_TYPE (NautilusPropertiesModel, + nautilus_properties_model, + NAUTILUS, PROPERTIES_MODEL, + GObject) + +/** + * SECTION:nautilus-properties-model + * @title: NautilusPropertiesModel + * @short_description: Properties set descriptor model + * + * #NautilusPropertiesModel is an model that describes a set of file properties. + * Extensions can provide #NautilusPropertiesModel objects by registering a + * #NautilusPropertiesModelProvider and returning them from + * nautilus_properties_model_provider_get_models(), which will be called by + * the main application when creating file properties. + */ + +/** + * nautilus_properties_model_new: + * @title: the user-visible name for the set of properties in this model + * @model: a #GListModel containing #NautilusPropertyItem objects. + * + * Returns: (transfer full): a new #NautilusPropertiesModel + */ +NautilusPropertiesModel *nautilus_properties_model_new (const char *title, + GListModel *model); + +/** + * nautilus_properties_model_get_title: + * @self: the properties model + * + * Returns: (transfer none): the title of this #NautilusPropertiesModel + */ +const char *nautilus_properties_model_get_title (NautilusPropertiesModel *self); + +/** + * nautilus_properties_model_set_title: + * @self: the properties model + * @title: the new title of this #NautilusPropertiesModel + */ +void nautilus_properties_model_set_title (NautilusPropertiesModel *self, + const char *title); + +/** + * nautilus_properties_model_get_model: + * @self: the properties model + * + * Returns: (transfer none): a #GListModel containing #NautilusPropertiesItem. + */ +GListModel * nautilus_properties_model_get_model (NautilusPropertiesModel *self); + + +G_END_DECLS -- cgit v1.2.1