From 9bb71b8ea82ca21a1026d9ab07ada2d054af2adf Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 9 Feb 2023 15:39:03 -0800 Subject: [PATCH] lib: add MksScreenAttributes and mks_screen_configure() MksScreenAttributes is an opaque type with setters so that we can potentially extend it in the future without ABI issues. Furthermore, this adds a configure API for both sync and async to MksScreen. Currently, I get NOT_SUPPORTED back from Qemu, but I think that's because I'm not even past the bootloader/EFI stage for tests. --- lib/libmks.h | 1 + lib/meson.build | 2 + lib/mks-init.c | 2 + lib/mks-screen-attributes-private.h | 38 +++++++ lib/mks-screen-attributes.c | 115 ++++++++++++++++++++++ lib/mks-screen-attributes.h | 66 +++++++++++++ lib/mks-screen.c | 147 ++++++++++++++++++++++++++++ lib/mks-screen.h | 31 ++++-- lib/mks-types.h | 13 +-- 9 files changed, 401 insertions(+), 14 deletions(-) create mode 100644 lib/mks-screen-attributes-private.h create mode 100644 lib/mks-screen-attributes.c create mode 100644 lib/mks-screen-attributes.h diff --git a/lib/libmks.h b/lib/libmks.h index 3fd0460..b8c38fe 100644 --- a/lib/libmks.h +++ b/lib/libmks.h @@ -32,6 +32,7 @@ G_BEGIN_DECLS # include "mks-mouse.h" # include "mks-paintable.h" # include "mks-screen.h" +# include "mks-screen-attributes.h" # include "mks-session.h" # include "mks-types.h" # include "mks-version.h" diff --git a/lib/meson.build b/lib/meson.build index b29ccd9..55c6040 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -5,6 +5,7 @@ libmks_sources = [ 'mks-mouse.c', 'mks-paintable.c', 'mks-screen.c', + 'mks-screen-attributes.c', 'mks-session.c', ] @@ -16,6 +17,7 @@ libmks_headers = [ 'mks-mouse.h', 'mks-paintable.h', 'mks-screen.h', + 'mks-screen-attributes.h', 'mks-session.h', 'mks-types.h', ] diff --git a/lib/mks-init.c b/lib/mks-init.c index 1c73895..ba6dc3b 100644 --- a/lib/mks-init.c +++ b/lib/mks-init.c @@ -30,6 +30,7 @@ #include "mks-qemu.h" #include "mks-read-only-list-model-private.h" #include "mks-screen.h" +#include "mks-screen-attributes.h" #include "mks-session.h" #include "mks-version.h" @@ -56,6 +57,7 @@ mks_init_gtypes (void) g_type_ensure (MKS_TYPE_MOUSE); g_type_ensure (MKS_TYPE_PAINTABLE); g_type_ensure (MKS_TYPE_SCREEN); + g_type_ensure (MKS_TYPE_SCREEN_ATTRIBUTES); g_type_ensure (MKS_TYPE_SESSION); } diff --git a/lib/mks-screen-attributes-private.h b/lib/mks-screen-attributes-private.h new file mode 100644 index 0000000..8869be0 --- /dev/null +++ b/lib/mks-screen-attributes-private.h @@ -0,0 +1,38 @@ +/* + * mks-screen-attributes-private.h + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "mks-screen-attributes.h" + +G_BEGIN_DECLS + +struct _MksScreenAttributes +{ + guint16 width_mm; + guint16 height_mm; + int x_offset; + int y_offset; + guint width; + guint height; +}; + +G_END_DECLS diff --git a/lib/mks-screen-attributes.c b/lib/mks-screen-attributes.c new file mode 100644 index 0000000..3edc519 --- /dev/null +++ b/lib/mks-screen-attributes.c @@ -0,0 +1,115 @@ +/* + * mks-screen-attributes.c + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include "mks-screen-attributes-private.h" + +G_DEFINE_BOXED_TYPE (MksScreenAttributes, + mks_screen_attributes, + mks_screen_attributes_copy, + mks_screen_attributes_free) + +/** + * mks_screen_attributes_new: + * + * Creates a new #MksScreenAttributes. + * + * Returns: (transfer full): A newly created #MksScreenAttributes + */ +MksScreenAttributes * +mks_screen_attributes_new (void) +{ + return g_new0 (MksScreenAttributes, 1); +} + +/** + * mks_screen_attributes_copy: + * @self: (nullable): a #MksScreenAttributes + * + * Makes a deep copy of a #MksScreenAttributes. + * + * Returns: (transfer full): A newly created #MksScreenAttributes with the same + * contents as @self. If @self is %NULL, %NULL is returned. + */ +MksScreenAttributes * +mks_screen_attributes_copy (MksScreenAttributes *self) +{ + if (self == NULL) + return NULL; + + return g_memdup2 (self, sizeof *self); +} + +/** + * mks_screen_attributes_free: + * @self: a #MksScreenAttributes + * + * Frees a #MksScreenAttributes allocated using mks_screen_attributes_new() + * or mks_screen_attributes_copy(). + */ +void +mks_screen_attributes_free (MksScreenAttributes *self) +{ + g_free (self); +} + +void +mks_screen_attributes_set_width_mm (MksScreenAttributes *self, + guint16 width_mm) +{ + self->width_mm = width_mm; +} + +void +mks_screen_attributes_set_height_mm (MksScreenAttributes *self, + guint16 height_mm) +{ + self->height_mm = height_mm; +} + +void +mks_screen_attributes_set_x_offset (MksScreenAttributes *self, + int x_offset) +{ + self->x_offset = x_offset; +} + +void +mks_screen_attributes_set_y_offset (MksScreenAttributes *self, + int y_offset) +{ + self->y_offset = y_offset; +} + +void +mks_screen_attributes_set_width (MksScreenAttributes *self, + guint width) +{ + self->width = width; +} + +void +mks_screen_attributes_set_height (MksScreenAttributes *self, + guint height) +{ + self->height = height; +} diff --git a/lib/mks-screen-attributes.h b/lib/mks-screen-attributes.h new file mode 100644 index 0000000..22e20e6 --- /dev/null +++ b/lib/mks-screen-attributes.h @@ -0,0 +1,66 @@ +/* + * mks-screen-attributes.h + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#if !defined(MKS_INSIDE) && !defined(MKS_COMPILATION) +# error "Only can be included directly." +#endif + +#include + +#include "mks-types.h" +#include "mks-version-macros.h" + +G_BEGIN_DECLS + +#define MKS_TYPE_SCREEN_ATTRIBUTES (mks_screen_attributes_get_type ()) + +MKS_AVAILABLE_IN_ALL +GType mks_screen_attributes_get_type (void) G_GNUC_CONST; +MKS_AVAILABLE_IN_ALL +MksScreenAttributes *mks_screen_attributes_new (void); +MKS_AVAILABLE_IN_ALL +MksScreenAttributes *mks_screen_attributes_copy (MksScreenAttributes *self); +MKS_AVAILABLE_IN_ALL +void mks_screen_attributes_free (MksScreenAttributes *self); +MKS_AVAILABLE_IN_ALL +void mks_screen_attributes_set_width_mm (MksScreenAttributes *self, + guint16 width_mm); +MKS_AVAILABLE_IN_ALL +void mks_screen_attributes_set_height_mm (MksScreenAttributes *self, + guint16 height_mm); +MKS_AVAILABLE_IN_ALL +void mks_screen_attributes_set_x_offset (MksScreenAttributes *self, + int x_offset); +MKS_AVAILABLE_IN_ALL +void mks_screen_attributes_set_y_offset (MksScreenAttributes *self, + int y_offset); +MKS_AVAILABLE_IN_ALL +void mks_screen_attributes_set_width (MksScreenAttributes *self, + guint width); +MKS_AVAILABLE_IN_ALL +void mks_screen_attributes_set_height (MksScreenAttributes *self, + guint height); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MksScreenAttributes, mks_screen_attributes_free) + +G_END_DECLS diff --git a/lib/mks-screen.c b/lib/mks-screen.c index 05d3c1c..7182a1e 100644 --- a/lib/mks-screen.c +++ b/lib/mks-screen.c @@ -26,6 +26,7 @@ #include "mks-qemu.h" #include "mks-keyboard-private.h" #include "mks-mouse-private.h" +#include "mks-screen-attributes-private.h" #include "mks-screen-private.h" struct _MksScreenClass @@ -409,3 +410,149 @@ mks_screen_get_device_address (MksScreen *self) return NULL; } + +static gboolean +check_console (MksScreen *self, + GError **error) +{ + if (self->console == NULL) + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_CONNECTED, + "Not connected"); + return FALSE; + } + + return TRUE; +} + +static void +mks_screen_configure_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + MksQemuConsole *console = (MksQemuConsole *)object; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = user_data; + + g_assert (MKS_QEMU_IS_CONSOLE (console)); + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (G_IS_TASK (task)); + + if (!mks_qemu_console_call_set_uiinfo_finish (console, result, &error)) + g_task_return_error (task, g_steal_pointer (&error)); + else + g_task_return_boolean (task, TRUE); +} + +/** + * mks_screen_configure_async: + * @self: an #MksScreen + * @attributes: (transfer full): a #MksScreenAttributes + * @cancellable: (nullable): a #GCancellable + * @callback: a #GAsyncReadyCallback to execute upon completion + * @user_data: closure data for @callback + * + * Requests the Qemu instance reconfigure the screen with @attributes. + * + * This function takes ownership of @attributes. + * + * @callback is executed upon acknowledgment from the Qemu instance or + * if the request timed out. + * + * Call mks_screen_configure_finish() to get the result. + */ +void +mks_screen_configure (MksScreen *self, + MksScreenAttributes *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + g_autoptr(GError) error = NULL; + + g_return_if_fail (MKS_IS_SCREEN (self)); + g_return_if_fail (attributes != NULL); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, mks_screen_configure); + + if (!check_console (self, &error)) + g_task_return_error (task, g_steal_pointer (&error)); + else + mks_qemu_console_call_set_uiinfo (self->console, + attributes->width_mm, + attributes->height_mm, + attributes->x_offset, + attributes->y_offset, + attributes->width, + attributes->height, + cancellable, + mks_screen_configure_cb, + g_steal_pointer (&task)); + + mks_screen_attributes_free (attributes); +} + +/** + * mks_screen_configure_finish: + * @self: an #MksScreen + * @result: a #GAsyncResult provided to callback + * @error: a location for a #GError, or %NULL + * + * Completes a call to mks_screen_configure(). + * + * Returns: %TRUE if the operation completed successfully; otherwise %FALSE + * and @error is set. + */ +gboolean +mks_screen_configure_finish (MksScreen *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (MKS_IS_SCREEN (self), FALSE); + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +/** + * mks_screen_configure_sync: + * @self: a #MksScreen + * @attributes: (transfer full): a #MksScreenAttributes + * @cancellable: a #GCancellable + * @error: a location for a #GError, or %NULL + * + * Requests the Qemu instance reconfigure the screen using @attributes. + * + * This function takes ownership of @attributes. + * + * Returns: %TRUE if the operation completed successfully; otherwise %FALSE + * and @error is set. + */ +gboolean +mks_screen_configure_sync (MksScreen *self, + MksScreenAttributes *attributes, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (MKS_IS_SCREEN (self), FALSE); + g_return_val_if_fail (attributes != NULL, FALSE); + g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE); + + if (!check_console (self, error)) + return FALSE; + + return mks_qemu_console_call_set_uiinfo_sync (self->console, + attributes->width_mm, + attributes->height_mm, + attributes->x_offset, + attributes->y_offset, + attributes->width, + attributes->height, + cancellable, + error); +} diff --git a/lib/mks-screen.h b/lib/mks-screen.h index 18d16eb..e2385dc 100644 --- a/lib/mks-screen.h +++ b/lib/mks-screen.h @@ -25,7 +25,7 @@ # error "Only can be included directly." #endif -#include +#include #include "mks-types.h" #include "mks-version-macros.h" @@ -51,19 +51,34 @@ typedef enum _MksScreenKind MKS_AVAILABLE_IN_ALL GType mks_screen_get_type (void) G_GNUC_CONST; MKS_AVAILABLE_IN_ALL -MksScreenKind mks_screen_get_kind (MksScreen *self); +MksScreenKind mks_screen_get_kind (MksScreen *self); MKS_AVAILABLE_IN_ALL -MksKeyboard *mks_screen_get_keyboard (MksScreen *self); +MksKeyboard *mks_screen_get_keyboard (MksScreen *self); MKS_AVAILABLE_IN_ALL -MksMouse *mks_screen_get_mouse (MksScreen *self); +MksMouse *mks_screen_get_mouse (MksScreen *self); MKS_AVAILABLE_IN_ALL -guint mks_screen_get_width (MksScreen *self); +guint mks_screen_get_width (MksScreen *self); MKS_AVAILABLE_IN_ALL -guint mks_screen_get_height (MksScreen *self); +guint mks_screen_get_height (MksScreen *self); MKS_AVAILABLE_IN_ALL -guint mks_screen_get_number (MksScreen *self); +guint mks_screen_get_number (MksScreen *self); MKS_AVAILABLE_IN_ALL -const char *mks_screen_get_device_address (MksScreen *self); +const char *mks_screen_get_device_address (MksScreen *self); +MKS_AVAILABLE_IN_ALL +void mks_screen_configure (MksScreen *self, + MksScreenAttributes *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +MKS_AVAILABLE_IN_ALL +gboolean mks_screen_configure_finish (MksScreen *self, + GAsyncResult *result, + GError **error); +MKS_AVAILABLE_IN_ALL +gboolean mks_screen_configure_sync (MksScreen *self, + MksScreenAttributes *attributes, + GCancellable *cancellable, + GError **error); G_DEFINE_AUTOPTR_CLEANUP_FUNC (MksScreen, g_object_unref) diff --git a/lib/mks-types.h b/lib/mks-types.h index 02a6e02..33eaddd 100644 --- a/lib/mks-types.h +++ b/lib/mks-types.h @@ -29,15 +29,16 @@ G_BEGIN_DECLS +typedef struct _MksDevice MksDevice; +typedef struct _MksKeyboard MksKeyboard; +typedef struct _MksMouse MksMouse; +typedef struct _MksScreen MksScreen; +typedef struct _MksSession MksSession; +typedef struct _MksScreenAttributes MksScreenAttributes; + typedef struct _MksAudio MksAudio; typedef struct _MksChardev MksChardev; typedef struct _MksClipboard MksClipboard; -typedef struct _MksDevice MksDevice; -typedef struct _MksKeyboard MksKeyboard; -typedef struct _MksMouse MksMouse; -typedef struct _MksScreen MksScreen; -typedef struct _MksSerial MksSerial; -typedef struct _MksSession MksSession; typedef struct _MksUsb MksUsb; G_END_DECLS