[virt-tools-list] [PATCH virt-viewer] Use the display ID to configure fullscreen monitors
Pavel Grunt
pgrunt at redhat.com
Fri Oct 9 08:53:31 UTC 2015
On Thu, 2015-10-08 at 16:03 -0500, Jonathon Jongsma wrote:
> When starting virt-viewer in fullscreen mode, we generally try to
> arrange guest displays exactly the same as client monitors. So if a
> client machine has two monitors, we'll try to enable display 0 and 1 on
> the guest (in that order). However, when using the configuration file to
> map fullscreen displays to different monitors, the guest displays may
> not be sequential, or there may be displays missing. For example,
> consider the following configuration:
>
> monitor-mapping=1:2;2:1
>
> In virt_viewer_session_spice_fullscreen_auto_conf(), we were building an
> array of GdkRectangles for the initial monitors that we want to enable
> on the guest. We then configured the guest displays using the index of
> the array for the as the id of the guest display. But when displays
> are sparse or are out-of-sequence, the array index will not match the
> intended display ID> This created problems where displays were arranged
> incorrectly. By changing the simple array into a GHashTable, we can keep
> the display ID together with the GdkRectangle until we need to use it,
> and things will be configured correctly.
>
Yes, ack.
> This regression was introduced by c586dc8c.
>
> Fixes: rhbz#1269918
and rhbz#1267184
Thanks,
Pavel
> ---
> src/virt-viewer-session-spice.c | 43 +++++++++++++++++-------------
> src/virt-viewer-session.c | 30 ++++++---------------
> src/virt-viewer-session.h | 3 ++-
> src/virt-viewer-util.c | 58 +++++++++++++++++++++++++++-------------
> -
> src/virt-viewer-util.h | 4 +--
> 5 files changed, 76 insertions(+), 62 deletions(-)
>
> diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c
> index f792294..eb0761d 100644
> --- a/src/virt-viewer-session-spice.c
> +++ b/src/virt-viewer-session-spice.c
> @@ -85,7 +85,7 @@ static void
> virt_viewer_session_spice_channel_destroy(SpiceSession *s,
> static void virt_viewer_session_spice_smartcard_insert(VirtViewerSession
> *session);
> static void virt_viewer_session_spice_smartcard_remove(VirtViewerSession
> *session);
> static gboolean
> virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self);
> -static void
> virt_viewer_session_spice_apply_monitor_geometry(VirtViewerSession *self,
> GdkRectangle *monitors, guint nmonitors);
> +static void
> virt_viewer_session_spice_apply_monitor_geometry(VirtViewerSession *self,
> GHashTable *monitors);
>
> static void virt_viewer_session_spice_clear_displays(VirtViewerSessionSpice
> *self)
> {
> @@ -966,9 +966,10 @@
> virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self)
> GdkScreen *screen = gdk_screen_get_default();
> SpiceMainChannel* cmain =
> virt_viewer_session_spice_get_main_channel(self);
> VirtViewerApp *app = NULL;
> - GdkRectangle *displays;
> + GHashTable *displays;
> + GHashTableIter iter;
> + gpointer key, value;
> gboolean agent_connected;
> - gint i;
> GList *initial_displays, *l;
> guint ndisplays;
>
> @@ -1003,29 +1004,32 @@
> virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self)
> initial_displays = virt_viewer_app_get_initial_displays(app);
> ndisplays = g_list_length(initial_displays);
> g_debug("Performing full screen auto-conf, %u host monitors", ndisplays);
> - displays = g_new0(GdkRectangle, ndisplays);
> + displays = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
> g_free);
>
> - for (i = 0, l = initial_displays; l != NULL; l = l->next, i++) {
> - GdkRectangle* rect = &displays[i];
> + for (l = initial_displays; l != NULL; l = l->next) {
> + GdkRectangle* rect = g_new0(GdkRectangle, 1);;
> gint j = virt_viewer_app_get_initial_monitor_for_display(app,
> GPOINTER_TO_INT(l->data));
> if (j == -1)
> continue;
>
> gdk_screen_get_monitor_geometry(screen, j, rect);
> + g_hash_table_insert(displays, l->data, rect);
> }
> - g_list_free(initial_displays);
>
> - virt_viewer_shift_monitors_to_origin(displays, ndisplays);
> + virt_viewer_shift_monitors_to_origin(displays);
>
> - for (i = 0; i < ndisplays; i++) {
> - GdkRectangle *rect = &displays[i];
> + g_hash_table_iter_init(&iter, displays);
> + while (g_hash_table_iter_next(&iter, &key, &value)) {
> + GdkRectangle *rect = value;
> + gint j = GPOINTER_TO_INT(key);
>
> - spice_main_set_display(cmain, i, rect->x, rect->y, rect->width, rect-
> >height);
> - spice_main_set_display_enabled(cmain, i, TRUE);
> + spice_main_set_display(cmain, j, rect->x, rect->y, rect->width, rect-
> >height);
> + spice_main_set_display_enabled(cmain, j, TRUE);
> g_debug("Set SPICE display %d to (%d,%d)-(%dx%d)",
> - i, rect->x, rect->y, rect->width, rect->height);
> + j, rect->x, rect->y, rect->width, rect->height);
> }
> - g_free(displays);
> + g_list_free(initial_displays);
> + g_hash_table_unref(displays);
>
> spice_main_send_monitor_config(cmain);
> self->priv->did_auto_conf = TRUE;
> @@ -1109,13 +1113,16 @@
> virt_viewer_session_spice_smartcard_remove(VirtViewerSession *session
> G_GNUC_UNU
> }
>
> static void
> -virt_viewer_session_spice_apply_monitor_geometry(VirtViewerSession *session,
> GdkRectangle *monitors, guint nmonitors)
> +virt_viewer_session_spice_apply_monitor_geometry(VirtViewerSession *session,
> GHashTable *monitors)
> {
> - guint i;
> + GHashTableIter iter;
> + gpointer key = NULL, value = NULL;
> VirtViewerSessionSpice *self = VIRT_VIEWER_SESSION_SPICE(session);
>
> - for (i = 0; i < nmonitors; i++) {
> - GdkRectangle* rect = &monitors[i];
> + g_hash_table_iter_init(&iter, monitors);
> + while (g_hash_table_iter_next(&iter, &key, &value)) {
> + gint i = GPOINTER_TO_INT(key);
> + GdkRectangle* rect = value;
>
> spice_main_set_display(self->priv->main_channel, i, rect->x,
> rect->y, rect->width, rect->height);
> diff --git a/src/virt-viewer-session.c b/src/virt-viewer-session.c
> index 9405281..2699f41 100644
> --- a/src/virt-viewer-session.c
> +++ b/src/virt-viewer-session.c
> @@ -404,49 +404,35 @@
> virt_viewer_session_on_monitor_geometry_changed(VirtViewerSession* self,
> {
> VirtViewerSessionClass *klass;
> gboolean all_fullscreen = TRUE;
> - guint nmonitors = 0;
> - GdkRectangle *monitors = NULL;
> + /* GHashTable<gint, GdkRectangle*> */
> + GHashTable *monitors = g_hash_table_new_full(g_direct_hash,
> g_direct_equal, NULL, g_free);
> GList *l;
>
> klass = VIRT_VIEWER_SESSION_GET_CLASS(self);
> if (!klass->apply_monitor_geometry)
> return;
>
> - /* find highest monitor ID so we can create the sparse array */
> for (l = self->priv->displays; l; l = l->next) {
> VirtViewerDisplay *d = VIRT_VIEWER_DISPLAY(l->data);
> guint nth = 0;
> - g_object_get(d, "nth-display", &nth, NULL);
> -
> - nmonitors = MAX(nth + 1, nmonitors);
> - }
> -
> - if (nmonitors == 0)
> - return;
> -
> - monitors = g_new0(GdkRectangle, nmonitors);
> - for (l = self->priv->displays; l; l = l->next) {
> - VirtViewerDisplay *d = VIRT_VIEWER_DISPLAY(l->data);
> - guint nth = 0;
> - GdkRectangle *rect = NULL;
> + GdkRectangle *rect = g_new0(GdkRectangle, 1);
>
> g_object_get(d, "nth-display", &nth, NULL);
> - g_return_if_fail(nth < nmonitors);
> - rect = &monitors[nth];
> virt_viewer_display_get_preferred_monitor_geometry(d, rect);
>
> if (virt_viewer_display_get_enabled(d) &&
> !virt_viewer_display_get_fullscreen(d))
> all_fullscreen = FALSE;
> + g_hash_table_insert(monitors, GINT_TO_POINTER(nth), rect);
> }
>
> if (!all_fullscreen)
> - virt_viewer_align_monitors_linear(monitors, nmonitors);
> + virt_viewer_align_monitors_linear(monitors);
>
> - virt_viewer_shift_monitors_to_origin(monitors, nmonitors);
> + virt_viewer_shift_monitors_to_origin(monitors);
>
> - klass->apply_monitor_geometry(self, monitors, nmonitors);
> - g_free(monitors);
> + klass->apply_monitor_geometry(self, monitors);
> + g_hash_table_unref(monitors);
> }
>
> void virt_viewer_session_add_display(VirtViewerSession *session,
> diff --git a/src/virt-viewer-session.h b/src/virt-viewer-session.h
> index 85f17cc..d3a9ccc 100644
> --- a/src/virt-viewer-session.h
> +++ b/src/virt-viewer-session.h
> @@ -94,7 +94,8 @@ struct _VirtViewerSessionClass {
> void (*session_cut_text)(VirtViewerSession *session, const gchar *str);
> void (*session_bell)(VirtViewerSession *session);
> void (*session_cancelled)(VirtViewerSession *session);
> - void (*apply_monitor_geometry)(VirtViewerSession *session, GdkRectangle*
> monitors, guint nmonitors);
> + /* monitors = GHashTable<int, GdkRectangle*> */
> + void (*apply_monitor_geometry)(VirtViewerSession *session, GHashTable*
> monitors);
> gboolean (*can_share_folder)(VirtViewerSession *session);
> gboolean (*can_retry_auth)(VirtViewerSession *session);
> };
> diff --git a/src/virt-viewer-util.c b/src/virt-viewer-util.c
> index 19a475e..e9f771b 100644
> --- a/src/virt-viewer-util.c
> +++ b/src/virt-viewer-util.c
> @@ -536,11 +536,11 @@ static int
> displays_cmp(const void *p1, const void *p2, gpointer user_data)
> {
> guint diff;
> - GdkRectangle *displays = user_data;
> + GHashTable *displays = user_data;
> guint i = *(guint*)p1;
> guint j = *(guint*)p2;
> - GdkRectangle *m1 = &displays[i];
> - GdkRectangle *m2 = &displays[j];
> + GdkRectangle *m1 = g_hash_table_lookup(displays, GINT_TO_POINTER(i));
> + GdkRectangle *m2 = g_hash_table_lookup(displays, GINT_TO_POINTER(j));
> diff = m1->x - m2->x;
> if (diff == 0)
> diff = m1->y - m2->y;
> @@ -550,28 +550,44 @@ displays_cmp(const void *p1, const void *p2, gpointer
> user_data)
> return diff;
> }
>
> +static void find_max_id(gpointer key,
> + gpointer value G_GNUC_UNUSED,
> + gpointer user_data)
> +{
> + guint *max_id = user_data;
> + guint id = GPOINTER_TO_INT(key);
> + *max_id = MAX(*max_id, id);
> +}
> +
> void
> -virt_viewer_align_monitors_linear(GdkRectangle *displays, guint ndisplays)
> +virt_viewer_align_monitors_linear(GHashTable *displays)
> {
> gint i, x = 0;
> guint *sorted_displays;
> + guint max_id = 0;
> + GHashTableIter iter;
> + gpointer key, value;
>
> g_return_if_fail(displays != NULL);
>
> - if (ndisplays == 0)
> + if (g_hash_table_size(displays) == 0)
> return;
>
> - sorted_displays = g_new0(guint, ndisplays);
> - for (i = 0; i < ndisplays; i++)
> - sorted_displays[i] = i;
> - g_qsort_with_data(sorted_displays, ndisplays, sizeof(guint),
> displays_cmp, displays);
> + g_hash_table_foreach(displays, find_max_id, &max_id);
> + sorted_displays = g_new0(guint, max_id);
> +
> + g_hash_table_iter_init(&iter, displays);
> + while (g_hash_table_iter_next(&iter, &key, &value))
> + sorted_displays[GPOINTER_TO_INT(key)] = GPOINTER_TO_INT(key);
> +
> + g_qsort_with_data(sorted_displays, max_id, sizeof(guint), displays_cmp,
> displays);
>
> /* adjust monitor positions so that there's no gaps or overlap between
> * monitors */
> - for (i = 0; i < ndisplays; i++) {
> + for (i = 0; i < max_id; i++) {
> guint nth = sorted_displays[i];
> - g_assert(nth < ndisplays);
> - GdkRectangle *rect = &displays[nth];
> + g_assert(nth < max_id);
> + GdkRectangle *rect = g_hash_table_lookup(displays,
> GINT_TO_POINTER(nth));
> rect->x = x;
> rect->y = 0;
> x += rect->width;
> @@ -591,16 +607,19 @@ virt_viewer_align_monitors_linear(GdkRectangle
> *displays, guint ndisplays)
> * screen of that size.
> */
> void
> -virt_viewer_shift_monitors_to_origin(GdkRectangle *displays, guint ndisplays)
> +virt_viewer_shift_monitors_to_origin(GHashTable *displays)
> {
> gint xmin = G_MAXINT;
> gint ymin = G_MAXINT;
> - gint i;
> + GHashTableIter iter;
> + gpointer key, value;
>
> - g_return_if_fail(ndisplays > 0);
> + if (g_hash_table_size(displays) == 0)
> + return;
>
> - for (i = 0; i < ndisplays; i++) {
> - GdkRectangle *display = &displays[i];
> + g_hash_table_iter_init(&iter, displays);
> + while (g_hash_table_iter_next(&iter, &key, &value)) {
> + GdkRectangle *display = value;
> if (display->width > 0 && display->height > 0) {
> xmin = MIN(xmin, display->x);
> ymin = MIN(ymin, display->y);
> @@ -610,8 +629,9 @@ virt_viewer_shift_monitors_to_origin(GdkRectangle
> *displays, guint ndisplays)
>
> if (xmin > 0 || ymin > 0) {
> g_debug("%s: Shifting all monitors by (%i, %i)", G_STRFUNC, xmin,
> ymin);
> - for (i = 0; i < ndisplays; i++) {
> - GdkRectangle *display = &displays[i];
> + g_hash_table_iter_init(&iter, displays);
> + while (g_hash_table_iter_next(&iter, &key, &value)) {
> + GdkRectangle *display = value;
> if (display->width > 0 && display->height > 0) {
> display->x -= xmin;
> display->y -= ymin;
> diff --git a/src/virt-viewer-util.h b/src/virt-viewer-util.h
> index 98badd2..f1cb08b 100644
> --- a/src/virt-viewer-util.h
> +++ b/src/virt-viewer-util.h
> @@ -57,8 +57,8 @@ gchar* spice_hotkey_to_gtk_accelerator(const gchar *key);
> gint virt_viewer_compare_buildid(const gchar *s1, const gchar *s2);
>
> /* monitor alignment */
> -void virt_viewer_align_monitors_linear(GdkRectangle *displays, guint
> ndisplays);
> -void virt_viewer_shift_monitors_to_origin(GdkRectangle *displays, guint
> ndisplays);
> +void virt_viewer_align_monitors_linear(GHashTable *displays);
> +void virt_viewer_shift_monitors_to_origin(GHashTable *displays);
>
> #endif
>
More information about the virt-tools-list
mailing list