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 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 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; }