aboutsummaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/clipboard.c66
-rw-r--r--ui/cocoa.m69
-rw-r--r--ui/console-vc.c166
-rw-r--r--ui/console.c95
-rw-r--r--ui/curses.c4
-rw-r--r--ui/cursor.c24
-rw-r--r--ui/dbus-chardev.c4
-rw-r--r--ui/dbus-clipboard.c2
-rw-r--r--ui/dbus-console.c31
-rw-r--r--ui/dbus-display1.xml110
-rw-r--r--ui/dbus-listener.c290
-rw-r--r--ui/dbus.c28
-rw-r--r--ui/dmabuf.c80
-rw-r--r--ui/egl-context.c2
-rw-r--r--ui/egl-headless.c2
-rw-r--r--ui/egl-helpers.c127
-rw-r--r--ui/gtk-clipboard.c13
-rw-r--r--ui/gtk-egl.c60
-rw-r--r--ui/gtk-gl-area.c55
-rw-r--r--ui/gtk.c264
-rw-r--r--ui/input-barrier.c6
-rw-r--r--ui/input-legacy.c37
-rw-r--r--ui/input-linux.c7
-rw-r--r--ui/input.c42
-rw-r--r--ui/meson.build7
-rw-r--r--ui/qemu-pixman.c87
-rw-r--r--ui/sdl2-gl.c10
-rw-r--r--ui/sdl2-input.c5
-rw-r--r--ui/sdl2.c77
-rw-r--r--ui/spice-app.c6
-rw-r--r--ui/spice-core.c6
-rw-r--r--ui/spice-display.c108
-rw-r--r--ui/trace-events1
-rw-r--r--ui/ui-hmp-cmds.c2
-rw-r--r--ui/vdagent.c207
-rw-r--r--ui/vnc-auth-sasl.c75
-rw-r--r--ui/vnc-enc-tight.c20
-rw-r--r--ui/vnc-enc-zrle.c2
-rw-r--r--ui/vnc-jobs.c2
-rw-r--r--ui/vnc.c38
-rw-r--r--ui/vnc.h5
-rw-r--r--ui/win32-kbd-hook.c2
42 files changed, 1594 insertions, 650 deletions
diff --git a/ui/clipboard.c b/ui/clipboard.c
index 132086e..ec00a0b 100644
--- a/ui/clipboard.c
+++ b/ui/clipboard.c
@@ -1,4 +1,5 @@
#include "qemu/osdep.h"
+#include "system/runstate.h"
#include "ui/clipboard.h"
#include "trace.h"
@@ -7,8 +8,62 @@ static NotifierList clipboard_notifiers =
static QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
+static VMChangeStateEntry *cb_change_state_entry = NULL;
+
+static bool cb_reset_serial_on_resume = false;
+
+static const VMStateDescription vmstate_cbcontent = {
+ .name = "clipboard/content",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BOOL(available, QemuClipboardContent),
+ VMSTATE_BOOL(requested, QemuClipboardContent),
+ VMSTATE_UINT32(size, QemuClipboardContent),
+ VMSTATE_VBUFFER_ALLOC_UINT32(data, QemuClipboardContent, 0, 0, size),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+const VMStateDescription vmstate_cbinfo = {
+ .name = "clipboard",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (const VMStateField[]) {
+ VMSTATE_INT32(selection, QemuClipboardInfo),
+ VMSTATE_BOOL(has_serial, QemuClipboardInfo),
+ VMSTATE_UINT32(serial, QemuClipboardInfo),
+ VMSTATE_STRUCT_ARRAY(types, QemuClipboardInfo, QEMU_CLIPBOARD_TYPE__COUNT, 0, vmstate_cbcontent, QemuClipboardContent),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void qemu_clipboard_change_state(void *opaque, bool running, RunState state)
+{
+ int i;
+
+ if (!running) {
+ return;
+ }
+
+ if (cb_reset_serial_on_resume) {
+ qemu_clipboard_reset_serial();
+ }
+
+ for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
+ if (cbinfo[i]) {
+ qemu_clipboard_update(cbinfo[i]);
+ }
+ }
+
+}
+
void qemu_clipboard_peer_register(QemuClipboardPeer *peer)
{
+ if (cb_change_state_entry == NULL) {
+ cb_change_state_entry = qemu_add_vm_change_state_handler(qemu_clipboard_change_state, NULL);
+ }
+
notifier_list_add(&clipboard_notifiers, &peer->notifier);
}
@@ -83,7 +138,9 @@ void qemu_clipboard_update(QemuClipboardInfo *info)
}
}
- notifier_list_notify(&clipboard_notifiers, &notify);
+ if (runstate_is_running() || runstate_check(RUN_STATE_SUSPENDED)) {
+ notifier_list_notify(&clipboard_notifiers, &notify);
+ }
if (cbinfo[info->selection] != info) {
qemu_clipboard_info_unref(cbinfo[info->selection]);
@@ -163,7 +220,12 @@ void qemu_clipboard_reset_serial(void)
info->serial = 0;
}
}
- notifier_list_notify(&clipboard_notifiers, &notify);
+
+ if (runstate_is_running() || runstate_check(RUN_STATE_SUSPENDED)) {
+ notifier_list_notify(&clipboard_notifiers, &notify);
+ } else {
+ cb_reset_serial_on_resume = true;
+ }
}
void qemu_clipboard_set_data(QemuClipboardPeer *peer,
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 4c2dd33..23b7a73 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -34,15 +34,15 @@
#include "ui/console.h"
#include "ui/input.h"
#include "ui/kbd-state.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
-#include "sysemu/runstate-action.h"
-#include "sysemu/cpu-throttle.h"
+#include "system/system.h"
+#include "system/runstate.h"
+#include "system/runstate-action.h"
+#include "system/cpu-throttle.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-block.h"
#include "qapi/qapi-commands-machine.h"
#include "qapi/qapi-commands-misc.h"
-#include "sysemu/blockdev.h"
+#include "system/blockdev.h"
#include "qemu-version.h"
#include "qemu/cutils.h"
#include "qemu/main-loop.h"
@@ -73,6 +73,8 @@ typedef struct {
int height;
} QEMUScreen;
+@class QemuCocoaPasteboardTypeOwner;
+
static void cocoa_update(DisplayChangeListener *dcl,
int x, int y, int w, int h);
@@ -107,6 +109,7 @@ static bool allow_events;
static NSInteger cbchangecount = -1;
static QemuClipboardInfo *cbinfo;
static QemuEvent cbevent;
+static QemuCocoaPasteboardTypeOwner *cbowner;
// Utility functions to run specified code block with the BQL held
typedef void (^CodeBlock)(void);
@@ -639,6 +642,9 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
[self setBoundsSize:NSMakeSize(screen.width, screen.height)];
}
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
- (void) updateUIInfoLocked
{
/* Must be called with the BQL, i.e. via updateUIInfo */
@@ -685,6 +691,8 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
dpy_set_ui_info(dcl.con, &info, TRUE);
}
+#pragma clang diagnostic pop
+
- (void) updateUIInfo
{
if (!allow_events) {
@@ -1321,8 +1329,10 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
{
COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
- if (cocoaView)
- [cocoaView release];
+ [cocoaView release];
+ [cbowner release];
+ cbowner = nil;
+
[super dealloc];
}
@@ -1938,8 +1948,6 @@ static Notifier mouse_mode_change_notifier = {
@end
-static QemuCocoaPasteboardTypeOwner *cbowner;
-
static void cocoa_clipboard_notify(Notifier *notifier, void *data);
static void cocoa_clipboard_request(QemuClipboardInfo *info,
QemuClipboardType type);
@@ -2002,43 +2010,8 @@ static void cocoa_clipboard_request(QemuClipboardInfo *info,
}
}
-/*
- * The startup process for the OSX/Cocoa UI is complicated, because
- * OSX insists that the UI runs on the initial main thread, and so we
- * need to start a second thread which runs the qemu_default_main():
- * in main():
- * in cocoa_display_init():
- * assign cocoa_main to qemu_main
- * create application, menus, etc
- * in cocoa_main():
- * create qemu-main thread
- * enter OSX run loop
- */
-
-static void *call_qemu_main(void *opaque)
-{
- int status;
-
- COCOA_DEBUG("Second thread: calling qemu_default_main()\n");
- bql_lock();
- status = qemu_default_main();
- bql_unlock();
- COCOA_DEBUG("Second thread: qemu_default_main() returned, exiting\n");
- [cbowner release];
- exit(status);
-}
-
static int cocoa_main(void)
{
- QemuThread thread;
-
- COCOA_DEBUG("Entered %s()\n", __func__);
-
- bql_unlock();
- qemu_thread_create(&thread, "qemu_main", call_qemu_main,
- NULL, QEMU_THREAD_DETACHED);
-
- // Start the main event loop
COCOA_DEBUG("Main thread: entering OSX run loop\n");
[NSApp run];
COCOA_DEBUG("Main thread: left OSX run loop, which should never happen\n");
@@ -2120,8 +2093,6 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
- qemu_main = cocoa_main;
-
// Pull this console process up to being a fully-fledged graphical
// app with a menubar and Dock icon
ProcessSerialNumber psn = { 0, kCurrentProcess };
@@ -2185,6 +2156,12 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
qemu_clipboard_peer_register(&cbpeer);
[pool release];
+
+ /*
+ * The Cocoa UI will run the NSApplication runloop on the main thread
+ * rather than the default Core Foundation one.
+ */
+ qemu_main = cocoa_main;
}
static QemuDisplay qemu_display_cocoa = {
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 8393d53..8308420 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -42,6 +42,8 @@ enum TTYState {
TTY_STATE_NORM,
TTY_STATE_ESC,
TTY_STATE_CSI,
+ TTY_STATE_G0,
+ TTY_STATE_G1,
};
typedef struct QemuTextConsole {
@@ -88,6 +90,7 @@ struct VCChardev {
int esc_params[MAX_ESC_PARAMS];
int nb_esc_params;
TextAttributes t_attrib; /* currently active text attributes */
+ TextAttributes t_attrib_saved;
int x_saved, y_saved;
};
typedef struct VCChardev VCChardev;
@@ -615,10 +618,9 @@ static void vc_put_one(VCChardev *vc, int ch)
static void vc_respond_str(VCChardev *vc, const char *buf)
{
- while (*buf) {
- vc_put_one(vc, *buf);
- buf++;
- }
+ QemuTextConsole *s = vc->console;
+
+ qemu_chr_be_write(s->chr, (const uint8_t *)buf, strlen(buf));
}
/* set cursor, checking bounds */
@@ -643,12 +645,119 @@ static void vc_set_cursor(VCChardev *vc, int x, int y)
s->y = y;
}
+/**
+ * vc_csi_P() - (DCH) deletes one or more characters from the cursor
+ * position to the right. As characters are deleted, the remaining
+ * characters between the cursor and right margin move to the
+ * left. Character attributes move with the characters.
+ */
+static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
+{
+ QemuTextConsole *s = vc->console;
+ TextCell *c1, *c2;
+ unsigned int x1, x2, y;
+ unsigned int end, len;
+
+ if (!nr) {
+ nr = 1;
+ }
+ if (nr > s->width - s->x) {
+ nr = s->width - s->x;
+ if (!nr) {
+ return;
+ }
+ }
+
+ x1 = s->x;
+ x2 = s->x + nr;
+ len = s->width - x2;
+ if (len) {
+ y = (s->y_base + s->y) % s->total_height;
+ c1 = &s->cells[y * s->width + x1];
+ c2 = &s->cells[y * s->width + x2];
+ memmove(c1, c2, len * sizeof(*c1));
+ for (end = x1 + len; x1 < end; x1++) {
+ vc_update_xy(vc, x1, s->y);
+ }
+ }
+ /* Clear the rest */
+ for (; x1 < s->width; x1++) {
+ vc_clear_xy(vc, x1, s->y);
+ }
+}
+
+/**
+ * vc_csi_at() - (ICH) inserts `nr` blank characters with the default
+ * character attribute. The cursor remains at the beginning of the
+ * blank characters. Text between the cursor and right margin moves to
+ * the right. Characters scrolled past the right margin are lost.
+ */
+static void vc_csi_at(struct VCChardev *vc, unsigned int nr)
+{
+ QemuTextConsole *s = vc->console;
+ TextCell *c1, *c2;
+ unsigned int x1, x2, y;
+ unsigned int end, len;
+
+ if (!nr) {
+ nr = 1;
+ }
+ if (nr > s->width - s->x) {
+ nr = s->width - s->x;
+ if (!nr) {
+ return;
+ }
+ }
+
+ x1 = s->x + nr;
+ x2 = s->x;
+ len = s->width - x1;
+ if (len) {
+ y = (s->y_base + s->y) % s->total_height;
+ c1 = &s->cells[y * s->width + x1];
+ c2 = &s->cells[y * s->width + x2];
+ memmove(c1, c2, len * sizeof(*c1));
+ for (end = x1 + len; x1 < end; x1++) {
+ vc_update_xy(vc, x1, s->y);
+ }
+ }
+ /* Insert blanks */
+ for (x1 = s->x; x1 < s->x + nr; x1++) {
+ vc_clear_xy(vc, x1, s->y);
+ }
+}
+
+/**
+ * vc_save_cursor() - saves cursor position and character attributes.
+ */
+static void vc_save_cursor(VCChardev *vc)
+{
+ QemuTextConsole *s = vc->console;
+
+ vc->x_saved = s->x;
+ vc->y_saved = s->y;
+ vc->t_attrib_saved = vc->t_attrib;
+}
+
+/**
+ * vc_restore_cursor() - restores cursor position and character
+ * attributes from saved state.
+ */
+static void vc_restore_cursor(VCChardev *vc)
+{
+ QemuTextConsole *s = vc->console;
+
+ s->x = vc->x_saved;
+ s->y = vc->y_saved;
+ vc->t_attrib = vc->t_attrib_saved;
+}
+
static void vc_putchar(VCChardev *vc, int ch)
{
QemuTextConsole *s = vc->console;
int i;
int x, y;
- char response[40];
+ g_autofree char *response = NULL;
switch(vc->state) {
case TTY_STATE_NORM:
@@ -694,6 +803,16 @@ static void vc_putchar(VCChardev *vc, int ch)
vc->esc_params[i] = 0;
vc->nb_esc_params = 0;
vc->state = TTY_STATE_CSI;
+ } else if (ch == '(') {
+ vc->state = TTY_STATE_G0;
+ } else if (ch == ')') {
+ vc->state = TTY_STATE_G1;
+ } else if (ch == '7') {
+ vc_save_cursor(vc);
+ vc->state = TTY_STATE_NORM;
+ } else if (ch == '8') {
+ vc_restore_cursor(vc);
+ vc->state = TTY_STATE_NORM;
} else {
vc->state = TTY_STATE_NORM;
}
@@ -810,6 +929,9 @@ static void vc_putchar(VCChardev *vc, int ch)
break;
}
break;
+ case 'P':
+ vc_csi_P(vc, vc->esc_params[0]);
+ break;
case 'm':
vc_handle_escape(vc);
break;
@@ -821,22 +943,20 @@ static void vc_putchar(VCChardev *vc, int ch)
break;
case 6:
/* report cursor position */
- sprintf(response, "\033[%d;%dR",
- (s->y_base + s->y) % s->total_height + 1,
- s->x + 1);
+ response = g_strdup_printf("\033[%d;%dR",
+ s->y + 1, s->x + 1);
vc_respond_str(vc, response);
break;
}
break;
case 's':
- /* save cursor position */
- vc->x_saved = s->x;
- vc->y_saved = s->y;
+ vc_save_cursor(vc);
break;
case 'u':
- /* restore cursor position */
- s->x = vc->x_saved;
- s->y = vc->y_saved;
+ vc_restore_cursor(vc);
+ break;
+ case '@':
+ vc_csi_at(vc, vc->esc_params[0]);
break;
default:
trace_console_putchar_unhandled(ch);
@@ -844,6 +964,16 @@ static void vc_putchar(VCChardev *vc, int ch)
}
break;
}
+ break;
+ case TTY_STATE_G0: /* set character sets */
+ case TTY_STATE_G1: /* set character sets */
+ switch (ch) {
+ case 'B':
+ /* Latin-1 map */
+ break;
+ }
+ vc->state = TTY_STATE_NORM;
+ break;
}
}
@@ -906,7 +1036,7 @@ qemu_text_console_finalize(Object *obj)
}
static void
-qemu_text_console_class_init(ObjectClass *oc, void *data)
+qemu_text_console_class_init(ObjectClass *oc, const void *data)
{
if (!cursor_timer) {
cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME, cursor_timer_cb, NULL);
@@ -935,7 +1065,7 @@ qemu_fixed_text_console_finalize(Object *obj)
}
static void
-qemu_fixed_text_console_class_init(ObjectClass *oc, void *data)
+qemu_fixed_text_console_class_init(ObjectClass *oc, const void *data)
{
}
@@ -1051,7 +1181,7 @@ static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp)
}
}
-static void char_vc_class_init(ObjectClass *oc, void *data)
+static void char_vc_class_init(ObjectClass *oc, const void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -1073,6 +1203,6 @@ void qemu_console_early_init(void)
{
/* set the default vc driver */
if (!object_class_by_name(TYPE_CHARDEV_VC)) {
- type_register(&char_vc_type_info);
+ type_register_static(&char_vc_type_info);
}
}
diff --git a/ui/console.c b/ui/console.c
index e8f0083..2d00828 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -35,8 +35,9 @@
#include "qemu/option.h"
#include "chardev/char.h"
#include "trace.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qom/object.h"
+#include "qemu/memfd.h"
#include "console-priv.h"
@@ -400,7 +401,7 @@ qemu_console_finalize(Object *obj)
}
static void
-qemu_console_class_init(ObjectClass *oc, void *data)
+qemu_console_class_init(ObjectClass *oc, const void *data)
{
}
@@ -436,7 +437,7 @@ qemu_graphic_console_prop_get_head(Object *obj, Visitor *v, const char *name,
}
static void
-qemu_graphic_console_class_init(ObjectClass *oc, void *data)
+qemu_graphic_console_class_init(ObjectClass *oc, const void *data)
{
object_class_property_add_link(oc, "device", TYPE_DEVICE,
offsetof(QemuGraphicConsole, device),
@@ -452,60 +453,26 @@ qemu_graphic_console_init(Object *obj)
{
}
-#ifdef WIN32
-void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
- HANDLE h, uint32_t offset)
+void qemu_displaysurface_set_share_handle(DisplaySurface *surface,
+ qemu_pixman_shareable handle,
+ uint32_t offset)
{
- assert(!surface->handle);
+ assert(surface->share_handle == SHAREABLE_NONE);
- surface->handle = h;
- surface->handle_offset = offset;
-}
-
-static void
-win32_pixman_image_destroy(pixman_image_t *image, void *data)
-{
- DisplaySurface *surface = data;
-
- if (!surface->handle) {
- return;
- }
+ surface->share_handle = handle;
+ surface->share_handle_offset = offset;
- assert(surface->handle_offset == 0);
-
- qemu_win32_map_free(
- pixman_image_get_data(surface->image),
- surface->handle,
- &error_warn
- );
}
-#endif
DisplaySurface *qemu_create_displaysurface(int width, int height)
{
- DisplaySurface *surface;
- void *bits = NULL;
-#ifdef WIN32
- HANDLE handle = NULL;
-#endif
-
trace_displaysurface_create(width, height);
-#ifdef WIN32
- bits = qemu_win32_map_alloc(width * height * 4, &handle, &error_abort);
-#endif
-
- surface = qemu_create_displaysurface_from(
+ return qemu_create_displaysurface_from(
width, height,
PIXMAN_x8r8g8b8,
- width * 4, bits
+ width * 4, NULL
);
- surface->flags = QEMU_ALLOCATED_FLAG;
-
-#ifdef WIN32
- qemu_displaysurface_win32_set_handle(surface, handle, 0);
-#endif
- return surface;
}
DisplaySurface *qemu_create_displaysurface_from(int width, int height,
@@ -515,15 +482,25 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
DisplaySurface *surface = g_new0(DisplaySurface, 1);
trace_displaysurface_create_from(surface, width, height, format);
- surface->image = pixman_image_create_bits(format,
- width, height,
- (void *)data, linesize);
- assert(surface->image != NULL);
-#ifdef WIN32
- pixman_image_set_destroy_function(surface->image,
- win32_pixman_image_destroy, surface);
-#endif
+ surface->share_handle = SHAREABLE_NONE;
+
+ if (data) {
+ surface->image = pixman_image_create_bits(format,
+ width, height,
+ (void *)data, linesize);
+ } else {
+ qemu_pixman_image_new_shareable(&surface->image,
+ &surface->share_handle,
+ "displaysurface",
+ format,
+ width,
+ height,
+ linesize,
+ &error_abort);
+ surface->flags = QEMU_ALLOCATED_FLAG;
+ }
+ assert(surface->image != NULL);
return surface;
}
@@ -532,6 +509,7 @@ DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
DisplaySurface *surface = g_new0(DisplaySurface, 1);
trace_displaysurface_create_pixman(surface);
+ surface->share_handle = SHAREABLE_NONE;
surface->image = pixman_image_ref(image);
return surface;
@@ -1182,7 +1160,7 @@ DisplayState *init_displaystate(void)
* all QemuConsoles are created and the order / numbering
* doesn't change any more */
name = g_strdup_printf("console[%d]", con->index);
- object_property_add_child(container_get(object_get_root(), "/backend"),
+ object_property_add_child(object_get_container("backend"),
name, OBJECT(con));
g_free(name);
}
@@ -1408,9 +1386,7 @@ char *qemu_console_get_label(QemuConsole *con)
object_get_typename(c->device),
c->head);
} else {
- return g_strdup_printf("%s", dev->id ?
- dev->id :
- object_get_typename(c->device));
+ return g_strdup(dev->id ? : object_get_typename(c->device));
}
}
return g_strdup("VGA");
@@ -1632,4 +1608,9 @@ void qemu_display_help(void)
printf("%s\n", DisplayType_str(dpys[idx]->type));
}
}
+ printf("\n"
+ "Some display backends support suboptions, which can be set with\n"
+ " -display backend,option=value,option=value...\n"
+ "For a short list of the suboptions for each display, see the "
+ "top-level -help output; more detail is in the documentation.\n");
}
diff --git a/ui/curses.c b/ui/curses.c
index ec61615..a39aee8 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -36,9 +36,9 @@
#include "qemu/module.h"
#include "ui/console.h"
#include "ui/input.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
-#if defined(__APPLE__) || defined(__OpenBSD__)
+#ifdef __APPLE__
#define _XOPEN_SOURCE_EXTENDED 1
#endif
diff --git a/ui/cursor.c b/ui/cursor.c
index dd38533..6e23244 100644
--- a/ui/cursor.c
+++ b/ui/cursor.c
@@ -197,30 +197,6 @@ void cursor_set_mono(QEMUCursor *c,
}
}
-void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image)
-{
- uint32_t *data = c->data;
- uint8_t bit;
- int x,y,bpl;
-
- bpl = cursor_get_mono_bpl(c);
- memset(image, 0, bpl * c->height);
- for (y = 0; y < c->height; y++) {
- bit = 0x80;
- for (x = 0; x < c->width; x++, data++) {
- if (((*data & 0xff000000) == 0xff000000) &&
- ((*data & 0x00ffffff) == foreground)) {
- image[x/8] |= bit;
- }
- bit >>= 1;
- if (bit == 0) {
- bit = 0x80;
- }
- }
- image += bpl;
- }
-}
-
void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask)
{
uint32_t *data = c->data;
diff --git a/ui/dbus-chardev.c b/ui/dbus-chardev.c
index 1d3a712..d05ddda 100644
--- a/ui/dbus-chardev.c
+++ b/ui/dbus-chardev.c
@@ -106,7 +106,7 @@ dbus_chardev_init(DBusDisplay *dpy)
dpy->notifier.notify = dbus_display_on_notify;
dbus_display_notifier_add(&dpy->notifier);
- object_child_foreach(container_get(object_get_root(), "/chardevs"),
+ object_child_foreach(object_get_container("chardevs"),
dbus_display_chardev_foreach, dpy);
}
@@ -269,7 +269,7 @@ dbus_chr_parse(QemuOpts *opts, ChardevBackend *backend,
}
static void
-char_dbus_class_init(ObjectClass *oc, void *data)
+char_dbus_class_init(ObjectClass *oc, const void *data)
{
DBusChardevClass *klass = DBUS_CHARDEV_CLASS(oc);
ChardevClass *cc = CHARDEV_CLASS(oc);
diff --git a/ui/dbus-clipboard.c b/ui/dbus-clipboard.c
index fbb043a..6787a77 100644
--- a/ui/dbus-clipboard.c
+++ b/ui/dbus-clipboard.c
@@ -26,7 +26,7 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qom/object_interfaces.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qapi/error.h"
#include "trace.h"
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index 578b67f..85e215e 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -41,7 +41,7 @@ struct _DBusDisplayConsole {
DisplayChangeListener dcl;
DBusDisplay *display;
- GHashTable *listeners;
+ GPtrArray *listeners;
QemuDBusDisplay1Console *iface;
QemuDBusDisplay1Keyboard *iface_kbd;
@@ -142,8 +142,7 @@ dbus_display_console_init(DBusDisplayConsole *object)
{
DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
- ddc->listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, g_object_unref);
+ ddc->listeners = g_ptr_array_new_with_free_func(g_object_unref);
ddc->dcl.ops = &dbus_console_dcl_ops;
}
@@ -157,7 +156,7 @@ dbus_display_console_dispose(GObject *object)
g_clear_object(&ddc->iface_mouse);
g_clear_object(&ddc->iface_kbd);
g_clear_object(&ddc->iface);
- g_clear_pointer(&ddc->listeners, g_hash_table_unref);
+ g_clear_pointer(&ddc->listeners, g_ptr_array_unref);
g_clear_pointer(&ddc->kbd, qkbd_state_free);
G_OBJECT_CLASS(dbus_display_console_parent_class)->dispose(object);
@@ -179,7 +178,7 @@ listener_vanished_cb(DBusDisplayListener *listener)
trace_dbus_listener_vanished(name);
- g_hash_table_remove(ddc->listeners, name);
+ g_ptr_array_remove_fast(ddc->listeners, listener);
qkbd_state_lift_all_keys(ddc->kbd);
}
@@ -267,16 +266,6 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
DBusDisplayListener *listener;
int fd;
- if (sender && g_hash_table_contains(ddc->listeners, sender)) {
- g_dbus_method_invocation_return_error(
- invocation,
- DBUS_DISPLAY_ERROR,
- DBUS_DISPLAY_ERROR_INVALID,
- "`%s` is already registered!",
- sender);
- return DBUS_METHOD_INVOCATION_HANDLED;
- }
-
#ifdef G_OS_WIN32
if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
return DBUS_METHOD_INVOCATION_HANDLED;
@@ -316,10 +305,16 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
#endif
);
+ GDBusConnectionFlags flags =
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER;
+#ifdef WIN32
+ flags |= G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
+#endif
+
listener_conn = g_dbus_connection_new_sync(
G_IO_STREAM(socket_conn),
guid,
- G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
+ flags,
NULL, NULL, &err);
if (err) {
error_report("Failed to setup peer connection: %s", err->message);
@@ -331,9 +326,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED;
}
- g_hash_table_insert(ddc->listeners,
- (gpointer)dbus_display_listener_get_bus_name(listener),
- listener);
+ g_ptr_array_add(ddc->listeners, listener);
g_object_connect(listener_conn,
"swapped-signal::closed", listener_vanished_cb, listener,
NULL);
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index ce35d64..4a41a7e 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -470,23 +470,71 @@
</interface>
<!--
+ org.qemu.Display1.Listener.Unix.Map:
+
+ This optional client-side interface can complement
+ org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for
+ Unix-specific shared memory scanouts.
+ -->
+ <?if $(env.HOST_OS) != windows?>
+ <interface name="org.qemu.Display1.Listener.Unix.Map">
+ <!--
+ ScanoutMap:
+ @handle: the shared map FD.
+ @offset: mapping offset, in bytes.
+ @width: display width, in pixels.
+ @height: display height, in pixels.
+ @stride: stride, in bytes.
+ @pixman_format: image format (ex: ``PIXMAN_X8R8G8B8``).
+
+ Resize and update the display content with a shared map.
+ -->
+ <method name="ScanoutMap">
+ <arg type="h" name="handle" direction="in"/>
+ <arg type="u" name="offset" direction="in"/>
+ <arg type="u" name="width" direction="in"/>
+ <arg type="u" name="height" direction="in"/>
+ <arg type="u" name="stride" direction="in"/>
+ <arg type="u" name="pixman_format" direction="in"/>
+ </method>
+
+ <!--
+ UpdateMap:
+ @x: the X update position, in pixels.
+ @y: the Y update position, in pixels.
+ @width: the update width, in pixels.
+ @height: the update height, in pixels.
+
+ Update the display content with the current shared map and the given region.
+ -->
+ <method name="UpdateMap">
+ <arg type="i" name="x" direction="in"/>
+ <arg type="i" name="y" direction="in"/>
+ <arg type="i" name="width" direction="in"/>
+ <arg type="i" name="height" direction="in"/>
+ </method>
+ </interface>
+ <?endif?>
+
+ <!--
org.qemu.Display1.Listener.Win32.Map:
This optional client-side interface can complement
org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for Windows
specific shared memory scanouts.
-->
+ <?if $(env.HOST_OS) == windows?>
<interface name="org.qemu.Display1.Listener.Win32.Map">
<!--
ScanoutMap:
- @handle: the shared map handle value.
+ @handle: the shared file mapping handle value (not a file handle)
@offset: mapping offset.
@width: display width, in pixels.
@height: display height, in pixels.
@stride: stride, in bytes.
@pixman_format: image format (ex: ``PIXMAN_X8R8G8B8``).
- Resize and update the display content with a shared map.
+ Resize and update the display content with a shared file mapping object.
-->
<method name="ScanoutMap">
<arg type="t" name="handle" direction="in"/>
@@ -513,6 +561,7 @@
<arg type="i" name="height" direction="in"/>
</method>
</interface>
+ <?endif?>
<!--
org.qemu.Display1.Listener.Win32.D3d11:
@@ -566,6 +615,51 @@
</interface>
<!--
+ org.qemu.Display1.Listener.Unix.ScanoutDMABUF2:
+
+ This optional client-side interface can complement
+ org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for
+ Unix-specific DMABUF scanout setup which support multi plane.
+ -->
+ <?if $(env.HOST_OS) != windows?>
+ <interface name="org.qemu.Display1.Listener.Unix.ScanoutDMABUF2">
+ <!--
+ ScanoutDMABUF2:
+ @dmabuf: DMABUF file descriptor of each plane.
+ @x: display x offset, in pixels
+ @y: display y offset, in pixels
+ @width: display width, in pixels.
+ @height: display height, in pixels.
+ @offset: offset of each plane, in bytes.
+ @stride: stride of each plane, in bytes.
+ @num_planes: plane number.
+ @fourcc: DMABUF fourcc.
+ @backing_width: backing framebuffer width, in pixels
+ @backing_height: backing framebuffer height, in pixels
+ @modifier: DMABUF modifier.
+ @y0_top: whether Y position 0 is the top or not.
+
+ Resize and update the display content with DMABUF.
+ -->
+ <method name="ScanoutDMABUF2">
+ <arg type="ah" name="dmabuf" direction="in"/>
+ <arg type="u" name="x" direction="in"/>
+ <arg type="u" name="y" direction="in"/>
+ <arg type="u" name="width" direction="in"/>
+ <arg type="u" name="height" direction="in"/>
+ <arg type="au" name="offset" direction="in"/>
+ <arg type="au" name="stride" direction="in"/>
+ <arg type="u" name="num_planes" direction="in"/>
+ <arg type="u" name="fourcc" direction="in"/>
+ <arg type="u" name="backing_width" direction="in"/>
+ <arg type="u" name="backing_height" direction="in"/>
+ <arg type="t" name="modifier" direction="in"/>
+ <arg type="b" name="y0_top" direction="in"/>
+ </method>
+ </interface>
+ <?endif?>
+
+ <!--
org.qemu.Display1.Clipboard:
This interface must be implemented by both the client and the server on
@@ -725,6 +819,18 @@
</method>
<!--
+ NSamples:
+
+ The number of samples per read/write frames. (for example the default is
+ 480, or 10ms at 48kHz)
+
+ (earlier version of the display interface do not provide this property)
+ -->
+ <property name="NSamples" type="u" access="read">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
+ </property>
+
+ <!--
Interfaces:
This property lists extra interfaces provided by the
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index a54123a..42875b8 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -24,8 +24,9 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "dbus.h"
+#include "glib.h"
#ifdef G_OS_UNIX
#include <gio/gunixfdlist.h>
#endif
@@ -82,10 +83,14 @@ struct _DBusDisplayListener {
#ifdef CONFIG_OPENGL
egl_fb fb;
#endif
+#else /* !WIN32 */
+ QemuDBusDisplay1ListenerUnixMap *map_proxy;
+ QemuDBusDisplay1ListenerUnixScanoutDMABUF2 *scanout_dmabuf_v2_proxy;
#endif
guint dbus_filter;
- guint32 out_serial_to_discard;
+ guint32 display_serial_to_discard;
+ guint32 cursor_serial_to_discard;
};
G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
@@ -93,10 +98,20 @@ G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
static void dbus_gfx_update(DisplayChangeListener *dcl,
int x, int y, int w, int h);
-static void ddl_discard_pending_messages(DBusDisplayListener *ddl)
+static void ddl_discard_display_messages(DBusDisplayListener *ddl)
{
- ddl->out_serial_to_discard = g_dbus_connection_get_last_serial(
+ guint32 serial = g_dbus_connection_get_last_serial(
g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
+
+ g_atomic_int_set(&ddl->display_serial_to_discard, serial);
+}
+
+static void ddl_discard_cursor_messages(DBusDisplayListener *ddl)
+{
+ guint32 serial = g_dbus_connection_get_last_serial(
+ g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
+
+ g_atomic_int_set(&ddl->cursor_serial_to_discard, serial);
}
#ifdef CONFIG_OPENGL
@@ -104,6 +119,8 @@ static void dbus_scanout_disable(DisplayChangeListener *dcl)
{
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+ ddl_discard_display_messages(ddl);
+
qemu_dbus_display1_listener_call_disable(
ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
}
@@ -272,10 +289,9 @@ static void dbus_call_update_gl(DisplayChangeListener *dcl,
}
#ifdef CONFIG_GBM
-static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
- QemuDmaBuf *dmabuf)
+static void dbus_scanout_dmabuf_v1(DBusDisplayListener *ddl,
+ QemuDmaBuf *dmabuf)
{
- DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
g_autoptr(GError) err = NULL;
g_autoptr(GUnixFDList) fd_list = NULL;
int fd;
@@ -283,18 +299,18 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
uint64_t modifier;
bool y0_top;
- fd = qemu_dmabuf_get_fd(dmabuf);
+ fd = qemu_dmabuf_get_fds(dmabuf, NULL)[0];
fd_list = g_unix_fd_list_new();
if (g_unix_fd_list_append(fd_list, fd, &err) != 0) {
error_report("Failed to setup dmabuf fdlist: %s", err->message);
return;
}
- ddl_discard_pending_messages(ddl);
+ ddl_discard_display_messages(ddl);
width = qemu_dmabuf_get_width(dmabuf);
height = qemu_dmabuf_get_height(dmabuf);
- stride = qemu_dmabuf_get_stride(dmabuf);
+ stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
fourcc = qemu_dmabuf_get_fourcc(dmabuf);
modifier = qemu_dmabuf_get_modifier(dmabuf);
y0_top = qemu_dmabuf_get_y0_top(dmabuf);
@@ -306,6 +322,87 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
y0_top, G_DBUS_CALL_FLAGS_NONE,
-1, fd_list, NULL, NULL, NULL);
}
+
+static void dbus_scanout_dmabuf_v2(DBusDisplayListener *ddl,
+ QemuDmaBuf *dmabuf)
+{
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ int i, fd_index[DMABUF_MAX_PLANES], num_fds;
+ uint32_t x, y, width, height, fourcc, backing_width, backing_height;
+ GVariant *fd, *offset, *stride, *fd_handles[DMABUF_MAX_PLANES];
+ uint64_t modifier;
+ bool y0_top;
+ int nfds, noffsets, nstrides;
+ const int *fds = qemu_dmabuf_get_fds(dmabuf, &nfds);
+ const uint32_t *offsets = qemu_dmabuf_get_offsets(dmabuf, &noffsets);
+ const uint32_t *strides = qemu_dmabuf_get_strides(dmabuf, &nstrides);
+ uint32_t num_planes = qemu_dmabuf_get_num_planes(dmabuf);
+
+ assert(nfds >= num_planes);
+ assert(noffsets >= num_planes);
+ assert(nstrides >= num_planes);
+
+ fd_list = g_unix_fd_list_new();
+
+ for (num_fds = 0; num_fds < num_planes; num_fds++) {
+ int plane_fd = fds[num_fds];
+
+ if (plane_fd < 0) {
+ break;
+ }
+
+ fd_index[num_fds] = g_unix_fd_list_append(fd_list, plane_fd, &err);
+ if (fd_index[num_fds] < 0) {
+ error_report("Failed to setup dmabuf fdlist: %s", err->message);
+ return;
+ }
+ }
+
+ ddl_discard_display_messages(ddl);
+
+ x = qemu_dmabuf_get_x(dmabuf);
+ y = qemu_dmabuf_get_y(dmabuf);
+ width = qemu_dmabuf_get_width(dmabuf);
+ height = qemu_dmabuf_get_height(dmabuf);
+ fourcc = qemu_dmabuf_get_fourcc(dmabuf);
+ backing_width = qemu_dmabuf_get_backing_width(dmabuf);
+ backing_height = qemu_dmabuf_get_backing_height(dmabuf);
+ modifier = qemu_dmabuf_get_modifier(dmabuf);
+ y0_top = qemu_dmabuf_get_y0_top(dmabuf);
+
+ offset = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+ offsets, num_planes, sizeof(uint32_t));
+ stride = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+ strides, num_planes, sizeof(uint32_t));
+
+ for (i = 0; i < num_fds; i++) {
+ fd_handles[i] = g_variant_new_handle(fd_index[i]);
+ }
+ fd = g_variant_new_array(G_VARIANT_TYPE_HANDLE, fd_handles, num_fds);
+
+ qemu_dbus_display1_listener_unix_scanout_dmabuf2_call_scanout_dmabuf2(
+ ddl->scanout_dmabuf_v2_proxy, fd, x, y, width, height, offset, stride,
+ num_planes, fourcc, backing_width, backing_height, modifier, y0_top,
+ G_DBUS_CALL_FLAGS_NONE, -1, fd_list, NULL, NULL, NULL);
+}
+
+static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf)
+{
+ DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+
+ if (ddl->scanout_dmabuf_v2_proxy) {
+ dbus_scanout_dmabuf_v2(ddl, dmabuf);
+ } else {
+ if (qemu_dmabuf_get_num_planes(dmabuf) > 1) {
+ g_debug("org.qemu.Display1.Listener.ScanoutDMABUF "
+ "does not support mutli plane");
+ return;
+ }
+ dbus_scanout_dmabuf_v1(ddl, dmabuf);
+ }
+}
#endif /* GBM */
#endif /* OPENGL */
@@ -320,13 +417,13 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
return true;
}
- if (!ddl->can_share_map || !ddl->ds->handle) {
+ if (!ddl->can_share_map || !ddl->ds->share_handle) {
return false;
}
success = DuplicateHandle(
GetCurrentProcess(),
- ddl->ds->handle,
+ ddl->ds->share_handle,
ddl->peer_process,
&target_handle,
FILE_MAP_READ | SECTION_QUERY,
@@ -338,12 +435,12 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
return false;
}
- ddl_discard_pending_messages(ddl);
+ ddl_discard_display_messages(ddl);
if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
ddl->map_proxy,
GPOINTER_TO_UINT(target_handle),
- ddl->ds->handle_offset,
+ ddl->ds->share_handle_offset,
surface_width(ddl->ds),
surface_height(ddl->ds),
surface_stride(ddl->ds),
@@ -401,7 +498,7 @@ dbus_scanout_share_d3d_texture(
return false;
}
- ddl_discard_pending_messages(ddl);
+ ddl_discard_display_messages(ddl);
qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
ddl->d3d11_proxy,
@@ -427,6 +524,51 @@ dbus_scanout_share_d3d_texture(
return true;
}
#endif /* CONFIG_OPENGL */
+#else /* !WIN32 */
+static bool dbus_scanout_map(DBusDisplayListener *ddl)
+{
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+
+ if (ddl->ds_share == SHARE_KIND_MAPPED) {
+ return true;
+ }
+
+ if (!ddl->can_share_map || ddl->ds->share_handle == SHAREABLE_NONE) {
+ return false;
+ }
+
+ ddl_discard_display_messages(ddl);
+ fd_list = g_unix_fd_list_new();
+ if (g_unix_fd_list_append(fd_list, ddl->ds->share_handle, &err) != 0) {
+ g_debug("Failed to setup scanout map fdlist: %s", err->message);
+ ddl->can_share_map = false;
+ return false;
+ }
+
+ if (!qemu_dbus_display1_listener_unix_map_call_scanout_map_sync(
+ ddl->map_proxy,
+ g_variant_new_handle(0),
+ ddl->ds->share_handle_offset,
+ surface_width(ddl->ds),
+ surface_height(ddl->ds),
+ surface_stride(ddl->ds),
+ surface_format(ddl->ds),
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_DEFAULT_TIMEOUT,
+ fd_list,
+ NULL,
+ NULL,
+ &err)) {
+ g_debug("Failed to call ScanoutMap: %s", err->message);
+ ddl->can_share_map = false;
+ return false;
+ }
+
+ ddl->ds_share = SHARE_KIND_MAPPED;
+
+ return true;
+}
#endif /* WIN32 */
#ifdef CONFIG_OPENGL
@@ -443,19 +585,18 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
backing_width, backing_height, x, y, w, h);
#ifdef CONFIG_GBM
g_autoptr(QemuDmaBuf) dmabuf = NULL;
- int fd;
- uint32_t stride, fourcc;
+ int fd[DMABUF_MAX_PLANES], num_planes;
+ uint32_t offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc;
uint64_t modifier;
assert(tex_id);
- fd = egl_get_fd_for_texture(tex_id, (EGLint *)&stride, (EGLint *)&fourcc,
- &modifier);
- if (fd < 0) {
- error_report("%s: failed to get fd for texture", __func__);
+ if (!egl_dmabuf_export_texture(tex_id, fd, (EGLint *)offset, (EGLint *)stride,
+ (EGLint *)&fourcc, &num_planes, &modifier)) {
+ error_report("%s: failed to export dmabuf for texture", __func__);
return;
}
- dmabuf = qemu_dmabuf_new(w, h, stride, x, y, backing_width,
- backing_height, fourcc, modifier, fd,
+ dmabuf = qemu_dmabuf_new(w, h, offset, stride, x, y, backing_width,
+ backing_height, fourcc, modifier, fd, num_planes,
false, backing_y_0_top);
dbus_scanout_dmabuf(dcl, dmabuf);
@@ -497,6 +638,8 @@ static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
return;
}
+ ddl_discard_cursor_messages(ddl);
+
egl_dmabuf_import_texture(dmabuf);
texture = qemu_dmabuf_get_texture(dmabuf);
if (!texture) {
@@ -659,7 +802,7 @@ static void ddl_scanout(DBusDisplayListener *ddl)
surface_stride(ddl->ds) * surface_height(ddl->ds), TRUE,
(GDestroyNotify)pixman_image_unref, pixman_image_ref(ddl->ds->image));
- ddl_discard_pending_messages(ddl);
+ ddl_discard_display_messages(ddl);
qemu_dbus_display1_listener_call_scanout(
ddl->proxy, surface_width(ddl->ds), surface_height(ddl->ds),
@@ -677,16 +820,22 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
trace_dbus_update(x, y, w, h);
-#ifdef WIN32
if (dbus_scanout_map(ddl)) {
+#ifdef WIN32
qemu_dbus_display1_listener_win32_map_call_update_map(
ddl->map_proxy,
x, y, w, h,
G_DBUS_CALL_FLAGS_NONE,
DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
+#else
+ qemu_dbus_display1_listener_unix_map_call_update_map(
+ ddl->map_proxy,
+ x, y, w, h,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
+#endif
return;
}
-#endif
if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) {
return ddl_scanout(ddl);
@@ -740,6 +889,8 @@ static void dbus_cursor_define(DisplayChangeListener *dcl,
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
GVariant *v_data = NULL;
+ ddl_discard_cursor_messages(ddl);
+
v_data = g_variant_new_from_data(
G_VARIANT_TYPE("ay"),
c->data,
@@ -812,6 +963,8 @@ dbus_display_listener_dispose(GObject *object)
#ifdef CONFIG_OPENGL
egl_fb_destroy(&ddl->fb);
#endif
+#else /* !WIN32 */
+ g_clear_object(&ddl->scanout_dmabuf_v2_proxy);
#endif
G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
@@ -861,7 +1014,6 @@ dbus_display_listener_get_console(DBusDisplayListener *ddl)
return ddl->console;
}
-#ifdef WIN32
static bool
dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
{
@@ -876,6 +1028,7 @@ dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
return implements;
}
+#ifdef WIN32
static bool
dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl)
{
@@ -958,10 +1111,11 @@ dbus_display_listener_setup_d3d11(DBusDisplayListener *ddl)
static void
dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
{
-#ifdef WIN32
g_autoptr(GError) err = NULL;
- if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener.Win32.Map")) {
+#ifdef WIN32
+ if (!dbus_display_listener_implements(
+ ddl, "org.qemu.Display1.Listener.Win32.Map")) {
return;
}
@@ -982,6 +1136,40 @@ dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
}
ddl->can_share_map = true;
+#else /* !WIN32 */
+ if (!dbus_display_listener_implements(
+ ddl, "org.qemu.Display1.Listener.Unix.Map")) {
+ return;
+ }
+ ddl->map_proxy = qemu_dbus_display1_listener_unix_map_proxy_new_sync(
+ ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
+ "/org/qemu/Display1/Listener", NULL, &err);
+ if (!ddl->map_proxy) {
+ g_debug("Failed to setup Unix map proxy: %s", err->message);
+ return;
+ }
+
+ ddl->can_share_map = true;
+#endif
+}
+
+static void dbus_display_listener_setup_scanout_dmabuf_v2(DBusDisplayListener *ddl)
+{
+#ifndef WIN32
+ g_autoptr(GError) err = NULL;
+
+ if (!dbus_display_listener_implements(
+ ddl, "org.qemu.Display1.Listener.Unix.ScanoutDMABUF2")) {
+ return;
+ }
+ ddl->scanout_dmabuf_v2_proxy =
+ qemu_dbus_display1_listener_unix_scanout_dmabuf2_proxy_new_sync(
+ ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
+ "/org/qemu/Display1/Listener", NULL, &err);
+ if (!ddl->scanout_dmabuf_v2_proxy) {
+ g_debug("Failed to setup Unix scanout dmabuf v2 proxy: %s", err->message);
+ return;
+ }
#endif
}
@@ -992,16 +1180,50 @@ dbus_filter(GDBusConnection *connection,
gpointer user_data)
{
DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(user_data);
- guint32 serial;
+ guint32 serial, discard_serial;
if (incoming) {
return message;
}
serial = g_dbus_message_get_serial(message);
- if (serial <= ddl->out_serial_to_discard) {
- trace_dbus_filter(serial, ddl->out_serial_to_discard);
- return NULL;
+
+ discard_serial = g_atomic_int_get(&ddl->display_serial_to_discard);
+ if (serial <= discard_serial) {
+ const char *member = g_dbus_message_get_member(message);
+ static const char *const display_messages[] = {
+ "Scanout",
+ "Update",
+#ifdef CONFIG_GBM
+ "ScanoutDMABUF",
+ "UpdateDMABUF",
+#endif
+ "ScanoutMap",
+ "UpdateMap",
+ "Disable",
+ NULL,
+ };
+
+ if (g_strv_contains(display_messages, member)) {
+ trace_dbus_filter(serial, discard_serial);
+ g_object_unref(message);
+ return NULL;
+ }
+ }
+
+ discard_serial = g_atomic_int_get(&ddl->cursor_serial_to_discard);
+ if (serial <= discard_serial) {
+ const gchar *member = g_dbus_message_get_member(message);
+ static const char *const cursor_messages[] = {
+ "CursorDefine",
+ NULL
+ };
+
+ if (g_strv_contains(cursor_messages, member)) {
+ trace_dbus_filter(serial, discard_serial);
+ g_object_unref(message);
+ return NULL;
+ }
}
return message;
@@ -1037,7 +1259,9 @@ dbus_display_listener_new(const char *bus_name,
ddl->console = console;
dbus_display_listener_setup_shared_map(ddl);
+ trace_dbus_can_share_map(ddl->can_share_map);
dbus_display_listener_setup_d3d11(ddl);
+ dbus_display_listener_setup_scanout_dmabuf_v2(ddl);
con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
assert(con);
diff --git a/ui/dbus.c b/ui/dbus.c
index e08b5de..dd03367 100644
--- a/ui/dbus.c
+++ b/ui/dbus.c
@@ -28,7 +28,7 @@
#include "qemu/main-loop.h"
#include "qemu/option.h"
#include "qom/object_interfaces.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "ui/dbus-module.h"
#ifdef CONFIG_OPENGL
#include "ui/egl-helpers.h"
@@ -176,7 +176,7 @@ dbus_display_add_console(DBusDisplay *dd, int idx, Error **errp)
assert(con);
if (qemu_console_is_graphic(con) &&
- dd->gl_mode != DISPLAYGL_MODE_OFF) {
+ dd->gl_mode != DISPLAY_GL_MODE_OFF) {
qemu_console_set_display_gl_ctx(con, &dd->glctx);
}
@@ -317,11 +317,17 @@ dbus_display_add_client(int csock, Error **errp)
conn = g_socket_connection_factory_create_connection(socket);
dbus_display->add_client_cancellable = g_cancellable_new();
+ GDBusConnectionFlags flags =
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER |
+ G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING;
+
+#ifdef WIN32
+ flags |= G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
+#endif
g_dbus_connection_new(G_IO_STREAM(conn),
guid,
- G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER |
- G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
+ flags,
NULL,
dbus_display->add_client_cancellable,
dbus_display_add_client_ready,
@@ -398,7 +404,7 @@ set_gl_mode(Object *o, int val, Error **errp)
}
static void
-dbus_display_class_init(ObjectClass *oc, void *data)
+dbus_display_class_init(ObjectClass *oc, const void *data)
{
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
@@ -447,7 +453,7 @@ dbus_vc_parse(QemuOpts *opts, ChardevBackend *backend,
}
static void
-dbus_vc_class_init(ObjectClass *oc, void *data)
+dbus_vc_class_init(ObjectClass *oc, const void *data)
{
DBusVCClass *klass = DBUS_VC_CLASS(oc);
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -466,9 +472,9 @@ static const TypeInfo dbus_vc_type_info = {
static void
early_dbus_init(DisplayOptions *opts)
{
- DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_OFF;
+ DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAY_GL_MODE_OFF;
- if (mode != DISPLAYGL_MODE_OFF) {
+ if (mode != DISPLAY_GL_MODE_OFF) {
#ifdef CONFIG_OPENGL
egl_init(opts->u.dbus.rendernode, mode, &error_fatal);
#else
@@ -476,13 +482,13 @@ early_dbus_init(DisplayOptions *opts)
#endif
}
- type_register(&dbus_vc_type_info);
+ type_register_static(&dbus_vc_type_info);
}
static void
dbus_init(DisplayState *ds, DisplayOptions *opts)
{
- DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_OFF;
+ DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAY_GL_MODE_OFF;
if (opts->u.dbus.addr && opts->u.dbus.p2p) {
error_report("dbus: can't accept both addr=X and p2p=yes options");
@@ -508,7 +514,7 @@ static const TypeInfo dbus_display_info = {
.instance_init = dbus_display_init,
.instance_finalize = dbus_display_finalize,
.class_init = dbus_display_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_USER_CREATABLE },
{ }
}
diff --git a/ui/dmabuf.c b/ui/dmabuf.c
index df7a097..7433a26 100644
--- a/ui/dmabuf.c
+++ b/ui/dmabuf.c
@@ -11,10 +11,12 @@
#include "ui/dmabuf.h"
struct QemuDmaBuf {
- int fd;
+ int fd[DMABUF_MAX_PLANES];
uint32_t width;
uint32_t height;
- uint32_t stride;
+ uint32_t offset[DMABUF_MAX_PLANES];
+ uint32_t stride[DMABUF_MAX_PLANES];
+ uint32_t num_planes;
uint32_t fourcc;
uint64_t modifier;
uint32_t texture;
@@ -30,28 +32,33 @@ struct QemuDmaBuf {
};
QemuDmaBuf *qemu_dmabuf_new(uint32_t width, uint32_t height,
- uint32_t stride, uint32_t x,
- uint32_t y, uint32_t backing_width,
- uint32_t backing_height, uint32_t fourcc,
- uint64_t modifier, int32_t dmabuf_fd,
+ const uint32_t *offset, const uint32_t *stride,
+ uint32_t x, uint32_t y,
+ uint32_t backing_width, uint32_t backing_height,
+ uint32_t fourcc, uint64_t modifier,
+ const int32_t *dmabuf_fd, uint32_t num_planes,
bool allow_fences, bool y0_top) {
QemuDmaBuf *dmabuf;
+ assert(num_planes > 0 && num_planes <= DMABUF_MAX_PLANES);
+
dmabuf = g_new0(QemuDmaBuf, 1);
dmabuf->width = width;
dmabuf->height = height;
- dmabuf->stride = stride;
+ memcpy(dmabuf->offset, offset, num_planes * sizeof(*offset));
+ memcpy(dmabuf->stride, stride, num_planes * sizeof(*stride));
dmabuf->x = x;
dmabuf->y = y;
dmabuf->backing_width = backing_width;
dmabuf->backing_height = backing_height;
dmabuf->fourcc = fourcc;
dmabuf->modifier = modifier;
- dmabuf->fd = dmabuf_fd;
+ memcpy(dmabuf->fd, dmabuf_fd, num_planes * sizeof(*dmabuf_fd));
dmabuf->allow_fences = allow_fences;
dmabuf->y0_top = y0_top;
dmabuf->fence_fd = -1;
+ dmabuf->num_planes = num_planes;
return dmabuf;
}
@@ -65,31 +72,40 @@ void qemu_dmabuf_free(QemuDmaBuf *dmabuf)
g_free(dmabuf);
}
-int qemu_dmabuf_get_fd(QemuDmaBuf *dmabuf)
+const int *qemu_dmabuf_get_fds(QemuDmaBuf *dmabuf, int *nfds)
{
assert(dmabuf != NULL);
+ if (nfds) {
+ *nfds = ARRAY_SIZE(dmabuf->fd);
+ }
+
return dmabuf->fd;
}
-int qemu_dmabuf_dup_fd(QemuDmaBuf *dmabuf)
+void qemu_dmabuf_dup_fds(QemuDmaBuf *dmabuf, int *fds, int nfds)
{
+ int i;
+
assert(dmabuf != NULL);
+ assert(nfds >= dmabuf->num_planes);
- if (dmabuf->fd >= 0) {
- return dup(dmabuf->fd);
- } else {
- return -1;
+ for (i = 0; i < dmabuf->num_planes; i++) {
+ fds[i] = dmabuf->fd[i] >= 0 ? dup(dmabuf->fd[i]) : -1;
}
}
void qemu_dmabuf_close(QemuDmaBuf *dmabuf)
{
+ int i;
+
assert(dmabuf != NULL);
- if (dmabuf->fd >= 0) {
- close(dmabuf->fd);
- dmabuf->fd = -1;
+ for (i = 0; i < dmabuf->num_planes; i++) {
+ if (dmabuf->fd[i] >= 0) {
+ close(dmabuf->fd[i]);
+ dmabuf->fd[i] = -1;
+ }
}
}
@@ -107,13 +123,35 @@ uint32_t qemu_dmabuf_get_height(QemuDmaBuf *dmabuf)
return dmabuf->height;
}
-uint32_t qemu_dmabuf_get_stride(QemuDmaBuf *dmabuf)
+const uint32_t *qemu_dmabuf_get_offsets(QemuDmaBuf *dmabuf, int *noffsets)
+{
+ assert(dmabuf != NULL);
+
+ if (noffsets) {
+ *noffsets = ARRAY_SIZE(dmabuf->offset);
+ }
+
+ return dmabuf->offset;
+}
+
+const uint32_t *qemu_dmabuf_get_strides(QemuDmaBuf *dmabuf, int *nstrides)
{
assert(dmabuf != NULL);
+ if (nstrides) {
+ *nstrides = ARRAY_SIZE(dmabuf->stride);
+ }
+
return dmabuf->stride;
}
+uint32_t qemu_dmabuf_get_num_planes(QemuDmaBuf *dmabuf)
+{
+ assert(dmabuf != NULL);
+
+ return dmabuf->num_planes;
+}
+
uint32_t qemu_dmabuf_get_fourcc(QemuDmaBuf *dmabuf)
{
assert(dmabuf != NULL);
@@ -221,9 +259,3 @@ void qemu_dmabuf_set_draw_submitted(QemuDmaBuf *dmabuf, bool draw_submitted)
assert(dmabuf != NULL);
dmabuf->draw_submitted = draw_submitted;
}
-
-void qemu_dmabuf_set_fd(QemuDmaBuf *dmabuf, int32_t fd)
-{
- assert(dmabuf != NULL);
- dmabuf->fd = fd;
-}
diff --git a/ui/egl-context.c b/ui/egl-context.c
index 9e0df46..aed3e3b 100644
--- a/ui/egl-context.c
+++ b/ui/egl-context.c
@@ -17,7 +17,7 @@ QEMUGLContext qemu_egl_create_context(DisplayGLCtx *dgc,
EGL_CONTEXT_MINOR_VERSION_KHR, params->minor_ver,
EGL_NONE
};
- bool gles = (qemu_egl_mode == DISPLAYGL_MODE_ES);
+ bool gles = (qemu_egl_mode == DISPLAY_GL_MODE_ES);
ctx = eglCreateContext(qemu_egl_display, qemu_egl_config,
eglGetCurrentContext(),
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index 6187249..1f6b845 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -207,7 +207,7 @@ static const DisplayGLCtxOps eglctx_ops = {
static void early_egl_headless_init(DisplayOptions *opts)
{
- DisplayGLMode mode = DISPLAYGL_MODE_ON;
+ DisplayGLMode mode = DISPLAY_GL_MODE_ON;
if (opts->has_gl) {
mode = opts->gl;
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 99b2ebbe..5503a79 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -20,9 +20,10 @@
#include "qemu/error-report.h"
#include "ui/console.h"
#include "ui/egl-helpers.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qapi/error.h"
#include "trace.h"
+#include "standard-headers/drm/drm_fourcc.h"
EGLDisplay *qemu_egl_display;
EGLConfig qemu_egl_config;
@@ -92,14 +93,18 @@ void egl_fb_destroy(egl_fb *fb)
fb->width = 0;
fb->height = 0;
+ fb->x = 0;
+ fb->y = 0;
fb->texture = 0;
fb->framebuffer = 0;
}
-void egl_fb_setup_default(egl_fb *fb, int width, int height)
+void egl_fb_setup_default(egl_fb *fb, int width, int height, int x, int y)
{
fb->width = width;
fb->height = height;
+ fb->x = x;
+ fb->y = y;
fb->framebuffer = 0; /* default framebuffer */
}
@@ -144,6 +149,7 @@ void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip)
glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer);
glViewport(0, 0, dst->width, dst->height);
+ glClear(GL_COLOR_BUFFER_BIT);
if (src->dmabuf) {
x1 = qemu_dmabuf_get_x(src->dmabuf);
@@ -160,7 +166,8 @@ void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip)
x2 = x1 + w;
glBlitFramebuffer(x1, y1, x2, y2,
- 0, 0, dst->width, dst->height,
+ dst->x, dst->y,
+ dst->x + dst->width, dst->y + dst->height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
@@ -257,6 +264,11 @@ int egl_rendernode_init(const char *rendernode, DisplayGLMode mode)
error_report("egl: EGL_MESA_image_dma_buf_export not supported");
goto err;
}
+ if (!epoxy_has_egl_extension(qemu_egl_display,
+ "EGL_EXT_image_dma_buf_import_modifiers")) {
+ error_report("egl: EGL_EXT_image_dma_buf_import_modifiers not supported");
+ goto err;
+ }
qemu_egl_rn_ctx = qemu_egl_init_ctx();
if (!qemu_egl_rn_ctx) {
@@ -277,44 +289,86 @@ err:
return -1;
}
-int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc,
- EGLuint64KHR *modifier)
+bool egl_dmabuf_export_texture(uint32_t tex_id, int *fd, EGLint *offset,
+ EGLint *stride, EGLint *fourcc, int *num_planes,
+ EGLuint64KHR *modifier)
{
EGLImageKHR image;
- EGLint num_planes, fd;
+ EGLuint64KHR modifiers[DMABUF_MAX_PLANES];
image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(),
EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)(unsigned long)tex_id,
NULL);
if (!image) {
- return -1;
+ return false;
}
eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc,
- &num_planes, modifier);
- if (num_planes != 1) {
- eglDestroyImageKHR(qemu_egl_display, image);
- return -1;
- }
- eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL);
+ num_planes, modifiers);
+ eglExportDMABUFImageMESA(qemu_egl_display, image, fd, stride, offset);
eglDestroyImageKHR(qemu_egl_display, image);
- return fd;
+ /* Only first modifier matters. */
+ if (modifier) {
+ *modifier = modifiers[0];
+ }
+
+ return true;
}
void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
{
EGLImageKHR image = EGL_NO_IMAGE_KHR;
EGLint attrs[64];
- int i = 0;
- uint64_t modifier;
+ int i = 0, j;
+ uint64_t modifier = qemu_dmabuf_get_modifier(dmabuf);
uint32_t texture = qemu_dmabuf_get_texture(dmabuf);
+ int nfds, noffsets, nstrides;
+ const int *fds = qemu_dmabuf_get_fds(dmabuf, &nfds);
+ const uint32_t *offsets = qemu_dmabuf_get_offsets(dmabuf, &noffsets);
+ const uint32_t *strides = qemu_dmabuf_get_strides(dmabuf, &nstrides);
+ uint32_t num_planes = qemu_dmabuf_get_num_planes(dmabuf);
+
+ EGLint fd_attrs[] = {
+ EGL_DMA_BUF_PLANE0_FD_EXT,
+ EGL_DMA_BUF_PLANE1_FD_EXT,
+ EGL_DMA_BUF_PLANE2_FD_EXT,
+ EGL_DMA_BUF_PLANE3_FD_EXT,
+ };
+ EGLint offset_attrs[] = {
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE1_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE2_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE3_OFFSET_EXT,
+ };
+ EGLint stride_attrs[] = {
+ EGL_DMA_BUF_PLANE0_PITCH_EXT,
+ EGL_DMA_BUF_PLANE1_PITCH_EXT,
+ EGL_DMA_BUF_PLANE2_PITCH_EXT,
+ EGL_DMA_BUF_PLANE3_PITCH_EXT,
+ };
+ EGLint modifier_lo_attrs[] = {
+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
+ };
+ EGLint modifier_hi_attrs[] = {
+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
+ EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
+ EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
+ EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
+ };
if (texture != 0) {
return;
}
+ assert(nfds >= num_planes);
+ assert(noffsets >= num_planes);
+ assert(nstrides >= num_planes);
+
attrs[i++] = EGL_WIDTH;
attrs[i++] = qemu_dmabuf_get_backing_width(dmabuf);
attrs[i++] = EGL_HEIGHT;
@@ -322,21 +376,22 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
attrs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
attrs[i++] = qemu_dmabuf_get_fourcc(dmabuf);
- attrs[i++] = EGL_DMA_BUF_PLANE0_FD_EXT;
- attrs[i++] = qemu_dmabuf_get_fd(dmabuf);
- attrs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
- attrs[i++] = qemu_dmabuf_get_stride(dmabuf);
- attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
- attrs[i++] = 0;
-#ifdef EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT
- modifier = qemu_dmabuf_get_modifier(dmabuf);
- if (modifier) {
- attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
- attrs[i++] = (modifier >> 0) & 0xffffffff;
- attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
- attrs[i++] = (modifier >> 32) & 0xffffffff;
+ for (j = 0; j < num_planes; j++) {
+ attrs[i++] = fd_attrs[j];
+ /* fd[1-3] may be -1 if using a joint buffer for all planes */
+ attrs[i++] = fds[j] >= 0 ? fds[j] : fds[0];
+ attrs[i++] = stride_attrs[j];
+ attrs[i++] = strides[j];
+ attrs[i++] = offset_attrs[j];
+ attrs[i++] = offsets[j];
+ if (modifier != DRM_FORMAT_MOD_INVALID) {
+ attrs[i++] = modifier_lo_attrs[j];
+ attrs[i++] = (modifier >> 0) & 0xffffffff;
+ attrs[i++] = modifier_hi_attrs[j];
+ attrs[i++] = (modifier >> 32) & 0xffffffff;
+ }
}
-#endif
+
attrs[i++] = EGL_NONE;
image = eglCreateImageKHR(qemu_egl_display,
@@ -503,7 +558,7 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
EGLint major, minor;
EGLBoolean b;
EGLint n;
- bool gles = (mode == DISPLAYGL_MODE_ES);
+ bool gles = (mode == DISPLAY_GL_MODE_ES);
qemu_egl_display = qemu_egl_get_display(dpy, platform);
if (qemu_egl_display == EGL_NO_DISPLAY) {
@@ -533,7 +588,7 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
return -1;
}
- qemu_egl_mode = gles ? DISPLAYGL_MODE_ES : DISPLAYGL_MODE_CORE;
+ qemu_egl_mode = gles ? DISPLAY_GL_MODE_ES : DISPLAY_GL_MODE_CORE;
return 0;
}
@@ -564,8 +619,8 @@ int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode)
int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode)
{
/* prefer GL ES, as that's what ANGLE supports */
- if (mode == DISPLAYGL_MODE_ON) {
- mode = DISPLAYGL_MODE_ES;
+ if (mode == DISPLAY_GL_MODE_ON) {
+ mode = DISPLAY_GL_MODE_ES;
}
if (qemu_egl_init_dpy(dpy, 0, mode) < 0) {
@@ -618,7 +673,7 @@ EGLContext qemu_egl_init_ctx(void)
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
- bool gles = (qemu_egl_mode == DISPLAYGL_MODE_ES);
+ bool gles = (qemu_egl_mode == DISPLAY_GL_MODE_ES);
EGLContext ectx;
EGLBoolean b;
@@ -642,7 +697,7 @@ bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp)
{
ERRP_GUARD();
- if (mode == DISPLAYGL_MODE_OFF) {
+ if (mode == DISPLAY_GL_MODE_OFF) {
error_setg(errp, "egl: turning off GL doesn't make sense");
return false;
}
diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c
index 8d8a636..65d89ec 100644
--- a/ui/gtk-clipboard.c
+++ b/ui/gtk-clipboard.c
@@ -19,6 +19,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "ui/gtk.h"
@@ -95,11 +96,13 @@ static void gd_clipboard_update_info(GtkDisplayState *gd,
gtk_clipboard_clear(gd->gtkcb[s]);
if (targets) {
gd->cbowner[s] = true;
- gtk_clipboard_set_with_data(gd->gtkcb[s],
- targets, n_targets,
- gd_clipboard_get_data,
- gd_clipboard_clear,
- gd);
+ if (!gtk_clipboard_set_with_data(gd->gtkcb[s],
+ targets, n_targets,
+ gd_clipboard_get_data,
+ gd_clipboard_clear,
+ gd)) {
+ warn_report("Failed to set GTK clipboard");
+ }
gtk_target_table_free(targets, n_targets);
}
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 9831c10..0b787be 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -22,7 +22,7 @@
#include "ui/egl-helpers.h"
#include "ui/shader.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
static void gtk_egl_set_scanout_mode(VirtualConsole *vc, bool scanout)
{
@@ -70,16 +70,18 @@ void gd_egl_draw(VirtualConsole *vc)
QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf;
int fence_fd;
#endif
- int ww, wh, ws;
+ int ww, wh, pw, ph, gs;
if (!vc->gfx.gls) {
return;
}
window = gtk_widget_get_window(vc->gfx.drawing_area);
- ws = gdk_window_get_scale_factor(window);
- ww = gdk_window_get_width(window) * ws;
- wh = gdk_window_get_height(window) * ws;
+ gs = gdk_window_get_scale_factor(window);
+ ww = gdk_window_get_width(window);
+ wh = gdk_window_get_height(window);
+ pw = ww * gs;
+ ph = wh * gs;
if (vc->gfx.scanout_mode) {
#ifdef CONFIG_GBM
@@ -93,8 +95,9 @@ void gd_egl_draw(VirtualConsole *vc)
#endif
gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h);
- vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds);
- vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.ds);
+ gd_update_scale(vc, ww, wh,
+ surface_width(vc->gfx.ds),
+ surface_height(vc->gfx.ds));
glFlush();
#ifdef CONFIG_GBM
@@ -115,13 +118,14 @@ void gd_egl_draw(VirtualConsole *vc)
eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
vc->gfx.esurface, vc->gfx.ectx);
- surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
+ surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, pw, ph);
surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
- vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds);
- vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.ds);
+ gd_update_scale(vc, ww, wh,
+ surface_width(vc->gfx.ds),
+ surface_height(vc->gfx.ds));
glFlush();
}
@@ -336,7 +340,11 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl,
{
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
GdkWindow *window;
- int ww, wh, ws;
+ int px_offset, py_offset;
+ int gs;
+ int pw_widget, ph_widget, pw_surface, ph_surface;
+ int ww_widget, wh_widget, ww_surface, wh_surface;
+ int fbw, fbh;
if (!vc->gfx.scanout_mode) {
return;
@@ -349,10 +357,32 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl,
vc->gfx.esurface, vc->gfx.ectx);
window = gtk_widget_get_window(vc->gfx.drawing_area);
- ws = gdk_window_get_scale_factor(window);
- ww = gdk_window_get_width(window) * ws;
- wh = gdk_window_get_height(window) * ws;
- egl_fb_setup_default(&vc->gfx.win_fb, ww, wh);
+ gs = gdk_window_get_scale_factor(window);
+ ww_widget = gdk_window_get_width(window);
+ wh_widget = gdk_window_get_height(window);
+ fbw = surface_width(vc->gfx.ds);
+ fbh = surface_height(vc->gfx.ds);
+
+ gd_update_scale(vc, ww_widget, wh_widget, fbw, fbh);
+
+ ww_surface = fbw * vc->gfx.scale_x;
+ wh_surface = fbh * vc->gfx.scale_y;
+ pw_widget = ww_widget * gs;
+ ph_widget = wh_widget * gs;
+ pw_surface = ww_surface * gs;
+ ph_surface = wh_surface * gs;
+
+ px_offset = 0;
+ py_offset = 0;
+ if (pw_widget > pw_surface) {
+ px_offset = (pw_widget - pw_surface) / 2;
+ }
+ if (ph_widget > ph_surface) {
+ py_offset = (ph_widget - ph_surface) / 2;
+ }
+
+ egl_fb_setup_default(&vc->gfx.win_fb, pw_surface, ph_surface,
+ px_offset, py_offset);
if (vc->gfx.cursor_fb.texture) {
egl_texture_blit(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.guest_fb,
vc->gfx.y0_top);
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index b628b35..8151cc4 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -16,7 +16,7 @@
#include "ui/gtk.h"
#include "ui/egl-helpers.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
static void gtk_gl_area_set_scanout_mode(VirtualConsole *vc, bool scanout)
{
@@ -42,16 +42,37 @@ void gd_gl_area_draw(VirtualConsole *vc)
#ifdef CONFIG_GBM
QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf;
#endif
- int ww, wh, ws, y1, y2;
+ int pw, ph, gs, y1, y2;
+ int ww, wh;
+ int ww_surface, wh_surface;
+ int fbw, fbh;
+ int wx_offset, wy_offset;
if (!vc->gfx.gls) {
return;
}
gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
- ws = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area));
- ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area) * ws;
- wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area) * ws;
+ gs = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area));
+ fbw = surface_width(vc->gfx.ds);
+ fbh = surface_height(vc->gfx.ds);
+ ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area);
+ wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area);
+ pw = ww * gs;
+ ph = wh * gs;
+
+ gd_update_scale(vc, ww, wh, fbw, fbh);
+
+ ww_surface = fbw * vc->gfx.scale_x;
+ wh_surface = fbh * vc->gfx.scale_y;
+
+ wx_offset = wy_offset = 0;
+ if (ww > ww_surface) {
+ wx_offset = (ww - ww_surface) / 2;
+ }
+ if (wh > wh_surface) {
+ wy_offset = (wh - wh_surface) / 2;
+ }
if (vc->gfx.scanout_mode) {
if (!vc->gfx.guest_fb.framebuffer) {
@@ -71,11 +92,29 @@ void gd_gl_area_draw(VirtualConsole *vc)
glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.guest_fb.framebuffer);
/* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */
- glViewport(0, 0, ww, wh);
+ if (wx_offset > 0) {
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, 0, wx_offset * gs, wh * gs);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glScissor((ww - wx_offset) * gs, 0, wx_offset * gs, wh * gs);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDisable(GL_SCISSOR_TEST);
+ }
+ if (wy_offset > 0) {
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, 0, ww * gs, wy_offset * gs);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glScissor(0, (wh - wy_offset) * gs, ww * gs, wy_offset * gs);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDisable(GL_SCISSOR_TEST);
+ }
+
+ glViewport(0, 0, pw, ph);
y1 = vc->gfx.y0_top ? 0 : vc->gfx.h;
y2 = vc->gfx.y0_top ? vc->gfx.h : 0;
glBlitFramebuffer(0, y1, vc->gfx.w, y2,
- 0, 0, ww, wh,
+ wx_offset * gs, wy_offset * gs,
+ (ww - wx_offset) * gs, (wh - wy_offset) * gs,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
#ifdef CONFIG_GBM
if (dmabuf) {
@@ -101,7 +140,7 @@ void gd_gl_area_draw(VirtualConsole *vc)
}
gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
- surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
+ surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, pw, ph);
surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
}
}
diff --git a/ui/gtk.c b/ui/gtk.c
index 8e14c2a..8c4a94c 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -38,6 +38,7 @@
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
+#include "qemu-main.h"
#include "ui/console.h"
#include "ui/gtk.h"
@@ -55,8 +56,8 @@
#include "trace.h"
#include "ui/input.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/runstate.h"
+#include "system/system.h"
#include "keymaps.h"
#include "chardev/char.h"
#include "qom/object.h"
@@ -386,16 +387,16 @@ static void *gd_win32_get_hwnd(VirtualConsole *vc)
/** DisplayState Callbacks **/
static void gd_update(DisplayChangeListener *dcl,
- int x, int y, int w, int h)
+ int fbx, int fby, int fbw, int fbh)
{
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
GdkWindow *win;
- int x1, x2, y1, y2;
- int mx, my;
- int fbw, fbh;
- int ww, wh;
+ int wx1, wx2, wy1, wy2;
+ int wx_offset, wy_offset;
+ int ww_surface, wh_surface;
+ int ww_widget, wh_widget;
- trace_gd_update(vc->label, x, y, w, h);
+ trace_gd_update(vc->label, fbx, fby, fbw, fbh);
if (!gtk_widget_get_realized(vc->gfx.drawing_area)) {
return;
@@ -404,35 +405,36 @@ static void gd_update(DisplayChangeListener *dcl,
if (vc->gfx.convert) {
pixman_image_composite(PIXMAN_OP_SRC, vc->gfx.ds->image,
NULL, vc->gfx.convert,
- x, y, 0, 0, x, y, w, h);
+ fbx, fby, 0, 0, fbx, fby, fbw, fbh);
}
- x1 = floor(x * vc->gfx.scale_x);
- y1 = floor(y * vc->gfx.scale_y);
+ wx1 = floor(fbx * vc->gfx.scale_x);
+ wy1 = floor(fby * vc->gfx.scale_y);
- x2 = ceil(x * vc->gfx.scale_x + w * vc->gfx.scale_x);
- y2 = ceil(y * vc->gfx.scale_y + h * vc->gfx.scale_y);
+ wx2 = ceil(fbx * vc->gfx.scale_x + fbw * vc->gfx.scale_x);
+ wy2 = ceil(fby * vc->gfx.scale_y + fbh * vc->gfx.scale_y);
- fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
- fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
+ ww_surface = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
+ wh_surface = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
win = gtk_widget_get_window(vc->gfx.drawing_area);
if (!win) {
return;
}
- ww = gdk_window_get_width(win);
- wh = gdk_window_get_height(win);
+ ww_widget = gdk_window_get_width(win);
+ wh_widget = gdk_window_get_height(win);
- mx = my = 0;
- if (ww > fbw) {
- mx = (ww - fbw) / 2;
+ wx_offset = wy_offset = 0;
+ if (ww_widget > ww_surface) {
+ wx_offset = (ww_widget - ww_surface) / 2;
}
- if (wh > fbh) {
- my = (wh - fbh) / 2;
+ if (wh_widget > wh_surface) {
+ wy_offset = (wh_widget - wh_surface) / 2;
}
gtk_widget_queue_draw_area(vc->gfx.drawing_area,
- mx + x1, my + y1, (x2 - x1), (y2 - y1));
+ wx_offset + wx1, wy_offset + wy1,
+ (wx2 - wx1), (wy2 - wy1));
}
static void gd_refresh(DisplayChangeListener *dcl)
@@ -770,8 +772,21 @@ static void gd_resize_event(GtkGLArea *area,
gint width, gint height, gpointer *opaque)
{
VirtualConsole *vc = (void *)opaque;
+ double pw = width, ph = height;
+ double sx = vc->gfx.scale_x, sy = vc->gfx.scale_y;
+ GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(area));
+ const int gs = gdk_window_get_scale_factor(window);
- gd_set_ui_size(vc, width, height);
+ if (!vc->s->free_scale && !vc->s->full_screen) {
+ pw /= sx;
+ ph /= sy;
+ }
+
+ /**
+ * width and height here are in pixel coordinate, so we must divide it
+ * by global window scale (gs)
+ */
+ gd_set_ui_size(vc, pw / gs, ph / gs);
}
#endif
@@ -799,12 +814,95 @@ void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget)
#endif
}
+void gd_update_scale(VirtualConsole *vc, int ww, int wh, int fbw, int fbh)
+{
+ if (!vc) {
+ return;
+ }
+
+ if (vc->s->full_screen) {
+ vc->gfx.scale_x = (double)ww / fbw;
+ vc->gfx.scale_y = (double)wh / fbh;
+ } else if (vc->s->free_scale) {
+ double sx, sy;
+
+ sx = (double)ww / fbw;
+ sy = (double)wh / fbh;
+
+ vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy);
+ }
+}
+/**
+ * DOC: Coordinate handling.
+ *
+ * We are coping with sizes and positions in various coordinates and the
+ * handling of these coordinates is somewhat confusing. It would benefit us
+ * all if we define these coordinates explicitly and clearly. Besides, it's
+ * also helpful to follow the same naming convention for variables
+ * representing values in different coordinates.
+ *
+ * I. Definitions
+ *
+ * - (guest) buffer coordinate: this is the coordinates that the guest will
+ * see. The x/y offsets and width/height specified in commands sent by
+ * guest is basically in buffer coordinate.
+ *
+ * - (host) pixel coordinate: this is the coordinate in pixel level on the
+ * host destop. A window/widget of width 300 in pixel coordinate means it
+ * occupies 300 pixels horizontally.
+ *
+ * - (host) logical window coordinate: the existence of global scaling
+ * factor in desktop level makes this kind of coordinate play a role. It
+ * always holds that (logical window size) * (global scale factor) =
+ * (pixel size).
+ *
+ * - global scale factor: this is specified in desktop level and is
+ * typically invariant during the life cycle of the process. Users with
+ * high-DPI monitors might set this scale, for example, to 2, in order to
+ * make the UI look larger.
+ *
+ * - zooming scale: this can be freely controlled by the QEMU user to zoom
+ * in/out the guest content.
+ *
+ * II. Representation
+ *
+ * We'd like to use consistent representation for variables in different
+ * coordinates:
+ * - buffer coordinate: prefix fb
+ * - pixel coordinate: prefix p
+ * - logical window coordinate: prefix w
+ *
+ * For scales:
+ * - global scale factor: prefix gs
+ * - zooming scale: prefix scale/s
+ *
+ * Example: fbw, pw, ww for width in different coordinates
+ *
+ * III. Equation
+ *
+ * - fbw * gs * scale_x = pw
+ * - pw = gs * ww
+ *
+ * Consequently we have
+ *
+ * - fbw * scale_x = ww
+ *
+ * Example: assuming we are running QEMU on a 3840x2160 screen and have set
+ * global scaling factor to 2, if the guest buffer size is 1920x1080 and the
+ * zooming scale is 0.5, then we have:
+ * - fbw = 1920, fbh = 1080
+ * - pw = 1920, ph = 1080
+ * - ww = 960, wh = 540
+ * A bonus of this configuration is that we can achieve pixel to pixel
+ * presentation of the guest content.
+ */
+
static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
{
VirtualConsole *vc = opaque;
GtkDisplayState *s = vc->s;
- int mx, my;
- int ww, wh;
+ int wx_offset, wy_offset;
+ int ww_widget, wh_widget, ww_surface, wh_surface;
int fbw, fbh;
#if defined(CONFIG_OPENGL)
@@ -838,46 +936,37 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
fbw = surface_width(vc->gfx.ds);
fbh = surface_height(vc->gfx.ds);
- ww = gdk_window_get_width(gtk_widget_get_window(widget));
- wh = gdk_window_get_height(gtk_widget_get_window(widget));
-
- if (s->full_screen) {
- vc->gfx.scale_x = (double)ww / fbw;
- vc->gfx.scale_y = (double)wh / fbh;
- } else if (s->free_scale) {
- double sx, sy;
-
- sx = (double)ww / fbw;
- sy = (double)wh / fbh;
+ ww_widget = gdk_window_get_width(gtk_widget_get_window(widget));
+ wh_widget = gdk_window_get_height(gtk_widget_get_window(widget));
- vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy);
- }
+ gd_update_scale(vc, ww_widget, wh_widget, fbw, fbh);
- fbw *= vc->gfx.scale_x;
- fbh *= vc->gfx.scale_y;
+ ww_surface = fbw * vc->gfx.scale_x;
+ wh_surface = fbh * vc->gfx.scale_y;
- mx = my = 0;
- if (ww > fbw) {
- mx = (ww - fbw) / 2;
+ wx_offset = wy_offset = 0;
+ if (ww_widget > ww_surface) {
+ wx_offset = (ww_widget - ww_surface) / 2;
}
- if (wh > fbh) {
- my = (wh - fbh) / 2;
+ if (wh_widget > wh_surface) {
+ wy_offset = (wh_widget - wh_surface) / 2;
}
- cairo_rectangle(cr, 0, 0, ww, wh);
+ cairo_rectangle(cr, 0, 0, ww_widget, wh_widget);
/* Optionally cut out the inner area where the pixmap
will be drawn. This avoids 'flashing' since we're
not double-buffering. Note we're using the undocumented
behaviour of drawing the rectangle from right to left
to cut out the whole */
- cairo_rectangle(cr, mx + fbw, my,
- -1 * fbw, fbh);
+ cairo_rectangle(cr, wx_offset + ww_surface, wy_offset,
+ -1 * ww_surface, wh_surface);
cairo_fill(cr);
cairo_scale(cr, vc->gfx.scale_x, vc->gfx.scale_y);
cairo_set_source_surface(cr, vc->gfx.surface,
- mx / vc->gfx.scale_x, my / vc->gfx.scale_y);
+ wx_offset / vc->gfx.scale_x,
+ wy_offset / vc->gfx.scale_y);
cairo_paint(cr);
return TRUE;
@@ -888,19 +977,19 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
{
VirtualConsole *vc = opaque;
GtkDisplayState *s = vc->s;
- int x, y;
- int mx, my;
- int fbh, fbw;
- int ww, wh;
+ int fbx, fby;
+ int wx_offset, wy_offset;
+ int wh_surface, ww_surface;
+ int ww_widget, wh_widget;
if (!vc->gfx.ds) {
return TRUE;
}
- fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
- fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
- ww = gtk_widget_get_allocated_width(widget);
- wh = gtk_widget_get_allocated_height(widget);
+ ww_surface = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
+ wh_surface = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
+ ww_widget = gtk_widget_get_allocated_width(widget);
+ wh_widget = gtk_widget_get_allocated_height(widget);
/*
* `widget` may not have the same size with the frame buffer.
@@ -908,41 +997,42 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
* To achieve that, `vc` will be displayed at (mx, my)
* so that it is displayed at the center of the widget.
*/
- mx = my = 0;
- if (ww > fbw) {
- mx = (ww - fbw) / 2;
+ wx_offset = wy_offset = 0;
+ if (ww_widget > ww_surface) {
+ wx_offset = (ww_widget - ww_surface) / 2;
}
- if (wh > fbh) {
- my = (wh - fbh) / 2;
+ if (wh_widget > wh_surface) {
+ wy_offset = (wh_widget - wh_surface) / 2;
}
/*
* `motion` is reported in `widget` coordinates
* so translating it to the coordinates in `vc`.
*/
- x = (motion->x - mx) / vc->gfx.scale_x;
- y = (motion->y - my) / vc->gfx.scale_y;
+ fbx = (motion->x - wx_offset) / vc->gfx.scale_x;
+ fby = (motion->y - wy_offset) / vc->gfx.scale_y;
- trace_gd_motion_event(ww, wh, gtk_widget_get_scale_factor(widget), x, y);
+ trace_gd_motion_event(ww_widget, wh_widget,
+ gtk_widget_get_scale_factor(widget), fbx, fby);
if (qemu_input_is_absolute(vc->gfx.dcl.con)) {
- if (x < 0 || y < 0 ||
- x >= surface_width(vc->gfx.ds) ||
- y >= surface_height(vc->gfx.ds)) {
+ if (fbx < 0 || fby < 0 ||
+ fbx >= surface_width(vc->gfx.ds) ||
+ fby >= surface_height(vc->gfx.ds)) {
return TRUE;
}
- qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, x,
+ qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, fbx,
0, surface_width(vc->gfx.ds));
- qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, y,
+ qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, fby,
0, surface_height(vc->gfx.ds));
qemu_input_event_sync();
} else if (s->last_set && s->ptr_owner == vc) {
- qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, x - s->last_x);
- qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, y - s->last_y);
+ qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, fbx - s->last_x);
+ qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, fby - s->last_y);
qemu_input_event_sync();
}
- s->last_x = x;
- s->last_y = y;
+ s->last_x = fbx;
+ s->last_y = fby;
s->last_set = TRUE;
if (!qemu_input_is_absolute(vc->gfx.dcl.con) && s->ptr_owner == vc) {
@@ -1759,8 +1849,16 @@ static gboolean gd_configure(GtkWidget *widget,
GdkEventConfigure *cfg, gpointer opaque)
{
VirtualConsole *vc = opaque;
+ const double sx = vc->gfx.scale_x, sy = vc->gfx.scale_y;
+ double width = cfg->width, height = cfg->height;
+
+ if (!vc->s->free_scale && !vc->s->full_screen) {
+ width /= sx;
+ height /= sy;
+ }
+
+ gd_set_ui_size(vc, width, height);
- gd_set_ui_size(vc, cfg->width, cfg->height);
return FALSE;
}
@@ -1878,7 +1976,7 @@ static void gd_vc_open(Chardev *chr,
*be_opened = false;
}
-static void char_gd_vc_class_init(ObjectClass *oc, void *data)
+static void char_gd_vc_class_init(ObjectClass *oc, const void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -1943,8 +2041,7 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
vcd->console = vc;
snprintf(buffer, sizeof(buffer), "vc%d", idx);
- vc->label = g_strdup_printf("%s", vc->vte.chr->label
- ? vc->vte.chr->label : buffer);
+ vc->label = g_strdup(vc->vte.chr->label ? : buffer);
group = gd_vc_menu_init(s, vc, idx, group, view_menu);
vc->vte.terminal = vte_terminal_new();
@@ -2485,6 +2582,9 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
#ifdef CONFIG_GTK_CLIPBOARD
gd_clipboard_init(s);
#endif /* CONFIG_GTK_CLIPBOARD */
+
+ /* GTK's event polling must happen on the main thread. */
+ qemu_main = NULL;
}
static void early_gtk_display_init(DisplayOptions *opts)
@@ -2514,7 +2614,7 @@ static void early_gtk_display_init(DisplayOptions *opts)
}
assert(opts->type == DISPLAY_TYPE_GTK);
- if (opts->has_gl && opts->gl != DISPLAYGL_MODE_OFF) {
+ if (opts->has_gl && opts->gl != DISPLAY_GL_MODE_OFF) {
#if defined(CONFIG_OPENGL)
#if defined(GDK_WINDOWING_WAYLAND)
if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
@@ -2530,7 +2630,7 @@ static void early_gtk_display_init(DisplayOptions *opts)
#endif
{
#ifdef CONFIG_X11
- DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_ON;
+ DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAY_GL_MODE_ON;
gtk_egl_init(mode);
#endif
}
@@ -2540,7 +2640,7 @@ static void early_gtk_display_init(DisplayOptions *opts)
keycode_map = gd_get_keymap(&keycode_maplen);
#if defined(CONFIG_VTE)
- type_register(&char_gd_vc_type_info);
+ type_register_static(&char_gd_vc_type_info);
#endif
}
diff --git a/ui/input-barrier.c b/ui/input-barrier.c
index 2d57ca7..9793258 100644
--- a/ui/input-barrier.c
+++ b/ui/input-barrier.c
@@ -11,7 +11,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qemu/main-loop.h"
#include "qemu/sockets.h"
#include "qapi/error.h"
@@ -696,7 +696,7 @@ static void input_barrier_instance_init(Object *obj)
ib->height = 1080;
}
-static void input_barrier_class_init(ObjectClass *oc, void *data)
+static void input_barrier_class_init(ObjectClass *oc, const void *data)
{
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
@@ -732,7 +732,7 @@ static const TypeInfo input_barrier_info = {
.instance_size = sizeof(InputBarrier),
.instance_init = input_barrier_instance_init,
.instance_finalize = input_barrier_instance_finalize,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_USER_CREATABLE },
{ }
}
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index 210ae5e..ca4bccb 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -109,43 +109,6 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
g_free(up);
}
-static void legacy_kbd_event(DeviceState *dev, QemuConsole *src,
- InputEvent *evt)
-{
- QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev;
- int scancodes[3], i, count;
- InputKeyEvent *key = evt->u.key.data;
-
- if (!entry || !entry->put_kbd) {
- return;
- }
- count = qemu_input_key_value_to_scancode(key->key,
- key->down,
- scancodes);
- for (i = 0; i < count; i++) {
- entry->put_kbd(entry->opaque, scancodes[i]);
- }
-}
-
-static const QemuInputHandler legacy_kbd_handler = {
- .name = "legacy-kbd",
- .mask = INPUT_EVENT_MASK_KEY,
- .event = legacy_kbd_event,
-};
-
-QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
-{
- QEMUPutKbdEntry *entry;
-
- entry = g_new0(QEMUPutKbdEntry, 1);
- entry->put_kbd = func;
- entry->opaque = opaque;
- entry->s = qemu_input_handler_register((DeviceState *)entry,
- &legacy_kbd_handler);
- qemu_input_handler_activate(entry->s);
- return entry;
-}
-
static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
InputEvent *evt)
{
diff --git a/ui/input-linux.c b/ui/input-linux.c
index e572a2e..92e1a1a 100644
--- a/ui/input-linux.c
+++ b/ui/input-linux.c
@@ -12,7 +12,7 @@
#include "qemu/sockets.h"
#include "ui/input.h"
#include "qom/object_interfaces.h"
-#include "sysemu/iothread.h"
+#include "system/iothread.h"
#include "block/aio.h"
#include <sys/ioctl.h>
@@ -412,7 +412,6 @@ err_read_event_bits:
err_close:
close(il->fd);
- return;
}
static void input_linux_instance_finalize(Object *obj)
@@ -495,7 +494,7 @@ static void input_linux_instance_init(Object *obj)
{
}
-static void input_linux_class_init(ObjectClass *oc, void *data)
+static void input_linux_class_init(ObjectClass *oc, const void *data)
{
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
@@ -523,7 +522,7 @@ static const TypeInfo input_linux_info = {
.instance_size = sizeof(InputLinux),
.instance_init = input_linux_instance_init,
.instance_finalize = input_linux_instance_finalize,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_USER_CREATABLE },
{ }
}
diff --git a/ui/input.c b/ui/input.c
index dc74586..147e69c 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -1,12 +1,12 @@
#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-ui.h"
#include "trace.h"
#include "ui/input.h"
#include "ui/console.h"
-#include "sysemu/replay.h"
-#include "sysemu/runstate.h"
+#include "system/replay.h"
+#include "system/runstate.h"
struct QemuInputHandlerState {
DeviceState *dev;
@@ -174,37 +174,6 @@ void qmp_input_send_event(const char *device,
qemu_input_event_sync();
}
-static int qemu_input_transform_invert_abs_value(int value)
-{
- return (int64_t)INPUT_EVENT_ABS_MAX - value + INPUT_EVENT_ABS_MIN;
-}
-
-static void qemu_input_transform_abs_rotate(InputEvent *evt)
-{
- InputMoveEvent *move = evt->u.abs.data;
- switch (graphic_rotate) {
- case 90:
- if (move->axis == INPUT_AXIS_X) {
- move->axis = INPUT_AXIS_Y;
- } else if (move->axis == INPUT_AXIS_Y) {
- move->axis = INPUT_AXIS_X;
- move->value = qemu_input_transform_invert_abs_value(move->value);
- }
- break;
- case 180:
- move->value = qemu_input_transform_invert_abs_value(move->value);
- break;
- case 270:
- if (move->axis == INPUT_AXIS_X) {
- move->axis = INPUT_AXIS_Y;
- move->value = qemu_input_transform_invert_abs_value(move->value);
- } else if (move->axis == INPUT_AXIS_Y) {
- move->axis = INPUT_AXIS_X;
- }
- break;
- }
-}
-
static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
{
const char *name;
@@ -340,11 +309,6 @@ void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
qemu_input_event_trace(src, evt);
- /* pre processing */
- if (graphic_rotate && (evt->type == INPUT_EVENT_KIND_ABS)) {
- qemu_input_transform_abs_rotate(evt);
- }
-
/* send event */
s = qemu_input_find_handler(1 << evt->type, src);
if (!s) {
diff --git a/ui/meson.build b/ui/meson.build
index 28c7381..6371422 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -1,7 +1,4 @@
system_ss.add(pixman)
-specific_ss.add(when: ['CONFIG_SYSTEM_ONLY'], if_true: pixman) # for the include path
-specific_ss.add(when: ['CONFIG_SYSTEM_ONLY'], if_true: opengl) # for the include path
-
system_ss.add(png)
system_ss.add(files(
'clipboard.c',
@@ -120,10 +117,6 @@ if gtk.found()
endif
if sdl.found()
- if host_os == 'windows'
- system_ss.add(files('win32-kbd-hook.c'))
- endif
-
sdl_ss = ss.source_set()
sdl_ss.add(sdl, sdl_image, pixman, glib, files(
'sdl2-2d.c',
diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c
index 5ca55dd..ef4e71d 100644
--- a/ui/qemu-pixman.c
+++ b/ui/qemu-pixman.c
@@ -4,7 +4,9 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "ui/console.h"
+#include "qemu/memfd.h"
#include "standard-headers/drm/drm_fourcc.h"
#include "trace.h"
@@ -49,7 +51,6 @@ PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format)
break;
default:
g_assert_not_reached();
- break;
}
pf.amax = (1 << pf.abits) - 1;
@@ -125,33 +126,34 @@ uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman_format)
return 0;
}
-int qemu_pixman_get_type(int rshift, int gshift, int bshift)
+int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian)
{
int type = PIXMAN_TYPE_OTHER;
+ bool native_endian = (endian == G_BYTE_ORDER);
if (rshift > gshift && gshift > bshift) {
if (bshift == 0) {
- type = PIXMAN_TYPE_ARGB;
+ type = native_endian ? PIXMAN_TYPE_ARGB : PIXMAN_TYPE_BGRA;
} else {
- type = PIXMAN_TYPE_RGBA;
+ type = native_endian ? PIXMAN_TYPE_RGBA : PIXMAN_TYPE_ABGR;
}
} else if (rshift < gshift && gshift < bshift) {
if (rshift == 0) {
- type = PIXMAN_TYPE_ABGR;
+ type = native_endian ? PIXMAN_TYPE_ABGR : PIXMAN_TYPE_RGBA;
} else {
- type = PIXMAN_TYPE_BGRA;
+ type = native_endian ? PIXMAN_TYPE_BGRA : PIXMAN_TYPE_ARGB;
}
}
return type;
}
#ifdef CONFIG_PIXMAN
-pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf)
+pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf, int endian)
{
pixman_format_code_t format;
int type;
- type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift);
+ type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift, endian);
format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
pf->abits, pf->rbits, pf->gbits, pf->bbits);
if (!pixman_format_supported_source(format)) {
@@ -268,3 +270,72 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph,
pixman_image_unref(ibg);
}
#endif /* CONFIG_PIXMAN */
+
+static void *
+qemu_pixman_shareable_alloc(const char *name, size_t size,
+ qemu_pixman_shareable *handle,
+ Error **errp)
+{
+#ifdef WIN32
+ return qemu_win32_map_alloc(size, handle, errp);
+#else
+ return qemu_memfd_alloc(name, size, 0, handle, errp);
+#endif
+}
+
+static void
+qemu_pixman_shareable_free(qemu_pixman_shareable handle,
+ void *ptr, size_t size)
+{
+#ifdef WIN32
+ qemu_win32_map_free(ptr, handle, &error_warn);
+#else
+ qemu_memfd_free(ptr, size, handle);
+#endif
+}
+
+static void
+qemu_pixman_shared_image_destroy(pixman_image_t *image, void *data)
+{
+ qemu_pixman_shareable handle = PTR_TO_SHAREABLE(data);
+ void *ptr = pixman_image_get_data(image);
+ size_t size = pixman_image_get_height(image) * pixman_image_get_stride(image);
+
+ qemu_pixman_shareable_free(handle, ptr, size);
+}
+
+bool
+qemu_pixman_image_new_shareable(pixman_image_t **image,
+ qemu_pixman_shareable *handle,
+ const char *name,
+ pixman_format_code_t format,
+ int width,
+ int height,
+ int rowstride_bytes,
+ Error **errp)
+{
+ ERRP_GUARD();
+ size_t size = height * rowstride_bytes;
+ void *bits = NULL;
+
+ g_return_val_if_fail(image != NULL, false);
+ g_return_val_if_fail(handle != NULL, false);
+
+ bits = qemu_pixman_shareable_alloc(name, size, handle, errp);
+ if (!bits) {
+ return false;
+ }
+
+ *image = pixman_image_create_bits(format, width, height, bits, rowstride_bytes);
+ if (!*image) {
+ error_setg(errp, "Failed to allocate image");
+ qemu_pixman_shareable_free(*handle, bits, size);
+ return false;
+ }
+
+ pixman_image_set_destroy_function(*image,
+ qemu_pixman_shared_image_destroy,
+ SHAREABLE_TO_PTR(*handle));
+
+ return true;
+}
diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
index 91b7ee2..3be17d1 100644
--- a/ui/sdl2-gl.c
+++ b/ui/sdl2-gl.c
@@ -147,11 +147,11 @@ QEMUGLContext sdl2_gl_create_context(DisplayGLCtx *dgc,
SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
- if (scon->opts->gl == DISPLAYGL_MODE_ON ||
- scon->opts->gl == DISPLAYGL_MODE_CORE) {
+ if (scon->opts->gl == DISPLAY_GL_MODE_ON ||
+ scon->opts->gl == DISPLAY_GL_MODE_CORE) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE);
- } else if (scon->opts->gl == DISPLAYGL_MODE_ES) {
+ } else if (scon->opts->gl == DISPLAY_GL_MODE_ES) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_ES);
}
@@ -163,7 +163,7 @@ QEMUGLContext sdl2_gl_create_context(DisplayGLCtx *dgc,
/* If SDL fail to create a GL context and we use the "on" flag,
* then try to fallback to GLES.
*/
- if (!ctx && scon->opts->gl == DISPLAYGL_MODE_ON) {
+ if (!ctx && scon->opts->gl == DISPLAY_GL_MODE_ON) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_ES);
ctx = SDL_GL_CreateContext(scon->real_window);
@@ -241,7 +241,7 @@ void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
SDL_GetWindowSize(scon->real_window, &ww, &wh);
- egl_fb_setup_default(&scon->win_fb, ww, wh);
+ egl_fb_setup_default(&scon->win_fb, ww, wh, 0, 0);
egl_fb_blit(&scon->win_fb, &scon->guest_fb, !scon->y0_top);
SDL_GL_SwapWindow(scon->real_window);
diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c
index b02a89e..2286df4 100644
--- a/ui/sdl2-input.c
+++ b/ui/sdl2-input.c
@@ -58,3 +58,8 @@ void sdl2_process_key(struct sdl2_console *scon,
}
}
}
+
+void sdl2_release_modifiers(struct sdl2_console *scon)
+{
+ qkbd_state_lift_all_keys(scon->kbd);
+}
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 98ed974..b00e421 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -29,11 +29,11 @@
#include "ui/console.h"
#include "ui/input.h"
#include "ui/sdl2.h"
-#include "sysemu/runstate.h"
-#include "sysemu/runstate-action.h"
-#include "sysemu/sysemu.h"
-#include "ui/win32-kbd-hook.h"
+#include "system/runstate.h"
+#include "system/runstate-action.h"
+#include "system/system.h"
#include "qemu/log.h"
+#include "qemu-main.h"
static int sdl2_num_outputs;
static struct sdl2_console *sdl2_console;
@@ -107,7 +107,7 @@ void sdl2_window_create(struct sdl2_console *scon)
if (scon->opengl) {
const char *driver = "opengl";
- if (scon->opts->gl == DISPLAYGL_MODE_ES) {
+ if (scon->opts->gl == DISPLAY_GL_MODE_ES) {
driver = "opengles2";
}
@@ -115,6 +115,7 @@ void sdl2_window_create(struct sdl2_console *scon)
SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
scon->winctx = SDL_GL_CreateContext(scon->real_window);
+ SDL_GL_SetSwapInterval(0);
} else {
/* The SDL renderer is only used by sdl2-2D, when OpenGL is disabled */
scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
@@ -261,7 +262,6 @@ static void sdl_grab_start(struct sdl2_console *scon)
}
SDL_SetWindowGrab(scon->real_window, SDL_TRUE);
gui_grab = 1;
- win32_kbd_set_grab(true);
sdl_update_caption(scon);
}
@@ -269,7 +269,6 @@ static void sdl_grab_end(struct sdl2_console *scon)
{
SDL_SetWindowGrab(scon->real_window, SDL_FALSE);
gui_grab = 0;
- win32_kbd_set_grab(false);
sdl_show_cursor(scon);
sdl_update_caption(scon);
}
@@ -370,30 +369,18 @@ static int get_mod_state(void)
}
}
-static void *sdl2_win32_get_hwnd(struct sdl2_console *scon)
-{
-#ifdef CONFIG_WIN32
- SDL_SysWMinfo info;
-
- SDL_VERSION(&info.version);
- if (SDL_GetWindowWMInfo(scon->real_window, &info)) {
- return info.info.win.window;
- }
-#endif
- return NULL;
-}
-
static void handle_keydown(SDL_Event *ev)
{
int win;
struct sdl2_console *scon = get_scon_from_window(ev->key.windowID);
int gui_key_modifier_pressed = get_mod_state();
- int gui_keysym = 0;
if (!scon) {
return;
}
+ scon->gui_keysym = false;
+
if (!scon->ignore_hotkeys && gui_key_modifier_pressed && !ev->key.repeat) {
switch (ev->key.keysym.scancode) {
case SDL_SCANCODE_2:
@@ -418,15 +405,16 @@ static void handle_keydown(SDL_Event *ev)
SDL_ShowWindow(sdl2_console[win].real_window);
}
}
- gui_keysym = 1;
+ sdl2_release_modifiers(scon);
+ scon->gui_keysym = true;
}
break;
case SDL_SCANCODE_F:
toggle_full_screen(scon);
- gui_keysym = 1;
+ scon->gui_keysym = true;
break;
case SDL_SCANCODE_G:
- gui_keysym = 1;
+ scon->gui_keysym = true;
if (!gui_grab) {
sdl_grab_start(scon);
} else if (!gui_fullscreen) {
@@ -439,7 +427,7 @@ static void handle_keydown(SDL_Event *ev)
/* re-create scon->texture */
sdl2_2d_switch(&scon->dcl, scon->surface);
}
- gui_keysym = 1;
+ scon->gui_keysym = true;
break;
#if 0
case SDL_SCANCODE_KP_PLUS:
@@ -458,14 +446,14 @@ static void handle_keydown(SDL_Event *ev)
__func__, width, height);
sdl_scale(scon, width, height);
sdl2_redraw(scon);
- gui_keysym = 1;
+ scon->gui_keysym = true;
}
#endif
default:
break;
}
}
- if (!gui_keysym) {
+ if (!scon->gui_keysym) {
sdl2_process_key(scon, &ev->key);
}
}
@@ -491,7 +479,7 @@ static void handle_textinput(SDL_Event *ev)
return;
}
- if (QEMU_IS_TEXT_CONSOLE(con)) {
+ if (!scon->gui_keysym && QEMU_IS_TEXT_CONSOLE(con)) {
qemu_text_console_put_string(QEMU_TEXT_CONSOLE(con), ev->text.text, strlen(ev->text.text));
}
}
@@ -500,14 +488,14 @@ static void handle_mousemotion(SDL_Event *ev)
{
int max_x, max_y;
struct sdl2_console *scon = get_scon_from_window(ev->motion.windowID);
+ int scr_w, scr_h, surf_w, surf_h, x, y, dx, dy;
if (!scon || !qemu_console_is_graphic(scon->dcl.con)) {
return;
}
+ SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
if (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) {
- int scr_w, scr_h;
- SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
max_x = scr_w - 1;
max_y = scr_h - 1;
if (gui_grab && !gui_fullscreen
@@ -521,9 +509,14 @@ static void handle_mousemotion(SDL_Event *ev)
sdl_grab_start(scon);
}
}
+ surf_w = surface_width(scon->surface);
+ surf_h = surface_height(scon->surface);
+ x = (int64_t)ev->motion.x * surf_w / scr_w;
+ y = (int64_t)ev->motion.y * surf_h / scr_h;
+ dx = (int64_t)ev->motion.xrel * surf_w / scr_w;
+ dy = (int64_t)ev->motion.yrel * surf_h / scr_h;
if (gui_grab || qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) {
- sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel,
- ev->motion.x, ev->motion.y, ev->motion.state);
+ sdl_send_mouse_event(scon, dx, dy, x, y, ev->motion.state);
}
}
@@ -532,12 +525,17 @@ static void handle_mousebutton(SDL_Event *ev)
int buttonstate = SDL_GetMouseState(NULL, NULL);
SDL_MouseButtonEvent *bev;
struct sdl2_console *scon = get_scon_from_window(ev->button.windowID);
+ int scr_w, scr_h, x, y;
if (!scon || !qemu_console_is_graphic(scon->dcl.con)) {
return;
}
bev = &ev->button;
+ SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
+ x = (int64_t)bev->x * surface_width(scon->surface) / scr_w;
+ y = (int64_t)bev->y * surface_height(scon->surface) / scr_h;
+
if (!gui_grab && !qemu_input_is_absolute(scon->dcl.con)) {
if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
/* start grabbing all events */
@@ -549,7 +547,7 @@ static void handle_mousebutton(SDL_Event *ev)
} else {
buttonstate &= ~SDL_BUTTON(bev->button);
}
- sdl_send_mouse_event(scon, 0, 0, bev->x, bev->y, buttonstate);
+ sdl_send_mouse_event(scon, 0, 0, x, y, buttonstate);
}
}
@@ -605,10 +603,6 @@ static void handle_windowevent(SDL_Event *ev)
sdl2_redraw(scon);
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
- win32_kbd_set_grab(gui_grab);
- if (qemu_console_is_graphic(scon->dcl.con)) {
- win32_kbd_set_window(sdl2_win32_get_hwnd(scon));
- }
/* fall through */
case SDL_WINDOWEVENT_ENTER:
if (!gui_grab && (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled)) {
@@ -624,9 +618,6 @@ static void handle_windowevent(SDL_Event *ev)
scon->ignore_hotkeys = get_mod_state();
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
- if (qemu_console_is_graphic(scon->dcl.con)) {
- win32_kbd_set_window(NULL);
- }
if (gui_grab && !gui_fullscreen) {
sdl_grab_end(scon);
}
@@ -866,10 +857,7 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR /* only available since SDL 2.0.8 */
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
#endif
-#ifndef CONFIG_WIN32
- /* QEMU uses its own low level keyboard hook procedure on Windows */
SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1");
-#endif
#ifdef SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED
SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, "0");
#endif
@@ -962,6 +950,9 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
}
atexit(sdl_cleanup);
+
+ /* SDL's event polling (in dpy_refresh) must happen on the main thread. */
+ qemu_main = NULL;
}
static QemuDisplay qemu_display_sdl2 = {
diff --git a/ui/spice-app.c b/ui/spice-app.c
index a10b4a5..24f78f3 100644
--- a/ui/spice-app.c
+++ b/ui/spice-app.c
@@ -36,7 +36,7 @@
#include "qapi/error.h"
#include "io/channel-command.h"
#include "chardev/spice.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "qom/object.h"
static const char *tmp_dir;
@@ -101,7 +101,7 @@ static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp)
/* fqdn is dealt with in vc_chr_open() */
}
-static void char_vc_class_init(ObjectClass *oc, void *data)
+static void char_vc_class_init(ObjectClass *oc, const void *data)
{
VCChardevClass *vc = CHARDEV_VC_CLASS(oc);
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -173,7 +173,7 @@ static void spice_app_display_early_init(DisplayOptions *opts)
exit(1);
}
- type_register(&char_vc_type_info);
+ type_register_static(&char_vc_type_info);
sock_path = g_strjoin("", app_dir, "/", "spice.sock", NULL);
qopts = qemu_opts_create(list, NULL, 0, &error_abort);
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 15be640..0326c63 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -18,8 +18,8 @@
#include "qemu/osdep.h"
#include <spice.h>
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
+#include "system/system.h"
+#include "system/runstate.h"
#include "ui/qemu-spice.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
@@ -840,7 +840,7 @@ static void qemu_spice_init(void)
"incompatible with -spice port/tls-port");
exit(1);
}
- egl_init(qemu_opt_get(opts, "rendernode"), DISPLAYGL_MODE_ON, &error_fatal);
+ egl_init(qemu_opt_get(opts, "rendernode"), DISPLAY_GL_MODE_ON, &error_fatal);
spice_opengl = 1;
}
#endif
diff --git a/ui/spice-display.c b/ui/spice-display.c
index c794ae0..9c39d2c 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -28,6 +28,8 @@
#include "ui/spice-display.h"
+#include "standard-headers/drm/drm_fourcc.h"
+
bool spice_opengl;
int qemu_spice_rect_is_empty(const QXLRect* r)
@@ -872,23 +874,48 @@ static void spice_gl_update(DisplayChangeListener *dcl,
ssd->gl_updates++;
}
+static void spice_server_gl_scanout(QXLInstance *qxl,
+ const int *fd,
+ uint32_t width, uint32_t height,
+ const uint32_t *offset,
+ const uint32_t *stride,
+ uint32_t num_planes, uint32_t format,
+ uint64_t modifier, int y_0_top)
+{
+#ifdef HAVE_SPICE_QXL_GL_SCANOUT2
+ spice_qxl_gl_scanout2(qxl, fd, width, height, offset, stride,
+ num_planes, format, modifier, y_0_top);
+#else
+ if (num_planes <= 1) {
+ spice_qxl_gl_scanout(qxl, fd[0], width, height, stride[0], format, y_0_top);
+ } else {
+ error_report("SPICE server does not support multi plane GL scanout");
+ }
+#endif
+}
+
static void spice_gl_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
- EGLint stride, fourcc;
- int fd;
if (ssd->ds) {
surface_gl_destroy_texture(ssd->gls, ssd->ds);
}
ssd->ds = new_surface;
if (ssd->ds) {
+ uint32_t offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES];
+ int fd[DMABUF_MAX_PLANES], num_planes, fourcc;
+ uint64_t modifier;
+
surface_gl_create_texture(ssd->gls, ssd->ds);
- fd = egl_get_fd_for_texture(ssd->ds->texture,
- &stride, &fourcc,
- NULL);
- if (fd < 0) {
+ if (!egl_dmabuf_export_texture(ssd->ds->texture,
+ fd,
+ (EGLint *)offset,
+ (EGLint *)stride,
+ &fourcc,
+ &num_planes,
+ &modifier)) {
surface_gl_destroy_texture(ssd->gls, ssd->ds);
return;
}
@@ -899,10 +926,11 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
fourcc);
/* note: spice server will close the fd */
- spice_qxl_gl_scanout(&ssd->qxl, fd,
- surface_width(ssd->ds),
- surface_height(ssd->ds),
- stride, fourcc, false);
+ spice_server_gl_scanout(&ssd->qxl, fd,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds),
+ offset, stride, num_planes,
+ fourcc, modifier, false);
ssd->have_surface = true;
ssd->have_scanout = false;
@@ -925,7 +953,8 @@ static void qemu_spice_gl_scanout_disable(DisplayChangeListener *dcl)
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
trace_qemu_spice_gl_scanout_disable(ssd->qxl.id);
- spice_qxl_gl_scanout(&ssd->qxl, -1, 0, 0, 0, 0, false);
+ spice_server_gl_scanout(&ssd->qxl, NULL, 0, 0, NULL, NULL, 0, DRM_FORMAT_INVALID,
+ DRM_FORMAT_MOD_INVALID, false);
qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0);
ssd->have_surface = false;
ssd->have_scanout = false;
@@ -941,20 +970,23 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
void *d3d_tex2d)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
- EGLint stride = 0, fourcc = 0;
- int fd = -1;
+ EGLint offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc = 0;
+ int fd[DMABUF_MAX_PLANES], num_planes;
+ uint64_t modifier;
assert(tex_id);
- fd = egl_get_fd_for_texture(tex_id, &stride, &fourcc, NULL);
- if (fd < 0) {
- fprintf(stderr, "%s: failed to get fd for texture\n", __func__);
+ if (!egl_dmabuf_export_texture(tex_id, fd, offset, stride, &fourcc,
+ &num_planes, &modifier)) {
+ fprintf(stderr, "%s: failed to export dmabuf for texture\n", __func__);
return;
}
+
trace_qemu_spice_gl_scanout_texture(ssd->qxl.id, w, h, fourcc);
/* note: spice server will close the fd */
- spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
- stride, fourcc, y_0_top);
+ spice_server_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
+ (uint32_t *)offset, (uint32_t *)stride, num_planes,
+ fourcc, modifier, y_0_top);
qemu_spice_gl_monitor_config(ssd, x, y, w, h);
ssd->have_surface = false;
ssd->have_scanout = true;
@@ -1025,11 +1057,10 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
- EGLint stride = 0, fourcc = 0;
+ EGLint fourcc = 0;
bool render_cursor = false;
bool y_0_top = false; /* FIXME */
uint64_t cookie;
- int fd;
uint32_t width, height, texture;
if (!ssd->have_scanout) {
@@ -1064,26 +1095,47 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
/* dest framebuffer */
if (ssd->blit_fb.width != width ||
ssd->blit_fb.height != height) {
+ int fds[DMABUF_MAX_PLANES], num_planes;
+ uint32_t offsets[DMABUF_MAX_PLANES], strides[DMABUF_MAX_PLANES];
+ uint64_t modifier;
+
trace_qemu_spice_gl_render_dmabuf(ssd->qxl.id, width,
height);
egl_fb_destroy(&ssd->blit_fb);
egl_fb_setup_new_tex(&ssd->blit_fb,
width, height);
- fd = egl_get_fd_for_texture(ssd->blit_fb.texture,
- &stride, &fourcc, NULL);
- spice_qxl_gl_scanout(&ssd->qxl, fd, width, height,
- stride, fourcc, false);
+ if (!egl_dmabuf_export_texture(ssd->blit_fb.texture, fds,
+ (EGLint *)offsets, (EGLint *)strides,
+ &fourcc, &num_planes, &modifier)) {
+ fprintf(stderr,
+ "%s: failed to export dmabuf for texture\n", __func__);
+ return;
+ }
+
+ spice_server_gl_scanout(&ssd->qxl, fds, width, height, offsets, strides,
+ num_planes, fourcc, modifier, false);
}
} else {
- stride = qemu_dmabuf_get_stride(dmabuf);
+ int fds[DMABUF_MAX_PLANES];
+ int noffsets, nstrides;
+ const uint32_t *offsets = qemu_dmabuf_get_offsets(dmabuf, &noffsets);
+ const uint32_t *strides = qemu_dmabuf_get_strides(dmabuf, &nstrides);
+ uint32_t num_planes = qemu_dmabuf_get_num_planes(dmabuf);
+
+ assert(noffsets >= num_planes);
+ assert(nstrides >= num_planes);
+
fourcc = qemu_dmabuf_get_fourcc(dmabuf);
y_0_top = qemu_dmabuf_get_y0_top(dmabuf);
- fd = qemu_dmabuf_dup_fd(dmabuf);
+ qemu_dmabuf_dup_fds(dmabuf, fds, DMABUF_MAX_PLANES);
trace_qemu_spice_gl_forward_dmabuf(ssd->qxl.id, width, height);
/* note: spice server will close the fd, so hand over a dup */
- spice_qxl_gl_scanout(&ssd->qxl, fd, width, height,
- stride, fourcc, y_0_top);
+ spice_server_gl_scanout(&ssd->qxl, fds, width, height,
+ offsets, strides, num_planes,
+ fourcc,
+ qemu_dmabuf_get_modifier(dmabuf),
+ y_0_top);
}
qemu_spice_gl_monitor_config(ssd, 0, 0, width, height);
ssd->guest_dmabuf_refresh = false;
diff --git a/ui/trace-events b/ui/trace-events
index fb253c1..3da0d5e 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -166,6 +166,7 @@ dbus_clipboard_unregister(const char *bus_name) "peer %s"
dbus_scanout_texture(uint32_t tex_id, bool backing_y_0_top, uint32_t backing_width, uint32_t backing_height, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "tex_id:%u y0top:%d back:%ux%u %u+%u-%ux%u"
dbus_gl_gfx_switch(void *p) "surf: %p"
dbus_filter(unsigned int serial, unsigned int filter) "serial=%u (<= %u)"
+dbus_can_share_map(bool share) "can_share_map: %d"
# egl-helpers.c
egl_init_d3d11_device(void *p) "d3d device: %p"
diff --git a/ui/ui-hmp-cmds.c b/ui/ui-hmp-cmds.c
index 26c8ced..980a8bb 100644
--- a/ui/ui-hmp-cmds.c
+++ b/ui/ui-hmp-cmds.c
@@ -21,7 +21,7 @@
#include "monitor/monitor-internal.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-ui.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qemu/cutils.h"
#include "ui/console.h"
#include "ui/input.h"
diff --git a/ui/vdagent.c b/ui/vdagent.c
index 724eff9..c0746fe 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -6,10 +6,10 @@
#include "qemu/option.h"
#include "qemu/units.h"
#include "hw/qdev-core.h"
-#include "migration/blocker.h"
#include "ui/clipboard.h"
#include "ui/console.h"
#include "ui/input.h"
+#include "migration/vmstate.h"
#include "trace.h"
#include "qapi/qapi-types-char.h"
@@ -32,14 +32,12 @@
struct VDAgentChardev {
Chardev parent;
- /* TODO: migration isn't yet supported */
- Error *migration_blocker;
-
/* config */
bool mouse;
bool clipboard;
/* guest vdagent */
+ bool connected;
uint32_t caps;
VDIChunkHeader chunk;
uint32_t chunksize;
@@ -47,7 +45,7 @@ struct VDAgentChardev {
uint32_t msgsize;
uint8_t *xbuf;
uint32_t xoff, xsize;
- Buffer outbuf;
+ GByteArray *outbuf;
/* mouse */
DeviceState mouse_dev;
@@ -142,16 +140,16 @@ static void vdagent_send_buf(VDAgentChardev *vd)
{
uint32_t len;
- while (!buffer_empty(&vd->outbuf)) {
+ while (vd->outbuf->len) {
len = qemu_chr_be_can_write(CHARDEV(vd));
if (len == 0) {
return;
}
- if (len > vd->outbuf.offset) {
- len = vd->outbuf.offset;
+ if (len > vd->outbuf->len) {
+ len = vd->outbuf->len;
}
- qemu_chr_be_write(CHARDEV(vd), vd->outbuf.buffer, len);
- buffer_advance(&vd->outbuf, len);
+ qemu_chr_be_write(CHARDEV(vd), vd->outbuf->data, len);
+ g_byte_array_remove_range(vd->outbuf, 0, len);
}
}
@@ -166,7 +164,7 @@ static void vdagent_send_msg(VDAgentChardev *vd, VDAgentMessage *msg)
msg->protocol = VD_AGENT_PROTOCOL;
- if (vd->outbuf.offset + msgsize > VDAGENT_BUFFER_LIMIT) {
+ if (vd->outbuf->len + msgsize > VDAGENT_BUFFER_LIMIT) {
error_report("buffer full, dropping message");
return;
}
@@ -177,9 +175,8 @@ static void vdagent_send_msg(VDAgentChardev *vd, VDAgentMessage *msg)
if (chunk.size > 1024) {
chunk.size = 1024;
}
- buffer_reserve(&vd->outbuf, sizeof(chunk) + chunk.size);
- buffer_append(&vd->outbuf, &chunk, sizeof(chunk));
- buffer_append(&vd->outbuf, msgbuf + msgoff, chunk.size);
+ g_byte_array_append(vd->outbuf, (void *)&chunk, sizeof(chunk));
+ g_byte_array_append(vd->outbuf, msgbuf + msgoff, chunk.size);
msgoff += chunk.size;
}
vdagent_send_buf(vd);
@@ -672,10 +669,6 @@ static void vdagent_chr_open(Chardev *chr,
return;
#endif
- if (migrate_add_blocker(&vd->migration_blocker, errp) != 0) {
- return;
- }
-
vd->mouse = VDAGENT_MOUSE_DEFAULT;
if (cfg->has_mouse) {
vd->mouse = cfg->mouse;
@@ -694,6 +687,18 @@ static void vdagent_chr_open(Chardev *chr,
*be_opened = true;
}
+static void vdagent_clipboard_peer_register(VDAgentChardev *vd)
+{
+ if (vd->cbpeer.notifier.notify != NULL) {
+ return;
+ }
+
+ vd->cbpeer.name = "vdagent";
+ vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
+ vd->cbpeer.request = vdagent_clipboard_request;
+ qemu_clipboard_peer_register(&vd->cbpeer);
+}
+
static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
{
VDAgentAnnounceCapabilities *caps = (void *)msg->data;
@@ -720,13 +725,9 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
memset(vd->last_serial, 0, sizeof(vd->last_serial));
- if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) {
+ if (have_clipboard(vd)) {
qemu_clipboard_reset_serial();
-
- vd->cbpeer.name = "vdagent";
- vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
- vd->cbpeer.request = vdagent_clipboard_request;
- qemu_clipboard_peer_register(&vd->cbpeer);
+ vdagent_clipboard_peer_register(vd);
}
}
@@ -859,7 +860,8 @@ static void vdagent_disconnect(VDAgentChardev *vd)
{
trace_vdagent_disconnect();
- buffer_reset(&vd->outbuf);
+ vd->connected = false;
+ g_byte_array_set_size(vd->outbuf, 0);
vdagent_reset_bufs(vd);
vd->caps = 0;
if (vd->mouse_hs) {
@@ -877,6 +879,10 @@ static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
trace_vdagent_fe_open(fe_open);
+ if (vd->connected == fe_open) {
+ return;
+ }
+
if (!fe_open) {
trace_vdagent_close();
vdagent_disconnect(vd);
@@ -886,6 +892,7 @@ static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
return;
}
+ vd->connected = true;
vdagent_send_caps(vd, true);
}
@@ -905,7 +912,7 @@ static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend,
/* ------------------------------------------------------------------ */
-static void vdagent_chr_class_init(ObjectClass *oc, void *data)
+static void vdagent_chr_class_init(ObjectClass *oc, const void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -916,25 +923,163 @@ static void vdagent_chr_class_init(ObjectClass *oc, void *data)
cc->chr_accept_input = vdagent_chr_accept_input;
}
+static int post_load(void *opaque, int version_id)
+{
+ VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(opaque);
+
+ if (have_mouse(vd) && vd->mouse_hs) {
+ qemu_input_handler_activate(vd->mouse_hs);
+ }
+
+ if (have_clipboard(vd)) {
+ vdagent_clipboard_peer_register(vd);
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_chunk = {
+ .name = "vdagent/chunk",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(port, VDIChunkHeader),
+ VMSTATE_UINT32(size, VDIChunkHeader),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_vdba = {
+ .name = "vdagent/bytearray",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(len, GByteArray),
+ VMSTATE_VBUFFER_ALLOC_UINT32(data, GByteArray, 0, 0, len),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+struct CBInfoArray {
+ uint32_t n;
+ QemuClipboardInfo cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
+};
+
+static const VMStateDescription vmstate_cbinfo_array = {
+ .name = "cbinfoarray",
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(n, struct CBInfoArray),
+ VMSTATE_STRUCT_VARRAY_UINT32(cbinfo, struct CBInfoArray, n,
+ 0, vmstate_cbinfo, QemuClipboardInfo),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int put_cbinfo(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field, JSONWriter *vmdesc)
+{
+ VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(pv);
+ struct CBInfoArray cbinfo = {};
+ int i;
+
+ if (!have_clipboard(vd)) {
+ return 0;
+ }
+
+ for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
+ if (qemu_clipboard_peer_owns(&vd->cbpeer, i)) {
+ cbinfo.cbinfo[cbinfo.n++] = *qemu_clipboard_info(i);
+ }
+ }
+
+ return vmstate_save_state(f, &vmstate_cbinfo_array, &cbinfo, vmdesc);
+}
+
+static int get_cbinfo(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field)
+{
+ VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(pv);
+ struct CBInfoArray cbinfo = {};
+ int i, ret;
+
+ if (!have_clipboard(vd)) {
+ return 0;
+ }
+
+ vdagent_clipboard_peer_register(vd);
+
+ ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0);
+ if (ret) {
+ return ret;
+ }
+
+ for (i = 0; i < cbinfo.n; i++) {
+ g_autoptr(QemuClipboardInfo) info =
+ qemu_clipboard_info_new(&vd->cbpeer, cbinfo.cbinfo[i].selection);
+ /* this will steal clipboard data pointer from cbinfo.types */
+ memcpy(info->types, cbinfo.cbinfo[i].types, sizeof(cbinfo.cbinfo[i].types));
+ qemu_clipboard_update(info);
+ }
+
+ return 0;
+}
+
+static const VMStateInfo vmstate_cbinfos = {
+ .name = "vdagent/cbinfos",
+ .get = get_cbinfo,
+ .put = put_cbinfo,
+};
+
+static const VMStateDescription vmstate_vdagent = {
+ .name = "vdagent",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .post_load = post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BOOL(connected, VDAgentChardev),
+ VMSTATE_UINT32(caps, VDAgentChardev),
+ VMSTATE_STRUCT(chunk, VDAgentChardev, 0, vmstate_chunk, VDIChunkHeader),
+ VMSTATE_UINT32(chunksize, VDAgentChardev),
+ VMSTATE_UINT32(msgsize, VDAgentChardev),
+ VMSTATE_VBUFFER_ALLOC_UINT32(msgbuf, VDAgentChardev, 0, 0, msgsize),
+ VMSTATE_UINT32(xsize, VDAgentChardev),
+ VMSTATE_UINT32(xoff, VDAgentChardev),
+ VMSTATE_VBUFFER_ALLOC_UINT32(xbuf, VDAgentChardev, 0, 0, xsize),
+ VMSTATE_STRUCT_POINTER(outbuf, VDAgentChardev, vmstate_vdba, GByteArray),
+ VMSTATE_UINT32(mouse_x, VDAgentChardev),
+ VMSTATE_UINT32(mouse_y, VDAgentChardev),
+ VMSTATE_UINT32(mouse_btn, VDAgentChardev),
+ VMSTATE_UINT32(mouse_display, VDAgentChardev),
+ VMSTATE_UINT32_ARRAY(last_serial, VDAgentChardev,
+ QEMU_CLIPBOARD_SELECTION__COUNT),
+ VMSTATE_UINT32_ARRAY(cbpending, VDAgentChardev,
+ QEMU_CLIPBOARD_SELECTION__COUNT),
+ {
+ .name = "cbinfos",
+ .info = &vmstate_cbinfos,
+ .flags = VMS_SINGLE,
+ },
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void vdagent_chr_init(Object *obj)
{
VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
- buffer_init(&vd->outbuf, "vdagent-outbuf");
- error_setg(&vd->migration_blocker,
- "The vdagent chardev doesn't yet support migration");
+ vd->outbuf = g_byte_array_new();
+ vmstate_register_any(NULL, &vmstate_vdagent, vd);
}
static void vdagent_chr_fini(Object *obj)
{
VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
- migrate_del_blocker(&vd->migration_blocker);
vdagent_disconnect(vd);
if (vd->mouse_hs) {
qemu_input_handler_unregister(vd->mouse_hs);
}
- buffer_free(&vd->outbuf);
+ g_clear_pointer(&vd->outbuf, g_byte_array_unref);
}
static const TypeInfo vdagent_chr_type_info = {
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 47fdae5..3f4cfc4 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -263,8 +263,14 @@ static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t le
/* NB, distinction of NULL vs "" is *critical* in SASL */
if (datalen) {
clientdata = (char*)data;
- clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */
- datalen--; /* Don't count NULL byte when passing to _start() */
+ if (clientdata[datalen - 1] != '\0') {
+ trace_vnc_auth_fail(vs, vs->auth, "Malformed SASL client data",
+ "Missing SASL NUL padding byte");
+ sasl_dispose(&vs->sasl.conn);
+ vs->sasl.conn = NULL;
+ goto authabort;
+ }
+ datalen--; /* Discard the extra NUL padding byte */
}
err = sasl_server_step(vs->sasl.conn,
@@ -289,9 +295,10 @@ static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t le
goto authabort;
}
- if (serveroutlen) {
+ if (serverout) {
vnc_write_u32(vs, serveroutlen + 1);
- vnc_write(vs, serverout, serveroutlen + 1);
+ vnc_write(vs, serverout, serveroutlen);
+ vnc_write_u8(vs, '\0');
} else {
vnc_write_u32(vs, 0);
}
@@ -384,8 +391,14 @@ static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t l
/* NB, distinction of NULL vs "" is *critical* in SASL */
if (datalen) {
clientdata = (char*)data;
- clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */
- datalen--; /* Don't count NULL byte when passing to _start() */
+ if (clientdata[datalen - 1] != '\0') {
+ trace_vnc_auth_fail(vs, vs->auth, "Malformed SASL client data",
+ "Missing SASL NUL padding byte");
+ sasl_dispose(&vs->sasl.conn);
+ vs->sasl.conn = NULL;
+ goto authabort;
+ }
+ datalen--; /* Discard the extra NUL padding byte */
}
err = sasl_server_start(vs->sasl.conn,
@@ -410,9 +423,10 @@ static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t l
goto authabort;
}
- if (serveroutlen) {
+ if (serverout) {
vnc_write_u32(vs, serveroutlen + 1);
- vnc_write(vs, serverout, serveroutlen + 1);
+ vnc_write(vs, serverout, serveroutlen);
+ vnc_write_u8(vs, '\0');
} else {
vnc_write_u32(vs, 0);
}
@@ -524,13 +538,13 @@ static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, s
return 0;
}
-static char *
+static int
vnc_socket_ip_addr_string(QIOChannelSocket *ioc,
bool local,
+ char **addrstr,
Error **errp)
{
SocketAddress *addr;
- char *ret;
if (local) {
addr = qio_channel_socket_get_local_address(ioc, errp);
@@ -538,17 +552,24 @@ vnc_socket_ip_addr_string(QIOChannelSocket *ioc,
addr = qio_channel_socket_get_remote_address(ioc, errp);
}
if (!addr) {
- return NULL;
+ return -1;
}
if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
- error_setg(errp, "Not an inet socket type");
+ *addrstr = NULL;
qapi_free_SocketAddress(addr);
- return NULL;
+ return 0;
}
- ret = g_strdup_printf("%s;%s", addr->u.inet.host, addr->u.inet.port);
+ *addrstr = g_strdup_printf("%s;%s", addr->u.inet.host, addr->u.inet.port);
qapi_free_SocketAddress(addr);
- return ret;
+ return 0;
+}
+
+static bool
+vnc_socket_is_unix(QIOChannelSocket *ioc)
+{
+ SocketAddress *addr = qio_channel_socket_get_local_address(ioc, NULL);
+ return addr && addr->type == SOCKET_ADDRESS_TYPE_UNIX;
}
void start_auth_sasl(VncState *vs)
@@ -561,15 +582,15 @@ void start_auth_sasl(VncState *vs)
int mechlistlen;
/* Get local & remote client addresses in form IPADDR;PORT */
- localAddr = vnc_socket_ip_addr_string(vs->sioc, true, &local_err);
- if (!localAddr) {
+ if (vnc_socket_ip_addr_string(vs->sioc, true,
+ &localAddr, &local_err) < 0) {
trace_vnc_auth_fail(vs, vs->auth, "Cannot format local IP",
error_get_pretty(local_err));
goto authabort;
}
- remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, &local_err);
- if (!remoteAddr) {
+ if (vnc_socket_ip_addr_string(vs->sioc, false,
+ &remoteAddr, &local_err) < 0) {
trace_vnc_auth_fail(vs, vs->auth, "Cannot format remote IP",
error_get_pretty(local_err));
g_free(localAddr);
@@ -621,16 +642,17 @@ void start_auth_sasl(VncState *vs)
goto authabort;
}
} else {
- vs->sasl.wantSSF = 1;
+ vs->sasl.wantSSF = !vnc_socket_is_unix(vs->sioc);
}
memset (&secprops, 0, sizeof secprops);
/* Inform SASL that we've got an external SSF layer from TLS.
*
- * Disable SSF, if using TLS+x509+SASL only. TLS without x509
- * is not sufficiently strong
+ * Disable SSF, if using TLS+x509+SASL only, or UNIX sockets.
+ * TLS without x509 is not sufficiently strong, nor is plain
+ * TCP
*/
- if (vs->vd->is_unix ||
+ if (vnc_socket_is_unix(vs->sioc) ||
(vs->auth == VNC_AUTH_VENCRYPT &&
vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)) {
/* If we've got TLS or UNIX domain sock, we don't care about SSF */
@@ -674,6 +696,13 @@ void start_auth_sasl(VncState *vs)
}
trace_vnc_auth_sasl_mech_list(vs, mechlist);
+ if (g_str_equal(mechlist, "")) {
+ trace_vnc_auth_fail(vs, vs->auth, "no available SASL mechanisms", "");
+ sasl_dispose(&vs->sasl.conn);
+ vs->sasl.conn = NULL;
+ goto authabort;
+ }
+
vs->sasl.mechlist = g_strdup(mechlist);
mechlistlen = strlen(mechlist);
vnc_write_u32(vs, mechlistlen);
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 41f559e..25c7b2c 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -150,7 +150,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
* If client is big-endian, color samples begin from the second
* byte (offset 1) of a 32-bit pixel value.
*/
- off = vs->client_be;
+ off = vs->client_endian == G_BIG_ENDIAN ? 1 : 0;
memset(stats, 0, sizeof (stats));
@@ -891,7 +891,7 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
buf8 = buf;
- if (1 /* FIXME */) {
+ if (vs->client_endian == G_BYTE_ORDER) {
rshift = vs->client_pf.rshift;
gshift = vs->client_pf.gshift;
bshift = vs->client_pf.bshift;
@@ -1001,16 +1001,24 @@ static int send_mono_rect(VncState *vs, int x, int y,
break;
}
case 2:
- vnc_write(vs, &bg, 2);
- vnc_write(vs, &fg, 2);
+ {
+ uint16_t bg16 = bg;
+ uint16_t fg16 = fg;
+ vnc_write(vs, &bg16, 2);
+ vnc_write(vs, &fg16, 2);
tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg);
break;
+ }
default:
- vnc_write_u8(vs, bg);
- vnc_write_u8(vs, fg);
+ {
+ uint8_t bg8 = bg;
+ uint8_t fg8 = fg;
+ vnc_write_u8(vs, bg8);
+ vnc_write_u8(vs, fg8);
tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg);
break;
}
+ }
vs->tight->tight.offset = bytes;
bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c
index bd33b89..97ec6c7 100644
--- a/ui/vnc-enc-zrle.c
+++ b/ui/vnc-enc-zrle.c
@@ -255,7 +255,7 @@ static void zrle_write_u8(VncState *vs, uint8_t value)
static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
int w, int h)
{
- bool be = vs->client_be;
+ bool be = vs->client_endian == G_BIG_ENDIAN;
size_t bytes;
int zywrle_level;
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index fcca7ec..d3486af 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -188,7 +188,7 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
local->lossy_rect = orig->lossy_rect;
local->write_pixels = orig->write_pixels;
local->client_pf = orig->client_pf;
- local->client_be = orig->client_be;
+ local->client_endian = orig->client_endian;
local->tight = orig->tight;
local->zlib = orig->zlib;
local->hextile = orig->hextile;
diff --git a/ui/vnc.c b/ui/vnc.c
index dae5d51..e9c30aa 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -29,8 +29,8 @@
#include "vnc-jobs.h"
#include "trace.h"
#include "hw/qdev-core.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/runstate.h"
+#include "system/system.h"
+#include "system/runstate.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
@@ -146,8 +146,6 @@ static void vnc_init_basic_info(SocketAddress *addr,
default:
abort();
}
-
- return;
}
static void vnc_init_basic_info_from_server_addr(QIOChannelSocket *ioc,
@@ -893,7 +891,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
buf[0] = v;
break;
case 2:
- if (vs->client_be) {
+ if (vs->client_endian == G_BIG_ENDIAN) {
buf[0] = v >> 8;
buf[1] = v;
} else {
@@ -903,7 +901,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
break;
default:
case 4:
- if (vs->client_be) {
+ if (vs->client_endian == G_BIG_ENDIAN) {
buf[0] = v >> 24;
buf[1] = v >> 16;
buf[2] = v >> 8;
@@ -1935,7 +1933,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
}
qkbd_state_key_event(vs->vd->kbd, qcode, down);
- if (!qemu_console_is_graphic(vs->vd->dcl.con)) {
+ if (QEMU_IS_TEXT_CONSOLE(vs->vd->dcl.con)) {
QemuTextConsole *con = QEMU_TEXT_CONSOLE(vs->vd->dcl.con);
bool numlock = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK);
bool control = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_CTRL);
@@ -2242,7 +2240,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
static void set_pixel_conversion(VncState *vs)
{
- pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf);
+ pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf,
+ vs->client_endian);
if (fmt == VNC_SERVER_FB_FORMAT) {
vs->write_pixels = vnc_write_pixels_copy;
@@ -2314,7 +2313,7 @@ static void set_pixel_format(VncState *vs, int bits_per_pixel,
vs->client_pf.bits_per_pixel = bits_per_pixel;
vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
- vs->client_be = big_endian_flag;
+ vs->client_endian = big_endian_flag ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
if (!true_color_flag) {
send_color_map(vs);
@@ -2783,7 +2782,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
vnc_munge_des_rfb_key(key, sizeof(key));
cipher = qcrypto_cipher_new(
- QCRYPTO_CIPHER_ALG_DES,
+ QCRYPTO_CIPHER_ALGO_DES,
QCRYPTO_CIPHER_MODE_ECB,
key, G_N_ELEMENTS(key),
&err);
@@ -3386,6 +3385,16 @@ static const DisplayChangeListenerOps dcl_ops = {
.dpy_cursor_define = vnc_dpy_cursor_define,
};
+static void vmstate_change_handler(void *opaque, bool running, RunState state)
+{
+ VncDisplay *vd = opaque;
+
+ if (state != RUN_STATE_RUNNING) {
+ return;
+ }
+ update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
+}
+
void vnc_display_init(const char *id, Error **errp)
{
VncDisplay *vd;
@@ -3422,6 +3431,8 @@ void vnc_display_init(const char *id, Error **errp)
vd->dcl.ops = &dcl_ops;
register_displaychangelistener(&vd->dcl);
vd->kbd = qkbd_state_init(vd->dcl.con);
+ vd->vmstate_handler_entry = qemu_add_vm_change_state_handler(
+ &vmstate_change_handler, vd);
}
@@ -3430,7 +3441,6 @@ static void vnc_display_close(VncDisplay *vd)
if (!vd) {
return;
}
- vd->is_unix = false;
if (vd->listener) {
qio_net_listener_disconnect(vd->listener);
@@ -3852,7 +3862,7 @@ static int vnc_display_get_addresses(QemuOpts *opts,
return 0;
}
if (qemu_opt_get(opts, "websocket") &&
- !qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
+ !qcrypto_hash_supports(QCRYPTO_HASH_ALGO_SHA1)) {
error_setg(errp,
"SHA1 hash support is required for websockets");
return -1;
@@ -3932,8 +3942,6 @@ static int vnc_display_connect(VncDisplay *vd,
error_setg(errp, "Expected a single address in reverse mode");
return -1;
}
- /* TODO SOCKET_ADDRESS_TYPE_FD when fd has AF_UNIX */
- vd->is_unix = saddr_list->value->type == SOCKET_ADDRESS_TYPE_UNIX;
sioc = qio_channel_socket_new();
qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-reverse");
if (qio_channel_socket_connect_sync(sioc, saddr_list->value, errp) < 0) {
@@ -4064,7 +4072,7 @@ void vnc_display_open(const char *id, Error **errp)
}
if (password) {
if (!qcrypto_cipher_supports(
- QCRYPTO_CIPHER_ALG_DES, QCRYPTO_CIPHER_MODE_ECB)) {
+ QCRYPTO_CIPHER_ALGO_DES, QCRYPTO_CIPHER_MODE_ECB)) {
error_setg(errp,
"Cipher backend does not support DES algorithm");
goto fail;
diff --git a/ui/vnc.h b/ui/vnc.h
index e5fa2ef..b3e0726 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -168,7 +168,6 @@ struct VncDisplay
const char *id;
QTAILQ_ENTRY(VncDisplay) next;
- bool is_unix;
char *password;
time_t expires;
int auth;
@@ -186,6 +185,8 @@ struct VncDisplay
#endif
AudioState *audio_state;
+
+ VMChangeStateEntry *vmstate_handler_entry;
};
typedef struct VncTight {
@@ -324,7 +325,7 @@ struct VncState
VncWritePixels *write_pixels;
PixelFormat client_pf;
pixman_format_code_t client_format;
- bool client_be;
+ int client_endian; /* G_LITTLE_ENDIAN or G_BIG_ENDIAN */
CaptureVoiceOut *audio_cap;
struct audsettings as;
diff --git a/ui/win32-kbd-hook.c b/ui/win32-kbd-hook.c
index 1ac237d..f448247 100644
--- a/ui/win32-kbd-hook.c
+++ b/ui/win32-kbd-hook.c
@@ -7,7 +7,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/sysemu.h"
+#include "system/system.h"
#include "ui/win32-kbd-hook.h"
static Notifier win32_unhook_notifier;