From dc242e46c2b881780fd67245997aa801213a345b Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Fri, 19 Jul 2013 18:47:01 +0200 Subject: [PATCH] Extend the DBus XRandR protocol to expose cloning restriction Turns out that even if two outputs say that they can be controlled by a given CRTC, you can't configure them in the same CRTC unless they are marked as "possible clones" one of the other. This can further restrict the configuration options, so we need to expose this limitation in the DBus API. https://bugzilla.gnome.org/show_bug.cgi?id=705670 --- src/core/monitor-private.h | 3 +++ src/core/monitor.c | 48 +++++++++++++++++++++++++++++++++++--- src/xrandr.xml | 7 +++++- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/core/monitor-private.h b/src/core/monitor-private.h index 98f310175..4385b3ef8 100644 --- a/src/core/monitor-private.h +++ b/src/core/monitor-private.h @@ -70,6 +70,9 @@ struct _MetaOutput MetaCRTC **possible_crtcs; unsigned int n_possible_crtcs; + MetaOutput **possible_clones; + unsigned int n_possible_clones; + /* The low-level bits used to build the high-level info in MetaMonitorInfo diff --git a/src/core/monitor.c b/src/core/monitor.c index 8ee1a5452..8d576963d 100644 --- a/src/core/monitor.c +++ b/src/core/monitor.c @@ -144,6 +144,8 @@ make_dummy_monitor_config (MetaMonitorManager *manager) manager->outputs[0].n_possible_crtcs = 1; manager->outputs[0].possible_crtcs = g_new0 (MetaCRTC *, 1); manager->outputs[0].possible_crtcs[0] = &manager->crtcs[0]; + manager->outputs[0].n_possible_clones = 0; + manager->outputs[0].possible_clones = g_new0 (MetaOutput *, 0); } #ifdef HAVE_RANDR @@ -273,6 +275,17 @@ read_monitor_infos_from_xrandr (MetaMonitorManager *manager) } } + meta_output->n_possible_clones = output->nclone; + meta_output->possible_clones = g_new0 (MetaOutput *, meta_output->n_possible_clones); + /* We can build the list of clones now, because we don't have the list of outputs + yet, so temporarily set the pointers to the bare XIDs, and then we'll fix them + in a second pass + */ + for (j = 0; j < (unsigned)output->nclone; j++) + { + meta_output->possible_clones = GINT_TO_POINTER (output->clones[j]); + } + meta_output->is_primary = ((XID)meta_output->output_id == primary_output); meta_output->is_presentation = FALSE; @@ -284,6 +297,28 @@ read_monitor_infos_from_xrandr (MetaMonitorManager *manager) manager->n_outputs = n_actual_outputs; + /* Now fix the clones */ + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *meta_output; + + meta_output = &manager->outputs[i]; + + for (j = 0; j < meta_output->n_possible_clones; j++) + { + RROutput clone = GPOINTER_TO_INT (meta_output->possible_clones[j]); + + for (k = 0; k < manager->n_outputs; k++) + { + if (clone == (XID)manager->outputs[k].output_id) + { + meta_output->possible_clones[j] = &manager->outputs[k]; + break; + } + } + } + } + XRRFreeScreenResources (resources); } @@ -463,6 +498,7 @@ free_output_array (MetaOutput *old_outputs, g_free (old_outputs[i].serial); g_free (old_outputs[i].modes); g_free (old_outputs[i].possible_crtcs); + g_free (old_outputs[i].possible_clones); } g_free (old_outputs); @@ -567,7 +603,7 @@ handle_get_resources (MetaDBusDisplayConfig *skeleton, unsigned int i, j; g_variant_builder_init (&crtc_builder, G_VARIANT_TYPE ("a(uxiiiiiuaua{sv})")); - g_variant_builder_init (&output_builder, G_VARIANT_TYPE ("a(uxiausaua{sv})")); + g_variant_builder_init (&output_builder, G_VARIANT_TYPE ("a(uxiausauaua{sv})")); g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uxuud)")); for (i = 0; i < manager->n_crtcs; i++) @@ -594,7 +630,7 @@ handle_get_resources (MetaDBusDisplayConfig *skeleton, for (i = 0; i < manager->n_outputs; i++) { MetaOutput *output = &manager->outputs[i]; - GVariantBuilder crtcs, modes, properties; + GVariantBuilder crtcs, modes, clones, properties; g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au")); for (j = 0; j < output->n_possible_crtcs; j++) @@ -606,6 +642,11 @@ handle_get_resources (MetaDBusDisplayConfig *skeleton, g_variant_builder_add (&modes, "u", (unsigned)(output->modes[j] - manager->modes)); + g_variant_builder_init (&clones, G_VARIANT_TYPE ("au")); + for (j = 0; j < output->n_possible_clones; j++) + g_variant_builder_add (&clones, "u", + (unsigned)(output->possible_clones[j] - manager->outputs)); + g_variant_builder_init (&properties, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&properties, "{sv}", "vendor", g_variant_new_string (output->vendor)); @@ -620,13 +661,14 @@ handle_get_resources (MetaDBusDisplayConfig *skeleton, g_variant_builder_add (&properties, "{sv}", "presentation", g_variant_new_boolean (output->is_presentation)); - g_variant_builder_add (&output_builder, "(uxiausaua{sv})", + g_variant_builder_add (&output_builder, "(uxiausauaua{sv})", i, /* ID */ output->output_id, (int)(output->crtc ? output->crtc - manager->crtcs : -1), &crtcs, output->name, &modes, + &clones, &properties); } diff --git a/src/xrandr.xml b/src/xrandr.xml index 8b5aa72dc..408bc3c30 100644 --- a/src/xrandr.xml +++ b/src/xrandr.xml @@ -76,6 +76,11 @@ * s name: the name of the connector to which the output is attached (like VGA1 or HDMI) * au modes: valid modes for this output + * au clones: valid clones for this output, ie other outputs that + can be assigned the same CRTC as this one; if you + want to mirror two outputs that don't have each other + in the clone list, you must configure two different + CRTCs for the same geometry * a{sv} properties: other high-level properties that affect this output; they are not necessarily reflected in the hardware. @@ -123,7 +128,7 @@ - +