From aa4f4058ba8cde200e62ef3dafc4e1595f6033e9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 9 Sep 2015 09:57:01 +0200 Subject: [PATCH 1/6] gtk: check for existing grabs in gd_grab_{pointer,keyboard} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a grab is already active for our window, do nothing. If a grab is already active for another window, release it. Cleanup some checks and ungrab calls in the code which are not needed any more. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau --- ui/gtk.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index df2a79e7ac..24a1edb988 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -167,6 +167,8 @@ struct GtkDisplayState { static void gd_grab_pointer(VirtualConsole *vc); static void gd_ungrab_pointer(GtkDisplayState *s); +static void gd_grab_keyboard(VirtualConsole *vc); +static void gd_ungrab_keyboard(GtkDisplayState *s); /** Utility Functions **/ @@ -849,7 +851,6 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, /* implicitly grab the input at the first click in the relative mode */ if (button->button == 1 && button->type == GDK_BUTTON_PRESS && !qemu_input_is_absolute() && s->ptr_owner != vc) { - gd_ungrab_pointer(s); if (!vc->window) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE); @@ -1259,6 +1260,14 @@ static void gd_grab_devices(VirtualConsole *vc, bool grab, static void gd_grab_keyboard(VirtualConsole *vc) { + if (vc->s->kbd_owner) { + if (vc->s->kbd_owner == vc) { + return; + } else { + gd_ungrab_keyboard(vc->s); + } + } + #if GTK_CHECK_VERSION(3, 0, 0) gd_grab_devices(vc, true, GDK_SOURCE_KEYBOARD, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, @@ -1292,6 +1301,15 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) static void gd_grab_pointer(VirtualConsole *vc) { GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area); + + if (vc->s->ptr_owner) { + if (vc->s->ptr_owner == vc) { + return; + } else { + gd_ungrab_pointer(vc->s); + } + } + #if GTK_CHECK_VERSION(3, 0, 0) GdkDeviceManager *mgr = gdk_display_get_device_manager(display); gd_grab_devices(vc, true, GDK_SOURCE_MOUSE, @@ -1352,9 +1370,7 @@ static void gd_menu_grab_input(GtkMenuItem *item, void *opaque) VirtualConsole *vc = gd_vc_find_current(s); if (gd_is_grab_active(s)) { - if (!gd_grab_on_hover(s)) { - gd_grab_keyboard(vc); - } + gd_grab_keyboard(vc); gd_grab_pointer(vc); } else { gd_ungrab_keyboard(s); @@ -1415,7 +1431,6 @@ static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing, GtkDisplayState *s = vc->s; if (gd_grab_on_hover(s)) { - gd_ungrab_keyboard(s); gd_grab_keyboard(vc); gd_update_caption(s); } From 695cc59d42f2e285abd5cf278bdc07360a995eaa Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 9 Sep 2015 10:03:59 +0200 Subject: [PATCH 2/6] gtk: move gd_update_caption calls to gd_{grab,ungrab}_{pointer,keyboard} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Then we don't have to pair the grab/ungrab calls with update_caption calls any more because things happen automatically ;) Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau --- ui/gtk.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 24a1edb988..5f87475f2e 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -856,7 +856,6 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, TRUE); } else { gd_grab_pointer(vc); - gd_update_caption(s); } return TRUE; } @@ -1095,7 +1094,6 @@ static gboolean gd_win_grab(void *opaque) } else { gd_grab_pointer(vc); } - gd_update_caption(vc->s); return TRUE; } @@ -1278,6 +1276,7 @@ static void gd_grab_keyboard(VirtualConsole *vc) GDK_CURRENT_TIME); #endif vc->s->kbd_owner = vc; + gd_update_caption(vc->s); trace_gd_grab(vc->label, "kbd", true); } @@ -1295,6 +1294,7 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) #else gdk_keyboard_ungrab(GDK_CURRENT_TIME); #endif + gd_update_caption(s); trace_gd_grab(vc->label, "kbd", false); } @@ -1336,6 +1336,7 @@ static void gd_grab_pointer(VirtualConsole *vc) &vc->s->grab_x_root, &vc->s->grab_y_root, NULL); #endif vc->s->ptr_owner = vc; + gd_update_caption(vc->s); trace_gd_grab(vc->label, "ptr", true); } @@ -1361,6 +1362,7 @@ static void gd_ungrab_pointer(GtkDisplayState *s) gtk_widget_get_screen(vc->gfx.drawing_area), vc->s->grab_x_root, vc->s->grab_y_root); #endif + gd_update_caption(s); trace_gd_grab(vc->label, "ptr", false); } @@ -1377,7 +1379,6 @@ static void gd_menu_grab_input(GtkMenuItem *item, void *opaque) gd_ungrab_pointer(s); } - gd_update_caption(s); gd_update_cursor(vc); } @@ -1432,7 +1433,6 @@ static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing, if (gd_grab_on_hover(s)) { gd_grab_keyboard(vc); - gd_update_caption(s); } return TRUE; } @@ -1445,7 +1445,6 @@ static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, if (gd_grab_on_hover(s)) { gd_ungrab_keyboard(s); - gd_update_caption(s); } return TRUE; } From d531deef119666d4b3605e186a43010782efd899 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 9 Sep 2015 10:12:20 +0200 Subject: [PATCH 3/6] gtk: trace input grab reason MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a reason to grab calls and trace points, so it is easier to debug grab related ui issues. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau --- trace-events | 3 ++- ui/gtk.c | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/trace-events b/trace-events index 1927c764a9..3d1857b270 100644 --- a/trace-events +++ b/trace-events @@ -1150,7 +1150,8 @@ ppm_save(const char *filename, void *display_surface) "%s surface=%p" gd_switch(const char *tab, int width, int height) "tab=%s, width=%d, height=%d" gd_update(const char *tab, int x, int y, int w, int h) "tab=%s, x=%d, y=%d, w=%d, h=%d" gd_key_event(const char *tab, int gdk_keycode, int qemu_keycode, const char *action) "tab=%s, translated GDK keycode %d to QEMU keycode %d (%s)" -gd_grab(const char *tab, const char *device, bool on) "tab=%s, %s %d" +gd_grab(const char *tab, const char *device, const char *reason) "tab=%s, dev=%s, reason=%s" +gd_ungrab(const char *tab, const char *device) "tab=%s, dev=%s" # ui/vnc.c vnc_key_guest_leds(bool caps, bool num, bool scroll) "caps %d, num %d, scroll %d" diff --git a/ui/gtk.c b/ui/gtk.c index 5f87475f2e..322d112410 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -165,9 +165,9 @@ struct GtkDisplayState { bool ignore_keys; }; -static void gd_grab_pointer(VirtualConsole *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); +static void gd_grab_keyboard(VirtualConsole *vc, const char *reason); static void gd_ungrab_keyboard(GtkDisplayState *s); /** Utility Functions **/ @@ -855,7 +855,7 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE); } else { - gd_grab_pointer(vc); + gd_grab_pointer(vc, "relative-mode-click"); } return TRUE; } @@ -1092,7 +1092,7 @@ static gboolean gd_win_grab(void *opaque) if (vc->s->ptr_owner) { gd_ungrab_pointer(vc->s); } else { - gd_grab_pointer(vc); + gd_grab_pointer(vc, "user-request-detached-tab"); } return TRUE; } @@ -1256,7 +1256,7 @@ static void gd_grab_devices(VirtualConsole *vc, bool grab, } #endif -static void gd_grab_keyboard(VirtualConsole *vc) +static void gd_grab_keyboard(VirtualConsole *vc, const char *reason) { if (vc->s->kbd_owner) { if (vc->s->kbd_owner == vc) { @@ -1277,7 +1277,7 @@ static void gd_grab_keyboard(VirtualConsole *vc) #endif vc->s->kbd_owner = vc; gd_update_caption(vc->s); - trace_gd_grab(vc->label, "kbd", true); + trace_gd_grab(vc->label, "kbd", reason); } static void gd_ungrab_keyboard(GtkDisplayState *s) @@ -1295,10 +1295,10 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) gdk_keyboard_ungrab(GDK_CURRENT_TIME); #endif gd_update_caption(s); - trace_gd_grab(vc->label, "kbd", false); + trace_gd_ungrab(vc->label, "kbd"); } -static void gd_grab_pointer(VirtualConsole *vc) +static void gd_grab_pointer(VirtualConsole *vc, const char *reason) { GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area); @@ -1337,7 +1337,7 @@ static void gd_grab_pointer(VirtualConsole *vc) #endif vc->s->ptr_owner = vc; gd_update_caption(vc->s); - trace_gd_grab(vc->label, "ptr", true); + trace_gd_grab(vc->label, "ptr", reason); } static void gd_ungrab_pointer(GtkDisplayState *s) @@ -1363,7 +1363,7 @@ static void gd_ungrab_pointer(GtkDisplayState *s) vc->s->grab_x_root, vc->s->grab_y_root); #endif gd_update_caption(s); - trace_gd_grab(vc->label, "ptr", false); + trace_gd_ungrab(vc->label, "ptr"); } static void gd_menu_grab_input(GtkMenuItem *item, void *opaque) @@ -1372,8 +1372,8 @@ static void gd_menu_grab_input(GtkMenuItem *item, void *opaque) VirtualConsole *vc = gd_vc_find_current(s); if (gd_is_grab_active(s)) { - gd_grab_keyboard(vc); - gd_grab_pointer(vc); + gd_grab_keyboard(vc, "user-request-main-window"); + gd_grab_pointer(vc, "user-request-main-window"); } else { gd_ungrab_keyboard(s); gd_ungrab_pointer(s); @@ -1432,7 +1432,7 @@ static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing, GtkDisplayState *s = vc->s; if (gd_grab_on_hover(s)) { - gd_grab_keyboard(vc); + gd_grab_keyboard(vc, "grab-on-hover"); } return TRUE; } From 1d73cd782fb910811a2e6b9d9b3375c4803d731c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 9 Sep 2015 10:34:41 +0200 Subject: [PATCH 4/6] gtk: set free_scale when setting zoom_fit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit free_scale field tracks zoom-fit menu toggle state, so we should keep them in sync ... Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau --- ui/gtk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/gtk.c b/ui/gtk.c index 322d112410..2629d979e0 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1782,6 +1782,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, if (dpy_ui_info_supported(vc->gfx.dcl.con)) { gtk_menu_item_activate(GTK_MENU_ITEM(s->zoom_fit_item)); + s->free_scale = true; } return group; From 78aee081122837cb488b12657a00deeb676b4730 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 9 Sep 2015 10:14:54 +0200 Subject: [PATCH 5/6] gtk: don't grab input when entering fullscreen. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kick off all grabbing logic from fullscreen mode. In the current state it seems to create more problems than it solves. Try running qemu/gtk fullscreen on one head of a multihead host for example ... There probably was a reason the grab-on-fullscreen logic was added in the first place. So please test and report any issues so we can try to find a sane way to handle it. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau --- ui/gtk.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 2629d979e0..a17b1d1771 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1140,10 +1140,6 @@ 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); - 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; @@ -1156,8 +1152,6 @@ static void gd_menu_full_screen(GtkMenuItem *item, void *opaque) vc->gfx.scale_x = 1.0; vc->gfx.scale_y = 1.0; gd_update_windowsize(vc); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), - FALSE); } } From 2cb5d2a47c655331bcf0ab16bab8fe4701182c58 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Thu, 10 Sep 2015 18:19:32 +0300 Subject: [PATCH 6/6] gtk: use setlocale() for LC_MESSAGES only The QEMU code is not internationalized and assumes that it runs under the C locale, but if we use the GTK+ UI we'll end up importing the locale settings from the environment. This can break things, such as the JSON generator and iotest 120 in locales that use a decimal comma. We do however have translations for a few simple strings for the GTK+ menu items, so in order to run QEMU using the C locale, and yet have a translated UI let's use setlocale() for LC_MESSAGES only. Cc: qemu-stable@nongnu.org Signed-off-by: Alberto Garcia Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/ui/gtk.c b/ui/gtk.c index a17b1d1771..187de74b2c 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1950,7 +1950,8 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover) s->free_scale = FALSE; - setlocale(LC_ALL, ""); + /* LC_MESSAGES only. See early_gtk_display_init() for details */ + setlocale(LC_MESSAGES, ""); bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR); textdomain("qemu"); @@ -2019,6 +2020,24 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover) void early_gtk_display_init(int opengl) { + /* The QEMU code relies on the assumption that it's always run in + * the C locale. Therefore it is not prepared to deal with + * operations that produce different results depending on the + * locale, such as printf's formatting of decimal numbers, and + * possibly others. + * + * Since GTK+ calls setlocale() by default -importing the locale + * settings from the environment- we must prevent it from doing so + * using gtk_disable_setlocale(). + * + * QEMU's GTK+ UI, however, _does_ have translations for some of + * the menu items. As a trade-off between a functionally correct + * QEMU and a fully internationalized UI we support importing + * LC_MESSAGES from the environment (see the setlocale() call + * earlier in this file). This allows us to display translated + * messages leaving everything else untouched. + */ + gtk_disable_setlocale(); gtkinit = gtk_init_check(NULL, NULL); if (!gtkinit) { /* don't exit yet, that'll break -help */