From 3bb33d384f7ed087555e31a5703e911e664b3233 Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Fri, 19 Jul 2013 14:39:28 +0200 Subject: [PATCH] Introduce a new DBus interface for display configuration This new interface will be used by the control center and possibly the settings daemon to configure the screens. It is designed to resemble a simplified XRandR, while still exposing all the quirks of the hardware, so that the panel can limit the user choices appropriately. To do so, MetaMonitorMode needs to track CRTCs, outputs and modes, so the low level objects have been decoupled from the high-level MetaMonitorInfo, which is used by core and API and offers a simplified view of HW, that hides away the details of what is cloned and how. This is still not efficient as it should be, because on every HW change we drop all data structures and rebuild them from scratch (which is not expensive because there aren't many of them, but at least in the XRandR path it involves a few sync X calls) https://bugzilla.gnome.org/show_bug.cgi?id=705670 --- src/Makefile.am | 10 + src/core/monitor-private.h | 74 ++++- src/core/monitor.c | 618 +++++++++++++++++++++++++++++++------ src/core/util.c | 2 + src/meta/util.h | 3 +- src/xrandr.xml | 131 ++++++++ 6 files changed, 730 insertions(+), 108 deletions(-) create mode 100644 src/xrandr.xml diff --git a/src/Makefile.am b/src/Makefile.am index f62f3f49c..ac03bd4d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,7 @@ INCLUDES= \ -DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" mutter_built_sources = \ + $(dbus_xrandr_built_sources) \ mutter-enum-types.h \ mutter-enum-types.c @@ -325,3 +326,12 @@ mutter-enum-types.c: stamp-mutter-enum-types.h mutter-enum-types.c.in $(libmutterinclude_base_headers) ) >> xgen-tetc && \ cp xgen-tetc mutter-enum-types.c && \ rm -f xgen-tetc + +dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h + +$(dbus_xrandr_built_sources) : Makefile.am xrandr.xml + $(AM_V_GEN)gdbus-codegen \ + --interface-prefix org.gnome.Mutter \ + --c-namespace MetaDBus \ + --generate-c-code meta-dbus-xrandr \ + xrandr.xml diff --git a/src/core/monitor-private.h b/src/core/monitor-private.h index bc1ee25e1..98f310175 100644 --- a/src/core/monitor-private.h +++ b/src/core/monitor-private.h @@ -37,35 +37,99 @@ #ifndef META_MONITOR_PRIVATE_H #define META_MONITOR_PRIVATE_H +#include + #include "display-private.h" #include #include "stack-tracker.h" #include "ui.h" -#include - typedef struct _MetaOutput MetaOutput; +typedef struct _MetaCRTC MetaCRTC; +typedef struct _MetaMonitorMode MetaMonitorMode; typedef struct _MetaMonitorInfo MetaMonitorInfo; struct _MetaOutput { - MetaMonitorInfo *monitor; + /* The CRTC driving this output, NULL if the output is not enabled */ + MetaCRTC *crtc; + /* The low-level ID of this output, used to apply back configuration */ + glong output_id; char *name; + char *vendor; + char *product; + char *serial; int width_mm; int height_mm; CoglSubpixelOrder subpixel_order; + + MetaMonitorMode *preferred_mode; + MetaMonitorMode **modes; + unsigned int n_modes; + + MetaCRTC **possible_crtcs; + unsigned int n_possible_crtcs; + + /* The low-level bits used to build the high-level info + in MetaMonitorInfo + + XXX: flags maybe? + There is a lot of code that uses MonitorInfo->is_primary, + but nobody uses MetaOutput yet + */ + gboolean is_primary; + gboolean is_presentation; }; +struct _MetaCRTC +{ + glong crtc_id; + MetaRectangle rect; + MetaMonitorMode *current_mode; + + /* Only used to build the logical configuration + from the HW one + */ + MetaMonitorInfo *logical_monitor; +}; + +struct _MetaMonitorMode +{ + /* The low-level ID of this mode, used to apply back configuration */ + glong mode_id; + + int width; + int height; + float refresh_rate; +}; + +/** + * MetaMonitorInfo: + * + * A structure with high-level information about monitors. + * This corresponds to a subset of the compositor coordinate space. + * Clones are only reported once, irrespective of the way + * they're implemented (two CRTCs configured for the same + * coordinates or one CRTCs driving two outputs). Inactive CRTCs + * are ignored, and so are disabled outputs. + */ struct _MetaMonitorInfo { int number; int xinerama_index; MetaRectangle rect; gboolean is_primary; + gboolean is_presentation; /* XXX: not yet used */ gboolean in_fullscreen; - float refresh_rate; - /* The primary or first output for this crtc, 0 if we can't figure out. */ + /* The primary or first output for this monitor, 0 if we can't figure out. + It can be matched to an output_id of a MetaOutput. + + This is used as an opaque token on reconfiguration when switching from + clone to extened, to decide on what output the windows should go next + (it's an attempt to keep windows on the same monitor, and preferably on + the primary one). + */ glong output_id; }; diff --git a/src/core/monitor.c b/src/core/monitor.c index 05d4f2b41..8ee1a5452 100644 --- a/src/core/monitor.c +++ b/src/core/monitor.c @@ -27,33 +27,56 @@ #include "config.h" +#include +#include #include #ifdef HAVE_RANDR #include #endif +#include +#include #include "monitor-private.h" +#include "meta-dbus-xrandr.h" + struct _MetaMonitorManager { GObject parent_instance; - /* Outputs refers to physical screens, - while monitor_infos refer to logical ones (aka CRTC) - They can be different if two outputs are - in clone mode + /* XXX: this structure is very badly + packed, but I like the logical organization + of fields */ + + unsigned int serial; + + /* Outputs refer to physical screens, + CRTCs refer to stuff that can drive outputs + (like encoders, but less tied to the HW), + while monitor_infos refer to logical ones. + + See also the comment in monitor-private.h */ MetaOutput *outputs; - int primary_monitor_index; - int n_outputs; + unsigned int n_outputs; + + MetaMonitorMode *modes; + unsigned int n_modes; + + MetaCRTC *crtcs; + unsigned int n_crtcs; MetaMonitorInfo *monitor_infos; - int n_monitor_infos; + unsigned int n_monitor_infos; + int primary_monitor_index; #ifdef HAVE_RANDR Display *xdisplay; #endif + + int dbus_name_id; + MetaDBusDisplayConfig *skeleton; }; struct _MetaMonitorManagerClass @@ -73,144 +96,193 @@ G_DEFINE_TYPE (MetaMonitorManager, meta_monitor_manager, G_TYPE_OBJECT); static void make_dummy_monitor_config (MetaMonitorManager *manager) { - manager->monitor_infos = g_new0 (MetaMonitorInfo, 1); - manager->n_monitor_infos = 1; + manager->modes = g_new0 (MetaMonitorMode, 1); + manager->n_modes = 1; - manager->monitor_infos[0].number = 0; - manager->monitor_infos[0].xinerama_index = 0; - manager->monitor_infos[0].rect.x = 0; - manager->monitor_infos[0].rect.y = 0; + manager->modes[0].mode_id = 1; if (manager->xdisplay) { Screen *screen = ScreenOfDisplay (manager->xdisplay, DefaultScreen (manager->xdisplay)); - manager->monitor_infos[0].rect.width = WidthOfScreen (screen); - manager->monitor_infos[0].rect.height = HeightOfScreen (screen); + manager->modes[0].width = WidthOfScreen (screen); + manager->modes[0].height = HeightOfScreen (screen); } else { - manager->monitor_infos[0].rect.width = 1024; - manager->monitor_infos[0].rect.height = 768; + manager->modes[0].width = 1024; + manager->modes[0].height = 768; } - manager->monitor_infos[0].refresh_rate = 60.0f; - manager->monitor_infos[0].is_primary = TRUE; - manager->monitor_infos[0].in_fullscreen = -1; - manager->monitor_infos[0].output_id = 1; + manager->modes[0].refresh_rate = 60.0; + + manager->crtcs = g_new0 (MetaCRTC, 1); + manager->n_crtcs = 1; + + manager->crtcs[0].crtc_id = 2; + manager->crtcs[0].rect.x = 0; + manager->crtcs[0].rect.y = 0; + manager->crtcs[0].rect.width = manager->modes[0].width; + manager->crtcs[0].rect.height = manager->modes[0].height; + manager->crtcs[0].current_mode = &manager->modes[0]; manager->outputs = g_new0 (MetaOutput, 1); manager->n_outputs = 1; - manager->outputs[0].monitor = &manager->monitor_infos[0]; + manager->outputs[0].crtc = &manager->crtcs[0]; + manager->outputs[0].output_id = 3; manager->outputs[0].name = g_strdup ("LVDS"); + manager->outputs[0].vendor = g_strdup ("unknown"); + manager->outputs[0].product = g_strdup ("unknown"); + manager->outputs[0].serial = g_strdup (""); manager->outputs[0].width_mm = 222; manager->outputs[0].height_mm = 125; manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; + manager->outputs[0].preferred_mode = &manager->modes[0]; + manager->outputs[0].n_modes = 1; + manager->outputs[0].modes = g_new0 (MetaMonitorMode *, 1); + manager->outputs[0].modes[0] = &manager->modes[0]; + 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]; } #ifdef HAVE_RANDR -/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the - * outputs the "main". This is the one we consider "owning" the windows, so if - * the mirroring is changed to a dual monitor setup then the windows are moved to the - * crtc that now has that main output. If one of the outputs is the primary that is - * always the main, otherwise we just use the first. - */ -static void -find_main_output_for_crtc (MetaMonitorManager *manager, - XRRScreenResources *resources, - XRRCrtcInfo *crtc, - MetaMonitorInfo *info, - GArray *outputs) -{ - XRROutputInfo *output; - RROutput primary_output; - int i; - - primary_output = XRRGetOutputPrimary (manager->xdisplay, - DefaultRootWindow (manager->xdisplay)); - - for (i = 0; i < crtc->noutput; i++) - { - output = XRRGetOutputInfo (manager->xdisplay, resources, crtc->outputs[i]); - - if (output->connection != RR_Disconnected) - { - MetaOutput meta_output; - - meta_output.name = g_strdup (output->name); - meta_output.width_mm = output->mm_width; - meta_output.height_mm = output->mm_height; - meta_output.subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; - - g_array_append_val (outputs, meta_output); - - if (crtc->outputs[i] == primary_output) - { - info->output_id = crtc->outputs[i]; - info->is_primary = TRUE; - manager->primary_monitor_index = info->number; - } - else if (info->output_id == 0) - { - info->output_id = crtc->outputs[i]; - } - } - - XRRFreeOutputInfo (output); - } -} - static void read_monitor_infos_from_xrandr (MetaMonitorManager *manager) { XRRScreenResources *resources; - GArray *outputs; - int i, j; + RROutput primary_output; + unsigned int i, j, k; + unsigned int n_actual_outputs; resources = XRRGetScreenResourcesCurrent (manager->xdisplay, DefaultRootWindow (manager->xdisplay)); if (!resources) return make_dummy_monitor_config (manager); - outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput)); + manager->n_outputs = resources->noutput; + manager->n_crtcs = resources->ncrtc; + manager->n_modes = resources->nmode; + manager->outputs = g_new0 (MetaOutput, manager->n_outputs); + manager->modes = g_new0 (MetaMonitorMode, manager->n_modes); + manager->crtcs = g_new0 (MetaCRTC, manager->n_crtcs); - manager->n_outputs = 0; - manager->n_monitor_infos = resources->ncrtc; + for (i = 0; i < (unsigned)resources->nmode; i++) + { + XRRModeInfo *xmode = &resources->modes[i]; + MetaMonitorMode *mode; - manager->monitor_infos = g_new0 (MetaMonitorInfo, manager->n_monitor_infos); + mode = &manager->modes[i]; - for (i = 0; i < resources->ncrtc; i++) + mode->mode_id = xmode->id; + mode->width = xmode->width; + mode->height = xmode->height; + mode->refresh_rate = (xmode->dotClock / + ((float)xmode->hTotal * xmode->vTotal)); + } + + for (i = 0; i < (unsigned)resources->ncrtc; i++) { XRRCrtcInfo *crtc; - MetaMonitorInfo *info; + MetaCRTC *meta_crtc; crtc = XRRGetCrtcInfo (manager->xdisplay, resources, resources->crtcs[i]); - info = &manager->monitor_infos[i]; + meta_crtc = &manager->crtcs[i]; - info->number = i; - info->rect.x = crtc->x; - info->rect.y = crtc->y; - info->rect.width = crtc->width; - info->rect.height = crtc->height; - info->in_fullscreen = -1; + meta_crtc->crtc_id = resources->crtcs[i]; + meta_crtc->rect.x = crtc->x; + meta_crtc->rect.y = crtc->y; + meta_crtc->rect.width = crtc->width; + meta_crtc->rect.height = crtc->height; - for (j = 0; j < resources->nmode; j++) + for (j = 0; j < (unsigned)resources->nmode; j++) { if (resources->modes[j].id == crtc->mode) - info->refresh_rate = (resources->modes[j].dotClock / - ((float)resources->modes[j].hTotal * - resources->modes[j].vTotal)); + { + meta_crtc->current_mode = &manager->modes[j]; + break; + } } - find_main_output_for_crtc (manager, resources, crtc, info, outputs); - XRRFreeCrtcInfo (crtc); } - manager->n_outputs = outputs->len; - manager->outputs = (void*)g_array_free (outputs, FALSE); + primary_output = XRRGetOutputPrimary (manager->xdisplay, + DefaultRootWindow (manager->xdisplay)); + + n_actual_outputs = 0; + for (i = 0; i < (unsigned)resources->noutput; i++) + { + XRROutputInfo *output; + MetaOutput *meta_output; + + output = XRRGetOutputInfo (manager->xdisplay, resources, resources->outputs[i]); + + meta_output = &manager->outputs[n_actual_outputs]; + + if (output->connection != RR_Disconnected) + { + meta_output->output_id = resources->outputs[i]; + meta_output->name = g_strdup (output->name); + /* FIXME: to fill useful values for these we need an EDID parser */ + meta_output->vendor = g_strdup ("unknown"); + meta_output->product = g_strdup ("unknown"); + meta_output->serial = g_strdup (""); + meta_output->width_mm = output->mm_width; + meta_output->height_mm = output->mm_height; + meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; + + meta_output->n_modes = output->nmode; + meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes); + for (j = 0; j < meta_output->n_modes; j++) + { + for (k = 0; k < manager->n_modes; k++) + { + if (output->modes[j] == (XID)manager->modes[k].mode_id) + { + meta_output->modes[j] = &manager->modes[k]; + break; + } + } + } + meta_output->preferred_mode = meta_output->modes[0]; + + meta_output->n_possible_crtcs = output->ncrtc; + meta_output->possible_crtcs = g_new0 (MetaCRTC *, meta_output->n_possible_crtcs); + for (j = 0; j < (unsigned)output->ncrtc; j++) + { + for (k = 0; k < manager->n_crtcs; k++) + { + if ((XID)manager->crtcs[k].crtc_id == output->crtcs[j]) + { + meta_output->possible_crtcs[j] = &manager->crtcs[k]; + break; + } + } + } + + meta_output->crtc = NULL; + for (j = 0; j < manager->n_crtcs; j++) + { + if ((XID)manager->crtcs[j].crtc_id == output->crtc) + { + meta_output->crtc = &manager->crtcs[j]; + break; + } + } + + meta_output->is_primary = ((XID)meta_output->output_id == primary_output); + meta_output->is_presentation = FALSE; + + n_actual_outputs++; + } + + XRRFreeOutputInfo (output); + } + + manager->n_outputs = n_actual_outputs; XRRFreeScreenResources (resources); } @@ -234,9 +306,32 @@ meta_monitor_manager_init (MetaMonitorManager *manager) { } +static gboolean +make_debug_config (MetaMonitorManager *manager) +{ + const char *env; + + env = g_getenv ("META_DEBUG_MULTIMONITOR"); + + if (env == NULL) + return FALSE; + +#ifdef HAVE_RANDR + if (strcmp (env, "xrandr") == 0) + read_monitor_infos_from_xrandr (manager); + else +#endif + make_dummy_monitor_config (manager); + + return TRUE; +} + static void read_current_config (MetaMonitorManager *manager) { + if (make_debug_config (manager)) + return; + if (has_dummy_output ()) return make_dummy_monitor_config (manager); @@ -245,6 +340,101 @@ read_current_config (MetaMonitorManager *manager) #endif } +/* + * make_logical_config: + * + * Turn outputs and CRTCs into logical MetaMonitorInfo, + * that will be used by the core and API layer (MetaScreen + * and friends) + */ +static void +make_logical_config (MetaMonitorManager *manager) +{ + GArray *monitor_infos; + unsigned int i, j; + + monitor_infos = g_array_sized_new (FALSE, TRUE, sizeof (MetaMonitorInfo), + manager->n_outputs); + + /* Walk the list of MetaCRTCs, and build a MetaMonitorInfo + for each of them, unless they reference a rectangle that + is already there. + */ + for (i = 0; i < manager->n_crtcs; i++) + { + MetaCRTC *crtc = &manager->crtcs[i]; + + /* Ignore CRTCs not in use */ + if (crtc->current_mode == NULL) + continue; + + for (j = 0; j < monitor_infos->len; j++) + { + MetaMonitorInfo *info = &g_array_index (monitor_infos, MetaMonitorInfo, i); + if (meta_rectangle_equal (&crtc->rect, + &info->rect)) + { + crtc->logical_monitor = info; + break; + } + } + + if (crtc->logical_monitor == NULL) + { + MetaMonitorInfo info; + + info.number = monitor_infos->len; + info.rect = crtc->rect; + info.is_primary = FALSE; + /* This starts true because we want + is_presentation only if all outputs are + marked as such (while for primary it's enough + that any is marked) + */ + info.is_presentation = TRUE; + info.in_fullscreen = -1; + info.output_id = 0; + + g_array_append_val (monitor_infos, info); + + crtc->logical_monitor = &g_array_index (monitor_infos, MetaMonitorInfo, + info.number); + } + } + + /* Now walk the list of outputs applying extended properties (primary + and presentation) + */ + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *output; + MetaMonitorInfo *info; + + output = &manager->outputs[i]; + + /* Ignore outputs that are not active */ + if (output->crtc == NULL) + continue; + + /* We must have a logical monitor on every CRTC at this point */ + g_assert (output->crtc->logical_monitor != NULL); + + info = output->crtc->logical_monitor; + + info->is_primary = info->is_primary || output->is_primary; + info->is_presentation = info->is_presentation && output->is_presentation; + + if (output->is_primary || info->output_id == 0) + info->output_id = output->output_id; + + if (info->is_primary) + manager->primary_monitor_index = info->number; + } + + manager->n_monitor_infos = monitor_infos->len; + manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE); +} + static MetaMonitorManager * meta_monitor_manager_new (Display *display) { @@ -255,6 +445,7 @@ meta_monitor_manager_new (Display *display) manager->xdisplay = display; read_current_config (manager); + make_logical_config (manager); return manager; } @@ -265,7 +456,15 @@ free_output_array (MetaOutput *old_outputs, int i; for (i = 0; i < n_old_outputs; i++) - g_free (old_outputs[i].name); + { + g_free (old_outputs[i].name); + g_free (old_outputs[i].vendor); + g_free (old_outputs[i].product); + g_free (old_outputs[i].serial); + g_free (old_outputs[i].modes); + g_free (old_outputs[i].possible_crtcs); + } + g_free (old_outputs); } @@ -276,15 +475,34 @@ meta_monitor_manager_finalize (GObject *object) free_output_array (manager->outputs, manager->n_outputs); g_free (manager->monitor_infos); + g_free (manager->modes); + g_free (manager->crtcs); G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object); } +static void +meta_monitor_manager_dispose (GObject *object) +{ + MetaMonitorManager *manager = META_MONITOR_MANAGER (object); + + if (manager->dbus_name_id != 0) + { + g_bus_unown_name (manager->dbus_name_id); + manager->dbus_name_id = 0; + } + + g_clear_object (&manager->skeleton); + + G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object); +} + static void meta_monitor_manager_class_init (MetaMonitorManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->dispose = meta_monitor_manager_dispose; object_class->finalize = meta_monitor_manager_finalize; signals[MONITORS_CHANGED] = @@ -296,20 +514,208 @@ meta_monitor_manager_class_init (MetaMonitorManagerClass *klass) G_TYPE_NONE, 0); } -static MetaMonitorManager *global_manager; +static const double known_diagonals[] = { + 12.1, + 13.3, + 15.6 +}; + +static char * +diagonal_to_str (double d) +{ + unsigned int i; + + for (i = 0; i < G_N_ELEMENTS (known_diagonals); i++) + { + double delta; + + delta = fabs(known_diagonals[i] - d); + if (delta < 0.1) + return g_strdup_printf ("%0.1lf\"", known_diagonals[i]); + } + + return g_strdup_printf ("%d\"", (int) (d + 0.5)); +} + +static char * +make_display_name (MetaOutput *output) +{ + if (output->width_mm != -1 && output->height_mm != -1) + { + double d = sqrt (output->width_mm * output->width_mm + + output->height_mm * output->height_mm); + char *inches = diagonal_to_str (d / 25.4); + char *ret; + + ret = g_strdup_printf ("%s %s", output->vendor, inches); + + g_free (inches); + return ret; + } + else + { + return g_strdup (output->vendor); + } +} + +static gboolean +handle_get_resources (MetaDBusDisplayConfig *skeleton, + GDBusMethodInvocation *invocation, + MetaMonitorManager *manager) +{ + GVariantBuilder crtc_builder, output_builder, mode_builder; + 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 (&mode_builder, G_VARIANT_TYPE ("a(uxuud)")); + + for (i = 0; i < manager->n_crtcs; i++) + { + MetaCRTC *crtc = &manager->crtcs[i]; + GVariantBuilder transforms; + + g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au")); + g_variant_builder_add (&transforms, "u", 0); /* 0 = WL_OUTPUT_TRANSFORM_NORMAL */ + + g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})", + i, /* ID */ + crtc->crtc_id, + (int)crtc->rect.x, + (int)crtc->rect.y, + (int)crtc->rect.width, + (int)crtc->rect.height, + (int)(crtc->current_mode ? crtc->current_mode - manager->modes : -1), + 0, /* 0 = WL_OUTPUT_TRANSFORM_NORMAL */ + &transforms, + NULL /* properties */); + } + + for (i = 0; i < manager->n_outputs; i++) + { + MetaOutput *output = &manager->outputs[i]; + GVariantBuilder crtcs, modes, properties; + + g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au")); + for (j = 0; j < output->n_possible_crtcs; j++) + g_variant_builder_add (&crtcs, "u", + (unsigned)(output->possible_crtcs[j] - manager->crtcs)); + + g_variant_builder_init (&modes, G_VARIANT_TYPE ("au")); + for (j = 0; j < output->n_modes; j++) + g_variant_builder_add (&modes, "u", + (unsigned)(output->modes[j] - manager->modes)); + + g_variant_builder_init (&properties, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&properties, "{sv}", "vendor", + g_variant_new_string (output->vendor)); + g_variant_builder_add (&properties, "{sv}", "product", + g_variant_new_string (output->product)); + g_variant_builder_add (&properties, "{sv}", "serial", + g_variant_new_string (output->serial)); + g_variant_builder_add (&properties, "{sv}", "display-name", + g_variant_new_take_string (make_display_name (output))); + g_variant_builder_add (&properties, "{sv}", "primary", + g_variant_new_boolean (output->is_primary)); + g_variant_builder_add (&properties, "{sv}", "presentation", + g_variant_new_boolean (output->is_presentation)); + + g_variant_builder_add (&output_builder, "(uxiausaua{sv})", + i, /* ID */ + output->output_id, + (int)(output->crtc ? output->crtc - manager->crtcs : -1), + &crtcs, + output->name, + &modes, + &properties); + } + + for (i = 0; i < manager->n_modes; i++) + { + MetaMonitorMode *mode = &manager->modes[i]; + + g_variant_builder_add (&mode_builder, "(uxuud)", + i, /* ID */ + mode->mode_id, + mode->width, + mode->height, + (double)mode->refresh_rate); + } + + meta_dbus_display_config_complete_get_resources (skeleton, + invocation, + manager->serial, + g_variant_builder_end (&crtc_builder), + g_variant_builder_end (&output_builder), + g_variant_builder_end (&mode_builder)); + return FALSE; +} + +static void +on_bus_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + MetaMonitorManager *manager = user_data; + + manager->skeleton = META_DBUS_DISPLAY_CONFIG (meta_dbus_display_config_skeleton_new ()); + + g_signal_connect_object (manager->skeleton, "handle-get-resources", + G_CALLBACK (handle_get_resources), manager, 0); + + g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager->skeleton), + connection, + "/org/gnome/Mutter/DisplayConfig", + NULL); +} + +static void +on_name_acquired (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + meta_topic (META_DEBUG_DBUS, "Acquired name %s\n", name); +} + +static void +on_name_lost (GDBusConnection *connection, + const char *name, + gpointer user_data) +{ + meta_topic (META_DEBUG_DBUS, "Lost or failed to acquire name %s\n", name); +} + +static void +initialize_dbus_interface (MetaMonitorManager *manager) +{ + manager->dbus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION, + "org.gnome.Mutter.DisplayConfig", + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | + (meta_get_replace_current_wm () ? + G_BUS_NAME_OWNER_FLAGS_REPLACE : 0), + on_bus_acquired, + on_name_acquired, + on_name_lost, + g_object_ref (manager), + g_object_unref); +} + +static MetaMonitorManager *global_monitor_manager; void meta_monitor_manager_initialize (Display *display) { - global_manager = meta_monitor_manager_new (display); + global_monitor_manager = meta_monitor_manager_new (display); + + initialize_dbus_interface (global_monitor_manager); } MetaMonitorManager * meta_monitor_manager_get (void) { - g_assert (global_manager != NULL); + g_assert (global_monitor_manager != NULL); - return global_manager; + return global_monitor_manager; } MetaMonitorInfo * @@ -338,19 +744,27 @@ void meta_monitor_manager_invalidate (MetaMonitorManager *manager) { MetaOutput *old_outputs; + MetaCRTC *old_crtcs; MetaMonitorInfo *old_monitor_infos; + MetaMonitorMode *old_modes; int n_old_outputs; - /* Save the old monitor infos, so they stay valid during the update */ + /* Save the old structures, so they stay valid during the update */ old_outputs = manager->outputs; n_old_outputs = manager->n_outputs; old_monitor_infos = manager->monitor_infos; + old_modes = manager->modes; + old_crtcs = manager->crtcs; + manager->serial ++; read_current_config (manager); + make_logical_config (manager); g_signal_emit (manager, signals[MONITORS_CHANGED], 0); g_free (old_monitor_infos); free_output_array (old_outputs, n_old_outputs); + g_free (old_modes); + g_free (old_crtcs); } diff --git a/src/core/util.c b/src/core/util.c index 92a33e453..e36353f64 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -332,6 +332,8 @@ topic_name (MetaDebugTopic topic) return "COMPOSITOR"; case META_DEBUG_EDGE_RESISTANCE: return "EDGE_RESISTANCE"; + case META_DEBUG_DBUS: + return "DBUS"; case META_DEBUG_VERBOSE: return "VERBOSE"; } diff --git a/src/meta/util.h b/src/meta/util.h index be87190b0..65062653f 100644 --- a/src/meta/util.h +++ b/src/meta/util.h @@ -100,7 +100,8 @@ typedef enum META_DEBUG_RESIZING = 1 << 18, META_DEBUG_SHAPES = 1 << 19, META_DEBUG_COMPOSITOR = 1 << 20, - META_DEBUG_EDGE_RESISTANCE = 1 << 21 + META_DEBUG_EDGE_RESISTANCE = 1 << 21, + META_DEBUG_DBUS = 1 << 22 } MetaDebugTopic; void meta_topic_real (MetaDebugTopic topic, diff --git a/src/xrandr.xml b/src/xrandr.xml new file mode 100644 index 000000000..4812267c0 --- /dev/null +++ b/src/xrandr.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + +