Merge pull request #558 from Rafostar/tagged

clapper: Add taglist to media items
This commit is contained in:
Rafał Dzięgiel
2025-06-08 17:43:12 +02:00
committed by GitHub
7 changed files with 340 additions and 58 deletions

View File

@@ -43,6 +43,7 @@ struct _ClapperMediaItem
gchar *uri; gchar *uri;
gchar *suburi; gchar *suburi;
GstTagList *tags;
ClapperTimeline *timeline; ClapperTimeline *timeline;
guint id; guint id;
@@ -56,6 +57,13 @@ struct _ClapperMediaItem
gboolean used; gboolean used;
}; };
typedef struct
{
ClapperMediaItem *item;
gboolean changed;
gboolean from_user;
} ClapperMediaItemTagIterData;
enum enum
{ {
PROP_0, PROP_0,
@@ -63,6 +71,7 @@ enum
PROP_URI, PROP_URI,
PROP_SUBURI, PROP_SUBURI,
PROP_CACHE_LOCATION, PROP_CACHE_LOCATION,
PROP_TAGS,
PROP_TITLE, PROP_TITLE,
PROP_CONTAINER_FORMAT, PROP_CONTAINER_FORMAT,
PROP_DURATION, PROP_DURATION,
@@ -111,8 +120,8 @@ clapper_media_item_new (const gchar *uri)
/* FIXME: Set initial container format from file extension parsing */ /* FIXME: Set initial container format from file extension parsing */
GST_TRACE_OBJECT (item, "New media item, ID: %u, URI: %s, title: %s", GST_TRACE_OBJECT (item, "New media item, ID: %u, URI: \"%s\", title: \"%s\"",
item->id, item->uri, item->title); item->id, item->uri, GST_STR_NULL (item->title));
return item; return item;
} }
@@ -258,27 +267,6 @@ clapper_media_item_get_suburi (ClapperMediaItem *self)
return suburi; return suburi;
} }
static gboolean
clapper_media_item_take_title (ClapperMediaItem *self, gchar *title,
ClapperAppBus *app_bus)
{
gboolean changed;
GST_OBJECT_LOCK (self);
if ((changed = g_strcmp0 (self->title, title) != 0)) {
g_free (self->title);
self->title = title;
}
GST_OBJECT_UNLOCK (self);
if (changed)
clapper_app_bus_post_prop_notify (app_bus, GST_OBJECT_CAST (self), param_specs[PROP_TITLE]);
else
g_free (title);
return changed;
}
/** /**
* clapper_media_item_get_title: * clapper_media_item_get_title:
* @item: a #ClapperMediaItem * @item: a #ClapperMediaItem
@@ -305,25 +293,24 @@ clapper_media_item_get_title (ClapperMediaItem *self)
return title; return title;
} }
static gboolean static inline gboolean
clapper_media_item_take_container_format (ClapperMediaItem *self, gchar *container_format, _refresh_tag_prop_unlocked (ClapperMediaItem *self, const gchar *tag,
ClapperAppBus *app_bus) gboolean from_user, gchar **tag_ptr)
{ {
gboolean changed; const gchar *string;
GST_OBJECT_LOCK (self); if ((*tag_ptr && from_user) // if already set, user cannot modify it
if ((changed = g_strcmp0 (self->container_format, container_format) != 0)) { || !gst_tag_list_peek_string_index (self->tags, tag, 0, &string) // guarantees non-empty string
g_free (self->container_format); || (g_strcmp0 (*tag_ptr, string) == 0))
self->container_format = container_format; return FALSE;
}
GST_OBJECT_UNLOCK (self);
if (changed) GST_LOG_OBJECT (self, "Tag prop \"%s\" update: \"%s\" -> \"%s\"",
clapper_app_bus_post_prop_notify (app_bus, GST_OBJECT_CAST (self), param_specs[PROP_CONTAINER_FORMAT]); tag, GST_STR_NULL (*tag_ptr), string);
else
g_free (container_format);
return changed; g_free (*tag_ptr);
*tag_ptr = g_strdup (string);
return TRUE;
} }
/** /**
@@ -333,6 +320,8 @@ clapper_media_item_take_container_format (ClapperMediaItem *self, gchar *contain
* Get media item container format. * Get media item container format.
* *
* Returns: (transfer full) (nullable): media container format. * Returns: (transfer full) (nullable): media container format.
*
* Deprecated: 0.10: Get `container-format` from [property@Clapper.MediaItem:tags] instead.
*/ */
gchar * gchar *
clapper_media_item_get_container_format (ClapperMediaItem *self) clapper_media_item_get_container_format (ClapperMediaItem *self)
@@ -389,11 +378,207 @@ clapper_media_item_get_duration (ClapperMediaItem *self)
return duration; return duration;
} }
/**
* clapper_media_item_get_tags:
* @item: a #ClapperMediaItem
*
* Get readable list of tags stored in media item.
*
* Returns: (transfer full): a #GstTagList.
*
* Since: 0.10
*/
GstTagList *
clapper_media_item_get_tags (ClapperMediaItem *self)
{
GstTagList *tags = NULL;
g_return_val_if_fail (CLAPPER_IS_MEDIA_ITEM (self), NULL);
GST_OBJECT_LOCK (self);
tags = gst_tag_list_ref (self->tags);
GST_OBJECT_UNLOCK (self);
return tags;
}
static void
_tags_replace_func (const GstTagList *tags, const gchar *tag, ClapperMediaItemTagIterData *data)
{
ClapperMediaItem *self = data->item;
guint index = 0;
gboolean replace = FALSE;
while (TRUE) {
const GValue *old_value = gst_tag_list_get_value_index (self->tags, tag, index);
const GValue *new_value = gst_tag_list_get_value_index (tags, tag, index);
/* Number of old values is the same or greater and
* all values until this iteration were the same */
if (!new_value)
break;
/* A wild new tag appeared */
if (!old_value) {
replace = TRUE;
break;
}
/* Users can only set non-existing tags */
if (data->from_user)
break;
/* Check with tolerance for doubles */
if (G_VALUE_TYPE (old_value) == G_TYPE_DOUBLE
&& G_VALUE_TYPE (new_value) == G_TYPE_DOUBLE) {
gdouble old_dbl, new_dbl;
old_dbl = g_value_get_double (old_value);
new_dbl = g_value_get_double (new_value);
if ((replace = !G_APPROX_VALUE (old_dbl, new_dbl, FLT_EPSILON)))
break;
} else if (gst_value_compare (old_value, new_value) != GST_VALUE_EQUAL) {
replace = TRUE;
break;
}
++index;
}
if (replace) {
const GValue *value;
index = 0;
GST_LOG_OBJECT (self, "Replacing \"%s\" tag value", tag);
/* Ensure writable, but only when replacing something */
if (!data->changed) {
self->tags = gst_tag_list_make_writable (self->tags);
data->changed = TRUE;
}
/* Replace first tag value (so it becomes sole member) */
value = gst_tag_list_get_value_index (tags, tag, index);
gst_tag_list_add_value (self->tags, GST_TAG_MERGE_REPLACE, tag, value);
/* Append any remaining tags (so next time we iterate indexes will match) */
while ((value = gst_tag_list_get_value_index (tags, tag, ++index)))
gst_tag_list_add_value (self->tags, GST_TAG_MERGE_APPEND, tag, value);
}
}
static gboolean
clapper_media_item_insert_tags_internal (ClapperMediaItem *self, const GstTagList *tags,
ClapperAppBus *app_bus, gboolean from_user)
{
ClapperMediaItemTagIterData data;
gboolean title_changed = FALSE, cont_changed = FALSE;
GST_OBJECT_LOCK (self);
data.item = self;
data.changed = FALSE;
data.from_user = from_user;
if (G_LIKELY (tags != self->tags))
gst_tag_list_foreach (tags, (GstTagForeachFunc) _tags_replace_func, &data);
if (data.changed) {
title_changed = _refresh_tag_prop_unlocked (self, GST_TAG_TITLE,
from_user, &self->title);
cont_changed = _refresh_tag_prop_unlocked (self, GST_TAG_CONTAINER_FORMAT,
from_user, &self->container_format);
}
GST_OBJECT_UNLOCK (self);
if (!data.changed)
return FALSE;
if (app_bus) {
GstObject *src = GST_OBJECT_CAST (self);
clapper_app_bus_post_prop_notify (app_bus, src, param_specs[PROP_TAGS]);
if (title_changed)
clapper_app_bus_post_prop_notify (app_bus, src, param_specs[PROP_TITLE]);
if (cont_changed)
clapper_app_bus_post_prop_notify (app_bus, src, param_specs[PROP_CONTAINER_FORMAT]);
} else {
GObject *src = G_OBJECT (self);
clapper_utils_prop_notify_on_main_sync (src, param_specs[PROP_TAGS]);
if (title_changed)
clapper_utils_prop_notify_on_main_sync (src, param_specs[PROP_TITLE]);
if (cont_changed)
clapper_utils_prop_notify_on_main_sync (src, param_specs[PROP_CONTAINER_FORMAT]);
}
return TRUE;
}
/**
* clapper_media_item_populate_tags:
* @item: a #ClapperMediaItem
* @tags: a #GstTagList of GLOBAL scope
*
* Populate non-existing tags in @item tag list.
*
* Passed @tags must use [enum@Gst.TagScope.GLOBAL] scope.
*
* Note that tags are automatically determined during media playback
* and those take precedence. This function can be useful if an app can
* determine some tags that are not in media metadata or for filling
* item with some initial/cached tags to display in UI before playback.
*
* When a tag already exists in the tag list (was populated) this
* function will not overwrite it. If you really need to permanently
* override some tags in media, you can use `taginject` element as
* player video/audio filter instead.
*
* Returns: whether at least one tag got updated.
*
* Since: 0.10
*/
gboolean
clapper_media_item_populate_tags (ClapperMediaItem *self, const GstTagList *tags)
{
ClapperPlayer *player;
ClapperAppBus *app_bus = NULL;
gboolean changed;
g_return_val_if_fail (CLAPPER_IS_MEDIA_ITEM (self), FALSE);
g_return_val_if_fail (tags != NULL, FALSE);
if (G_UNLIKELY (gst_tag_list_get_scope (tags) != GST_TAG_SCOPE_GLOBAL)) {
g_warning ("Cannot populate media item tags using a list with non-global tag scope");
return FALSE;
}
if ((player = clapper_player_get_from_ancestor (GST_OBJECT_CAST (self))))
app_bus = player->app_bus;
changed = clapper_media_item_insert_tags_internal (self, tags, app_bus, TRUE);
if (changed && player) {
ClapperFeaturesManager *features_manager;
if ((features_manager = clapper_player_get_features_manager (player)))
clapper_features_manager_trigger_item_updated (features_manager, self);
}
gst_clear_object (&player);
return changed;
}
/** /**
* clapper_media_item_get_timeline: * clapper_media_item_get_timeline:
* @item: a #ClapperMediaItem * @item: a #ClapperMediaItem
* *
* Get the [class@Clapper.Timeline] assosiated with @item. * Get the [class@Clapper.Timeline] associated with @item.
* *
* Returns: (transfer none): a #ClapperTimeline of item. * Returns: (transfer none): a #ClapperTimeline of item.
*/ */
@@ -405,21 +590,6 @@ clapper_media_item_get_timeline (ClapperMediaItem *self)
return self->timeline; return self->timeline;
} }
static gboolean
clapper_media_item_update_from_container_tags (ClapperMediaItem *self, const GstTagList *tags,
ClapperAppBus *app_bus)
{
gchar *string = NULL;
gboolean changed = FALSE;
if (gst_tag_list_get_string (tags, GST_TAG_CONTAINER_FORMAT, &string))
changed |= clapper_media_item_take_container_format (self, string, app_bus);
if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &string))
changed |= clapper_media_item_take_title (self, string, app_bus);
return changed;
}
void void
clapper_media_item_update_from_tag_list (ClapperMediaItem *self, const GstTagList *tags, clapper_media_item_update_from_tag_list (ClapperMediaItem *self, const GstTagList *tags,
ClapperPlayer *player) ClapperPlayer *player)
@@ -427,7 +597,7 @@ clapper_media_item_update_from_tag_list (ClapperMediaItem *self, const GstTagLis
GstTagScope scope = gst_tag_list_get_scope (tags); GstTagScope scope = gst_tag_list_get_scope (tags);
if (scope == GST_TAG_SCOPE_GLOBAL) { if (scope == GST_TAG_SCOPE_GLOBAL) {
gboolean changed = clapper_media_item_update_from_container_tags (self, tags, player->app_bus); gboolean changed = clapper_media_item_insert_tags_internal (self, tags, player->app_bus, FALSE);
if (changed) { if (changed) {
ClapperFeaturesManager *features_manager; ClapperFeaturesManager *features_manager;
@@ -459,7 +629,7 @@ clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDisco
GstDiscovererContainerInfo *cinfo = (GstDiscovererContainerInfo *) sinfo; GstDiscovererContainerInfo *cinfo = (GstDiscovererContainerInfo *) sinfo;
if ((tags = gst_discoverer_container_info_get_tags (cinfo))) if ((tags = gst_discoverer_container_info_get_tags (cinfo)))
changed |= clapper_media_item_update_from_container_tags (self, tags, player->app_bus); changed |= clapper_media_item_insert_tags_internal (self, tags, player->app_bus, FALSE);
} }
gst_discoverer_stream_info_unref (sinfo); gst_discoverer_stream_info_unref (sinfo);
} }
@@ -542,6 +712,9 @@ clapper_media_item_get_used (ClapperMediaItem *self)
static void static void
clapper_media_item_init (ClapperMediaItem *self) clapper_media_item_init (ClapperMediaItem *self)
{ {
self->tags = gst_tag_list_new_empty ();
gst_tag_list_set_scope (self->tags, GST_TAG_SCOPE_GLOBAL);
self->timeline = clapper_timeline_new (); self->timeline = clapper_timeline_new ();
gst_object_set_parent (GST_OBJECT_CAST (self->timeline), GST_OBJECT_CAST (self)); gst_object_set_parent (GST_OBJECT_CAST (self->timeline), GST_OBJECT_CAST (self));
} }
@@ -571,6 +744,8 @@ clapper_media_item_finalize (GObject *object)
g_free (self->title); g_free (self->title);
g_free (self->container_format); g_free (self->container_format);
gst_tag_list_unref (self->tags);
gst_object_unparent (GST_OBJECT_CAST (self->timeline)); gst_object_unparent (GST_OBJECT_CAST (self->timeline));
gst_object_unref (self->timeline); gst_object_unref (self->timeline);
@@ -617,6 +792,9 @@ clapper_media_item_get_property (GObject *object, guint prop_id,
case PROP_SUBURI: case PROP_SUBURI:
g_value_take_string (value, clapper_media_item_get_suburi (self)); g_value_take_string (value, clapper_media_item_get_suburi (self));
break; break;
case PROP_TAGS:
g_value_take_boxed (value, clapper_media_item_get_tags (self));
break;
case PROP_TITLE: case PROP_TITLE:
g_value_take_string (value, clapper_media_item_get_title (self)); g_value_take_string (value, clapper_media_item_get_title (self));
break; break;
@@ -686,10 +864,27 @@ clapper_media_item_class_init (ClapperMediaItemClass *klass)
NULL, NULL, NULL, NULL, NULL, NULL,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperMediaItem:tags:
*
* A readable list of tags stored in media item.
*
* Since: 0.10
*/
param_specs[PROP_TAGS] = g_param_spec_boxed ("tags",
NULL, NULL, GST_TYPE_TAG_LIST,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/* FIXME: 1.0: Consider rename to e.g. "(menu/display)-title"
* and also make it non-nullable (return URI as final fallback) */
/** /**
* ClapperMediaItem:title: * ClapperMediaItem:title:
* *
* Media title. * Media title.
*
* This might be a different string compared to `title` from
* [property@Clapper.MediaItem:tags], as this gives parsed
* title from file name/URI as fallback when no `title` tag.
*/ */
param_specs[PROP_TITLE] = g_param_spec_string ("title", param_specs[PROP_TITLE] = g_param_spec_string ("title",
NULL, NULL, NULL, NULL, NULL, NULL,
@@ -699,15 +894,21 @@ clapper_media_item_class_init (ClapperMediaItemClass *klass)
* ClapperMediaItem:container-format: * ClapperMediaItem:container-format:
* *
* Media container format. * Media container format.
*
* Deprecated: 0.10: Get `container-format` from [property@Clapper.MediaItem:tags] instead.
*/ */
param_specs[PROP_CONTAINER_FORMAT] = g_param_spec_string ("container-format", param_specs[PROP_CONTAINER_FORMAT] = g_param_spec_string ("container-format",
NULL, NULL, NULL, NULL, NULL, NULL,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED);
/** /**
* ClapperMediaItem:duration: * ClapperMediaItem:duration:
* *
* Media duration as a decimal number in seconds. * Media duration as a decimal number in seconds.
*
* This might be a different value compared to `duration` from
* [property@Clapper.MediaItem:tags], as this value is updated
* during decoding instead of being a fixed value from metadata.
*/ */
param_specs[PROP_DURATION] = g_param_spec_double ("duration", param_specs[PROP_DURATION] = g_param_spec_double ("duration",
NULL, NULL, 0, G_MAXDOUBLE, 0, NULL, NULL, 0, G_MAXDOUBLE, 0,

View File

@@ -27,6 +27,7 @@
#include <glib-object.h> #include <glib-object.h>
#include <gio/gio.h> #include <gio/gio.h>
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/tag/tag.h>
#include <clapper/clapper-visibility.h> #include <clapper/clapper-visibility.h>
#include <clapper/clapper-timeline.h> #include <clapper/clapper-timeline.h>
@@ -63,12 +64,18 @@ gchar * clapper_media_item_get_suburi (ClapperMediaItem *item);
CLAPPER_API CLAPPER_API
gchar * clapper_media_item_get_title (ClapperMediaItem *item); gchar * clapper_media_item_get_title (ClapperMediaItem *item);
CLAPPER_API CLAPPER_DEPRECATED_FOR(clapper_media_item_get_tags)
gchar * clapper_media_item_get_container_format (ClapperMediaItem *item); gchar * clapper_media_item_get_container_format (ClapperMediaItem *item);
CLAPPER_API CLAPPER_API
gdouble clapper_media_item_get_duration (ClapperMediaItem *item); gdouble clapper_media_item_get_duration (ClapperMediaItem *item);
CLAPPER_API
GstTagList * clapper_media_item_get_tags (ClapperMediaItem *item);
CLAPPER_API
gboolean clapper_media_item_populate_tags (ClapperMediaItem *item, const GstTagList *tags);
CLAPPER_API CLAPPER_API
ClapperTimeline * clapper_media_item_get_timeline (ClapperMediaItem *item); ClapperTimeline * clapper_media_item_get_timeline (ClapperMediaItem *item);

View File

@@ -45,6 +45,9 @@ void clapper_utils_queue_remove_on_main_sync (ClapperQueue *queue, ClapperMediaI
G_GNUC_INTERNAL G_GNUC_INTERNAL
void clapper_utils_queue_clear_on_main_sync (ClapperQueue *queue); void clapper_utils_queue_clear_on_main_sync (ClapperQueue *queue);
G_GNUC_INTERNAL
void clapper_utils_prop_notify_on_main_sync (GObject *object, GParamSpec *pspec);
G_GNUC_INTERNAL G_GNUC_INTERNAL
gchar * clapper_utils_uri_from_file (GFile *file); gchar * clapper_utils_uri_from_file (GFile *file);

View File

@@ -39,6 +39,12 @@ typedef struct
ClapperUtilsQueueAlterMethod method; ClapperUtilsQueueAlterMethod method;
} ClapperUtilsQueueAlterData; } ClapperUtilsQueueAlterData;
typedef struct
{
GObject *object;
GParamSpec *pspec;
} ClapperUtilsPropNotifyData;
void void
clapper_utils_initialize (void) clapper_utils_initialize (void)
{ {
@@ -71,6 +77,27 @@ clapper_utils_queue_alter_data_free (ClapperUtilsQueueAlterData *data)
g_free (data); g_free (data);
} }
static ClapperUtilsPropNotifyData *
clapper_utils_prop_notify_data_new (GObject *object, GParamSpec *pspec)
{
ClapperUtilsPropNotifyData *data = g_new (ClapperUtilsPropNotifyData, 1);
data->object = object;
data->pspec = pspec;
GST_TRACE ("Created prop notify data: %p", data);
return data;
}
static void
clapper_utils_prop_notify_data_free (ClapperUtilsPropNotifyData *data)
{
GST_TRACE ("Freeing prop notify data: %p", data);
g_free (data);
}
static gpointer static gpointer
clapper_utils_queue_alter_on_main (ClapperUtilsQueueAlterData *data) clapper_utils_queue_alter_on_main (ClapperUtilsQueueAlterData *data)
{ {
@@ -110,6 +137,15 @@ clapper_utils_queue_alter_on_main (ClapperUtilsQueueAlterData *data)
return NULL; return NULL;
} }
static gpointer
clapper_utils_prop_notify_on_main (ClapperUtilsPropNotifyData *data)
{
GST_DEBUG ("Prop notify invoked");
g_object_notify_by_pspec (data->object, data->pspec);
return NULL;
}
static inline void static inline void
clapper_utils_queue_alter_invoke_on_main_sync_take (ClapperUtilsQueueAlterData *data) clapper_utils_queue_alter_invoke_on_main_sync_take (ClapperUtilsQueueAlterData *data)
{ {
@@ -155,6 +191,27 @@ clapper_utils_queue_clear_on_main_sync (ClapperQueue *queue)
clapper_utils_queue_alter_invoke_on_main_sync_take (data); clapper_utils_queue_alter_invoke_on_main_sync_take (data);
} }
void
clapper_utils_prop_notify_on_main_sync (GObject *object, GParamSpec *pspec)
{
ClapperUtilsPropNotifyData *data;
if (g_main_context_is_owner (g_main_context_default ())) { // already in main thread
g_object_notify_by_pspec (object, pspec);
return;
}
data = clapper_utils_prop_notify_data_new (object, pspec);
GST_DEBUG ("Invoking prop notify on main...");
clapper_shared_utils_context_invoke_sync_full (g_main_context_default (),
(GThreadFunc) clapper_utils_prop_notify_on_main, data,
(GDestroyNotify) clapper_utils_prop_notify_data_free);
GST_DEBUG ("Prop notify invoke finished");
}
gchar * gchar *
clapper_utils_uri_from_file (GFile *file) clapper_utils_uri_from_file (GFile *file)
{ {

View File

@@ -235,6 +235,7 @@ if build_gir
clapper_enums, clapper_enums,
], ],
extra_args: [ extra_args: [
gir_init_section,
'--quiet', '--quiet',
'--warn-all', '--warn-all',
'-DCLAPPER_COMPILATION', '-DCLAPPER_COMPILATION',

View File

@@ -4,6 +4,13 @@ build_gir = (gir.found() and not get_option('introspection').disabled())
vapigen = find_program('vapigen', required: get_option('vapi')) vapigen = find_program('vapigen', required: get_option('vapi'))
build_vapi = (vapigen.found() and not get_option('vapi').disabled()) build_vapi = (vapigen.found() and not get_option('vapi').disabled())
gir_init_section = '--add-init-section=extern void gst_init(gint*,gchar**);' + \
'g_setenv("GST_REGISTRY_DISABLE", "yes", TRUE);' + \
'g_setenv("GST_REGISTRY_1_0", "@0@", TRUE);'.format(meson.current_build_dir() + '/gir_empty_registry.reg') + \
'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \
'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \
'gst_init(NULL,NULL);'
subdir('gst') subdir('gst')
subdir('clapper') subdir('clapper')
subdir('clapper-gtk') subdir('clapper-gtk')

View File

@@ -41,5 +41,11 @@
#endif #endif
#define @CLAPPER_API@_API _@CLAPPER_API@_VISIBILITY #define @CLAPPER_API@_API _@CLAPPER_API@_VISIBILITY
#if !defined(@CLAPPER_API@_COMPILATION)
#define @CLAPPER_API@_DEPRECATED G_DEPRECATED _@CLAPPER_API@_VISIBILITY #define @CLAPPER_API@_DEPRECATED G_DEPRECATED _@CLAPPER_API@_VISIBILITY
#define @CLAPPER_API@_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _@CLAPPER_API@_VISIBILITY #define @CLAPPER_API@_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _@CLAPPER_API@_VISIBILITY
#else
#define @CLAPPER_API@_DEPRECATED _@CLAPPER_API@_VISIBILITY
#define @CLAPPER_API@_DEPRECATED_FOR(f) _@CLAPPER_API@_VISIBILITY
#endif