With "detach-all=on" for display, QEMU starts with all VC windows detached automatically.
If used with "full-screen=on", it places individual windows (from top window) starting from monitor 0 or monitor n in case monitor=n. In case # mon < # VCs, only same number of VCs as # mon will be sent to the monitors for full-screen while others are remaining in windowed-mode. Target monitor number for individual VC is rotated in case monitor=n (n != 0) (e.g. if monitor=1 and # VCs = 2, the top window will be full-screened on monitor 1 and top second window will be full-screened on monitor 0.) v2: update Since version to 7.1 Cc: Philippe Mathieu-Daudé <phi...@redhat.com> Cc: Paolo Bonzini <pbonz...@redhat.com> Cc: Gerd Hoffmann <kra...@redhat.com> Cc: Vivek Kasireddy <vivek.kasire...@intel.com> Signed-off-by: Dongwon Kim <dongwon....@intel.com> --- qapi/ui.json | 5 ++++- ui/gtk.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/qapi/ui.json b/qapi/ui.json index ddcea7349b..a5b1550937 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1378,6 +1378,8 @@ # @show-cursor: Force showing the mouse cursor (default: off). # (since: 5.0) # @gl: Enable OpenGL support (default: off). +# @detach-all: Start QEMU with all VC windows detached (default: off) +# (since: 7.1) # # Since: 2.12 # @@ -1387,7 +1389,8 @@ '*full-screen' : 'bool', '*window-close' : 'bool', '*show-cursor' : 'bool', - '*gl' : 'DisplayGLMode' }, + '*gl' : 'DisplayGLMode', + '*detach-all' : 'bool' }, 'discriminator' : 'type', 'data' : { 'gtk': { 'type': 'DisplayGTK', 'if': 'CONFIG_GTK' }, diff --git a/ui/gtk.c b/ui/gtk.c index d9971d65ac..f1ca6a7275 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -2305,6 +2305,8 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) GdkDisplay *window_display; GtkIconTheme *theme; char *dir; + int num_mon; + int i; if (!gtkinit) { fprintf(stderr, "gtk initialization failed\n"); @@ -2374,18 +2376,57 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts) gtk_widget_set_sensitive(s->copy_item, vc && vc->type == GD_VC_VTE); #endif - if (opts->u.gtk.has_monitor && - opts->u.gtk.monitor < gdk_display_get_n_monitors(window_display)) { + opts->u.gtk.monitor < + (num_mon = gdk_display_get_n_monitors(window_display))) { GdkRectangle mon_dest; gdk_monitor_get_geometry( gdk_display_get_monitor(window_display, opts->u.gtk.monitor), &mon_dest); gtk_window_move(GTK_WINDOW(s->window), mon_dest.x, mon_dest.y); } + if (opts->has_detach_all && + opts->detach_all) { + for (i = 0; i < s->nb_vcs - 1; i++) { + gtk_menu_item_activate(GTK_MENU_ITEM(s->untabify_item)); + } + } if (opts->has_full_screen && opts->full_screen) { - gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item)); + bool no_mon_left = 0; + int next_mon = 0; + if (!opts->u.gtk.has_monitor || + (opts->u.gtk.has_monitor && opts->u.gtk.monitor < num_mon)) { + next_mon = (opts->u.gtk.has_monitor) ? opts->u.gtk.monitor : 0; + for (i = 0; i < s->nb_vcs - 1; i++) { + if (!s->vc[i].window) { + continue; + } + + gtk_window_fullscreen_on_monitor( + GTK_WINDOW(s->vc[i].window), + gdk_display_get_default_screen(window_display), + next_mon++); + + if (next_mon == opts->u.gtk.monitor) { + no_mon_left = true; + break; + } + + if (next_mon == num_mon) { + next_mon = 0; + } + } + } + + if (!no_mon_left) { + GdkRectangle mon_dest; + gdk_monitor_get_geometry( + gdk_display_get_monitor(window_display, next_mon), + &mon_dest); + gtk_window_move(GTK_WINDOW(s->window), mon_dest.x, mon_dest.y); + gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item)); + } } if (opts->u.gtk.has_grab_on_hover && opts->u.gtk.grab_on_hover) { -- 2.30.2