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 @@ + + + + + + + + + + + + + + + +