mirror of
https://gitlab.gnome.org/GNOME/libmks.git
synced 2024-11-05 00:11:16 +00:00
2e842f7e7f
This just starts on the DMA-BUF code and abstracts MksPaintable so it can encapsulate both MksDmabufPaintable and MksCairoFramebuffer. Currently, the dmabuf just tailes everything (fully) but we can fix that with snapshot work stil. Either way, want to get the abstraction landed first before we dive deeper into that.
659 lines
22 KiB
C
659 lines
22 KiB
C
/*
|
|
* mks-paintable.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 <errno.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include <glib/gstdio.h>
|
|
#include <pixman.h>
|
|
|
|
#include "mks-cairo-framebuffer-private.h"
|
|
#include "mks-dmabuf-paintable-private.h"
|
|
#include "mks-paintable-private.h"
|
|
#include "mks-qemu.h"
|
|
|
|
struct _MksPaintable
|
|
{
|
|
GObject parent_instance;
|
|
GdkGLContext *gl_context;
|
|
MksQemuListener *listener;
|
|
GDBusConnection *connection;
|
|
GdkPaintable *child;
|
|
};
|
|
|
|
static cairo_format_t
|
|
_pixman_format_to_cairo_format (guint pixman_format)
|
|
{
|
|
switch (pixman_format)
|
|
{
|
|
case PIXMAN_rgba_float:
|
|
return CAIRO_FORMAT_RGBA128F;
|
|
case PIXMAN_rgb_float:
|
|
return CAIRO_FORMAT_RGB96F;
|
|
case PIXMAN_a8r8g8b8:
|
|
return CAIRO_FORMAT_ARGB32;
|
|
case PIXMAN_x2r10g10b10:
|
|
return CAIRO_FORMAT_RGB30;
|
|
case PIXMAN_x8r8g8b8:
|
|
return CAIRO_FORMAT_RGB24;
|
|
case PIXMAN_a8:
|
|
return CAIRO_FORMAT_A8;
|
|
case PIXMAN_a1:
|
|
return CAIRO_FORMAT_A1;
|
|
case PIXMAN_r5g6b5:
|
|
return CAIRO_FORMAT_RGB16_565;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
mks_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
|
{
|
|
GdkPaintable *child = MKS_PAINTABLE (paintable)->child;
|
|
|
|
return child ? gdk_paintable_get_intrinsic_height (child) : 0;
|
|
}
|
|
|
|
static int
|
|
mks_paintable_get_intrinsic_width (GdkPaintable *paintable)
|
|
{
|
|
GdkPaintable *child = MKS_PAINTABLE (paintable)->child;
|
|
|
|
return child ? gdk_paintable_get_intrinsic_width (child) : 0;
|
|
}
|
|
|
|
static double
|
|
mks_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
|
|
{
|
|
GdkPaintable *child = MKS_PAINTABLE (paintable)->child;
|
|
|
|
return child ? gdk_paintable_get_intrinsic_aspect_ratio (child) : .0;
|
|
}
|
|
|
|
static void
|
|
mks_paintable_snapshot (GdkPaintable *paintable,
|
|
GdkSnapshot *snapshot,
|
|
double width,
|
|
double height)
|
|
{
|
|
GdkPaintable *child = MKS_PAINTABLE (paintable)->child;
|
|
|
|
if (child != NULL)
|
|
gdk_paintable_snapshot (child, snapshot, width, height);
|
|
}
|
|
|
|
static void
|
|
paintable_iface_init (GdkPaintableInterface *iface)
|
|
{
|
|
iface->get_intrinsic_height = mks_paintable_get_intrinsic_height;
|
|
iface->get_intrinsic_width = mks_paintable_get_intrinsic_width;
|
|
iface->get_intrinsic_aspect_ratio = mks_paintable_get_intrinsic_aspect_ratio;
|
|
iface->snapshot = mks_paintable_snapshot;
|
|
}
|
|
|
|
G_DEFINE_FINAL_TYPE_WITH_CODE (MksPaintable, mks_paintable, G_TYPE_OBJECT,
|
|
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, paintable_iface_init))
|
|
|
|
static GdkGLContext *
|
|
mks_paintable_get_gl_context (MksPaintable *self,
|
|
GError **error)
|
|
{
|
|
g_assert (MKS_IS_PAINTABLE (self));
|
|
|
|
if (self->gl_context == NULL)
|
|
{
|
|
GdkDisplay *display = gdk_display_get_default ();
|
|
|
|
if (!(self->gl_context = gdk_display_create_gl_context (display, error)))
|
|
return NULL;
|
|
}
|
|
|
|
return self->gl_context;
|
|
}
|
|
|
|
static void
|
|
mks_paintable_dispose (GObject *object)
|
|
{
|
|
MksPaintable *self = (MksPaintable *)object;
|
|
|
|
g_clear_object (&self->connection);
|
|
g_clear_object (&self->listener);
|
|
g_clear_object (&self->child);
|
|
g_clear_object (&self->gl_context);
|
|
|
|
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 void
|
|
mks_paintable_invalidate_contents_cb (MksPaintable *self,
|
|
GdkPaintable *paintable)
|
|
{
|
|
g_assert (MKS_IS_PAINTABLE (self));
|
|
g_assert (GDK_IS_PAINTABLE (paintable));
|
|
|
|
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
|
}
|
|
|
|
static void
|
|
mks_paintable_invalidate_size_cb (MksPaintable *self,
|
|
GdkPaintable *paintable)
|
|
{
|
|
g_assert (MKS_IS_PAINTABLE (self));
|
|
g_assert (GDK_IS_PAINTABLE (paintable));
|
|
|
|
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
|
|
}
|
|
|
|
static void
|
|
mks_paintable_set_child (MksPaintable *self,
|
|
GdkPaintable *child)
|
|
{
|
|
gboolean size_changed;
|
|
|
|
g_assert (MKS_IS_PAINTABLE (self));
|
|
g_assert (!child || GDK_IS_PAINTABLE (child));
|
|
|
|
if (self->child == child)
|
|
return;
|
|
|
|
size_changed = self->child == NULL ||
|
|
child == NULL ||
|
|
gdk_paintable_get_intrinsic_width (self->child) != gdk_paintable_get_intrinsic_width (child) ||
|
|
gdk_paintable_get_intrinsic_height (self->child) != gdk_paintable_get_intrinsic_height (child);
|
|
|
|
if (self->child != NULL)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (self->child,
|
|
G_CALLBACK (mks_paintable_invalidate_size_cb),
|
|
self);
|
|
g_signal_handlers_disconnect_by_func (self->child,
|
|
G_CALLBACK (mks_paintable_invalidate_contents_cb),
|
|
self);
|
|
g_clear_object (&self->child);
|
|
}
|
|
|
|
if (child != NULL)
|
|
{
|
|
self->child = g_object_ref (child);
|
|
g_signal_connect_object (self->child,
|
|
"invalidate-size",
|
|
G_CALLBACK (mks_paintable_invalidate_size_cb),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (self->child,
|
|
"invalidate-contents",
|
|
G_CALLBACK (mks_paintable_invalidate_contents_cb),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
}
|
|
|
|
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
|
|
|
if (size_changed)
|
|
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
|
|
}
|
|
|
|
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)
|
|
{
|
|
g_autoptr(MksDmabufPaintable) child = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autofd int dmabuf_fd = -1;
|
|
GdkGLContext *gl_context;
|
|
guint handle;
|
|
|
|
g_assert (MKS_IS_PAINTABLE (self));
|
|
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
|
g_assert (MKS_QEMU_IS_LISTENER (listener));
|
|
g_assert (g_variant_is_of_type (dmabuf, G_VARIANT_TYPE_HANDLE));
|
|
|
|
handle = g_variant_get_handle (dmabuf);
|
|
|
|
if (handle >= g_unix_fd_list_get_length (unix_fd_list))
|
|
{
|
|
g_dbus_method_invocation_return_error_literal (invocation,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Invalid handle to DMA-BUF");
|
|
return TRUE;
|
|
}
|
|
|
|
if (-1 == (dmabuf_fd = g_unix_fd_list_get (unix_fd_list, handle, &error)) ||
|
|
!(gl_context = mks_paintable_get_gl_context (self, &error)) ||
|
|
!(child = mks_dmabuf_paintable_new (gl_context,
|
|
dmabuf_fd,
|
|
width, height,
|
|
stride, fourcc,
|
|
modifier, y0_top,
|
|
&error)))
|
|
{
|
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
|
return TRUE;
|
|
}
|
|
|
|
mks_paintable_set_child (self, GDK_PAINTABLE (child));
|
|
|
|
mks_qemu_listener_complete_scanout_dmabuf (listener, invocation, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
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));
|
|
|
|
if (MKS_IS_DMABUF_PAINTABLE (self->child))
|
|
mks_dmabuf_paintable_invalidate (MKS_DMABUF_PAINTABLE (self->child), x, y, width, height);
|
|
|
|
mks_qemu_listener_complete_update_dmabuf (listener, invocation);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
mks_paintable_listener_update (MksPaintable *self,
|
|
GDBusMethodInvocation *invocation,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height,
|
|
guint stride,
|
|
guint pixman_format,
|
|
GVariant *bytestring,
|
|
MksQemuListener *listener)
|
|
{
|
|
g_autoptr(GBytes) bytes = NULL;
|
|
cairo_surface_t *source;
|
|
const guint8 *data;
|
|
cairo_t *cr;
|
|
cairo_format_t format;
|
|
gsize data_len;
|
|
|
|
g_assert (MKS_IS_PAINTABLE (self));
|
|
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
|
g_assert (MKS_QEMU_IS_LISTENER (listener));
|
|
|
|
if (!MKS_IS_CAIRO_FRAMEBUFFER (self->child) ||
|
|
!(format = _pixman_format_to_cairo_format (pixman_format)))
|
|
{
|
|
g_dbus_method_invocation_return_error_literal (invocation,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"Invalid operation");
|
|
return TRUE;
|
|
}
|
|
|
|
bytes = g_variant_get_data_as_bytes (bytestring);
|
|
data = g_bytes_get_data (bytes, &data_len);
|
|
|
|
if (data_len < cairo_format_stride_for_width (format, width) * height)
|
|
{
|
|
g_dbus_method_invocation_return_error_literal (invocation,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"Stride invalid for size");
|
|
return TRUE;
|
|
}
|
|
|
|
/* We can get in a protocol race condition here in that we will get updates
|
|
* for framebuffer content _BEFORE_ we'll get notified of property changes
|
|
* about the MksQemuConsole's size.
|
|
*
|
|
* To overcome that, if we detect something larger than our current
|
|
* framebuffer, we'll resize it and draw over the old contents in a
|
|
* new framebuffer.
|
|
*
|
|
* When shrinking, we can do this as well and then handle it when the
|
|
* console size notification arrives.
|
|
*
|
|
* Generally this is seen at startup during EFI/BIOS.
|
|
*/
|
|
if (x + width > gdk_paintable_get_intrinsic_width (self->child) ||
|
|
y + height > gdk_paintable_get_intrinsic_height (self->child))
|
|
{
|
|
guint max_width = MAX (gdk_paintable_get_intrinsic_width (self->child), x + width);
|
|
guint max_height = MAX (gdk_paintable_get_intrinsic_height (self->child), y + height);
|
|
g_autoptr(MksCairoFramebuffer) framebuffer = mks_cairo_framebuffer_new (format, max_width, max_height);
|
|
|
|
mks_cairo_framebuffer_copy_to (MKS_CAIRO_FRAMEBUFFER (self->child), framebuffer);
|
|
mks_paintable_set_child (self, GDK_PAINTABLE (framebuffer));
|
|
}
|
|
|
|
source = cairo_image_surface_create_for_data ((guint8 *)data, format, width, height, stride);
|
|
cr = mks_cairo_framebuffer_update (MKS_CAIRO_FRAMEBUFFER (self->child), x, y, width, height);
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
|
cairo_set_source_surface (cr, source, 0, 0);
|
|
cairo_rectangle (cr, 0, 0, width, height);
|
|
cairo_paint (cr);
|
|
cairo_destroy (cr);
|
|
cairo_surface_destroy (source);
|
|
|
|
mks_qemu_listener_complete_update (listener, invocation);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
mks_paintable_listener_scanout (MksPaintable *self,
|
|
GDBusMethodInvocation *invocation,
|
|
guint width,
|
|
guint height,
|
|
guint stride,
|
|
guint pixman_format,
|
|
GVariant *bytestring,
|
|
MksQemuListener *listener)
|
|
{
|
|
g_autoptr(GBytes) bytes = NULL;
|
|
cairo_surface_t *source;
|
|
const guint8 *data;
|
|
cairo_t *cr;
|
|
cairo_format_t format;
|
|
gsize data_len;
|
|
|
|
g_assert (MKS_IS_PAINTABLE (self));
|
|
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
|
|
g_assert (MKS_QEMU_IS_LISTENER (listener));
|
|
g_assert (g_variant_is_of_type (bytestring, G_VARIANT_TYPE_BYTESTRING));
|
|
|
|
if (!(format = _pixman_format_to_cairo_format (pixman_format)))
|
|
{
|
|
g_dbus_method_invocation_return_error_literal (invocation,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"Pixman format not supported");
|
|
return TRUE;
|
|
}
|
|
|
|
bytes = g_variant_get_data_as_bytes (bytestring);
|
|
data = g_bytes_get_data (bytes, &data_len);
|
|
|
|
if (data_len < cairo_format_stride_for_width (format, width) * height)
|
|
{
|
|
g_dbus_method_invocation_return_error_literal (invocation,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
"Stride invalid for size");
|
|
return TRUE;
|
|
}
|
|
|
|
if (self->child == NULL ||
|
|
!MKS_IS_CAIRO_FRAMEBUFFER (self->child) ||
|
|
width != gdk_paintable_get_intrinsic_width (self->child) ||
|
|
height != gdk_paintable_get_intrinsic_height (self->child))
|
|
{
|
|
g_autoptr(MksCairoFramebuffer) child = mks_cairo_framebuffer_new (format, width, height);
|
|
|
|
mks_paintable_set_child (self, GDK_PAINTABLE (child));
|
|
}
|
|
|
|
source = cairo_image_surface_create_for_data ((guint8 *)data, format, width, height, stride);
|
|
cr = mks_cairo_framebuffer_update (MKS_CAIRO_FRAMEBUFFER (self->child), 0, 0, width, height);
|
|
cairo_set_source_surface (cr, source, 0, 0);
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
|
cairo_rectangle (cr, 0, 0, width, height);
|
|
cairo_paint (cr);
|
|
cairo_destroy (cr);
|
|
cairo_surface_destroy (source);
|
|
|
|
mks_qemu_listener_complete_scanout (listener, invocation);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
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));
|
|
|
|
mks_qemu_listener_complete_cursor_define (listener, invocation);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
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));
|
|
|
|
mks_qemu_listener_complete_mouse_set (listener, invocation);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
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));
|
|
|
|
if (MKS_IS_CAIRO_FRAMEBUFFER (self->child))
|
|
mks_cairo_framebuffer_clear (MKS_CAIRO_FRAMEBUFFER (self->child));
|
|
|
|
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
|
|
|
|
mks_qemu_listener_complete_disable (listener, invocation);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
create_socketpair (int *us,
|
|
int *them,
|
|
GError **error)
|
|
{
|
|
int fds[2];
|
|
int rv;
|
|
|
|
rv = socketpair (AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, 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
|
|
mks_paintable_connection_cb (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(MksPaintable) self = user_data;
|
|
g_autoptr(GDBusConnection) connection = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
g_assert (MKS_IS_PAINTABLE (self));
|
|
g_assert (G_IS_ASYNC_RESULT (result));
|
|
|
|
if (!(connection = g_dbus_connection_new_finish (result, &error)))
|
|
{
|
|
g_warning ("Failed to create D-Bus connection: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
g_set_object (&self->connection, connection);
|
|
|
|
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->listener),
|
|
connection,
|
|
"/org/qemu/Display1/Listener",
|
|
&error))
|
|
{
|
|
g_warning ("Failed to export listener on bus: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
g_dbus_connection_start_message_processing (connection);
|
|
|
|
}
|
|
|
|
GdkPaintable *
|
|
_mks_paintable_new (GCancellable *cancellable,
|
|
int *peer_fd,
|
|
GError **error)
|
|
{
|
|
g_autoptr(MksPaintable) self = 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 listener and callbacks to process requests */
|
|
self->listener = mks_qemu_listener_skeleton_new ();
|
|
g_signal_connect_object (self->listener,
|
|
"handle-scanout",
|
|
G_CALLBACK (mks_paintable_listener_scanout),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (self->listener,
|
|
"handle-update",
|
|
G_CALLBACK (mks_paintable_listener_update),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (self->listener,
|
|
"handle-scanout-dmabuf",
|
|
G_CALLBACK (mks_paintable_listener_scanout_dmabuf),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (self->listener,
|
|
"handle-update-dmabuf",
|
|
G_CALLBACK (mks_paintable_listener_update_dmabuf),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (self->listener,
|
|
"handle-disable",
|
|
G_CALLBACK (mks_paintable_listener_disable),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (self->listener,
|
|
"handle-cursor-define",
|
|
G_CALLBACK (mks_paintable_listener_cursor_define),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (self->listener,
|
|
"handle-mouse-set",
|
|
G_CALLBACK (mks_paintable_listener_mouse_set),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
|
|
/* Asynchronously create connection because we can't do it synchronously
|
|
* as the other side is doing AUTHENTICATION_SERVER for no good reason.
|
|
*/
|
|
g_dbus_connection_new (G_IO_STREAM (io_stream),
|
|
NULL,
|
|
G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING|G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
|
|
NULL,
|
|
cancellable,
|
|
mks_paintable_connection_cb,
|
|
g_object_ref (self));
|
|
|
|
*peer_fd = g_steal_fd (&them);
|
|
|
|
g_assert (*peer_fd != -1);
|
|
g_assert (MKS_IS_PAINTABLE (self));
|
|
g_assert (MKS_QEMU_IS_LISTENER (self->listener));
|
|
|
|
return GDK_PAINTABLE (g_steal_pointer (&self));
|
|
}
|