summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/Makefile.objs5
-rw-r--r--ui/cocoa.m2
-rw-r--r--ui/console.c267
-rw-r--r--ui/gtk.c112
-rw-r--r--ui/input-legacy.c11
-rw-r--r--ui/input.c40
-rw-r--r--ui/qemu-pixman.c90
-rw-r--r--ui/sdl.c5
-rw-r--r--ui/sdl2-keymap.h7
-rw-r--r--ui/sdl2.c1
-rw-r--r--ui/spice-core.c9
-rw-r--r--ui/spice-display.c20
-rw-r--r--ui/vnc-enc-tight.c12
-rw-r--r--ui/vnc-tls.c2
-rw-r--r--ui/vnc.c21
15 files changed, 385 insertions, 219 deletions
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 6afb52a93..801cba267 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -10,12 +10,13 @@ vnc-obj-y += vnc-jobs.o
common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o
common-obj-y += input.o input-keymap.o input-legacy.o
common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o
-common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o sdl2.o
+common-obj-$(CONFIG_SDL) += sdl.mo x_keymap.o
common-obj-$(CONFIG_COCOA) += cocoa.o
common-obj-$(CONFIG_CURSES) += curses.o
common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o
-$(obj)/sdl.o $(obj)/sdl_zoom.o $(obj)/sdl2.o: QEMU_CFLAGS += $(SDL_CFLAGS)
+sdl.mo-objs := sdl.o sdl_zoom.o sdl2.o
+sdl.mo-cflags := $(SDL_CFLAGS)
gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 314717811..d37c29b4a 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -857,7 +857,7 @@ QemuCocoaView *cocoaView;
[op setPrompt:@"Boot image"];
[op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
NSArray *filetypes = [NSArray arrayWithObjects:@"img", @"iso", @"dmg",
- @"qcow", @"qcow2", @"cow", @"cloop", @"vmdk", nil];
+ @"qcow", @"qcow2", @"cloop", @"vmdk", nil];
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
[op setAllowedFileTypes:filetypes];
[op beginSheetModalForWindow:normalWindow
diff --git a/ui/console.c b/ui/console.c
index ab8454903..258af5dff 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -28,6 +28,7 @@
#include "qmp-commands.h"
#include "sysemu/char.h"
#include "trace.h"
+#include "exec/memory.h"
#define DEFAULT_BACKSCROLL 512
#define CONSOLE_CURSOR_PERIOD 500
@@ -1224,61 +1225,77 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
return s;
}
-static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
- int linesize, PixelFormat pf, int newflags)
+static void qemu_alloc_display(DisplaySurface *surface, int width, int height)
{
- surface->pf = pf;
-
qemu_pixman_image_unref(surface->image);
surface->image = NULL;
- surface->format = qemu_pixman_get_format(&pf);
- assert(surface->format != 0);
+ surface->format = PIXMAN_x8r8g8b8;
surface->image = pixman_image_create_bits(surface->format,
width, height,
- NULL, linesize);
+ NULL, width * 4);
assert(surface->image != NULL);
- surface->flags = newflags | QEMU_ALLOCATED_FLAG;
-#ifdef HOST_WORDS_BIGENDIAN
- surface->flags |= QEMU_BIG_ENDIAN_FLAG;
-#endif
+ surface->flags = QEMU_ALLOCATED_FLAG;
}
DisplaySurface *qemu_create_displaysurface(int width, int height)
{
DisplaySurface *surface = g_new0(DisplaySurface, 1);
- int linesize = width * 4;
trace_displaysurface_create(surface, width, height);
- qemu_alloc_display(surface, width, height, linesize,
- qemu_default_pixelformat(32), 0);
+ qemu_alloc_display(surface, width, height);
return surface;
}
-DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
- int linesize, uint8_t *data,
- bool byteswap)
+DisplaySurface *qemu_create_displaysurface_from(int width, int height,
+ pixman_format_code_t format,
+ int linesize, uint8_t *data)
{
DisplaySurface *surface = g_new0(DisplaySurface, 1);
- trace_displaysurface_create_from(surface, width, height, bpp, byteswap);
- if (byteswap) {
- surface->pf = qemu_different_endianness_pixelformat(bpp);
- } else {
- surface->pf = qemu_default_pixelformat(bpp);
- }
-
- surface->format = qemu_pixman_get_format(&surface->pf);
- assert(surface->format != 0);
+ trace_displaysurface_create_from(surface, width, height, format);
+ surface->format = format;
surface->image = pixman_image_create_bits(surface->format,
width, height,
(void *)data, linesize);
assert(surface->image != NULL);
-#ifdef HOST_WORDS_BIGENDIAN
- surface->flags = QEMU_BIG_ENDIAN_FLAG;
-#endif
+ return surface;
+}
+
+static void qemu_unmap_displaysurface_guestmem(pixman_image_t *image,
+ void *unused)
+{
+ void *data = pixman_image_get_data(image);
+ uint32_t size = pixman_image_get_stride(image) *
+ pixman_image_get_height(image);
+ cpu_physical_memory_unmap(data, size, 0, 0);
+}
+
+DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
+ pixman_format_code_t format,
+ int linesize, uint64_t addr)
+{
+ DisplaySurface *surface;
+ hwaddr size;
+ void *data;
+
+ if (linesize == 0) {
+ linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
+ }
+
+ size = linesize * height;
+ data = cpu_physical_memory_map(addr, &size, 0);
+ if (size != linesize * height) {
+ cpu_physical_memory_unmap(data, size, 0, 0);
+ return NULL;
+ }
+
+ surface = qemu_create_displaysurface_from
+ (width, height, format, linesize, data);
+ pixman_image_set_destroy_function
+ (surface->image, qemu_unmap_displaysurface_guestmem, NULL);
return surface;
}
@@ -1557,6 +1574,67 @@ bool dpy_cursor_define_supported(QemuConsole *con)
return false;
}
+/*
+ * Call dpy_gfx_update for all dirity scanlines. Works for
+ * DisplaySurfaces backed by guest memory (i.e. the ones created
+ * using qemu_create_displaysurface_guestmem).
+ */
+void dpy_gfx_update_dirty(QemuConsole *con,
+ MemoryRegion *address_space,
+ hwaddr base,
+ bool invalidate)
+{
+ DisplaySurface *ds = qemu_console_surface(con);
+ int width = surface_stride(ds);
+ int height = surface_height(ds);
+ hwaddr size = width * height;
+ MemoryRegionSection mem_section;
+ MemoryRegion *mem;
+ ram_addr_t addr;
+ int first, last, i;
+ bool dirty;
+
+ mem_section = memory_region_find(address_space, base, size);
+ mem = mem_section.mr;
+ if (int128_get64(mem_section.size) != size ||
+ !memory_region_is_ram(mem_section.mr)) {
+ goto out;
+ }
+ assert(mem);
+
+ memory_region_sync_dirty_bitmap(mem);
+ addr = mem_section.offset_within_region;
+
+ first = -1;
+ last = -1;
+ for (i = 0; i < height; i++, addr += width) {
+ dirty = invalidate ||
+ memory_region_get_dirty(mem, addr, width, DIRTY_MEMORY_VGA);
+ if (dirty) {
+ if (first == -1) {
+ first = i;
+ }
+ last = i;
+ }
+ if (first != -1 && !dirty) {
+ assert(last != -1 && last >= first);
+ dpy_gfx_update(con, 0, first, surface_width(ds),
+ last - first + 1);
+ first = -1;
+ }
+ }
+ if (first != -1) {
+ assert(last != -1 && last >= first);
+ dpy_gfx_update(con, 0, first, surface_width(ds),
+ last - first + 1);
+ }
+
+ memory_region_reset_dirty(mem, mem_section.offset_within_region, size,
+ DIRTY_MEMORY_VGA);
+out:
+ memory_region_unref(mem);
+}
+
/***********************************************************/
/* register display */
@@ -1599,6 +1677,14 @@ DisplayState *init_displaystate(void)
return display_state;
}
+void graphic_console_set_hwops(QemuConsole *con,
+ const GraphicHwOps *hw_ops,
+ void *opaque)
+{
+ con->hw_ops = hw_ops;
+ con->hw = opaque;
+}
+
QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
const GraphicHwOps *hw_ops,
void *opaque)
@@ -1613,8 +1699,7 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
ds = get_alloc_displaystate();
trace_console_gfx_new();
s = new_console(ds, GRAPHIC_CONSOLE, head);
- s->hw_ops = hw_ops;
- s->hw = opaque;
+ graphic_console_set_hwops(s, hw_ops, opaque);
if (dev) {
object_property_set_link(OBJECT(s), OBJECT(dev), "device",
&error_abort);
@@ -1902,124 +1987,15 @@ DisplayState *qemu_console_displaystate(QemuConsole *console)
PixelFormat qemu_different_endianness_pixelformat(int bpp)
{
- PixelFormat pf;
-
- memset(&pf, 0x00, sizeof(PixelFormat));
-
- pf.bits_per_pixel = bpp;
- pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
- pf.depth = bpp == 32 ? 24 : bpp;
-
- switch (bpp) {
- case 24:
- pf.rmask = 0x000000FF;
- pf.gmask = 0x0000FF00;
- pf.bmask = 0x00FF0000;
- pf.rmax = 255;
- pf.gmax = 255;
- pf.bmax = 255;
- pf.rshift = 0;
- pf.gshift = 8;
- pf.bshift = 16;
- pf.rbits = 8;
- pf.gbits = 8;
- pf.bbits = 8;
- break;
- case 32:
- pf.rmask = 0x0000FF00;
- pf.gmask = 0x00FF0000;
- pf.bmask = 0xFF000000;
- pf.amask = 0x00000000;
- pf.amax = 255;
- pf.rmax = 255;
- pf.gmax = 255;
- pf.bmax = 255;
- pf.ashift = 0;
- pf.rshift = 8;
- pf.gshift = 16;
- pf.bshift = 24;
- pf.rbits = 8;
- pf.gbits = 8;
- pf.bbits = 8;
- pf.abits = 8;
- break;
- default:
- break;
- }
+ pixman_format_code_t fmt = qemu_default_pixman_format(bpp, false);
+ PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
return pf;
}
PixelFormat qemu_default_pixelformat(int bpp)
{
- PixelFormat pf;
-
- memset(&pf, 0x00, sizeof(PixelFormat));
-
- pf.bits_per_pixel = bpp;
- pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
- pf.depth = bpp == 32 ? 24 : bpp;
-
- switch (bpp) {
- case 15:
- pf.bits_per_pixel = 16;
- pf.rmask = 0x00007c00;
- pf.gmask = 0x000003E0;
- pf.bmask = 0x0000001F;
- pf.rmax = 31;
- pf.gmax = 31;
- pf.bmax = 31;
- pf.rshift = 10;
- pf.gshift = 5;
- pf.bshift = 0;
- pf.rbits = 5;
- pf.gbits = 5;
- pf.bbits = 5;
- break;
- case 16:
- pf.rmask = 0x0000F800;
- pf.gmask = 0x000007E0;
- pf.bmask = 0x0000001F;
- pf.rmax = 31;
- pf.gmax = 63;
- pf.bmax = 31;
- pf.rshift = 11;
- pf.gshift = 5;
- pf.bshift = 0;
- pf.rbits = 5;
- pf.gbits = 6;
- pf.bbits = 5;
- break;
- case 24:
- pf.rmask = 0x00FF0000;
- pf.gmask = 0x0000FF00;
- pf.bmask = 0x000000FF;
- pf.rmax = 255;
- pf.gmax = 255;
- pf.bmax = 255;
- pf.rshift = 16;
- pf.gshift = 8;
- pf.bshift = 0;
- pf.rbits = 8;
- pf.gbits = 8;
- pf.bbits = 8;
- break;
- case 32:
- pf.rmask = 0x00FF0000;
- pf.gmask = 0x0000FF00;
- pf.bmask = 0x000000FF;
- pf.rmax = 255;
- pf.gmax = 255;
- pf.bmax = 255;
- pf.rshift = 16;
- pf.gshift = 8;
- pf.bshift = 0;
- pf.rbits = 8;
- pf.gbits = 8;
- pf.bbits = 8;
- break;
- default:
- break;
- }
+ pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
+ PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
return pf;
}
@@ -2066,8 +2042,7 @@ static const TypeInfo qemu_console_info = {
static void register_types(void)
{
type_register_static(&qemu_console_info);
- register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
- qemu_chr_parse_vc);
+ register_char_driver("vc", CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc);
}
type_init(register_types);
diff --git a/ui/gtk.c b/ui/gtk.c
index 2345d7e3a..0385757bf 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -128,6 +128,7 @@ static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
#define GDK_KEY_q GDK_q
#define GDK_KEY_plus GDK_plus
#define GDK_KEY_minus GDK_minus
+#define GDK_KEY_Pause GDK_Pause
#endif
#define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK)
@@ -435,6 +436,15 @@ static void gtk_release_modifiers(GtkDisplayState *s)
}
}
+static void gd_widget_reparent(GtkWidget *from, GtkWidget *to,
+ GtkWidget *widget)
+{
+ g_object_ref(G_OBJECT(widget));
+ gtk_container_remove(GTK_CONTAINER(from), widget);
+ gtk_container_add(GTK_CONTAINER(to), widget);
+ g_object_unref(G_OBJECT(widget));
+}
+
/** DisplayState Callbacks **/
static void gd_update(DisplayChangeListener *dcl,
@@ -931,6 +941,12 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
int qemu_keycode;
int i;
+ if (key->keyval == GDK_KEY_Pause) {
+ qemu_input_event_send_key_qcode(vc->gfx.dcl.con, Q_KEY_CODE_PAUSE,
+ key->type == GDK_KEY_PRESS);
+ return TRUE;
+ }
+
qemu_keycode = gd_map_keycode(s, gtk_widget_get_display(widget),
gdk_keycode);
@@ -1005,6 +1021,12 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
}
}
+static void gd_accel_switch_vc(void *opaque)
+{
+ VirtualConsole *vc = opaque;
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE);
+}
+
static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
{
GtkDisplayState *s = opaque;
@@ -1025,7 +1047,7 @@ static gboolean gd_tab_window_close(GtkWidget *widget, GdkEvent *event,
GtkDisplayState *s = vc->s;
gtk_widget_set_sensitive(vc->menu_item, true);
- gtk_widget_reparent(vc->tab_item, s->notebook);
+ gd_widget_reparent(vc->window, s->notebook, vc->tab_item);
gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(s->notebook),
vc->tab_item, vc->label);
gtk_widget_destroy(vc->window);
@@ -1059,7 +1081,7 @@ static void gd_menu_untabify(GtkMenuItem *item, void *opaque)
if (!vc->window) {
gtk_widget_set_sensitive(vc->menu_item, false);
vc->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_widget_reparent(vc->tab_item, vc->window);
+ gd_widget_reparent(s->notebook, vc->window, vc->tab_item);
g_signal_connect(vc->window, "delete-event",
G_CALLBACK(gd_tab_window_close), vc);
@@ -1083,7 +1105,7 @@ static void gd_menu_full_screen(GtkMenuItem *item, void *opaque)
if (!s->full_screen) {
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
- gtk_widget_set_size_request(s->menu_bar, 0, 0);
+ gtk_widget_hide(s->menu_bar);
if (vc->type == GD_VC_GFX) {
gtk_widget_set_size_request(vc->gfx.drawing_area, -1, -1);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
@@ -1094,7 +1116,7 @@ static void gd_menu_full_screen(GtkMenuItem *item, void *opaque)
} else {
gtk_window_unfullscreen(GTK_WINDOW(s->window));
gd_menu_show_tabs(GTK_MENU_ITEM(s->show_tabs_item), s);
- gtk_widget_set_size_request(s->menu_bar, -1, -1);
+ gtk_widget_show(s->menu_bar);
s->full_screen = FALSE;
if (vc->type == GD_VC_GFX) {
vc->gfx.scale_x = 1.0;
@@ -1108,6 +1130,12 @@ static void gd_menu_full_screen(GtkMenuItem *item, void *opaque)
gd_update_cursor(vc);
}
+static void gd_accel_full_screen(void *opaque)
+{
+ GtkDisplayState *s = opaque;
+ gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item));
+}
+
static void gd_menu_zoom_in(GtkMenuItem *item, void *opaque)
{
GtkDisplayState *s = opaque;
@@ -1386,19 +1414,21 @@ static gboolean gd_focus_out_event(GtkWidget *widget,
static GSList *gd_vc_menu_init(GtkDisplayState *s, VirtualConsole *vc,
int idx, GSList *group, GtkWidget *view_menu)
{
- char path[32];
-
- snprintf(path, sizeof(path), "<QEMU>/View/VC%d", idx);
-
vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, vc->label);
- group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item));
- gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc->menu_item), path);
- gtk_accel_map_add_entry(path, GDK_KEY_1 + idx, HOTKEY_MODIFIERS);
+ gtk_accel_group_connect(s->accel_group, GDK_KEY_1 + idx,
+ HOTKEY_MODIFIERS, 0,
+ g_cclosure_new_swap(G_CALLBACK(gd_accel_switch_vc), vc, NULL));
+#if GTK_CHECK_VERSION(3, 8, 0)
+ gtk_accel_label_set_accel(
+ GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(vc->menu_item))),
+ GDK_KEY_1 + idx, HOTKEY_MODIFIERS);
+#endif
g_signal_connect(vc->menu_item, "activate",
G_CALLBACK(gd_menu_switch_vc), s);
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), vc->menu_item);
+ group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item));
return group;
}
@@ -1590,13 +1620,13 @@ static void gd_connect_signals(GtkDisplayState *s)
G_CALLBACK(gd_change_page), s);
}
-static GtkWidget *gd_create_menu_machine(GtkDisplayState *s, GtkAccelGroup *accel_group)
+static GtkWidget *gd_create_menu_machine(GtkDisplayState *s)
{
GtkWidget *machine_menu;
GtkWidget *separator;
machine_menu = gtk_menu_new();
- gtk_menu_set_accel_group(GTK_MENU(machine_menu), accel_group);
+ gtk_menu_set_accel_group(GTK_MENU(machine_menu), s->accel_group);
s->pause_item = gtk_check_menu_item_new_with_mnemonic(_("_Pause"));
gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), s->pause_item);
@@ -1636,10 +1666,9 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
QemuConsole *con, int idx,
GSList *group, GtkWidget *view_menu)
{
- Error *local_err = NULL;
Object *obj;
- obj = object_property_get_link(OBJECT(con), "device", &local_err);
+ obj = object_property_get_link(OBJECT(con), "device", NULL);
if (obj) {
vc->label = g_strdup_printf("%s", object_get_typename(obj));
} else {
@@ -1660,7 +1689,6 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
GDK_LEAVE_NOTIFY_MASK |
GDK_SCROLL_MASK |
GDK_KEY_PRESS_MASK);
- gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
gtk_widget_set_can_focus(vc->gfx.drawing_area, TRUE);
vc->type = GD_VC_GFX;
@@ -1678,7 +1706,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
return group;
}
-static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_group)
+static GtkWidget *gd_create_menu_view(GtkDisplayState *s)
{
GSList *group = NULL;
GtkWidget *view_menu;
@@ -1687,13 +1715,17 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_g
int vc;
view_menu = gtk_menu_new();
- gtk_menu_set_accel_group(GTK_MENU(view_menu), accel_group);
+ gtk_menu_set_accel_group(GTK_MENU(view_menu), s->accel_group);
s->full_screen_item = gtk_menu_item_new_with_mnemonic(_("_Fullscreen"));
- gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item),
- "<QEMU>/View/Full Screen");
- gtk_accel_map_add_entry("<QEMU>/View/Full Screen", GDK_KEY_f,
- HOTKEY_MODIFIERS);
+
+ gtk_accel_group_connect(s->accel_group, GDK_KEY_f, HOTKEY_MODIFIERS, 0,
+ g_cclosure_new_swap(G_CALLBACK(gd_accel_full_screen), s, NULL));
+#if GTK_CHECK_VERSION(3, 8, 0)
+ gtk_accel_label_set_accel(
+ GTK_ACCEL_LABEL(gtk_bin_get_child(GTK_BIN(s->full_screen_item))),
+ GDK_KEY_f, HOTKEY_MODIFIERS);
+#endif
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->full_screen_item);
separator = gtk_separator_menu_item_new();
@@ -1769,11 +1801,9 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_g
static void gd_create_menus(GtkDisplayState *s)
{
- GtkAccelGroup *accel_group;
-
- accel_group = gtk_accel_group_new();
- s->machine_menu = gd_create_menu_machine(s, accel_group);
- s->view_menu = gd_create_menu_view(s, accel_group);
+ s->accel_group = gtk_accel_group_new();
+ s->machine_menu = gd_create_menu_machine(s);
+ s->view_menu = gd_create_menu_view(s);
s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item),
@@ -1784,9 +1814,8 @@ static void gd_create_menus(GtkDisplayState *s)
gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu);
gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item);
- g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group);
- gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group);
- s->accel_group = accel_group;
+ g_object_set_data(G_OBJECT(s->window), "accel_group", s->accel_group);
+ gtk_window_add_accel_group(GTK_WINDOW(s->window), s->accel_group);
}
static void gd_set_keycode_type(GtkDisplayState *s)
@@ -1810,6 +1839,13 @@ static void gd_set_keycode_type(GtkDisplayState *s)
fprintf(stderr, "unknown keycodes `%s', please report to "
"qemu-devel@nongnu.org\n", keycodes);
}
+
+ if (desc) {
+ XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
+ }
+ if (keycodes) {
+ XFree(keycodes);
+ }
}
#endif
}
@@ -1873,15 +1909,17 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
#ifdef VTE_RESIZE_HACK
{
VirtualConsole *cur = gd_vc_find_current(s);
- int i;
-
- for (i = 0; i < s->nb_vcs; i++) {
- VirtualConsole *vc = &s->vc[i];
- if (vc && vc->type == GD_VC_VTE && vc != cur) {
- gtk_widget_hide(vc->vte.terminal);
+ if (cur) {
+ int i;
+
+ for (i = 0; i < s->nb_vcs; i++) {
+ VirtualConsole *vc = &s->vc[i];
+ if (vc && vc->type == GD_VC_VTE && vc != cur) {
+ gtk_widget_hide(vc->vte.terminal);
+ }
}
+ gd_update_windowsize(cur);
}
- gd_update_windowsize(cur);
}
#endif
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index 3025f50f4..a698a342b 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -85,6 +85,8 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
Error **errp)
{
KeyValueList *p;
+ KeyValue **up = NULL;
+ int count = 0;
if (!has_hold_time) {
hold_time = 0; /* use default */
@@ -93,11 +95,16 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
for (p = keys; p != NULL; p = p->next) {
qemu_input_event_send_key(NULL, copy_key_value(p->value), true);
qemu_input_event_send_key_delay(hold_time);
+ up = g_realloc(up, sizeof(*up) * (count+1));
+ up[count] = copy_key_value(p->value);
+ count++;
}
- for (p = keys; p != NULL; p = p->next) {
- qemu_input_event_send_key(NULL, copy_key_value(p->value), false);
+ while (count) {
+ count--;
+ qemu_input_event_send_key(NULL, up[count], false);
qemu_input_event_send_key_delay(hold_time);
}
+ g_free(up);
}
static void legacy_kbd_event(DeviceState *dev, QemuConsole *src,
diff --git a/ui/input.c b/ui/input.c
index 89d9db78c..7ba99e56b 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -122,6 +122,46 @@ qemu_input_find_handler(uint32_t mask, QemuConsole *con)
return NULL;
}
+void qmp_x_input_send_event(bool has_console, int64_t console,
+ InputEventList *events, Error **errp)
+{
+ InputEventList *e;
+ QemuConsole *con;
+
+ con = NULL;
+ if (has_console) {
+ con = qemu_console_lookup_by_index(console);
+ if (!con) {
+ error_setg(errp, "console %" PRId64 " not found", console);
+ return;
+ }
+ }
+
+ if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
+ error_setg(errp, "VM not running");
+ return;
+ }
+
+ for (e = events; e != NULL; e = e->next) {
+ InputEvent *event = e->value;
+
+ if (!qemu_input_find_handler(1 << event->kind, con)) {
+ error_setg(errp, "Input handler not found for "
+ "event type %s",
+ InputEventKind_lookup[event->kind]);
+ return;
+ }
+ }
+
+ for (e = events; e != NULL; e = e->next) {
+ InputEvent *event = e->value;
+
+ qemu_input_event_send(con, event);
+ }
+
+ qemu_input_event_sync();
+}
+
static void qemu_input_transform_abs_rotate(InputEvent *evt)
{
switch (graphic_rotate) {
diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c
index 254bd8ce1..1f6fea535 100644
--- a/ui/qemu-pixman.c
+++ b/ui/qemu-pixman.c
@@ -6,6 +6,87 @@
#include "qemu-common.h"
#include "ui/console.h"
+PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format)
+{
+ PixelFormat pf;
+ uint8_t bpp;
+
+ bpp = pf.bits_per_pixel = PIXMAN_FORMAT_BPP(format);
+ pf.bytes_per_pixel = PIXMAN_FORMAT_BPP(format) / 8;
+ pf.depth = PIXMAN_FORMAT_DEPTH(format);
+
+ pf.abits = PIXMAN_FORMAT_A(format);
+ pf.rbits = PIXMAN_FORMAT_R(format);
+ pf.gbits = PIXMAN_FORMAT_G(format);
+ pf.bbits = PIXMAN_FORMAT_B(format);
+
+ switch (PIXMAN_FORMAT_TYPE(format)) {
+ case PIXMAN_TYPE_ARGB:
+ pf.ashift = pf.bbits + pf.gbits + pf.rbits;
+ pf.rshift = pf.bbits + pf.gbits;
+ pf.gshift = pf.bbits;
+ pf.bshift = 0;
+ break;
+ case PIXMAN_TYPE_ABGR:
+ pf.ashift = pf.rbits + pf.gbits + pf.bbits;
+ pf.bshift = pf.rbits + pf.gbits;
+ pf.gshift = pf.rbits;
+ pf.rshift = 0;
+ break;
+ case PIXMAN_TYPE_BGRA:
+ pf.bshift = bpp - pf.bbits;
+ pf.gshift = bpp - (pf.bbits + pf.gbits);
+ pf.rshift = bpp - (pf.bbits + pf.gbits + pf.rbits);
+ pf.ashift = 0;
+ break;
+ case PIXMAN_TYPE_RGBA:
+ pf.rshift = bpp - pf.rbits;
+ pf.gshift = bpp - (pf.rbits + pf.gbits);
+ pf.bshift = bpp - (pf.rbits + pf.gbits + pf.bbits);
+ pf.ashift = 0;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ pf.amax = (1 << pf.abits) - 1;
+ pf.rmax = (1 << pf.rbits) - 1;
+ pf.gmax = (1 << pf.gbits) - 1;
+ pf.bmax = (1 << pf.bbits) - 1;
+ pf.amask = pf.amax << pf.ashift;
+ pf.rmask = pf.rmax << pf.rshift;
+ pf.gmask = pf.gmax << pf.gshift;
+ pf.bmask = pf.bmax << pf.bshift;
+
+ return pf;
+}
+
+pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian)
+{
+ if (native_endian) {
+ switch (bpp) {
+ case 15:
+ return PIXMAN_x1r5g5b5;
+ case 16:
+ return PIXMAN_r5g6b5;
+ case 24:
+ return PIXMAN_r8g8b8;
+ case 32:
+ return PIXMAN_x8r8g8b8;
+ }
+ } else {
+ switch (bpp) {
+ case 24:
+ return PIXMAN_b8g8r8;
+ case 32:
+ return PIXMAN_b8g8r8x8;
+ break;
+ }
+ }
+ g_assert_not_reached();
+}
+
int qemu_pixman_get_type(int rshift, int gshift, int bshift)
{
int type = PIXMAN_TYPE_OTHER;
@@ -52,6 +133,7 @@ pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format,
return image;
}
+/* fill linebuf from framebuffer */
void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb,
int width, int x, int y)
{
@@ -59,6 +141,14 @@ void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb,
x, y, 0, 0, 0, 0, width, 1);
}
+/* copy linebuf to framebuffer */
+void qemu_pixman_linebuf_copy(pixman_image_t *fb, int width, int x, int y,
+ pixman_image_t *linebuf)
+{
+ pixman_image_composite(PIXMAN_OP_SRC, linebuf, NULL, fb,
+ 0, 0, 0, 0, x, y, width, 1);
+}
+
pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format,
pixman_image_t *image)
{
diff --git a/ui/sdl.c b/ui/sdl.c
index 4e7f920e3..94c1d9dc3 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -127,6 +127,7 @@ static void do_sdl_resize(int width, int height, int bpp)
static void sdl_switch(DisplayChangeListener *dcl,
DisplaySurface *new_surface)
{
+ PixelFormat pf = qemu_pixelformat_from_pixman(new_surface->format);
/* temporary hack: allows to call sdl_switch to handle scaling changes */
if (new_surface) {
@@ -148,8 +149,8 @@ static void sdl_switch(DisplayChangeListener *dcl,
(surface_data(surface),
surface_width(surface), surface_height(surface),
surface_bits_per_pixel(surface), surface_stride(surface),
- surface->pf.rmask, surface->pf.gmask,
- surface->pf.bmask, surface->pf.amask);
+ pf.rmask, pf.gmask,
+ pf.bmask, pf.amask);
}
/* generic keyboard conversion */
diff --git a/ui/sdl2-keymap.h b/ui/sdl2-keymap.h
index 5a12f4543..cbedaa477 100644
--- a/ui/sdl2-keymap.h
+++ b/ui/sdl2-keymap.h
@@ -105,9 +105,10 @@ static const int sdl2_scancode_to_qcode[SDL_NUM_SCANCODES] = {
[SDL_SCANCODE_KP_9] = Q_KEY_CODE_KP_9,
[SDL_SCANCODE_KP_0] = Q_KEY_CODE_KP_0,
[SDL_SCANCODE_KP_PERIOD] = Q_KEY_CODE_KP_DECIMAL,
+
+ [SDL_SCANCODE_NONUSBACKSLASH] = Q_KEY_CODE_LESS,
+ [SDL_SCANCODE_APPLICATION] = Q_KEY_CODE_MENU,
#if 0
- [SDL_SCANCODE_NONUSBACKSLASH] = Q_KEY_CODE_NONUSBACKSLASH,
- [SDL_SCANCODE_APPLICATION] = Q_KEY_CODE_APPLICATION,
[SDL_SCANCODE_POWER] = Q_KEY_CODE_POWER,
[SDL_SCANCODE_KP_EQUALS] = Q_KEY_CODE_KP_EQUALS,
@@ -231,7 +232,7 @@ static const int sdl2_scancode_to_qcode[SDL_NUM_SCANCODES] = {
[SDL_SCANCODE_LGUI] = Q_KEY_CODE_META_L,
[SDL_SCANCODE_RCTRL] = Q_KEY_CODE_CTRL_R,
[SDL_SCANCODE_RSHIFT] = Q_KEY_CODE_SHIFT_R,
- [SDL_SCANCODE_RALT] = Q_KEY_CODE_ALTGR,
+ [SDL_SCANCODE_RALT] = Q_KEY_CODE_ALT_R,
[SDL_SCANCODE_RGUI] = Q_KEY_CODE_META_R,
#if 0
[SDL_SCANCODE_MODE] = Q_KEY_CODE_MODE,
diff --git a/ui/sdl2.c b/ui/sdl2.c
index fcac87b4b..1ad74baaf 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -35,7 +35,6 @@
#include "ui/console.h"
#include "ui/input.h"
#include "sysemu/sysemu.h"
-#include "sdl_zoom.h"
#include "sdl2-keymap.h"
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 7bb91e6ba..6467fa477 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -677,7 +677,7 @@ void qemu_spice_init(void)
if (tls_port) {
x509_dir = qemu_opt_get(opts, "x509-dir");
- if (NULL == x509_dir) {
+ if (!x509_dir) {
x509_dir = ".";
}
@@ -733,7 +733,7 @@ void qemu_spice_init(void)
tls_ciphers);
}
if (password) {
- spice_server_set_ticket(spice_server, password, 0, 0, 0);
+ qemu_spice_set_passwd(password, false, false);
}
if (qemu_opt_get_bool(opts, "sasl", 0)) {
if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 ||
@@ -803,7 +803,7 @@ void qemu_spice_init(void)
seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0);
spice_server_set_seamless_migration(spice_server, seamless_migration);
- if (0 != spice_server_init(spice_server, &core_interface)) {
+ if (spice_server_init(spice_server, &core_interface) != 0) {
error_report("failed to initialize spice server");
exit(1);
};
@@ -853,7 +853,6 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin)
}
static GSList *spice_consoles;
-static int display_id;
bool qemu_spice_have_display_interface(QemuConsole *con)
{
@@ -868,7 +867,7 @@ int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con)
if (g_slist_find(spice_consoles, con)) {
return -1;
}
- qxlin->id = display_id++;
+ qxlin->id = qemu_console_get_index(con);
spice_consoles = g_slist_append(spice_consoles, con);
return qemu_spice_add_interface(&qxlin->base);
}
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 66e25788c..def7b52e9 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -334,11 +334,23 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
{
QXLDevSurfaceCreate surface;
+ uint64_t surface_size;
memset(&surface, 0, sizeof(surface));
- dprint(1, "%s/%d: %dx%d\n", __func__, ssd->qxl.id,
- surface_width(ssd->ds), surface_height(ssd->ds));
+ surface_size = (uint64_t) surface_width(ssd->ds) *
+ surface_height(ssd->ds) * 4;
+ assert(surface_size > 0);
+ assert(surface_size < INT_MAX);
+ if (ssd->bufsize < surface_size) {
+ ssd->bufsize = surface_size;
+ g_free(ssd->buf);
+ ssd->buf = g_malloc(ssd->bufsize);
+ }
+
+ dprint(1, "%s/%d: %ux%u (size %" PRIu64 "/%d)\n", __func__, ssd->qxl.id,
+ surface_width(ssd->ds), surface_height(ssd->ds),
+ surface_size, ssd->bufsize);
surface.format = SPICE_SURFACE_FMT_32_xRGB;
surface.width = surface_width(ssd->ds);
@@ -369,8 +381,6 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd)
if (ssd->num_surfaces == 0) {
ssd->num_surfaces = 1024;
}
- ssd->bufsize = (16 * 1024 * 1024);
- ssd->buf = g_malloc(ssd->bufsize);
}
/* display listener callbacks */
@@ -495,7 +505,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
info->num_memslots = NUM_MEMSLOTS;
info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
info->internal_groupslot_id = 0;
- info->qxl_ram_size = ssd->bufsize;
+ info->qxl_ram_size = 16 * 1024 * 1024;
info->n_surfaces = ssd->num_surfaces;
}
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index f02352cc4..3d1b5cd06 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -220,8 +220,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
unsigned int errors; \
unsigned char *buf = vs->tight.tight.buffer; \
\
- endian = 0; /* FIXME: ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
- (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); */ \
+ endian = 0; /* FIXME */ \
\
\
max[0] = vs->client_pf.rmax; \
@@ -563,8 +562,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
buf32 = (uint32_t *)buf;
memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));
- if (1 /* FIXME: (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
- (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) */) {
+ if (1 /* FIXME */) {
shift[0] = vs->client_pf.rshift;
shift[1] = vs->client_pf.gshift;
shift[2] = vs->client_pf.bshift;
@@ -621,8 +619,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
\
memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int)); \
\
- endian = 0; /* FIXME: ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
- (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); */ \
+ endian = 0; /* FIXME */ \
\
max[0] = vs->client_pf.rmax; \
max[1] = vs->client_pf.gmax; \
@@ -898,8 +895,7 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
buf32 = (uint32_t *)buf;
- if (1 /* FIXME: (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
- (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) */) {
+ if (1 /* FIXME */) {
rshift = vs->client_pf.rshift;
gshift = vs->client_pf.gshift;
bshift = vs->client_pf.bshift;
diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c
index 63923265f..0f59f9b28 100644
--- a/ui/vnc-tls.c
+++ b/ui/vnc-tls.c
@@ -444,8 +444,6 @@ static int vnc_set_x509_credential(VncDisplay *vd,
struct stat sb;
g_free(*cred);
- *cred = NULL;
-
*cred = g_malloc(strlen(certdir) + strlen(filename) + 2);
strcpy(*cred, certdir);
diff --git a/ui/vnc.c b/ui/vnc.c
index f8d9b7db9..57070150d 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2026,6 +2026,16 @@ static void set_pixel_format(VncState *vs,
return;
}
+ switch (bits_per_pixel) {
+ case 8:
+ case 16:
+ case 32:
+ break;
+ default:
+ vnc_client_error(vs);
+ return;
+ }
+
vs->client_pf.rmax = red_max;
vs->client_pf.rbits = hweight_long(red_max);
vs->client_pf.rshift = red_shift;
@@ -2768,6 +2778,11 @@ static void vnc_refresh(DisplayChangeListener *dcl)
VncState *vs, *vn;
int has_dirty, rects = 0;
+ if (QTAILQ_EMPTY(&vd->clients)) {
+ update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX);
+ return;
+ }
+
graphic_hw_update(NULL);
if (vnc_trylock_display(vd)) {
@@ -2783,11 +2798,6 @@ static void vnc_refresh(DisplayChangeListener *dcl)
/* vs might be free()ed here */
}
- if (QTAILQ_EMPTY(&vd->clients)) {
- update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX);
- return;
- }
-
if (has_dirty && rects) {
vd->dcl.update_interval /= 2;
if (vd->dcl.update_interval < VNC_REFRESH_INTERVAL_BASE) {
@@ -2914,6 +2924,7 @@ static void vnc_listen_read(void *opaque, bool websocket)
}
if (csock != -1) {
+ socket_set_nodelay(csock);
vnc_connect(vs, csock, false, websocket);
}
}