# HG changeset patch
# Node ID bbae38830d3770b9a1c1d3b7e5f12eed1b4910f5
# Parent  409c424504a0234fb3279b14ebec0668dd32d434
diff --git a/gplugin-query/gplugin-query.c b/gplugin-query/gplugin-query.c
--- a/gplugin-query/gplugin-query.c
+++ b/gplugin-query/gplugin-query.c
@@ -119,6 +119,7 @@
 		GPluginPluginInfo *info = gplugin_plugin_get_info(plugin);
 		gboolean internal, loq, bind_global, unloadable;
 		guint32 abi_version;
+		char *discriminator = NULL;
 		char *name, *version;
 		char *license_id, *license_text, *license_url;
 		char *icon_name, *summary, *description, *category, *website;
@@ -140,6 +141,7 @@
 		g_object_get(
 			info,
 			"abi-version", &abi_version,
+			"discriminator", &discriminator,
 			"load-on-query", &loq,
 			"name", &name,
 			"version", &version,
@@ -196,6 +198,7 @@
 			GPluginLoader *loader = gplugin_plugin_get_loader(plugin);
 
 			g_print(MAIN_FORMAT_NEL "%08x\n", "abi version", abi_version);
+			g_print(MAIN_FORMAT, "discriminator", discriminator);
 			g_print(MAIN_FORMAT, "internal", (internal) ? "yes" : "no");
 			g_print(MAIN_FORMAT, "load on query", (loq) ? "yes" : "no");
 			g_print(MAIN_FORMAT, "bind globally", (bind_global) ? "yes" : "no");
@@ -221,6 +224,7 @@
 			}
 		}
 
+		g_free(discriminator);
 		g_free(name);
 		g_free(version);
 		g_free(license_id);
diff --git a/gplugin/gplugin-plugin-info.h b/gplugin/gplugin-plugin-info.h
--- a/gplugin/gplugin-plugin-info.h
+++ b/gplugin/gplugin-plugin-info.h
@@ -121,6 +121,9 @@
 const gchar *const *gplugin_plugin_info_get_dependencies(
 	GPluginPluginInfo *info);
 
+GPLUGIN_AVAILABLE_IN_0_44
+char *gplugin_plugin_info_get_discriminator(GPluginPluginInfo *info);
+
 GPLUGIN_AVAILABLE_IN_ALL
 gboolean gplugin_plugin_info_get_bind_global(GPluginPluginInfo *info);
 
diff --git a/gplugin/gplugin-plugin-info.c b/gplugin/gplugin-plugin-info.c
--- a/gplugin/gplugin-plugin-info.c
+++ b/gplugin/gplugin-plugin-info.c
@@ -38,6 +38,7 @@
  *****************************************************************************/
 typedef struct {
 	gchar *id;
+	guint32 discriminator;
 
 	gchar **provides;
 	gint priority;
@@ -74,6 +75,7 @@
 enum {
 	PROP_0,
 	PROP_ID,
+	PROP_DISCRIMINATOR,
 	PROP_PROVIDES,
 	PROP_PRIORITY,
 	PROP_ABI_VERSION,
@@ -350,6 +352,11 @@
 		case PROP_ID:
 			g_value_set_string(value, gplugin_plugin_info_get_id(info));
 			break;
+		case PROP_DISCRIMINATOR:
+			g_value_take_string(
+				value,
+				gplugin_plugin_info_get_discriminator(info));
+			break;
 		case PROP_PROVIDES:
 			g_value_set_boxed(value, gplugin_plugin_info_get_provides(info));
 			break;
@@ -555,8 +562,18 @@
 }
 
 static void
-gplugin_plugin_info_init(G_GNUC_UNUSED GPluginPluginInfo *info)
+gplugin_plugin_info_init(GPluginPluginInfo *info)
 {
+	GPluginPluginInfoPrivate *priv = NULL;
+	static guint32 discriminator = 0;
+
+	priv = gplugin_plugin_info_get_instance_private(info);
+	priv->discriminator = discriminator;
+
+	discriminator += 1;
+	if(discriminator < priv->discriminator) {
+		g_critical("plugin info discriminators have wrapped!");
+	}
 }
 
 static void
@@ -588,6 +605,22 @@
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
 	/**
+	 * GPluginPluginInfo:discriminator:
+	 *
+	 * A unique value that can be used to identify plugins with the same id.
+	 *
+	 * This is an opaque token and may change in the future.
+	 *
+	 * Since: 0.44
+	 */
+	properties[PROP_DISCRIMINATOR] = g_param_spec_string(
+		"discriminator",
+		NULL,
+		NULL,
+		NULL,
+		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+	/**
 	 * GPluginPluginInfo:provides:
 	 *
 	 * A list of additional plugin ids and versions that this plugin can
@@ -1389,6 +1422,28 @@
 }
 
 /**
+ * gplugin_plugin_info_get_discriminator:
+ * @info: The instance.
+ *
+ * Gets the discriminator from @info.
+ *
+ * Returns: (transfer full): The discriminator.
+ *
+ * Since: 0.44
+ */
+char *
+gplugin_plugin_info_get_discriminator(GPluginPluginInfo *info)
+{
+	GPluginPluginInfoPrivate *priv = NULL;
+
+	g_return_val_if_fail(GPLUGIN_IS_PLUGIN_INFO(info), NULL);
+
+	priv = gplugin_plugin_info_get_instance_private(info);
+
+	return g_strdup_printf("%08x", priv->discriminator);
+}
+
+/**
  * gplugin_plugin_info_get_bind_global:
  * @info: The plugin info instance.
  *
diff --git a/gplugin/tests/test-plugin-info.c b/gplugin/tests/test-plugin-info.c
--- a/gplugin/tests/test-plugin-info.c
+++ b/gplugin/tests/test-plugin-info.c
@@ -103,6 +103,7 @@
 	gchar *license_id = NULL, *license_text = NULL, *license_url = NULL;
 	gchar *summary = NULL, *description = NULL, *category = NULL;
 	gchar *website = NULL;
+	char *discriminator = NULL;
 	gchar **provides = NULL, **authors = NULL, **dependencies = NULL;
 	gint priority = 0;
 	guint abi_version = 0;
@@ -141,6 +142,7 @@
 	g_object_get(
 		info,
 		"id", &id,
+		"discriminator", &discriminator,
 		"provides", &provides,
 		"priority", &priority,
 		"abi_version", &abi_version,
@@ -162,6 +164,14 @@
 	/* clang-format on */
 
 	test_string(id, "gplugin-test/plugin-info-test");
+
+	/* We can't guaranty the value of the discriminator, so we just check that
+	 * it is not a NULL or an empty string.
+	 */
+	g_assert_nonnull(discriminator);
+	g_assert_cmpstr(discriminator, !=, "");
+	g_clear_pointer(&discriminator, g_free);
+
 	test_stringv(
 		provides,
 		r_provides,
