aboutsummaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/clipboard.c66
-rw-r--r--ui/egl-helpers.c10
-rw-r--r--ui/gtk-clipboard.c13
-rw-r--r--ui/gtk-egl.c58
-rw-r--r--ui/gtk-gl-area.c53
-rw-r--r--ui/gtk.c245
-rw-r--r--ui/qemu-pixman.c15
-rw-r--r--ui/sdl2-gl.c2
-rw-r--r--ui/sdl2.c20
-rw-r--r--ui/vdagent.c205
-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.c9
-rw-r--r--ui/vnc.h2
15 files changed, 562 insertions, 160 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/egl-helpers.c b/ui/egl-helpers.c
index 9cda2bb..5503a79 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -93,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 */
}
@@ -145,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);
@@ -161,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);
}
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 f7a428c..0b787be 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -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 2c9a0db..8151cc4 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -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 982037b..8c4a94c 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -387,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;
@@ -405,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)
@@ -771,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
@@ -800,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)
@@ -839,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));
+ ww_widget = gdk_window_get_width(gtk_widget_get_window(widget));
+ wh_widget = 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;
+ gd_update_scale(vc, ww_widget, wh_widget, fbw, fbh);
- sx = (double)ww / fbw;
- sy = (double)wh / fbh;
+ ww_surface = fbw * vc->gfx.scale_x;
+ wh_surface = fbh * vc->gfx.scale_y;
- vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy);
+ wx_offset = wy_offset = 0;
+ if (ww_widget > ww_surface) {
+ wx_offset = (ww_widget - ww_surface) / 2;
}
-
- fbw *= vc->gfx.scale_x;
- fbh *= vc->gfx.scale_y;
-
- mx = my = 0;
- if (ww > fbw) {
- mx = (ww - fbw) / 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;
@@ -889,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.
@@ -909,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) {
@@ -1760,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;
}
diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c
index 6ef4376..ef4e71d 100644
--- a/ui/qemu-pixman.c
+++ b/ui/qemu-pixman.c
@@ -126,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)) {
diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
index e01d9ab..3be17d1 100644
--- a/ui/sdl2-gl.c
+++ b/ui/sdl2-gl.c
@@ -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.c b/ui/sdl2.c
index cda4293..b00e421 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -488,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
@@ -509,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);
}
}
@@ -520,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 */
@@ -537,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);
}
}
diff --git a/ui/vdagent.c b/ui/vdagent.c
index 04513de..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);
}
@@ -916,25 +923,163 @@ static void vdagent_chr_class_init(ObjectClass *oc, const 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-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 9e097dc..d095cd7 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -891,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 {
@@ -901,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;
@@ -2240,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;
@@ -2312,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);
diff --git a/ui/vnc.h b/ui/vnc.h
index acc53a2..02613aa 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -323,7 +323,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;