From: Markus Armbruster <armbru@redhat.com>
To: Vivek Kasireddy <vivek.kasireddy@intel.com>
Cc: qemu-devel@nongnu.org, "Dongwon Kim" <dongwon.kim@intel.com>,
"Gerd Hoffmann" <kraxel@redhat.com>,
"Daniel P . Berrangé" <berrange@redhat.com>,
"Philippe Mathieu-Daudé" <f4bug@amsat.org>,
"Marc-André Lureau" <marcandre.lureau@redhat.com>,
"Thomas Huth" <thuth@redhat.com>
Subject: Re: [PATCH v1 3/3] ui/gtk: Add a new parameter to assign connectors/monitors to GFX VCs
Date: Wed, 21 Sep 2022 16:27:14 +0200 [thread overview]
Message-ID: <877d1wby65.fsf@pond.sub.org> (raw)
In-Reply-To: <20220917000731.465003-4-vivek.kasireddy@intel.com> (Vivek Kasireddy's message of "Fri, 16 Sep 2022 17:07:31 -0700")
Vivek Kasireddy <vivek.kasireddy@intel.com> writes:
> The new parameter named "connector" can be used to assign physical
> monitors/connectors to individual GFX VCs such that when the monitor
> is connected or hotplugged, the associated GTK window would be
> fullscreened on it. If the monitor is disconnected or unplugged,
> the associated GTK window would be destroyed and a relevant
> disconnect event would be sent to the Guest.
>
> Usage: -device virtio-gpu-pci,max_outputs=2,blob=true,xres=1920,yres=1080...
> -display gtk,gl=on,connector.0=eDP-1,connector.1=DP-1.....
>
> Cc: Dongwon Kim <dongwon.kim@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Daniel P. Berrangé <berrange@redhat.com>
> Cc: Markus Armbruster <armbru@redhat.com>
> Cc: Philippe Mathieu-Daudé <f4bug@amsat.org>
> Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
> Cc: Thomas Huth <thuth@redhat.com>
> Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
> ---
> qapi/ui.json | 9 ++-
> qemu-options.hx | 1 +
> ui/gtk.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 177 insertions(+), 1 deletion(-)
>
> diff --git a/qapi/ui.json b/qapi/ui.json
> index 286c5731d1..86787a4c95 100644
> --- a/qapi/ui.json
> +++ b/qapi/ui.json
> @@ -1199,13 +1199,20 @@
> # interfaces (e.g. VGA and virtual console character devices)
> # by default.
> # Since 7.1
> +# @connector: List of physical monitor/connector names where the GTK windows
> +# containing the respective graphics virtual consoles (VCs) are
> +# to be placed. If a mapping exists for a VC, it will be
> +# fullscreened on that specific monitor or else it would not be
> +# displayed anywhere and would appear disconnected to the guest.
Let's see whether I understand this... We have VCs numbered 0, 1, ...
VC #i is mapped to the i-th element of @connector, counting from zero.
Correct?
Ignorant question: what's a "physical monitor/connector name"?
Would you mind breaking the lines a bit earlier, between column 70 and
75?
> +# Since 7.2
> #
> # Since: 2.12
> ##
> { 'struct' : 'DisplayGTK',
> 'data' : { '*grab-on-hover' : 'bool',
> '*zoom-to-fit' : 'bool',
> - '*show-tabs' : 'bool' } }
> + '*show-tabs' : 'bool',
> + '*connector' : ['str'] } }
>
> ##
> # @DisplayEGLHeadless:
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 31c04f7eea..576b65ef9f 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1945,6 +1945,7 @@ DEF("display", HAS_ARG, QEMU_OPTION_display,
> #if defined(CONFIG_GTK)
> "-display gtk[,full-screen=on|off][,gl=on|off][,grab-on-hover=on|off]\n"
> " [,show-tabs=on|off][,show-cursor=on|off][,window-close=on|off]\n"
> + " [,connector.<id of VC>=<connector name>]\n"
Is "<id of VC>" a VC number?
> #endif
> #if defined(CONFIG_VNC)
> "-display vnc=<display>[,<optargs>]\n"
Remainder of my review is on style only. Style suggestions are not
demands :)
> diff --git a/ui/gtk.c b/ui/gtk.c
> index 945c550909..651aaaf174 100644
> --- a/ui/gtk.c
> +++ b/ui/gtk.c
> @@ -37,6 +37,7 @@
> #include "qapi/qapi-commands-misc.h"
> #include "qemu/cutils.h"
> #include "qemu/main-loop.h"
> +#include "qemu/option.h"
>
> #include "ui/console.h"
> #include "ui/gtk.h"
> @@ -115,6 +116,7 @@
> #endif
>
> #define HOTKEY_MODIFIERS (GDK_CONTROL_MASK | GDK_MOD1_MASK)
> +#define MAX_NUM_ATTEMPTS 5
Could use a comment, and maybe a more telling name (this one doesn't
tell me what is being attempted).
>
> static const guint16 *keycode_map;
> static size_t keycode_maplen;
> @@ -126,6 +128,15 @@ struct VCChardev {
> };
> typedef struct VCChardev VCChardev;
>
> +struct gd_monitor_data {
> + GtkDisplayState *s;
> + GdkDisplay *dpy;
> + GdkMonitor *monitor;
> + QEMUTimer *hp_timer;
> + int attempt;
> +};
> +typedef struct gd_monitor_data gd_monitor_data;
We usually contract these like
typedef struct gd_monitor_data {
...
} gd_monitor_data;
> +
> #define TYPE_CHARDEV_VC "chardev-vc"
> DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
> TYPE_CHARDEV_VC)
> @@ -1385,6 +1396,147 @@ static void gd_menu_untabify(GtkMenuItem *item, void *opaque)
> }
> }
>
> +static void gd_monitor_fullscreen(GdkDisplay *dpy, VirtualConsole *vc,
> + gint monitor_num)
> +{
> + GtkDisplayState *s = vc->s;
> +
> + if (!vc->window) {
> + gd_tab_window_create(vc);
> + }
> + gtk_window_fullscreen_on_monitor(GTK_WINDOW(vc->window),
> + gdk_display_get_default_screen(dpy),
> + monitor_num);
> + s->full_screen = TRUE;
> + gd_update_cursor(vc);
> +}
> +
> +static int gd_monitor_lookup(GdkDisplay *dpy, char *label)
> +{
> + GdkMonitor *monitor;
> + const char *monitor_name;
> + int i, total_monitors;
> +
> + total_monitors = gdk_display_get_n_monitors(dpy);
> + for (i = 0; i < total_monitors; i++) {
Suggest to format like this:
int total_monitors = gdk_display_get_n_monitors(dpy);
GdkMonitor *monitor;
const char *monitor_name;
int i;
for (i = 0; i < total_monitors; i++) {
> + monitor = gdk_display_get_monitor(dpy, i);
> + if (monitor) {
> + monitor_name = gdk_monitor_get_model(monitor);
> + if (monitor_name && !strcmp(monitor_name, label)) {
Would
if (monitor && !g_strcmp0(gdk_monitor_get_model(monitor), label)) {
do?
> + return i;
> + }
> + }
> + }
> + return -1;
> +}
> +
> +static void gd_monitor_check_vcs(GdkDisplay *dpy, GdkMonitor *monitor,
> + GtkDisplayState *s)
> +{
> + VirtualConsole *vc;
> + const char *monitor_name = gdk_monitor_get_model(monitor);
> + int i;
> +
> + for (i = 0; i < s->nb_vcs; i++) {
> + vc = &s->vc[i];
> + if (!strcmp(vc->label, monitor_name)) {
> + gd_monitor_fullscreen(dpy, vc, gd_monitor_lookup(dpy, vc->label));
> + gd_set_ui_size(vc, surface_width(vc->gfx.ds),
> + surface_height(vc->gfx.ds));
> + break;
> + }
> + }
> +}
> +
> +static void gd_monitor_hotplug_timer(void *opaque)
> +{
> + gd_monitor_data *data = opaque;
> + const char *monitor_name = gdk_monitor_get_model(data->monitor);
> +
> + if (monitor_name) {
> + gd_monitor_check_vcs(data->dpy, data->monitor, data->s);
> + }
> + if (monitor_name || data->attempt == MAX_NUM_ATTEMPTS) {
> + timer_del(data->hp_timer);
> + g_free(data);
> + } else {
> + data->attempt++;
> + timer_mod(data->hp_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 50);
Suggest to break the line like
timer_mod(data->hp_timer,
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 50);
for readability.
> + }
> +}
> +
> +static void gd_monitor_add(GdkDisplay *dpy, GdkMonitor *monitor,
> + void *opaque)
> +{
> + GtkDisplayState *s = opaque;
> + gd_monitor_data *data;
> + const char *monitor_name = gdk_monitor_get_model(monitor);
> +
> + if (!monitor_name) {
> + data = g_malloc0(sizeof(*data));
> + data->s = s;
> + data->dpy = dpy;
> + data->monitor = monitor;
> + data->hp_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
> + gd_monitor_hotplug_timer, data);
> + timer_mod(data->hp_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 50);
> + } else {
> + gd_monitor_check_vcs(dpy, monitor, s);
> + }
Often
if (cond) {
do stuff when cond
} else {
do stuff when !cond
}
is easier to read than
if (!cond) {
do stuff when !cond
} else {
do stuff when !!cond
}
Give it a thought.
> +}
> +
> +static void gd_monitor_remove(GdkDisplay *dpy, GdkMonitor *monitor,
> + void *opaque)
> +{
> + GtkDisplayState *s = opaque;
> + VirtualConsole *vc;
> + const char *monitor_name = gdk_monitor_get_model(monitor);
> + int i;
> +
> + if (!monitor_name) {
> + return;
> + }
> + for (i = 0; i < s->nb_vcs; i++) {
> + vc = &s->vc[i];
> + if (!strcmp(vc->label, monitor_name)) {
> + gd_tab_window_close(NULL, NULL, vc);
> + gd_set_ui_size(vc, 0, 0);
> + break;
> + }
> + }
> +}
> +
> +static void gd_connectors_init(GdkDisplay *dpy, GtkDisplayState *s)
> +{
> + VirtualConsole *vc;
> + strList *connector = s->opts->u.gtk.connector;
> + gint page_num = 0, monitor_num;
> +
> + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
> + gtk_widget_hide(s->menu_bar);
> + for (; connector; connector = connector->next) {
Please don't split off part of the loop control. What about
for (conn = s->opts->u.gtk.connector; conn; conn = conn->next) {
?
> + vc = gd_vc_find_by_page(s, page_num);
> + if (!vc) {
> + break;
> + }
> + if (page_num == 0) {
> + vc->window = s->window;
> + }
> +
> + g_free(vc->label);
> + vc->label = g_strdup(connector->value);
> + monitor_num = gd_monitor_lookup(dpy, vc->label);
> + if (monitor_num >= 0) {
> + gd_monitor_fullscreen(dpy, vc, monitor_num);
> + gd_set_ui_size(vc, surface_width(vc->gfx.ds),
> + surface_height(vc->gfx.ds));
> + } else {
> + gd_set_ui_size(vc, 0, 0);
> + }
> + page_num++;
> + }
> +}
> +
> static void gd_menu_show_menubar(GtkMenuItem *item, void *opaque)
> {
> GtkDisplayState *s = opaque;
> @@ -1705,7 +1857,14 @@ static gboolean gd_configure(GtkWidget *widget,
> GdkEventConfigure *cfg, gpointer opaque)
> {
> VirtualConsole *vc = opaque;
> + GtkDisplayState *s = vc->s;
> + GtkWidget *parent = gtk_widget_get_parent(widget);
>
> + if (s->opts->u.gtk.has_connector) {
> + if (!parent || !GTK_IS_WINDOW(parent)) {
> + return FALSE;
> + }
> + }
> gd_set_ui_size(vc, cfg->width, cfg->height);
> return FALSE;
> }
> @@ -2038,6 +2197,12 @@ static void gd_connect_signals(GtkDisplayState *s)
> G_CALLBACK(gd_menu_grab_input), s);
> g_signal_connect(s->notebook, "switch-page",
> G_CALLBACK(gd_change_page), s);
> + if (s->opts->u.gtk.has_connector) {
> + g_signal_connect(gtk_widget_get_display(s->window), "monitor-added",
> + G_CALLBACK(gd_monitor_add), s);
> + g_signal_connect(gtk_widget_get_display(s->window), "monitor-removed",
> + G_CALLBACK(gd_monitor_remove), s);
> + }
> }
>
> static GtkWidget *gd_create_menu_machine(GtkDisplayState *s)
> @@ -2402,6 +2567,9 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
> opts->u.gtk.show_tabs) {
> gtk_menu_item_activate(GTK_MENU_ITEM(s->show_tabs_item));
> }
> + if (s->opts->u.gtk.has_connector) {
> + gd_connectors_init(window_display, s);
> + }
> gd_clipboard_init(s);
> }
next prev parent reply other threads:[~2022-09-21 14:39 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-17 0:07 [PATCH v1 0/3] ui/gtk: Add a new parameter to assign connectors/monitors to Guests' windows Vivek Kasireddy
2022-09-17 0:07 ` [PATCH v1 1/3] ui/gtk: Disable the scanout when a detached tab is closed Vivek Kasireddy
2022-09-17 0:07 ` [PATCH v1 2/3] ui/gtk: Factor out tab window creation into a separate function Vivek Kasireddy
2022-09-17 0:07 ` [PATCH v1 3/3] ui/gtk: Add a new parameter to assign connectors/monitors to GFX VCs Vivek Kasireddy
2022-09-21 14:27 ` Markus Armbruster [this message]
2022-09-21 22:21 ` Kasireddy, Vivek
2022-09-22 4:52 ` Markus Armbruster
2022-09-20 15:04 ` [PATCH v1 0/3] ui/gtk: Add a new parameter to assign connectors/monitors to Guests' windows Markus Armbruster
2022-09-20 20:48 ` Kasireddy, Vivek
2022-09-21 6:06 ` Markus Armbruster
2022-09-28 23:29 ` Kim, Dongwon
2022-09-29 5:00 ` Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=877d1wby65.fsf@pond.sub.org \
--to=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=dongwon.kim@intel.com \
--cc=f4bug@amsat.org \
--cc=kraxel@redhat.com \
--cc=marcandre.lureau@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=thuth@redhat.com \
--cc=vivek.kasireddy@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.