From 482ec4f9f6dca6da5940cf616f85f4c9d075f37d Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Wed, 11 Oct 2023 14:33:52 +0200 Subject: [PATCH 1/3] session: Allow setting the unique name If multiple instances of QEMU are running, with the currently exposed API you can't interact with queued name owners and only with the main process. Also modify mks-connect to make use of this and display the unique name there as well. --- lib/mks-session.c | 167 ++++++++++++++++++++++++++++++++++++++------ lib/mks-session.h | 52 ++++++++++---- tools/mks-connect.c | 59 ++++++++++++---- 3 files changed, 228 insertions(+), 50 deletions(-) diff --git a/lib/mks-session.c b/lib/mks-session.c index 87c5cbe..9c55137 100644 --- a/lib/mks-session.c +++ b/lib/mks-session.c @@ -56,6 +56,8 @@ * with [method@Mks.Display.set_screen]. */ +#define QEMU_BUS_NAME "org.qemu" + static gboolean mks_session_initable_init (GInitable *initable, GCancellable *cancellable, GError **error); @@ -109,6 +111,7 @@ struct _MksSession char *name; char *uuid; + char *bus_name; }; static void @@ -131,6 +134,7 @@ G_DEFINE_FINAL_TYPE_WITH_CODE (MksSession, mks_session, G_TYPE_OBJECT, enum { PROP_0, PROP_CONNECTION, + PROP_BUS_NAME, PROP_DEVICES, PROP_NAME, PROP_UUID, @@ -309,6 +313,7 @@ mks_session_dispose (GObject *object) g_clear_object (&self->vm_object); g_clear_pointer (&self->name, g_free); g_clear_pointer (&self->uuid, g_free); + g_clear_pointer (&self->bus_name, g_free); G_OBJECT_CLASS (mks_session_parent_class)->dispose (object); } @@ -339,6 +344,10 @@ mks_session_get_property (GObject *object, g_value_set_object (value, mks_session_get_connection (self)); break; + case PROP_BUS_NAME: + g_value_set_string (value, self->bus_name); + break; + case PROP_DEVICES: g_value_set_object (value, mks_session_get_devices (self)); break; @@ -369,6 +378,9 @@ mks_session_set_property (GObject *object, case PROP_CONNECTION: mks_session_set_connection (self, g_value_get_object (value)); break; + case PROP_BUS_NAME: + g_set_str (&self->bus_name, g_value_get_string (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -395,6 +407,16 @@ mks_session_class_init (MksSessionClass *klass) G_TYPE_DBUS_CONNECTION, (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * MksSession:bus-name: + * + * The unique connection name to connect to or `org.qemu` as fallback. + */ + properties [PROP_BUS_NAME] = + g_param_spec_string ("bus-name", NULL, NULL, + QEMU_BUS_NAME, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** * MksSession:devices: * @@ -459,7 +481,7 @@ mks_session_initable_init (GInitable *initable, object_manager = mks_qemu_object_manager_client_new_sync (self->connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, - "org.qemu", + self->bus_name, "/org/qemu/Display1", cancellable, error); @@ -521,7 +543,7 @@ mks_session_async_initable_init_async (GAsyncInitable *async_initable, else mks_qemu_object_manager_client_new (self->connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, - "org.qemu", + self->bus_name, "/org/qemu/Display1", cancellable, mks_session_async_initable_vm_cb, @@ -604,25 +626,12 @@ mks_session_new_for_connection (GDBusConnection *connection, GAsyncReadyCallback callback, gpointer user_data) { - g_autoptr(MksSession) self = NULL; - g_autoptr(GTask) task = NULL; - - g_return_if_fail (G_IS_DBUS_CONNECTION (connection)); - g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); - - self = g_object_new (MKS_TYPE_SESSION, - "connection", connection, - NULL); - - task = g_task_new (self, cancellable, callback, user_data); - g_task_set_source_tag (task, mks_session_new_for_connection); - g_task_set_priority (task, io_priority); - - g_async_initable_init_async (G_ASYNC_INITABLE (self), - io_priority, - cancellable, - mks_session_new_for_connection_cb, - g_steal_pointer (&task)); + mks_session_new_for_connection_with_name (connection, + QEMU_BUS_NAME, + io_priority, + cancellable, + callback, + user_data); } /** @@ -663,12 +672,108 @@ mks_session_new_for_connection_sync (GDBusConnection *connection, GCancellable *cancellable, GError **error) { - g_autoptr(MksSession) self = NULL; + return mks_session_new_for_connection_with_name_sync (connection, + QEMU_BUS_NAME, + cancellable, + error); +} - g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); +/** + * mks_session_new_for_connection_with_name: + * @connection: a #GDBusConnection + * @bus_name: The unique name to connect + * @io_priority: priority for IO operations + * @cancellable: (nullable): a #GCancellable or %NULL + * @callback: a callback to execute upon completion of the operation + * @user_data: closure data for @callback + * + * Creates a #MksSession which communicates using @connection. + * + * The constructor is similar to [func@Mks.Session.new_for_connection] but allows + * to set the bus name to something else than the default `org.qemu`. + * + * use [ctor@Mks.Session.new_for_connection_with_name_finish] to get the result of + * this operation. + */ +void +mks_session_new_for_connection_with_name (GDBusConnection *connection, + const char *bus_name, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(MksSession) self = NULL; + g_autoptr(GTask) task = NULL; + + g_return_if_fail (G_IS_DBUS_CONNECTION (connection)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (bus_name != NULL); self = g_object_new (MKS_TYPE_SESSION, "connection", connection, + "bus-name", bus_name, + NULL); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, mks_session_new_for_connection); + g_task_set_priority (task, io_priority); + + g_async_initable_init_async (G_ASYNC_INITABLE (self), + io_priority, + cancellable, + mks_session_new_for_connection_cb, + g_steal_pointer (&task)); +} + +/** + * mks_session_new_for_connection_with_name_finish: + * @result: a #GAsyncResult provided to callback + * @error: (nullable): a location for a #GError or %NULL + * + * Completes a request to create a #MksSession for a [class@Gio.DBusConnection]. + * + * Returns: (transfer full): a #MksSession if successful; otherwise %NULL + * and @error is set. + */ +MksSession * +mks_session_new_for_connection_with_name_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (G_IS_TASK (result), NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} + +/** + * mks_session_new_for_connection_with_name_sync: + * @bus_name: The unique name to connect + * @connection: a private #GDBusConnetion to a QEMU instance + * @cancellable: (nullable): a #GCancellable, or %NULL + * @error: (nullable): a location for a #GError, or %NULL + * + * Synchronously creates a new #MksSession instance. + * + * The constructor is similar to [func@Mks.Session.new_for_connection_sync] except + * it allows to set the bus name to something else than the default `org.qemu`. + * + * Returns: (transfer full): a #MksSession if successful; otherwise %NULL + * and @error is set. + */ +MksSession * +mks_session_new_for_connection_with_name_sync (GDBusConnection *connection, + const char *bus_name, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(MksSession) self = NULL; + + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); + g_return_val_if_fail (bus_name != NULL, NULL); + + self = g_object_new (MKS_TYPE_SESSION, + "connection", connection, + "bus-name", bus_name, NULL); if (g_initable_init (G_INITABLE (self), cancellable, error)) @@ -694,6 +799,22 @@ mks_session_get_connection (MksSession *self) return self->connection; } +/** + * mks_session_get_bus_name: + * @self: a #MksSession + * + * Gets the DBus connection unique name or `org.qemu` as a fallback. + * + * Returns: A unique name the session is connected to + */ +const char * +mks_session_get_bus_name (MksSession *self) +{ + g_return_val_if_fail (MKS_IS_SESSION (self), NULL); + + return self->bus_name; +} + /** * mks_session_get_uuid: * @self: a #MksSession diff --git a/lib/mks-session.h b/lib/mks-session.h index 9a14de0..aa911ec 100644 --- a/lib/mks-session.h +++ b/lib/mks-session.h @@ -38,27 +38,49 @@ MKS_AVAILABLE_IN_ALL G_DECLARE_FINAL_TYPE (MksSession, mks_session, MKS, SESSION, GObject) MKS_AVAILABLE_IN_ALL -void mks_session_new_for_connection (GDBusConnection *connection, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +void mks_session_new_for_connection (GDBusConnection *connection, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + MKS_AVAILABLE_IN_ALL -MksSession *mks_session_new_for_connection_finish (GAsyncResult *result, - GError **error); +MksSession *mks_session_new_for_connection_finish (GAsyncResult *result, + GError **error); + MKS_AVAILABLE_IN_ALL -MksSession *mks_session_new_for_connection_sync (GDBusConnection *connection, - GCancellable *cancellable, - GError **error); +void mks_session_new_for_connection_with_name (GDBusConnection *connection, + const char *bus_name, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + MKS_AVAILABLE_IN_ALL -GDBusConnection *mks_session_get_connection (MksSession *self); +MksSession *mks_session_new_for_connection_with_name_finish (GAsyncResult *result, + GError **error); + MKS_AVAILABLE_IN_ALL -GListModel *mks_session_get_devices (MksSession *self); +MksSession *mks_session_new_for_connection_sync (GDBusConnection *connection, + GCancellable *cancellable, + GError **error); + MKS_AVAILABLE_IN_ALL -const char *mks_session_get_name (MksSession *self); +MksSession *mks_session_new_for_connection_with_name_sync (GDBusConnection *connection, + const char *bus_name, + GCancellable *cancellable, + GError **error); MKS_AVAILABLE_IN_ALL -const char *mks_session_get_uuid (MksSession *self); +GDBusConnection *mks_session_get_connection (MksSession *self); MKS_AVAILABLE_IN_ALL -MksScreen *mks_session_ref_screen (MksSession *self); +GListModel *mks_session_get_devices (MksSession *self); +MKS_AVAILABLE_IN_ALL +const char *mks_session_get_name (MksSession *self); +MKS_AVAILABLE_IN_ALL +const char *mks_session_get_uuid (MksSession *self); +MKS_AVAILABLE_IN_ALL +const char *mks_session_get_bus_name (MksSession *self); +MKS_AVAILABLE_IN_ALL +MksScreen *mks_session_ref_screen (MksSession *self); G_END_DECLS diff --git a/tools/mks-connect.c b/tools/mks-connect.c index 4f1ce53..7f2609e 100644 --- a/tools/mks-connect.c +++ b/tools/mks-connect.c @@ -79,6 +79,10 @@ main (int argc, g_autoptr(GDBusConnection) connection = NULL; g_autoptr(MksSession) session = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GVariant) variant = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autofree const char **queued_owners = NULL; + gsize n_queued_owners; GListModel *devices = NULL; guint n_items; @@ -106,25 +110,56 @@ main (int argc, return EXIT_FAILURE; } - if (!(session = mks_session_new_for_connection_sync (connection, NULL, &error))) + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + NULL, + &error); + + if (proxy == NULL) { - g_printerr ("Failed to create MksSession: %s\n", + g_printerr ("Failed to connect to `org.freedesktop.DBus`: %s\n", + error->message); + return EXIT_FAILURE; + } + variant = g_dbus_proxy_call_sync (proxy, "ListQueuedOwners", + g_variant_new ("(s)", "org.qemu"), G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + if (error != NULL) + { + g_printerr ("Failed to ListQueuedOwners: %s\n", error->message); return EXIT_FAILURE; } - g_print ("Session(uuid=\"%s\", name=\"%s\")\n", - mks_session_get_uuid (session), - mks_session_get_name (session)); + queued_owners = g_variant_get_strv (g_variant_get_child_value (variant, 0), + &n_queued_owners); - devices = mks_session_get_devices (session); - n_items = g_list_model_get_n_items (devices); - - for (guint i = 0; i < n_items; i++) + for (guint i = 0; i < n_queued_owners; i++) { - g_autoptr(MksDevice) device = g_list_model_get_item (devices, i); - print_device_info (device, 1); - } + if (!(session = mks_session_new_for_connection_with_name_sync (connection, queued_owners[i], NULL, &error))) + { + g_printerr ("Failed to create MksSession: %s\n", + error->message); + return EXIT_FAILURE; + } + g_print ("Session(uuid=\"%s\", name=\"%s\", bus-name=%s)\n", + mks_session_get_uuid (session), + mks_session_get_name (session), + mks_session_get_bus_name (session)); + + devices = mks_session_get_devices (session); + n_items = g_list_model_get_n_items (devices); + + for (guint j = 0; j < n_items; j++) + { + g_autoptr(MksDevice) device = g_list_model_get_item (devices, j); + print_device_info (device, 1); + } + } return EXIT_SUCCESS; } From 4bcff31a94208d0434f043f75809edc7b3d0a2cc Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Thu, 12 Oct 2023 10:12:28 +0200 Subject: [PATCH 2/3] ci: Use dbus-run-session to ensure the fdo bus is available --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index eb02c6f..a261ec9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,7 +22,7 @@ tests: - meson compile -C _build - meson test -C _build --suit "libmks" - cd tests - - BUILDDIR=_build xvfb-run ./functional.sh + - BUILDDIR=_build dbus-run-session xvfb-run -ad ./functional.sh - cd .. - rm -rf _build/subprojects - ninja coverage-html -C _build From c03395e68a96d8d6696c9bdd7cbe3ef70e3bbff8 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Thu, 12 Oct 2023 10:30:49 +0200 Subject: [PATCH 3/3] misc: Ignore images downloaded by functional test --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1b203fb..cf5e1e0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ subprojects/gtk subprojects/libsass subprojects/sassc +*.raw \ No newline at end of file