From f98f43eab0fcc536c5f95df3a94943d5dff5ccdc Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 27 Feb 2015 14:36:09 +0100 Subject: gtk: handle switch_surface(NULL) properly Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 51abac9..bcbf51a 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -363,6 +363,9 @@ static void gd_update_geometry_hints(VirtualConsole *vc) GtkWindow *geo_window; if (vc->type == GD_VC_GFX) { + if (!vc->gfx.ds) { + return; + } if (s->free_scale) { geo.min_width = surface_width(vc->gfx.ds) * VC_SCALE_MIN; geo.min_height = surface_height(vc->gfx.ds) * VC_SCALE_MIN; @@ -574,22 +577,28 @@ static void gd_switch(DisplayChangeListener *dcl, VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); bool resized = true; - trace_gd_switch(vc->label, surface_width(surface), surface_height(surface)); + trace_gd_switch(vc->label, + surface ? surface_width(surface) : 0, + surface ? surface_height(surface) : 0); if (vc->gfx.surface) { cairo_surface_destroy(vc->gfx.surface); + vc->gfx.surface = NULL; + } + if (vc->gfx.convert) { + pixman_image_unref(vc->gfx.convert); + vc->gfx.convert = NULL; } - if (vc->gfx.ds && + if (vc->gfx.ds && surface && surface_width(vc->gfx.ds) == surface_width(surface) && surface_height(vc->gfx.ds) == surface_height(surface)) { resized = false; } vc->gfx.ds = surface; - if (vc->gfx.convert) { - pixman_image_unref(vc->gfx.convert); - vc->gfx.convert = NULL; + if (!surface) { + return; } if (surface->format == PIXMAN_x8r8g8b8) { @@ -690,6 +699,9 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) if (!gtk_widget_get_realized(widget)) { return FALSE; } + if (!vc->gfx.ds) { + return FALSE; + } fbw = surface_width(vc->gfx.ds); fbh = surface_height(vc->gfx.ds); @@ -771,6 +783,10 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, int fbh, fbw; int ww, wh; + 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; -- cgit v1.1 From f8c223f69ac58488ea830597281b7ddd33037c4c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 22 May 2014 11:08:54 +0200 Subject: gtk: bind to text terminal consoles too This way gtk has text terminal consoles even when building without vte. Most notably you'll get a monitor tab on windows now. Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 109 ++++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 36 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index bcbf51a..c8d30fe 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -290,7 +290,8 @@ static void gd_update_cursor(VirtualConsole *vc) GtkDisplayState *s = vc->s; GdkWindow *window; - if (vc->type != GD_VC_GFX) { + if (vc->type != GD_VC_GFX || + !qemu_console_is_graphic(vc->gfx.dcl.con)) { return; } @@ -430,7 +431,8 @@ static void gtk_release_modifiers(GtkDisplayState *s) VirtualConsole *vc = gd_vc_find_current(s); int i, keycode; - if (vc->type != GD_VC_GFX) { + if (vc->type != GD_VC_GFX || + !qemu_console_is_graphic(vc->gfx.dcl.con)) { return; } for (i = 0; i < ARRAY_SIZE(modifier_keycode); i++) { @@ -458,6 +460,7 @@ static void gd_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + GdkWindow *win; int x1, x2, y1, y2; int mx, my; int fbw, fbh; @@ -484,8 +487,11 @@ static void gd_update(DisplayChangeListener *dcl, fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x; fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y; - gdk_drawable_get_size(gtk_widget_get_window(vc->gfx.drawing_area), - &ww, &wh); + win = gtk_widget_get_window(vc->gfx.drawing_area); + if (!win) { + return; + } + gdk_drawable_get_size(win, &ww, &wh); mx = my = 0; if (ww > fbw) { @@ -961,6 +967,23 @@ static int gd_map_keycode(GtkDisplayState *s, GdkDisplay *dpy, int gdk_keycode) return qemu_keycode; } +static gboolean gd_text_key_down(GtkWidget *widget, + GdkEventKey *key, void *opaque) +{ + VirtualConsole *vc = opaque; + QemuConsole *con = vc->gfx.dcl.con; + + 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), + key->hardware_keycode); + int qcode = qemu_input_key_number_to_qcode(num); + kbd_put_qcode_console(con, qcode); + } + return TRUE; +} + static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) { VirtualConsole *vc = opaque; @@ -1102,7 +1125,8 @@ static void gd_menu_untabify(GtkMenuItem *item, void *opaque) GtkDisplayState *s = opaque; VirtualConsole *vc = gd_vc_find_current(s); - if (vc->type == GD_VC_GFX) { + if (vc->type == GD_VC_GFX && + qemu_console_is_graphic(vc->gfx.dcl.con)) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE); } @@ -1115,11 +1139,14 @@ static void gd_menu_untabify(GtkMenuItem *item, void *opaque) G_CALLBACK(gd_tab_window_close), vc); gtk_widget_show_all(vc->window); - GtkAccelGroup *ag = gtk_accel_group_new(); - gtk_window_add_accel_group(GTK_WINDOW(vc->window), ag); + if (qemu_console_is_graphic(vc->gfx.dcl.con)) { + GtkAccelGroup *ag = gtk_accel_group_new(); + gtk_window_add_accel_group(GTK_WINDOW(vc->window), ag); - GClosure *cb = g_cclosure_new_swap(G_CALLBACK(gd_win_grab), vc, NULL); - gtk_accel_group_connect(ag, GDK_KEY_g, HOTKEY_MODIFIERS, 0, cb); + GClosure *cb = g_cclosure_new_swap(G_CALLBACK(gd_win_grab), + vc, NULL); + gtk_accel_group_connect(ag, GDK_KEY_g, HOTKEY_MODIFIERS, 0, cb); + } gd_update_geometry_hints(vc); gd_update_caption(s); @@ -1136,8 +1163,10 @@ static void gd_menu_full_screen(GtkMenuItem *item, void *opaque) 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), - TRUE); + if (qemu_console_is_graphic(vc->gfx.dcl.con)) { + gtk_check_menu_item_set_active + (GTK_CHECK_MENU_ITEM(s->grab_item), TRUE); + } } gtk_window_fullscreen(GTK_WINDOW(s->window)); s->full_screen = TRUE; @@ -1386,7 +1415,8 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, #endif gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE); - on_vga = (vc->type == GD_VC_GFX); + on_vga = (vc->type == GD_VC_GFX && + qemu_console_is_graphic(vc->gfx.dcl.con)); if (!on_vga) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE); @@ -1593,25 +1623,30 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc) g_signal_connect(vc->gfx.drawing_area, "expose-event", G_CALLBACK(gd_expose_event), vc); #endif - g_signal_connect(vc->gfx.drawing_area, "event", - G_CALLBACK(gd_event), vc); - g_signal_connect(vc->gfx.drawing_area, "button-press-event", - G_CALLBACK(gd_button_event), vc); - g_signal_connect(vc->gfx.drawing_area, "button-release-event", - G_CALLBACK(gd_button_event), vc); - g_signal_connect(vc->gfx.drawing_area, "scroll-event", - G_CALLBACK(gd_scroll_event), vc); - g_signal_connect(vc->gfx.drawing_area, "key-press-event", - G_CALLBACK(gd_key_event), vc); - g_signal_connect(vc->gfx.drawing_area, "key-release-event", - G_CALLBACK(gd_key_event), vc); - - g_signal_connect(vc->gfx.drawing_area, "enter-notify-event", - G_CALLBACK(gd_enter_event), vc); - g_signal_connect(vc->gfx.drawing_area, "leave-notify-event", - G_CALLBACK(gd_leave_event), vc); - g_signal_connect(vc->gfx.drawing_area, "focus-out-event", - G_CALLBACK(gd_focus_out_event), vc); + if (qemu_console_is_graphic(vc->gfx.dcl.con)) { + g_signal_connect(vc->gfx.drawing_area, "event", + G_CALLBACK(gd_event), vc); + g_signal_connect(vc->gfx.drawing_area, "button-press-event", + G_CALLBACK(gd_button_event), vc); + g_signal_connect(vc->gfx.drawing_area, "button-release-event", + G_CALLBACK(gd_button_event), vc); + g_signal_connect(vc->gfx.drawing_area, "scroll-event", + G_CALLBACK(gd_scroll_event), vc); + g_signal_connect(vc->gfx.drawing_area, "key-press-event", + G_CALLBACK(gd_key_event), vc); + g_signal_connect(vc->gfx.drawing_area, "key-release-event", + G_CALLBACK(gd_key_event), vc); + + g_signal_connect(vc->gfx.drawing_area, "enter-notify-event", + G_CALLBACK(gd_enter_event), vc); + g_signal_connect(vc->gfx.drawing_area, "leave-notify-event", + G_CALLBACK(gd_leave_event), vc); + g_signal_connect(vc->gfx.drawing_area, "focus-out-event", + G_CALLBACK(gd_focus_out_event), vc); + } else { + g_signal_connect(vc->gfx.drawing_area, "key-press-event", + G_CALLBACK(gd_text_key_down), vc); + } } static void gd_connect_signals(GtkDisplayState *s) @@ -1700,8 +1735,10 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, obj = object_property_get_link(OBJECT(con), "device", NULL); if (obj) { vc->label = g_strdup_printf("%s", object_get_typename(obj)); - } else { + } else if (qemu_console_is_graphic(con)) { vc->label = g_strdup_printf("VGA"); + } else { + vc->label = g_strdup_printf("vc%d", idx); } vc->s = s; @@ -1724,14 +1761,14 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, vc->tab_item = vc->gfx.drawing_area; gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), vc->tab_item, gtk_label_new(vc->label)); - gd_connect_vc_gfx_signals(vc); - - group = gd_vc_menu_init(s, vc, idx, group, view_menu); vc->gfx.dcl.ops = &dcl_ops; vc->gfx.dcl.con = con; register_displaychangelistener(&vc->gfx.dcl); + gd_connect_vc_gfx_signals(vc); + group = gd_vc_menu_init(s, vc, idx, group, view_menu); + return group; } @@ -1803,7 +1840,7 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s) /* gfx */ for (vc = 0;; vc++) { con = qemu_console_lookup_by_index(vc); - if (!con || !qemu_console_is_graphic(con)) { + if (!con) { break; } group = gd_vc_gfx_init(s, &s->vc[vc], con, -- cgit v1.1 From 779ce88fbd3f977112bc77ccb028b0ace762105e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 17 Feb 2015 10:41:08 +0100 Subject: console/gtk: add qemu_console_get_label Add a new function to get a nice label for a given QemuConsole. Drop the labeling code in gtk.c and use the new function instead. Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 1 + ui/console.c | 15 +++++++++++++++ ui/gtk.c | 12 +----------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 2f5b9f0..03cd665 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -307,6 +307,7 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head); bool qemu_console_is_visible(QemuConsole *con); bool qemu_console_is_graphic(QemuConsole *con); bool qemu_console_is_fixedsize(QemuConsole *con); +char *qemu_console_get_label(QemuConsole *con); int qemu_console_get_index(QemuConsole *con); uint32_t qemu_console_get_head(QemuConsole *con); QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con); diff --git a/ui/console.c b/ui/console.c index b15ca87..2927513 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1788,6 +1788,21 @@ bool qemu_console_is_fixedsize(QemuConsole *con) return con && (con->console_type != TEXT_CONSOLE); } +char *qemu_console_get_label(QemuConsole *con) +{ + if (con->console_type == GRAPHIC_CONSOLE) { + if (con->device) { + return g_strdup(object_get_typename(con->device)); + } + return g_strdup("VGA"); + } else { + if (con->chr && con->chr->label) { + return g_strdup(con->chr->label); + } + return g_strdup_printf("vc%d", con->index); + } +} + int qemu_console_get_index(QemuConsole *con) { if (con == NULL) { diff --git a/ui/gtk.c b/ui/gtk.c index c8d30fe..7180066 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1730,17 +1730,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, QemuConsole *con, int idx, GSList *group, GtkWidget *view_menu) { - Object *obj; - - obj = object_property_get_link(OBJECT(con), "device", NULL); - if (obj) { - vc->label = g_strdup_printf("%s", object_get_typename(obj)); - } else if (qemu_console_is_graphic(con)) { - vc->label = g_strdup_printf("VGA"); - } else { - vc->label = g_strdup_printf("vc%d", idx); - } - + vc->label = qemu_console_get_label(con); vc->s = s; vc->gfx.scale_x = 1.0; vc->gfx.scale_y = 1.0; -- cgit v1.1 From 9d677e1c2fa479336fb7a2b90aea78c10d037e98 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sun, 26 Apr 2015 21:04:20 +0200 Subject: gtk: Fix VTE focus grabbing At least on GTK2, the VTE terminal has to be specified as target of gtk_widget_grab_focus. Otherwise, switching from one VTE terminal to another causes the focus to get lost. CC: John Snow Signed-off-by: Jan Kiszka [ kraxel: fixed build with CONFIG_VTE=n ] Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 7180066..763d97a 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -170,6 +170,7 @@ typedef struct VirtualConsole { GtkWidget *window; GtkWidget *menu_item; GtkWidget *tab_item; + GtkWidget *focus; VirtualConsoleType type; union { VirtualGfxConsole gfx; @@ -1060,15 +1061,13 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque) GtkDisplayState *s = opaque; VirtualConsole *vc = gd_vc_find_by_menu(s); GtkNotebook *nb = GTK_NOTEBOOK(s->notebook); - GtkWidget *child; gint page; gtk_release_modifiers(s); if (vc) { page = gtk_notebook_page_num(nb, vc->tab_item); gtk_notebook_set_current_page(nb, page); - child = gtk_notebook_get_nth_page(nb, page); - gtk_widget_grab_focus(child); + gtk_widget_grab_focus(vc->focus); } } @@ -1588,6 +1587,7 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc, vc->type = GD_VC_VTE; vc->tab_item = box; + vc->focus = vc->vte.terminal; gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), vc->tab_item, gtk_label_new(vc->label)); @@ -1749,6 +1749,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, vc->type = GD_VC_GFX; vc->tab_item = vc->gfx.drawing_area; + vc->focus = vc->gfx.drawing_area; gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), vc->tab_item, gtk_label_new(vc->label)); -- cgit v1.1 From 1a01716a307387e5cf1336f61a96f772dddadc90 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sun, 26 Apr 2015 21:04:21 +0200 Subject: gtk: Avoid accel key leakage into guest on console switch GTK2 sends the accel key to the guest when switching to the graphic console via that shortcut. Resolve this by ignoring any keys until the next key-release event. However, do not ignore keys when switching via the menu or when on GTK3. Signed-off-by: Jan Kiszka Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index 763d97a..51ea1b9 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -231,6 +231,7 @@ struct GtkDisplayState { bool modifier_pressed[ARRAY_SIZE(modifier_keycode)]; bool has_evdev; + bool ignore_keys; }; static void gd_grab_pointer(VirtualConsole *vc); @@ -993,6 +994,11 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) int qemu_keycode; int i; + if (s->ignore_keys) { + s->ignore_keys = (key->type == GDK_KEY_PRESS); + return TRUE; + } + 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); @@ -1069,12 +1075,18 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque) gtk_notebook_set_current_page(nb, page); gtk_widget_grab_focus(vc->focus); } + s->ignore_keys = false; } 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); +#if !GTK_CHECK_VERSION(3, 0, 0) + /* GTK2 sends the accel key to the target console - ignore this until */ + vc->s->ignore_keys = true; +#endif } static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque) -- cgit v1.1