# HG changeset patch
# Node ID 555c5b51f7ac
# Parent  f03eee6f9596
diff --git a/gplugin/gplugin-loader-tests.c b/gplugin/gplugin-loader-tests.c
--- a/gplugin/gplugin-loader-tests.c
+++ b/gplugin/gplugin-loader-tests.c
@@ -78,6 +78,10 @@
 		gplugin_plugin_get_state(plugin),
 		==,
 		GPLUGIN_PLUGIN_STATE_QUERIED);
+	g_assert_cmpint(
+		gplugin_plugin_get_desired_state(plugin),
+		==,
+		GPLUGIN_PLUGIN_STATE_QUERIED);
 
 	gplugin_manager_load_plugin(manager, plugin, &error);
 	g_assert_no_error(error);
@@ -85,6 +89,10 @@
 		gplugin_plugin_get_state(plugin),
 		==,
 		GPLUGIN_PLUGIN_STATE_LOADED);
+	g_assert_cmpint(
+		gplugin_plugin_get_desired_state(plugin),
+		==,
+		GPLUGIN_PLUGIN_STATE_LOADED);
 
 	gplugin_manager_unload_plugin(manager, plugin, &error);
 	g_assert_no_error(error);
@@ -92,6 +100,10 @@
 		gplugin_plugin_get_state(plugin),
 		==,
 		GPLUGIN_PLUGIN_STATE_QUERIED);
+	g_assert_cmpint(
+		gplugin_plugin_get_desired_state(plugin),
+		==,
+		GPLUGIN_PLUGIN_STATE_QUERIED);
 
 	g_object_unref(G_OBJECT(plugin));
 }
@@ -120,6 +132,10 @@
 		gplugin_plugin_get_state(plugin),
 		==,
 		GPLUGIN_PLUGIN_STATE_LOAD_FAILED);
+	g_assert_cmpint(
+		gplugin_plugin_get_desired_state(plugin),
+		==,
+		GPLUGIN_PLUGIN_STATE_LOADED);
 
 	/* make sure that the plugin's error was set */
 	error = gplugin_plugin_get_error(plugin);
@@ -153,6 +169,11 @@
 		==,
 		GPLUGIN_PLUGIN_STATE_LOAD_FAILED);
 
+	g_assert_cmpint(
+		gplugin_plugin_get_desired_state(plugin),
+		==,
+		GPLUGIN_PLUGIN_STATE_LOADED);
+
 	/* make sure that the plugin's error was set */
 	error = gplugin_plugin_get_error(plugin);
 	g_assert_error(error, GPLUGIN_DOMAIN, 0);
@@ -197,6 +218,10 @@
 		gplugin_plugin_get_state(plugin),
 		==,
 		GPLUGIN_PLUGIN_STATE_QUERIED);
+	g_assert_cmpint(
+		gplugin_plugin_get_desired_state(plugin),
+		==,
+		GPLUGIN_PLUGIN_STATE_QUERIED);
 
 	g_object_unref(G_OBJECT(plugin));
 }
@@ -233,6 +258,10 @@
 		gplugin_plugin_get_state(plugin),
 		==,
 		GPLUGIN_PLUGIN_STATE_UNLOAD_FAILED);
+	g_assert_cmpint(
+		gplugin_plugin_get_desired_state(plugin),
+		==,
+		GPLUGIN_PLUGIN_STATE_QUERIED);
 
 	/* make sure that the plugin's error was set */
 	error = gplugin_plugin_get_error(plugin);
diff --git a/gplugin/gplugin-loader.c b/gplugin/gplugin-loader.c
--- a/gplugin/gplugin-loader.c
+++ b/gplugin/gplugin-loader.c
@@ -209,6 +209,11 @@
 	g_return_val_if_fail(filename, NULL);
 	g_return_val_if_fail(error != NULL, NULL);
 
+	/* We don't have a plugin instance yet, so we just set the desired-state at
+	 * the same time we set the state because that's the first opportunity we
+	 * have.
+	 */
+
 	klass = GPLUGIN_LOADER_GET_CLASS(loader);
 
 	if(klass != NULL && klass->query != NULL) {
@@ -230,10 +235,14 @@
 		 */
 		g_clear_error(&real_error);
 
-		/* Likewise, make sure the plugin's error is set to NULL. */
-		g_object_set(G_OBJECT(plugin), "error", NULL, NULL);
-
-		gplugin_plugin_set_state(plugin, GPLUGIN_PLUGIN_STATE_QUERIED);
+		/* Set a few properties. */
+		/* clang-format off */
+		g_object_set(G_OBJECT(plugin),
+			"error", NULL,
+			"state", GPLUGIN_PLUGIN_STATE_QUERIED,
+			"desired-state", GPLUGIN_PLUGIN_STATE_QUERIED,
+			NULL);
+		/* clang-format on */
 	}
 
 	return plugin;
@@ -269,6 +278,8 @@
 		return TRUE;
 	}
 
+	gplugin_plugin_set_desired_state(plugin, GPLUGIN_PLUGIN_STATE_LOADED);
+
 	klass = GPLUGIN_LOADER_GET_CLASS(loader);
 
 	if(klass != NULL && klass->load != NULL) {
@@ -340,6 +351,8 @@
 		return TRUE;
 	}
 
+	gplugin_plugin_set_desired_state(plugin, GPLUGIN_PLUGIN_STATE_QUERIED);
+
 	klass = GPLUGIN_LOADER_GET_CLASS(loader);
 
 	if(klass != NULL && klass->unload != NULL) {
diff --git a/gplugin/gplugin-native-plugin.c b/gplugin/gplugin-native-plugin.c
--- a/gplugin/gplugin-native-plugin.c
+++ b/gplugin/gplugin-native-plugin.c
@@ -130,6 +130,7 @@
 	GPluginLoader *loader;
 	GPluginPluginInfo *info;
 	GPluginPluginState state;
+	GPluginPluginState desired_state;
 	GError *error;
 };
 
@@ -147,6 +148,7 @@
 	PROP_LOADER,
 	PROP_INFO,
 	PROP_STATE,
+	PROP_DESIRED_STATE,
 	PROP_ERROR,
 };
 static GParamSpec *properties[N_PROPERTIES] = {
@@ -222,6 +224,9 @@
 		case PROP_STATE:
 			g_value_set_enum(value, plugin->state);
 			break;
+		case PROP_DESIRED_STATE:
+			g_value_set_enum(value, plugin->desired_state);
+			break;
 		case PROP_ERROR:
 			g_value_set_boxed(value, plugin->error);
 			break;
@@ -265,6 +270,9 @@
 		case PROP_STATE:
 			plugin->state = g_value_get_enum(value);
 			break;
+		case PROP_DESIRED_STATE:
+			plugin->desired_state = g_value_get_enum(value);
+			break;
 		case PROP_ERROR:
 			g_clear_error(&plugin->error);
 			plugin->error = g_value_dup_boxed(value);
@@ -349,6 +357,10 @@
 	g_object_class_override_property(obj_class, PROP_LOADER, "loader");
 	g_object_class_override_property(obj_class, PROP_INFO, "info");
 	g_object_class_override_property(obj_class, PROP_STATE, "state");
+	g_object_class_override_property(
+		obj_class,
+		PROP_DESIRED_STATE,
+		"desired-state");
 	g_object_class_override_property(obj_class, PROP_ERROR, "error");
 }
 
diff --git a/gplugin/gplugin-plugin.h b/gplugin/gplugin-plugin.h
--- a/gplugin/gplugin-plugin.h
+++ b/gplugin/gplugin-plugin.h
@@ -70,6 +70,11 @@
 GPluginPluginState gplugin_plugin_get_state(GPluginPlugin *plugin);
 void gplugin_plugin_set_state(GPluginPlugin *plugin, GPluginPluginState state);
 
+GPluginPluginState gplugin_plugin_get_desired_state(GPluginPlugin *plugin);
+void gplugin_plugin_set_desired_state(
+	GPluginPlugin *plugin,
+	GPluginPluginState state);
+
 GError *gplugin_plugin_get_error(GPluginPlugin *plugin);
 
 const gchar *gplugin_plugin_state_to_string(GPluginPluginState state);
diff --git a/gplugin/gplugin-plugin.c b/gplugin/gplugin-plugin.c
--- a/gplugin/gplugin-plugin.c
+++ b/gplugin/gplugin-plugin.c
@@ -126,6 +126,26 @@
 	g_object_interface_install_property(iface, pspec);
 
 	/**
+	 * GPluginPlugin:desired-state:
+	 *
+	 * The desired state of the plugin. Typically this just mirrors the state
+	 * property, but if a state change failed this will remain set to the state
+	 * that was attempted.
+	 *
+	 * See [method@GPlugin.Plugin.get_desired_state] for more information.
+	 *
+	 * Since: 0.38.0
+	 */
+	pspec = g_param_spec_enum(
+		"desired-state",
+		"desired-state",
+		"The desired state of the plugin",
+		GPLUGIN_TYPE_PLUGIN_STATE,
+		GPLUGIN_PLUGIN_STATE_UNKNOWN,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+	g_object_interface_install_property(iface, pspec);
+
+	/**
 	 * GPluginPlugin:error:
 	 *
 	 * An error that was returned if the plugin failed to load or unload.
@@ -282,6 +302,59 @@
 }
 
 /**
+ * gplugin_plugin_get_desired_state:
+ *
+ * Gets the desired state of the plugin. Typically this will hold the same
+ * value of [property@GPlugin.Plugin:state], but if a state change failed this
+ * will remain set to the state that was attempted.
+ *
+ * For example, say a user wants to unload a plugin but the plugin can't be
+ * unloaded for some reason. The state will be set to loaded, but the
+ * desired state will be set to unloaded.
+ *
+ * This behavior can be used to give the user the ability to disable a
+ * plugin that normally isn't unloadabled from being loaded during the next
+ * run of program.
+ *
+ * Returns: The desired state that the user has requested the plugin to be in.
+ *
+ * Since: 0.38.0
+ */
+GPluginPluginState
+gplugin_plugin_get_desired_state(GPluginPlugin *plugin)
+{
+	GPluginPluginState desired_state = GPLUGIN_PLUGIN_STATE_UNKNOWN;
+
+	g_return_val_if_fail(
+		GPLUGIN_IS_PLUGIN(plugin),
+		GPLUGIN_PLUGIN_STATE_UNKNOWN);
+
+	g_object_get(G_OBJECT(plugin), "desired-state", &desired_state, NULL);
+
+	return desired_state;
+}
+
+/**
+ * gplugin_plugin_set_desired_state:
+ * @plugin: The plugin instance.
+ * @state: The desired state.
+ *
+ * Sets the desired state of the plugin. This shouldn't need to be called by
+ * anyone except [class@GPlugin.Loader] which manages the state of plugins.
+ *
+ * Since: 0.38.0
+ */
+void
+gplugin_plugin_set_desired_state(
+	GPluginPlugin *plugin,
+	GPluginPluginState state)
+{
+	g_return_if_fail(GPLUGIN_IS_PLUGIN(plugin));
+
+	g_object_set(G_OBJECT(plugin), "desired-state", state, NULL);
+}
+
+/**
  * gplugin_plugin_get_error:
  * @plugin: The plugin instance.
  *
diff --git a/gplugin/tests/test-loader.c b/gplugin/tests/test-loader.c
--- a/gplugin/tests/test-loader.c
+++ b/gplugin/tests/test-loader.c
@@ -36,6 +36,7 @@
 	PROP_LOADER,
 	PROP_INFO,
 	PROP_STATE,
+	PROP_DESIRED_STATE,
 	PROP_ERROR,
 };
 
@@ -47,6 +48,7 @@
 	GPluginLoader *loader;
 	GPluginPluginInfo *info;
 	GPluginPluginState state;
+	GPluginPluginState desired_state;
 	GError *error;
 };
 
@@ -82,6 +84,9 @@
 		case PROP_STATE:
 			g_value_set_enum(value, plugin->state);
 			break;
+		case PROP_DESIRED_STATE:
+			g_value_set_enum(value, plugin->desired_state);
+			break;
 		case PROP_ERROR:
 			g_value_set_boxed(value, plugin->error);
 			break;
@@ -113,6 +118,9 @@
 		case PROP_STATE:
 			plugin->state = g_value_get_enum(value);
 			break;
+		case PROP_DESIRED_STATE:
+			plugin->desired_state = g_value_get_enum(value);
+			break;
 		case PROP_ERROR:
 			plugin->error = g_value_dup_boxed(value);
 			break;
@@ -153,6 +161,10 @@
 	g_object_class_override_property(obj_class, PROP_LOADER, "loader");
 	g_object_class_override_property(obj_class, PROP_INFO, "info");
 	g_object_class_override_property(obj_class, PROP_STATE, "state");
+	g_object_class_override_property(
+		obj_class,
+		PROP_DESIRED_STATE,
+		"desired-state");
 	g_object_class_override_property(obj_class, PROP_ERROR, "error");
 }
 
diff --git a/lua/gplugin-lua-plugin.c b/lua/gplugin-lua-plugin.c
--- a/lua/gplugin-lua-plugin.c
+++ b/lua/gplugin-lua-plugin.c
@@ -31,6 +31,7 @@
 	GPluginLoader *loader;
 	GPluginPluginInfo *info;
 	GPluginPluginState state;
+	GPluginPluginState desired_state;
 	GError *error;
 };
 
@@ -46,6 +47,7 @@
 	PROP_LOADER,
 	PROP_INFO,
 	PROP_STATE,
+	PROP_DESIRED_STATE,
 	PROP_ERROR,
 };
 static GParamSpec *properties[N_PROPERTIES] = {
@@ -100,6 +102,9 @@
 		case PROP_STATE:
 			g_value_set_enum(value, plugin->state);
 			break;
+		case PROP_DESIRED_STATE:
+			g_value_set_enum(value, plugin->desired_state);
+			break;
 		case PROP_ERROR:
 			g_value_set_boxed(value, plugin->error);
 			break;
@@ -137,6 +142,9 @@
 		case PROP_STATE:
 			plugin->state = g_value_get_enum(value);
 			break;
+		case PROP_DESIRED_STATE:
+			plugin->desired_state = g_value_get_enum(value);
+			break;
 		case PROP_ERROR:
 			plugin->error = g_value_dup_boxed(value);
 			break;
@@ -193,6 +201,10 @@
 	g_object_class_override_property(obj_class, PROP_LOADER, "loader");
 	g_object_class_override_property(obj_class, PROP_INFO, "info");
 	g_object_class_override_property(obj_class, PROP_STATE, "state");
+	g_object_class_override_property(
+		obj_class,
+		PROP_DESIRED_STATE,
+		"desired-state");
 	g_object_class_override_property(obj_class, PROP_ERROR, "error");
 }
 
diff --git a/perl5/gplugin-perl5-plugin.c b/perl5/gplugin-perl5-plugin.c
--- a/perl5/gplugin-perl5-plugin.c
+++ b/perl5/gplugin-perl5-plugin.c
@@ -30,6 +30,7 @@
 	GPluginLoader *loader;
 	GPluginPluginInfo *info;
 	GPluginPluginState state;
+	GPluginPluginState desired_state;
 	GError *error;
 };
 
@@ -45,6 +46,7 @@
 	PROP_LOADER,
 	PROP_INFO,
 	PROP_STATE,
+	PROP_DESIRED_STATE,
 	PROP_ERROR,
 };
 static GParamSpec *properties[N_PROPERTIES] = {
@@ -101,6 +103,9 @@
 		case PROP_STATE:
 			g_value_set_enum(value, plugin->state);
 			break;
+		case PROP_DESIRED_STATE:
+			g_value_set_enum(value, plugin->desired_state);
+			break;
 		case PROP_ERROR:
 			g_value_set_boxed(value, plugin->error);
 			break;
@@ -138,6 +143,9 @@
 		case PROP_STATE:
 			plugin->state = g_value_get_enum(value);
 			break;
+		case PROP_DESIRED_STATE:
+			plugin->desired_state = g_value_get_enum(value);
+			break;
 		case PROP_ERROR:
 			plugin->error = g_value_dup_boxed(value);
 			break;
@@ -196,6 +204,10 @@
 	g_object_class_override_property(obj_class, PROP_LOADER, "loader");
 	g_object_class_override_property(obj_class, PROP_INFO, "info");
 	g_object_class_override_property(obj_class, PROP_STATE, "state");
+	g_object_class_override_property(
+		obj_class,
+		PROP_DESIRED_STATE,
+		"desired-state");
 	g_object_class_override_property(obj_class, PROP_ERROR, "error");
 }
 
diff --git a/python3/gplugin-python3-plugin.c b/python3/gplugin-python3-plugin.c
--- a/python3/gplugin-python3-plugin.c
+++ b/python3/gplugin-python3-plugin.c
@@ -35,6 +35,7 @@
 	GPluginLoader *loader;
 	GPluginPluginInfo *info;
 	GPluginPluginState state;
+	GPluginPluginState desired_state;
 	GError *error;
 };
 
@@ -52,6 +53,7 @@
 	PROP_LOADER,
 	PROP_INFO,
 	PROP_STATE,
+	PROP_DESIRED_STATE,
 	PROP_ERROR,
 };
 static GParamSpec *properties[N_PROPERTIES] = {
@@ -176,6 +178,9 @@
 		case PROP_STATE:
 			g_value_set_enum(value, plugin->state);
 			break;
+		case PROP_DESIRED_STATE:
+			g_value_set_enum(value, plugin->desired_state);
+			break;
 		case PROP_ERROR:
 			g_value_set_boxed(value, plugin->error);
 			break;
@@ -225,6 +230,9 @@
 		case PROP_STATE:
 			plugin->state = g_value_get_enum(value);
 			break;
+		case PROP_DESIRED_STATE:
+			plugin->desired_state = g_value_get_enum(value);
+			break;
 		case PROP_ERROR:
 			plugin->error = g_value_dup_boxed(value);
 			break;
@@ -297,6 +305,10 @@
 	g_object_class_override_property(obj_class, PROP_LOADER, "loader");
 	g_object_class_override_property(obj_class, PROP_INFO, "info");
 	g_object_class_override_property(obj_class, PROP_STATE, "state");
+	g_object_class_override_property(
+		obj_class,
+		PROP_DESIRED_STATE,
+		"desired-state");
 	g_object_class_override_property(obj_class, PROP_ERROR, "error");
 }
 
