lib: move PaintableListener into MksPaintable

The goal here is to keep the MksPaintableListener inside of MksPaintable
so that we don't have to create API between the two. Additionally, the
MksPaintable can own it's own G-DBus connection as we don't want to share
them for updates with anything else (as they can have large data chunks
coming across).
This commit is contained in:
Christian Hergert 2023-02-10 16:14:51 -08:00
parent 07158dfa07
commit ed03ea5148
9 changed files with 322 additions and 517 deletions

View File

@ -30,7 +30,6 @@ G_BEGIN_DECLS
# include "mks-init.h" # include "mks-init.h"
# include "mks-keyboard.h" # include "mks-keyboard.h"
# include "mks-mouse.h" # include "mks-mouse.h"
# include "mks-paintable.h"
# include "mks-screen.h" # include "mks-screen.h"
# include "mks-screen-attributes.h" # include "mks-screen-attributes.h"
# include "mks-session.h" # include "mks-session.h"

View File

@ -15,7 +15,6 @@ libmks_headers = [
'mks-init.h', 'mks-init.h',
'mks-keyboard.h', 'mks-keyboard.h',
'mks-mouse.h', 'mks-mouse.h',
'mks-paintable.h',
'mks-screen.h', 'mks-screen.h',
'mks-screen-attributes.h', 'mks-screen-attributes.h',
'mks-session.h', 'mks-session.h',
@ -24,7 +23,6 @@ libmks_headers = [
libmks_private_sources = [ libmks_private_sources = [
'mks-framebuffer.c', 'mks-framebuffer.c',
'mks-paintable-listener.c',
'mks-read-only-list-model.c', 'mks-read-only-list-model.c',
gnome.gdbus_codegen('mks-qemu', gnome.gdbus_codegen('mks-qemu',

View File

@ -26,7 +26,7 @@
#include "mks-init.h" #include "mks-init.h"
#include "mks-keyboard.h" #include "mks-keyboard.h"
#include "mks-mouse.h" #include "mks-mouse.h"
#include "mks-paintable.h" #include "mks-paintable-private.h"
#include "mks-qemu.h" #include "mks-qemu.h"
#include "mks-read-only-list-model-private.h" #include "mks-read-only-list-model-private.h"
#include "mks-screen.h" #include "mks-screen.h"
@ -50,12 +50,12 @@ mks_init_gtypes (void)
/* Internal types not exposed in public API */ /* Internal types not exposed in public API */
g_type_ensure (MKS_TYPE_READ_ONLY_LIST_MODEL); g_type_ensure (MKS_TYPE_READ_ONLY_LIST_MODEL);
g_type_ensure (MKS_TYPE_PAINTABLE);
/* GTypes that are part of our public API */ /* GTypes that are part of our public API */
g_type_ensure (MKS_TYPE_DEVICE); g_type_ensure (MKS_TYPE_DEVICE);
g_type_ensure (MKS_TYPE_KEYBOARD); g_type_ensure (MKS_TYPE_KEYBOARD);
g_type_ensure (MKS_TYPE_MOUSE); g_type_ensure (MKS_TYPE_MOUSE);
g_type_ensure (MKS_TYPE_PAINTABLE);
g_type_ensure (MKS_TYPE_SCREEN); g_type_ensure (MKS_TYPE_SCREEN);
g_type_ensure (MKS_TYPE_SCREEN_ATTRIBUTES); g_type_ensure (MKS_TYPE_SCREEN_ATTRIBUTES);
g_type_ensure (MKS_TYPE_SESSION); g_type_ensure (MKS_TYPE_SESSION);

View File

@ -1,35 +0,0 @@
/*
* mks-paintable-listener-private.h
*
* Copyright 2023 Christian Hergert <chergert@redhat.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "mks-qemu.h"
G_BEGIN_DECLS
#define MKS_TYPE_PAINTABLE_LISTENER (mks_paintable_listener_get_type())
#define MKS_PAINTABLE_LISTENER_OBJECT_PATH "/org/qemu/Display1/Listener"
G_DECLARE_FINAL_TYPE (MksPaintableListener, mks_paintable_listener, MKS, PAINTABLE_LISTENER, MksQemuListenerSkeleton)
MksPaintableListener *mks_paintable_listener_new (void);
G_END_DECLS

View File

@ -1,150 +0,0 @@
/*
* mks-paintable-listener.c
*
* Copyright 2023 Christian Hergert <chergert@redhat.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "config.h"
#include "mks-paintable-listener-private.h"
struct _MksPaintableListener
{
MksQemuListenerSkeleton parent_instance;
};
static gboolean
mks_paintable_listener_update_dmabuf (MksQemuListener *listener,
GDBusMethodInvocation *invocation,
int x,
int y,
int width,
int height)
{
return FALSE;
}
static gboolean
mks_paintable_listener_scanout_dmabuf (MksQemuListener *listener,
GDBusMethodInvocation *invocation,
GUnixFDList *unix_fd_list,
GVariant *dmabuf,
guint width,
guint height,
guint stride,
guint fourcc,
guint64 modifier,
gboolean y0_top)
{
return FALSE;
}
static gboolean
mks_paintable_listener_update (MksQemuListener *listener,
GDBusMethodInvocation *invocation,
int x,
int y,
int width,
int height,
guint stride,
guint pixman_format,
GVariant *bytes)
{
return TRUE;
}
static gboolean
mks_paintable_listener_scanout (MksQemuListener *listener,
GDBusMethodInvocation *invocation,
guint width,
guint height,
guint stride,
guint pixman_format,
GVariant *bytes)
{
return TRUE;
}
static gboolean
mks_paintable_listener_cursor_define (MksQemuListener *listener,
GDBusMethodInvocation *invocation,
int width,
int height,
int hot_x,
int hot_y,
GVariant *bytes)
{
return FALSE;
}
static gboolean
mks_paintable_listener_mouse_set (MksQemuListener *listener,
GDBusMethodInvocation *invocation,
int x,
int y,
int on)
{
return FALSE;
}
static gboolean
mks_paintable_listener_disable (MksQemuListener *listener,
GDBusMethodInvocation *invocation)
{
return TRUE;
}
static void
listener_iface_init (MksQemuListenerIface *iface)
{
iface->handle_update = mks_paintable_listener_update;
iface->handle_scanout = mks_paintable_listener_scanout;
iface->handle_update_dmabuf = mks_paintable_listener_update_dmabuf;
iface->handle_scanout_dmabuf = mks_paintable_listener_scanout_dmabuf;
iface->handle_cursor_define = mks_paintable_listener_cursor_define;
iface->handle_mouse_set = mks_paintable_listener_mouse_set;
iface->handle_disable = mks_paintable_listener_disable;
}
G_DEFINE_FINAL_TYPE_WITH_CODE (MksPaintableListener, mks_paintable_listener, MKS_QEMU_TYPE_LISTENER_SKELETON,
G_IMPLEMENT_INTERFACE (MKS_QEMU_TYPE_LISTENER, listener_iface_init))
MksPaintableListener *
mks_paintable_listener_new (void)
{
return g_object_new (MKS_TYPE_PAINTABLE_LISTENER, NULL);
}
static void
mks_paintable_listener_finalize (GObject *object)
{
G_OBJECT_CLASS (mks_paintable_listener_parent_class)->finalize (object);
}
static void
mks_paintable_listener_class_init (MksPaintableListenerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = mks_paintable_listener_finalize;
}
static void
mks_paintable_listener_init (MksPaintableListener *self)
{
}

View File

@ -21,13 +21,16 @@
#pragma once #pragma once
#include "mks-paintable.h" #include <gdk/gdk.h>
#include "mks-paintable-listener-private.h"
G_BEGIN_DECLS G_BEGIN_DECLS
GdkPaintable *_mks_paintable_new (GDBusConnection *connection, #define MKS_TYPE_PAINTABLE (mks_paintable_get_type())
MksScreen *screen,
MksPaintableListener *listener); G_DECLARE_FINAL_TYPE (MksPaintable, mks_paintable, MKS, PAINTABLE, GObject)
GdkPaintable *_mks_paintable_new (GCancellable *cancellable,
int *peer_fd,
GError **error);
G_END_DECLS G_END_DECLS

View File

@ -21,185 +21,46 @@
#include "config.h" #include "config.h"
#include <errno.h>
#include <sys/socket.h>
#include <glib/gstdio.h>
#include "mks-paintable-private.h" #include "mks-paintable-private.h"
#include "mks-screen.h" #include "mks-qemu.h"
struct _MksPaintable struct _MksPaintable
{ {
GObject parent_instance; GObject parent_instance;
MksScreen *screen;
guint width;
guint height;
MksQemuListener *listener;
GDBusConnection *connection;
}; };
static void paintable_iface_init (GdkPaintableInterface *iface);
G_DEFINE_FINAL_TYPE_WITH_CODE (MksPaintable, mks_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, paintable_iface_init))
enum {
PROP_0,
PROP_SCREEN,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
GdkPaintable *
mks_paintable_new (MksScreen *screen)
{
g_return_val_if_fail (MKS_IS_SCREEN (screen), NULL);
return g_object_new (MKS_TYPE_PAINTABLE,
"screen", screen,
NULL);
}
static void
mks_paintable_set_screen (MksPaintable *self,
MksScreen *screen)
{
g_assert (MKS_IS_PAINTABLE (self));
g_assert (MKS_IS_SCREEN (screen));
if (g_set_object (&self->screen, screen))
{
g_signal_connect_object (self->screen,
"notify::width",
G_CALLBACK (gdk_paintable_invalidate_size),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (self->screen,
"notify::height",
G_CALLBACK (gdk_paintable_invalidate_size),
self,
G_CONNECT_SWAPPED);
}
}
static void
mks_paintable_dispose (GObject *object)
{
MksPaintable *self = (MksPaintable *)object;
g_clear_object (&self->screen);
G_OBJECT_CLASS (mks_paintable_parent_class)->dispose (object);
}
static void
mks_paintable_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MksPaintable *self = MKS_PAINTABLE (object);
switch (prop_id)
{
case PROP_SCREEN:
g_value_set_object (value, mks_paintable_get_screen (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
mks_paintable_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MksPaintable *self = MKS_PAINTABLE (object);
switch (prop_id)
{
case PROP_SCREEN:
mks_paintable_set_screen (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
mks_paintable_class_init (MksPaintableClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = mks_paintable_dispose;
object_class->get_property = mks_paintable_get_property;
object_class->set_property = mks_paintable_set_property;
properties [PROP_SCREEN] =
g_param_spec_object ("screen", NULL, NULL,
MKS_TYPE_SCREEN,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
mks_paintable_init (MksPaintable *self)
{
}
/**
* mks_paintable_get_screen:
* @self: a #MksPaintable
*
* Gets the #MksScreen displayed in the paintable.
*
* Returns: (nullable) (transfer none): a #MksScreen or %NULL
*/
MksScreen *
mks_paintable_get_screen (MksPaintable *self)
{
g_return_val_if_fail (MKS_IS_PAINTABLE (self), NULL);
return self->screen;
}
static int static int
mks_paintable_get_intrinsic_height (GdkPaintable *paintable) mks_paintable_get_intrinsic_height (GdkPaintable *paintable)
{ {
MksPaintable *self = MKS_PAINTABLE (paintable); return MKS_PAINTABLE (paintable)->height;
return self->screen ? mks_screen_get_height (self->screen) : 0;
} }
static int static int
mks_paintable_get_intrinsic_width (GdkPaintable *paintable) mks_paintable_get_intrinsic_width (GdkPaintable *paintable)
{ {
MksPaintable *self = MKS_PAINTABLE (paintable); return MKS_PAINTABLE (paintable)->width;
return self->screen ? mks_screen_get_width (self->screen) : 0;
} }
static double static double
mks_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable) mks_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
{ {
MksPaintable *self = MKS_PAINTABLE (paintable); MksPaintable *self = MKS_PAINTABLE (paintable);
double width;
double height;
if (self->screen == NULL) if (self->width == 0 || self->height == 0)
return 1.; return 1.;
width = mks_screen_get_width (self->screen); return (double)self->width / (double)self->height;
height = mks_screen_get_height (self->screen);
if (width == 0 || height == 0)
return 1;
return width / height;
}
static GdkPaintableFlags
mks_paintable_get_flags (GdkPaintable *paintable)
{
return 0;
} }
static void static void
@ -208,11 +69,6 @@ mks_paintable_snapshot (GdkPaintable *paintable,
double width, double width,
double height) double height)
{ {
MksPaintable *self = (MksPaintable *)paintable;
g_assert (MKS_IS_PAINTABLE (self));
g_assert (GDK_IS_SNAPSHOT (snapshot));
} }
static void static void
@ -220,21 +76,295 @@ paintable_iface_init (GdkPaintableInterface *iface)
{ {
iface->get_intrinsic_height = mks_paintable_get_intrinsic_height; iface->get_intrinsic_height = mks_paintable_get_intrinsic_height;
iface->get_intrinsic_width = mks_paintable_get_intrinsic_width; iface->get_intrinsic_width = mks_paintable_get_intrinsic_width;
iface->get_flags = mks_paintable_get_flags;
iface->get_intrinsic_aspect_ratio = mks_paintable_get_intrinsic_aspect_ratio; iface->get_intrinsic_aspect_ratio = mks_paintable_get_intrinsic_aspect_ratio;
iface->snapshot = mks_paintable_snapshot; iface->snapshot = mks_paintable_snapshot;
} }
GdkPaintable * G_DEFINE_FINAL_TYPE_WITH_CODE (MksPaintable, mks_paintable, G_TYPE_OBJECT,
_mks_paintable_new (GDBusConnection *connection, G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, paintable_iface_init))
MksScreen *screen,
MksPaintableListener *listener) static void
mks_paintable_dispose (GObject *object)
{ {
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); MksPaintable *self = (MksPaintable *)object;
g_return_val_if_fail (MKS_IS_SCREEN (screen), NULL);
g_return_val_if_fail (MKS_IS_PAINTABLE_LISTENER (listener), NULL);
/* TODO: */ g_clear_object (&self->connection);
g_clear_object (&self->listener);
return mks_paintable_new (screen); G_OBJECT_CLASS (mks_paintable_parent_class)->dispose (object);
}
static void
mks_paintable_class_init (MksPaintableClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = mks_paintable_dispose;
}
static void
mks_paintable_init (MksPaintable *self)
{
}
static gboolean
mks_paintable_listener_update_dmabuf (MksPaintable *self,
GDBusMethodInvocation *invocation,
int x,
int y,
int width,
int height,
MksQemuListener *listener)
{
g_assert (MKS_IS_PAINTABLE (self));
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
g_assert (MKS_QEMU_IS_LISTENER (listener));
return FALSE;
}
static gboolean
mks_paintable_listener_scanout_dmabuf (MksPaintable *self,
GDBusMethodInvocation *invocation,
GUnixFDList *unix_fd_list,
GVariant *dmabuf,
guint width,
guint height,
guint stride,
guint fourcc,
guint64 modifier,
gboolean y0_top,
MksQemuListener *listener)
{
gboolean size_changed;
g_assert (MKS_IS_PAINTABLE (self));
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
g_assert (MKS_QEMU_IS_LISTENER (listener));
size_changed = width != self->width || height != self->height;
if (size_changed)
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
else
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
return FALSE;
}
static gboolean
mks_paintable_listener_update (MksPaintable *self,
GDBusMethodInvocation *invocation,
int x,
int y,
int width,
int height,
guint stride,
guint pixman_format,
GVariant *bytes,
MksQemuListener *listener)
{
g_assert (MKS_IS_PAINTABLE (self));
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
g_assert (MKS_QEMU_IS_LISTENER (listener));
return FALSE;
}
static gboolean
mks_paintable_listener_scanout (MksPaintable *self,
GDBusMethodInvocation *invocation,
guint width,
guint height,
guint stride,
guint pixman_format,
GVariant *bytes,
MksQemuListener *listener)
{
gboolean size_changed;
g_assert (MKS_IS_PAINTABLE (self));
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
g_assert (MKS_QEMU_IS_LISTENER (listener));
size_changed = width != self->width || height != self->height;
if (size_changed)
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
else
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
return FALSE;
}
static gboolean
mks_paintable_listener_cursor_define (MksPaintable *self,
GDBusMethodInvocation *invocation,
int width,
int height,
int hot_x,
int hot_y,
GVariant *bytes,
MksQemuListener *listener)
{
g_assert (MKS_IS_PAINTABLE (self));
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
g_assert (MKS_QEMU_IS_LISTENER (listener));
return FALSE;
}
static gboolean
mks_paintable_listener_mouse_set (MksPaintable *self,
GDBusMethodInvocation *invocation,
int x,
int y,
int on,
MksQemuListener *listener)
{
g_assert (MKS_IS_PAINTABLE (self));
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
g_assert (MKS_QEMU_IS_LISTENER (listener));
return FALSE;
}
static gboolean
mks_paintable_listener_disable (MksPaintable *self,
GDBusMethodInvocation *invocation,
MksQemuListener *listener)
{
g_assert (MKS_IS_PAINTABLE (self));
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
g_assert (MKS_QEMU_IS_LISTENER (listener));
return FALSE;
}
static gboolean
create_socketpair (int *us,
int *them,
GError **error)
{
int fds[2];
int rv;
rv = socketpair (AF_UNIX, SOCK_NONBLOCK|SOCK_CLOEXEC, SOCK_STREAM, fds);
if (rv != 0)
{
int errsv = errno;
g_set_error_literal (error,
G_IO_ERROR,
g_io_error_from_errno (errsv),
g_strerror (errsv));
return FALSE;
}
*us = fds[0];
*them = fds[1];
return TRUE;
}
GdkPaintable *
_mks_paintable_new (GCancellable *cancellable,
int *peer_fd,
GError **error)
{
g_autoptr(MksPaintable) self = NULL;
g_autoptr(MksQemuListener) listener = NULL;
g_autoptr(GDBusConnection) connection = NULL;
g_autoptr(GSocketConnection) io_stream = NULL;
g_autoptr(GSocket) socket = NULL;
g_autofd int us = -1;
g_autofd int them = -1;
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (peer_fd != NULL, NULL);
*peer_fd = -1;
self = g_object_new (MKS_TYPE_PAINTABLE, NULL);
/* Create a socketpair() to use for D-Bus P2P protocol. We will be receiving
* DMA-BUF FDs over this.
*/
if (!create_socketpair (&us, &them, error))
return NULL;
/* Create socket for our side of the socket pair */
if (!(socket = g_socket_new_from_fd (us, error)))
return NULL;
us = -1;
/* And convert that socket into a GIOStream */
io_stream = g_socket_connection_factory_create_connection (socket);
/* Setup our GDBusConnection. We can do this synchronously because we are
* not connecting to a message bus, therefore nothing to process up front.
*/
if (!(connection = g_dbus_connection_new_sync (G_IO_STREAM (io_stream),
NULL,
G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
NULL,
cancellable,
error)))
return NULL;
/* Setup our listener and callbacks to process requests */
listener = mks_qemu_listener_skeleton_new ();
g_signal_connect_object (listener,
"handle-scanout",
G_CALLBACK (mks_paintable_listener_scanout),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (listener,
"handle-update",
G_CALLBACK (mks_paintable_listener_update),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (listener,
"handle-scanout-dmabuf",
G_CALLBACK (mks_paintable_listener_scanout_dmabuf),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (listener,
"handle-update-dmabuf",
G_CALLBACK (mks_paintable_listener_update_dmabuf),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (listener,
"handle-disable",
G_CALLBACK (mks_paintable_listener_disable),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (listener,
"handle-cursor-define",
G_CALLBACK (mks_paintable_listener_cursor_define),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (listener,
"handle-mouse-set",
G_CALLBACK (mks_paintable_listener_mouse_set),
self,
G_CONNECT_SWAPPED);
/* Export our listener before we return back so we know that when the peer
* tries to connect, we're guaranteed to already be available.
*/
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (listener),
connection,
"/org/qemu/Display1/Listener",
error))
return NULL;
self->connection = g_object_ref (connection);
self->listener = g_object_ref (listener);
g_dbus_connection_start_message_processing (connection);
*peer_fd = g_steal_fd (&them);
return GDK_PAINTABLE (g_steal_pointer (&self));
} }

View File

@ -1,45 +0,0 @@
/*
* mks-paintable.h
*
* Copyright 2023 Christian Hergert <chergert@redhat.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#if !defined(MKS_INSIDE) && !defined(MKS_COMPILATION)
# error "Only <libmks.h> can be included directly."
#endif
#include <gdk/gdk.h>
#include "mks-types.h"
#include "mks-version-macros.h"
G_BEGIN_DECLS
#define MKS_TYPE_PAINTABLE (mks_paintable_get_type())
MKS_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (MksPaintable, mks_paintable, MKS, PAINTABLE, GObject)
MKS_AVAILABLE_IN_ALL
GdkPaintable *mks_paintable_new (MksScreen *screen);
MKS_AVAILABLE_IN_ALL
MksScreen *mks_paintable_get_screen (MksPaintable *self);
G_END_DECLS

View File

@ -31,7 +31,6 @@
#include "mks-qemu.h" #include "mks-qemu.h"
#include "mks-keyboard-private.h" #include "mks-keyboard-private.h"
#include "mks-mouse-private.h" #include "mks-mouse-private.h"
#include "mks-paintable-listener-private.h"
#include "mks-paintable-private.h" #include "mks-paintable-private.h"
#include "mks-screen-attributes-private.h" #include "mks-screen-attributes-private.h"
#include "mks-screen-private.h" #include "mks-screen-private.h"
@ -564,35 +563,6 @@ mks_screen_configure_sync (MksScreen *self,
error); error);
} }
static gboolean
mks_screen_create_socketpair (int *us,
int *them,
GError **error)
{
int rv;
int fds[2];
g_assert (us != NULL);
g_assert (them != NULL);
rv = socketpair (AF_UNIX, SOCK_NONBLOCK | SOCK_CLOEXEC, SOCK_STREAM, fds);
if (rv != 0)
{
int errsv = errno;
g_set_error_literal (error,
G_IO_ERROR,
g_io_error_from_errno (errsv),
g_strerror (errsv));
return FALSE;
}
*us = fds[0];
*them = fds[1];
return TRUE;
}
static void static void
mks_screen_attach_cb (GObject *object, mks_screen_attach_cb (GObject *object,
GAsyncResult *result, GAsyncResult *result,
@ -635,15 +605,11 @@ mks_screen_attach (MksScreen *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
g_autoptr(MksPaintableListener) listener = NULL;
g_autoptr(GUnixFDList) unix_fd_list = NULL; g_autoptr(GUnixFDList) unix_fd_list = NULL;
g_autoptr(GDBusConnection) connection = NULL; g_autoptr(GdkPaintable) paintable = NULL;
g_autoptr(GSocketConnection) io_stream = NULL;
g_autoptr(GSocket) socket = NULL;
g_autoptr(GTask) task = NULL; g_autoptr(GTask) task = NULL;
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
g_autofd int us = -1; g_autofd int fd = -1;
g_autofd int them = -1;
g_return_if_fail (MKS_IS_SCREEN (self)); g_return_if_fail (MKS_IS_SCREEN (self));
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
@ -652,41 +618,12 @@ mks_screen_attach (MksScreen *self,
g_task_set_source_tag (task, mks_screen_attach); g_task_set_source_tag (task, mks_screen_attach);
if (!check_console (self, &error) || if (!check_console (self, &error) ||
!mks_screen_create_socketpair (&us, &them, &error)) !(paintable = _mks_paintable_new (cancellable, &fd, &error)))
goto failure; goto failure;
g_assert (us != -1); g_task_set_task_data (task, g_steal_pointer (&paintable), g_object_unref);
g_assert (them != -1);
if (!(socket = g_socket_new_from_fd (us, &error)))
goto failure;
us = -1;
io_stream = g_socket_connection_factory_create_connection (socket);
connection = g_dbus_connection_new_sync (G_IO_STREAM (io_stream),
NULL,
G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
NULL,
cancellable,
&error);
if (connection == NULL)
goto failure;
unix_fd_list = g_unix_fd_list_new_from_array (&them, 1);
them = -1;
listener = mks_paintable_listener_new ();
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (listener),
connection,
MKS_PAINTABLE_LISTENER_OBJECT_PATH,
&error))
goto failure;
g_task_set_task_data (task,
_mks_paintable_new (connection, self, listener),
g_object_unref);
unix_fd_list = g_unix_fd_list_new_from_array (&fd, 1), fd = -1;
mks_qemu_console_call_register_listener (self->console, mks_qemu_console_call_register_listener (self->console,
g_variant_new_handle (0), g_variant_new_handle (0),
unix_fd_list, unix_fd_list,
@ -694,8 +631,6 @@ mks_screen_attach (MksScreen *self,
mks_screen_attach_cb, mks_screen_attach_cb,
g_steal_pointer (&task)); g_steal_pointer (&task));
g_dbus_connection_start_message_processing (connection);
return; return;
failure: failure:
@ -747,47 +682,17 @@ mks_screen_attach_sync (MksScreen *self,
GError **error) GError **error)
{ {
g_autoptr(GUnixFDList) unix_fd_list = NULL; g_autoptr(GUnixFDList) unix_fd_list = NULL;
g_autoptr(GDBusConnection) connection = NULL; g_autoptr(GdkPaintable) paintable = NULL;
g_autoptr(GSocketConnection) io_stream = NULL; g_autofd int fd = -1;
g_autoptr(MksPaintableListener) listener = NULL;
g_autoptr(GSocket) socket = NULL;
g_autofd int us = -1;
g_autofd int them = -1;
g_return_val_if_fail (MKS_IS_SCREEN (self), NULL); g_return_val_if_fail (MKS_IS_SCREEN (self), NULL);
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
if (!check_console (self, error) || if (!check_console (self, error) ||
!mks_screen_create_socketpair (&us, &them, error)) !(paintable = _mks_paintable_new (cancellable, &fd, error)))
return NULL;
g_assert (us != -1);
g_assert (them != -1);
if (!(socket = g_socket_new_from_fd (us, error)))
return NULL;
us = -1;
io_stream = g_socket_connection_factory_create_connection (socket);
connection = g_dbus_connection_new_sync (G_IO_STREAM (io_stream),
NULL,
G_DBUS_CONNECTION_FLAGS_NONE,
NULL,
cancellable,
error);
if (connection == NULL)
return FALSE;
unix_fd_list = g_unix_fd_list_new_from_array (&them, 1);
them = -1;
listener = mks_paintable_listener_new ();
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (listener),
connection,
MKS_PAINTABLE_LISTENER_OBJECT_PATH,
error))
return NULL; return NULL;
unix_fd_list = g_unix_fd_list_new_from_array (&fd, 1), fd = -1;
if (!mks_qemu_console_call_register_listener_sync (self->console, if (!mks_qemu_console_call_register_listener_sync (self->console,
g_variant_new_handle (0), g_variant_new_handle (0),
unix_fd_list, unix_fd_list,
@ -796,5 +701,5 @@ mks_screen_attach_sync (MksScreen *self,
error)) error))
return NULL; return NULL;
return _mks_paintable_new (connection, self, listener); return g_steal_pointer (&paintable);
} }