#ifndef GDK_IS_X11_DISPLAY
#define GDK_IS_X11_DISPLAY(dpy) (dpy == dpy)
#endif
+#ifndef GDK_IS_WAYLAND_DISPLAY
+#define GDK_IS_WAYLAND_DISPLAY(dpy) (dpy == dpy)
+#endif
#ifndef GDK_IS_WIN32_DISPLAY
#define GDK_IS_WIN32_DISPLAY(dpy) (dpy == dpy)
#endif
-#ifndef GDK_KEY_0
+#if !GTK_CHECK_VERSION(2, 22, 0)
#define GDK_KEY_0 GDK_0
#define GDK_KEY_1 GDK_1
#define GDK_KEY_2 GDK_2
#define GDK_KEY_g GDK_g
#define GDK_KEY_q GDK_q
#define GDK_KEY_plus GDK_plus
+#define GDK_KEY_equal GDK_equal
#define GDK_KEY_minus GDK_minus
#define GDK_KEY_Pause GDK_Pause
+#define GDK_KEY_Delete GDK_Delete
#endif
/* Some older mingw versions lack this constant or have
bool ignore_keys;
};
+typedef struct VCChardev {
+ Chardev parent;
+ VirtualConsole *console;
+ bool echo;
+} VCChardev;
+
+#define TYPE_CHARDEV_VC "chardev-vc"
+#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
+
static void gd_grab_pointer(VirtualConsole *vc, const char *reason);
static void gd_ungrab_pointer(GtkDisplayState *s);
static void gd_grab_keyboard(VirtualConsole *vc, const char *reason);
if (!qemu_input_is_absolute() && s->ptr_owner == vc) {
GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area);
+ int screen_width, screen_height;
+
int x = (int)motion->x_root;
int y = (int)motion->y_root;
+#if GTK_CHECK_VERSION(3, 22, 0)
+ {
+ GdkDisplay *dpy = gtk_widget_get_display(widget);
+ GdkWindow *win = gtk_widget_get_window(widget);
+ GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
+ GdkRectangle geometry;
+ gdk_monitor_get_geometry(monitor, &geometry);
+ screen_width = geometry.width;
+ screen_height = geometry.height;
+ }
+#else
+ {
+ screen_width = gdk_screen_get_width(screen);
+ screen_height = gdk_screen_get_height(screen);
+ }
+#endif
+
/* In relative mode check to see if client pointer hit
* one of the screen edges, and if so move it back by
* 200 pixels. This is important because the pointer
if (y == 0) {
y += 200;
}
- if (x == (gdk_screen_get_width(screen) - 1)) {
+ if (x == (screen_width - 1)) {
x -= 200;
}
- if (y == (gdk_screen_get_height(screen) - 1)) {
+ if (y == (screen_height - 1)) {
y -= 200;
}
btn = INPUT_BUTTON_MIDDLE;
} else if (button->button == 3) {
btn = INPUT_BUTTON_RIGHT;
+ } else if (button->button == 8) {
+ btn = INPUT_BUTTON_SIDE;
+ } else if (button->button == 9) {
+ btn = INPUT_BUTTON_EXTRA;
} else {
return TRUE;
}
btn = INPUT_BUTTON_WHEEL_UP;
} else if (scroll->direction == GDK_SCROLL_DOWN) {
btn = INPUT_BUTTON_WHEEL_DOWN;
+#if GTK_CHECK_VERSION(3, 4, 0)
+ } else if (scroll->direction == GDK_SCROLL_SMOOTH) {
+ gdouble delta_x, delta_y;
+ if (!gdk_event_get_scroll_deltas((GdkEvent *)scroll,
+ &delta_x, &delta_y)) {
+ return TRUE;
+ }
+ if (delta_y > 0) {
+ btn = INPUT_BUTTON_WHEEL_DOWN;
+ } else {
+ btn = INPUT_BUTTON_WHEEL_UP;
+ }
+#endif
} else {
return TRUE;
}
} else {
qemu_keycode = translate_xfree86_keycode(gdk_keycode - 97);
}
+#endif
+#ifdef GDK_WINDOWING_WAYLAND
+ } else if (GDK_IS_WAYLAND_DISPLAY(dpy) && gdk_keycode < 158) {
+ qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
#endif
} else if (gdk_keycode == 208) { /* Hiragana_Katakana */
qemu_keycode = 0x70;
VirtualConsole *vc = opaque;
QemuConsole *con = vc->gfx.dcl.con;
- if (key->length) {
+ if (key->keyval == GDK_KEY_Delete) {
+ kbd_put_qcode_console(con, Q_KEY_CODE_DELETE);
+ } else if (key->length) {
kbd_put_string_console(con, key->string, key->length);
} else {
int num = gd_map_keycode(vc->s, gtk_widget_get_display(widget),
gd_update_windowsize(vc);
}
+static void gd_accel_zoom_in(void *opaque)
+{
+ GtkDisplayState *s = opaque;
+ gtk_menu_item_activate(GTK_MENU_ITEM(s->zoom_in_item));
+}
+
static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque)
{
GtkDisplayState *s = opaque;
TRUE);
}
gtk_widget_set_sensitive(s->grab_item, on_vga);
+#ifdef CONFIG_VTE
+ gtk_widget_set_sensitive(s->copy_item, vc->type == GD_VC_VTE);
+#endif
gd_update_windowsize(vc);
gd_update_cursor(vc);
}
}
-static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
- VirtualConsole *vc = chr->opaque;
+ VCChardev *vcd = VC_CHARDEV(chr);
+ VirtualConsole *vc = vcd->console;
vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
return len;
}
-static void gd_vc_chr_set_echo(CharDriverState *chr, bool echo)
+static void gd_vc_chr_set_echo(Chardev *chr, bool echo)
{
- VirtualConsole *vc = chr->opaque;
+ VCChardev *vcd = VC_CHARDEV(chr);
+ VirtualConsole *vc = vcd->console;
- vc->vte.echo = echo;
+ if (vc) {
+ vc->vte.echo = echo;
+ } else {
+ vcd->echo = echo;
+ }
}
static int nb_vcs;
-static CharDriverState *vcs[MAX_VCS];
+static Chardev *vcs[MAX_VCS];
+static const CharDriver gd_vc_driver;
-static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
+static void gd_vc_open(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
- ChardevCommon *common = qapi_ChardevVC_base(vc);
- CharDriverState *chr;
-
- chr = qemu_chr_alloc(common, errp);
- if (!chr) {
- return NULL;
+ if (nb_vcs == MAX_VCS) {
+ error_setg(errp, "Maximum number of consoles reached");
+ return;
}
- chr->chr_write = gd_vc_chr_write;
- chr->chr_set_echo = gd_vc_chr_set_echo;
-
- /* Temporary, until gd_vc_vte_init runs. */
- chr->opaque = g_new0(VirtualConsole, 1);
+ vcs[nb_vcs++] = chr;
- /* defer OPENED events until our vc is fully initialized */
- chr->explicit_be_open = true;
+ /* console/chardev init sometimes completes elsewhere in a 2nd
+ * stage, so defer OPENED events until they are fully initialized
+ */
+ *be_opened = false;
+}
- vcs[nb_vcs++] = chr;
+static void char_gd_vc_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
- return chr;
+ cc->open = gd_vc_open;
+ cc->chr_write = gd_vc_chr_write;
+ cc->chr_set_echo = gd_vc_chr_set_echo;
}
+static const TypeInfo char_gd_vc_type_info = {
+ .name = TYPE_CHARDEV_VC,
+ .parent = TYPE_CHARDEV,
+ .instance_size = sizeof(VCChardev),
+ .class_init = char_gd_vc_class_init,
+};
+
+static const CharDriver gd_vc_driver = {
+ .kind = CHARDEV_BACKEND_KIND_VC,
+ .parse = qemu_chr_parse_vc,
+};
+
static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
gpointer user_data)
{
}
static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
- CharDriverState *chr, int idx,
+ Chardev *chr, int idx,
GSList *group, GtkWidget *view_menu)
{
char buffer[32];
GtkWidget *box;
GtkWidget *scrollbar;
GtkAdjustment *vadjustment;
- VirtualConsole *tmp_vc = chr->opaque;
+ VCChardev *vcd = VC_CHARDEV(chr);
vc->s = s;
- vc->vte.echo = tmp_vc->vte.echo;
-
+ vc->vte.echo = vcd->echo;
vc->vte.chr = chr;
- chr->opaque = vc;
- g_free(tmp_vc);
+ vcd->console = vc;
snprintf(buffer, sizeof(buffer), "vc%d", idx);
vc->label = g_strdup_printf("%s", vc->vte.chr->label
gtk_label_new(vc->label));
qemu_chr_be_generic_open(vc->vte.chr);
- if (vc->vte.chr->init) {
- vc->vte.chr->init(vc->vte.chr);
- }
return group;
}
"<QEMU>/View/Zoom In");
gtk_accel_map_add_entry("<QEMU>/View/Zoom In", GDK_KEY_plus,
HOTKEY_MODIFIERS);
+ gtk_accel_group_connect(s->accel_group, GDK_KEY_equal, HOTKEY_MODIFIERS, 0,
+ g_cclosure_new_swap(G_CALLBACK(gd_accel_zoom_in), s, NULL));
gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->zoom_in_item);
s->zoom_out_item = gtk_menu_item_new_with_mnemonic(_("Zoom _Out"));
void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
{
+ VirtualConsole *vc;
+
GtkDisplayState *s = g_malloc0(sizeof(*s));
char *filename;
GdkDisplay *window_display;
s->free_scale = FALSE;
- /* LC_MESSAGES only. See early_gtk_display_init() for details */
+ /* Mostly LC_MESSAGES only. See early_gtk_display_init() for details. For
+ * LC_CTYPE, we need to make sure that non-ASCII characters are considered
+ * printable, but without changing any of the character classes to make
+ * sure that we don't accidentally break implicit assumptions. */
setlocale(LC_MESSAGES, "");
+ setlocale(LC_CTYPE, "C.UTF-8");
bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR);
textdomain("qemu");
}
#endif
+ vc = gd_vc_find_current(s);
+ gtk_widget_set_sensitive(s->view_menu, vc != NULL);
+#ifdef CONFIG_VTE
+ gtk_widget_set_sensitive(s->copy_item,
+ vc && vc->type == GD_VC_VTE);
+#endif
+
if (full_screen) {
gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item));
}
}
#if defined(CONFIG_VTE)
- register_vc_handler(gd_vc_handler);
+ type_register(&char_gd_vc_type_info);
+ register_char_driver(&gd_vc_driver);
#endif
}