diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/Makefile.objs | 5 | ||||
-rw-r--r-- | ui/cocoa.m | 2 | ||||
-rw-r--r-- | ui/console.c | 267 | ||||
-rw-r--r-- | ui/gtk.c | 112 | ||||
-rw-r--r-- | ui/input-legacy.c | 11 | ||||
-rw-r--r-- | ui/input.c | 40 | ||||
-rw-r--r-- | ui/qemu-pixman.c | 90 | ||||
-rw-r--r-- | ui/sdl.c | 5 | ||||
-rw-r--r-- | ui/sdl2-keymap.h | 7 | ||||
-rw-r--r-- | ui/sdl2.c | 1 | ||||
-rw-r--r-- | ui/spice-core.c | 9 | ||||
-rw-r--r-- | ui/spice-display.c | 20 | ||||
-rw-r--r-- | ui/vnc-enc-tight.c | 12 | ||||
-rw-r--r-- | ui/vnc-tls.c | 2 | ||||
-rw-r--r-- | ui/vnc.c | 21 |
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); @@ -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) { @@ -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, @@ -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); @@ -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); } } |