MonitorConfig: add CRTC assignment

Ripped off libgnome-desktop, trimming the parts that checked
that the configuration was plausible, as that should be done
in gnome-control-center before asking mutter for a change.

https://bugzilla.gnome.org/show_bug.cgi?id=705670
This commit is contained in:
Giovanni Campagna 2013-07-24 18:01:31 +02:00 committed by Giovanni Campagna
parent 8f4621240a
commit d0529b7482
3 changed files with 510 additions and 95 deletions

View File

@ -25,6 +25,15 @@
* 02111-1307, USA. * 02111-1307, USA.
*/ */
/*
* Portions of this file are derived from gnome-desktop/libgnome-desktop/gnome-rr-config.c
*
* Copyright 2007, 2008, Red Hat, Inc.
* Copyright 2010 Giovanni Campagna
*
* Author: Soren Sandmann <sandmann@redhat.com>
*/
#include "config.h" #include "config.h"
#include <string.h> #include <string.h>
@ -90,6 +99,11 @@ struct _MetaMonitorConfigClass {
G_DEFINE_TYPE (MetaMonitorConfig, meta_monitor_config, G_TYPE_OBJECT); G_DEFINE_TYPE (MetaMonitorConfig, meta_monitor_config, G_TYPE_OBJECT);
static gboolean meta_monitor_config_assign_crtcs (MetaConfiguration *config,
MetaMonitorManager *manager,
GPtrArray *crtcs,
GPtrArray *outputs);
static void static void
free_output_key (MetaOutputKey *key) free_output_key (MetaOutputKey *key)
{ {
@ -774,35 +788,37 @@ meta_monitor_config_get_stored (MetaMonitorConfig *self,
return stored; return stored;
} }
static void static gboolean
make_crtcs (MetaConfiguration *config,
MetaMonitorManager *manager,
GVariant **crtcs,
GVariant **outputs)
{
*crtcs = NULL;
*outputs = NULL;
/* FIXME */
}
static void
apply_configuration (MetaMonitorConfig *self, apply_configuration (MetaMonitorConfig *self,
MetaConfiguration *config, MetaConfiguration *config,
MetaMonitorManager *manager, MetaMonitorManager *manager,
gboolean stored) gboolean stored)
{ {
GVariant *crtcs, *outputs; GPtrArray *crtcs, *outputs;
make_crtcs (config, manager, &crtcs, &outputs); crtcs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_crtc_info_free);
meta_monitor_manager_apply_configuration (manager, crtcs, outputs); outputs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_output_info_free);
if (!meta_monitor_config_assign_crtcs (config, manager, crtcs, outputs))
{
g_ptr_array_unref (crtcs);
g_ptr_array_unref (outputs);
return FALSE;
}
meta_monitor_manager_apply_configuration (manager,
(MetaCRTCInfo**)crtcs->pdata, crtcs->len,
(MetaOutputInfo**)outputs->pdata, outputs->len);
if (self->current && !self->current_is_stored) if (self->current && !self->current_is_stored)
config_free (self->current); config_free (self->current);
self->current = config; self->current = config;
self->current_is_stored = stored; self->current_is_stored = stored;
g_variant_unref (crtcs); g_ptr_array_unref (crtcs);
g_variant_unref (outputs); g_ptr_array_unref (outputs);
return TRUE;
} }
gboolean gboolean
@ -818,8 +834,7 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
if (stored) if (stored)
{ {
apply_configuration (self, stored, manager, TRUE); return apply_configuration (self, stored, manager, TRUE);
return TRUE;
} }
else else
return FALSE; return FALSE;
@ -1039,3 +1054,329 @@ meta_monitor_config_make_persistent (MetaMonitorConfig *self)
meta_monitor_config_save (self); meta_monitor_config_save (self);
} }
/*
* CRTC assignment
*/
typedef struct
{
MetaConfiguration *config;
MetaMonitorManager *manager;
GHashTable *info;
} CrtcAssignment;
static gboolean
output_can_clone (MetaOutput *output,
MetaOutput *clone)
{
unsigned int i;
for (i = 0; i < output->n_possible_clones; i++)
if (output->possible_clones[i] == clone)
return TRUE;
return FALSE;
}
static gboolean
can_clone (MetaCRTCInfo *info,
MetaOutput *output)
{
unsigned int i;
for (i = 0; i < info->outputs->len; ++i)
{
MetaOutput *clone = info->outputs->pdata[i];
if (!output_can_clone (clone, output))
return FALSE;
}
return TRUE;
}
static gboolean
crtc_can_drive_output (MetaCRTC *crtc,
MetaOutput *output)
{
unsigned int i;
for (i = 0; i < output->n_possible_crtcs; i++)
if (output->possible_crtcs[i] == crtc)
return TRUE;
return FALSE;
}
static gboolean
output_supports_mode (MetaOutput *output,
MetaMonitorMode *mode)
{
unsigned int i;
for (i = 0; i < output->n_modes; i++)
if (output->modes[i] == mode)
return TRUE;
return FALSE;
}
static gboolean
crtc_assignment_assign (CrtcAssignment *assign,
MetaCRTC *crtc,
MetaMonitorMode *mode,
int x,
int y,
enum wl_output_transform transform,
MetaOutput *output)
{
MetaCRTCInfo *info = g_hash_table_lookup (assign->info, crtc);
if (!crtc_can_drive_output (crtc, output))
return FALSE;
if (!output_supports_mode (output, mode))
return FALSE;
if ((crtc->all_transforms & (1 << transform)) == 0)
return FALSE;
if (info)
{
if (!(info->mode == mode &&
info->x == x &&
info->y == y &&
info->transform == transform))
return FALSE;
if (!can_clone (info, output))
return FALSE;
g_ptr_array_add (info->outputs, output);
return TRUE;
}
else
{
MetaCRTCInfo *info = g_slice_new0 (MetaCRTCInfo);
info->crtc = crtc;
info->mode = mode;
info->x = x;
info->y = y;
info->transform = transform;
info->outputs = g_ptr_array_new ();
g_ptr_array_add (info->outputs, output);
g_hash_table_insert (assign->info, crtc, info);
return TRUE;
}
}
static void
crtc_assignment_unassign (CrtcAssignment *assign,
MetaCRTC *crtc,
MetaOutput *output)
{
MetaCRTCInfo *info = g_hash_table_lookup (assign->info, crtc);
if (info)
{
g_ptr_array_remove (info->outputs, output);
if (info->outputs->len == 0)
g_hash_table_remove (assign->info, crtc);
}
}
static MetaOutput *
find_output_by_key (MetaOutput *outputs,
unsigned int n_outputs,
MetaOutputKey *key)
{
unsigned int i;
for (i = 0; i < n_outputs; i++)
{
if (strcmp (outputs[i].name, key->connector) == 0)
{
/* This should be checked a lot earlier! */
g_warn_if_fail (strcmp (outputs[i].vendor, key->vendor) == 0 &&
strcmp (outputs[i].product, key->product) == 0 &&
strcmp (outputs[i].serial, key->serial) == 0);
return &outputs[i];
}
}
/* Just to satisfy GCC - this is a fatal error if occurs */
return NULL;
}
/* Check whether the given set of settings can be used
* at the same time -- ie. whether there is an assignment
* of CRTC's to outputs.
*
* Brute force - the number of objects involved is small
* enough that it doesn't matter.
*/
static gboolean
real_assign_crtcs (CrtcAssignment *assignment,
unsigned int output_num)
{
MetaMonitorMode *modes;
MetaCRTC *crtcs;
MetaOutput *outputs;
unsigned int n_crtcs, n_modes, n_outputs;
MetaOutputKey *output_key;
MetaOutputConfig *output_config;
unsigned int i;
gboolean success;
if (output_num == assignment->config->n_outputs)
return TRUE;
output_key = &assignment->config->keys[output_num];
output_config = &assignment->config->outputs[output_num];
/* It is always allowed for an output to be turned off */
if (!output_config->enabled)
return real_assign_crtcs (assignment, output_num + 1);
meta_monitor_manager_get_resources (assignment->manager,
&modes, &n_modes,
&crtcs, &n_crtcs,
&outputs, &n_outputs);
success = FALSE;
for (i = 0; i < n_crtcs; i++)
{
MetaCRTC *crtc = &crtcs[i];
unsigned int pass;
/* Make two passes, one where frequencies must match, then
* one where they don't have to
*/
for (pass = 0; pass < 2; pass++)
{
MetaOutput *output = find_output_by_key (outputs, n_outputs, output_key);
unsigned int j;
for (j = 0; j < n_modes; j++)
{
MetaMonitorMode *mode = &modes[j];
int width, height;
if (meta_monitor_transform_is_rotated (output_config->transform))
{
width = mode->height;
height = mode->width;
}
else
{
width = mode->width;
height = mode->height;
}
if (width == output_config->rect.width &&
height == output_config->rect.height &&
(pass == 1 || mode->refresh_rate == output_config->refresh_rate))
{
meta_verbose ("CRTC %ld: trying mode %dx%d@%fHz with output at %dx%d@%fHz (transform %d) (pass %d)\n",
crtc->crtc_id,
mode->width, mode->height, mode->refresh_rate,
output_config->rect.width, output_config->rect.height, output_config->refresh_rate,
output_config->transform,
pass);
if (crtc_assignment_assign (assignment, crtc, &modes[j],
output_config->rect.x, output_config->rect.y,
output_config->transform,
output))
{
if (real_assign_crtcs (assignment, output_num + 1))
{
success = TRUE;
goto out;
}
crtc_assignment_unassign (assignment, crtc, output);
}
}
}
}
}
out:
if (!success)
meta_warning ("Could not assign CRTC to outputs, ignoring configuration\n");
return success;
}
static gboolean
meta_monitor_config_assign_crtcs (MetaConfiguration *config,
MetaMonitorManager *manager,
GPtrArray *crtcs,
GPtrArray *outputs)
{
CrtcAssignment assignment;
GHashTableIter iter;
MetaCRTC *crtc;
MetaCRTCInfo *info;
unsigned int i;
MetaOutput *all_outputs;
unsigned int n_outputs;
assignment.config = config;
assignment.manager = manager;
assignment.info = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)meta_crtc_info_free);
if (!real_assign_crtcs (&assignment, 0))
{
g_hash_table_destroy (assignment.info);
return FALSE;
}
g_hash_table_iter_init (&iter, assignment.info);
while (g_hash_table_iter_next (&iter, (void**)&crtc, (void**)&info))
{
g_hash_table_iter_steal (&iter);
g_ptr_array_add (crtcs, info);
}
all_outputs = meta_monitor_manager_get_outputs (manager,
&n_outputs);
g_assert (n_outputs == config->n_outputs);
for (i = 0; i < n_outputs; i++)
{
MetaOutputInfo *output_info = g_slice_new (MetaOutputInfo);
MetaOutputConfig *output_config = &config->outputs[0];
output_info->output = find_output_by_key (all_outputs, n_outputs,
&config->keys[0]);
output_info->is_primary = output_config->is_primary;
output_info->is_presentation = output_config->is_presentation;
g_ptr_array_add (outputs, output_info);
}
g_hash_table_destroy (assignment.info);
return TRUE;
}
void
meta_crtc_info_free (MetaCRTCInfo *info)
{
g_ptr_array_free (info->outputs, TRUE);
g_slice_free (MetaCRTCInfo, info);
}
void
meta_output_info_free (MetaOutputInfo *info)
{
g_slice_free (MetaOutputInfo, info);
}

View File

@ -65,6 +65,8 @@ typedef struct _MetaOutput MetaOutput;
typedef struct _MetaCRTC MetaCRTC; typedef struct _MetaCRTC MetaCRTC;
typedef struct _MetaMonitorMode MetaMonitorMode; typedef struct _MetaMonitorMode MetaMonitorMode;
typedef struct _MetaMonitorInfo MetaMonitorInfo; typedef struct _MetaMonitorInfo MetaMonitorInfo;
typedef struct _MetaCRTCInfo MetaCRTCInfo;
typedef struct _MetaOutputInfo MetaOutputInfo;
struct _MetaOutput struct _MetaOutput
{ {
@ -161,6 +163,33 @@ struct _MetaMonitorInfo
glong output_id; glong output_id;
}; };
/*
* MetaCRTCInfo:
* This represents the writable part of a CRTC, as deserialized from DBus
* or built by MetaMonitorConfig
*
* Note: differently from the other structures in this file, MetaCRTCInfo
* is handled by pointer. This is to accomodate the usage in MetaMonitorConfig
*/
struct _MetaCRTCInfo {
MetaCRTC *crtc;
MetaMonitorMode *mode;
int x;
int y;
enum wl_output_transform transform;
GPtrArray *outputs;
};
/*
* MetaOutputInfo:
* this is the same as MetaOutputInfo, but for CRTCs
*/
struct _MetaOutputInfo {
MetaOutput *output;
gboolean is_primary;
gboolean is_presentation;
};
#define META_TYPE_MONITOR_MANAGER (meta_monitor_manager_get_type ()) #define META_TYPE_MONITOR_MANAGER (meta_monitor_manager_get_type ())
#define META_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManager)) #define META_MONITOR_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, MetaMonitorManager))
#define META_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass)) #define META_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_MONITOR_MANAGER, MetaMonitorManagerClass))
@ -182,6 +211,14 @@ MetaMonitorInfo *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *
MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager, MetaOutput *meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
unsigned int *n_outputs); unsigned int *n_outputs);
void meta_monitor_manager_get_resources (MetaMonitorManager *manager,
MetaMonitorMode **modes,
unsigned int *n_modes,
MetaCRTC **crtcs,
unsigned int *n_crtcs,
MetaOutput **outputs,
unsigned int *n_outputs);
int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager); int meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
gboolean meta_monitor_manager_handle_xevent (MetaMonitorManager *manager, gboolean meta_monitor_manager_handle_xevent (MetaMonitorManager *manager,
@ -191,9 +228,11 @@ void meta_monitor_manager_get_screen_size (MetaMonitorManager *
int *width, int *width,
int *height); int *height);
void meta_monitor_manager_apply_configuration (MetaMonitorManager *manager, void meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
GVariant *crtcs, MetaCRTCInfo **crtcs,
GVariant *outputs); unsigned int n_crtcs,
MetaOutputInfo **outputs,
unsigned int n_outputs);
#define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ()) #define META_TYPE_MONITOR_CONFIG (meta_monitor_config_get_type ())
#define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig)) #define META_MONITOR_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, MetaMonitorConfig))
@ -222,6 +261,9 @@ void meta_monitor_config_update_current (MetaMonitorConfig *confi
MetaMonitorManager *manager); MetaMonitorManager *manager);
void meta_monitor_config_make_persistent (MetaMonitorConfig *config); void meta_monitor_config_make_persistent (MetaMonitorConfig *config);
void meta_crtc_info_free (MetaCRTCInfo *info);
void meta_output_info_free (MetaOutputInfo *info);
/* Returns true if transform causes width and height to be inverted /* Returns true if transform causes width and height to be inverted
This is true for the odd transforms in the enum */ This is true for the odd transforms in the enum */
static inline gboolean static inline gboolean

View File

@ -1160,22 +1160,20 @@ wl_transform_to_xrandr (enum wl_output_transform transform)
static void static void
apply_config_xrandr (MetaMonitorManager *manager, apply_config_xrandr (MetaMonitorManager *manager,
GVariantIter *crtcs, MetaCRTCInfo **crtcs,
GVariantIter *outputs) unsigned int n_crtcs,
MetaOutputInfo **outputs,
unsigned int n_outputs)
{ {
GVariant *nested_outputs, *properties;
guint crtc_id, output_id, transform;
int new_mode, x, y;
unsigned i; unsigned i;
while (g_variant_iter_loop (crtcs, "(uiiiu@aua{sv})", for (i = 0; i < n_crtcs; i++)
&crtc_id, &new_mode, &x, &y,
&transform, &nested_outputs, NULL))
{ {
MetaCRTC *crtc = &manager->crtcs[crtc_id]; MetaCRTCInfo *crtc_info = crtcs[i];
MetaCRTC *crtc = crtc_info->crtc;
crtc->is_dirty = TRUE; crtc->is_dirty = TRUE;
if (new_mode == -1) if (crtc_info->mode == NULL)
{ {
XRRSetCrtcConfig (manager->xdisplay, XRRSetCrtcConfig (manager->xdisplay,
manager->resources, manager->resources,
@ -1190,54 +1188,47 @@ apply_config_xrandr (MetaMonitorManager *manager,
{ {
MetaMonitorMode *mode; MetaMonitorMode *mode;
XID *outputs; XID *outputs;
int i, n_outputs; int j, n_outputs;
guint output_id;
Status ok; Status ok;
mode = &manager->modes[new_mode]; mode = crtc_info->mode;
n_outputs = g_variant_n_children (nested_outputs); n_outputs = crtc_info->outputs->len;
outputs = g_new (XID, n_outputs); outputs = g_new (XID, n_outputs);
for (i = 0; i < n_outputs; i++) for (j = 0; j < n_outputs; j++)
{ outputs[i] = ((MetaOutput**)crtc_info->outputs->pdata)[i]->output_id;
g_variant_get_child (nested_outputs, i, "u", &output_id);
outputs[i] = manager->outputs[output_id].output_id;
}
meta_error_trap_push (meta_get_display ()); meta_error_trap_push (meta_get_display ());
ok = XRRSetCrtcConfig (manager->xdisplay, ok = XRRSetCrtcConfig (manager->xdisplay,
manager->resources, manager->resources,
(XID)crtc->crtc_id, (XID)crtc->crtc_id,
manager->time, manager->time,
x, y, crtc_info->x, crtc_info->y,
(XID)mode->mode_id, (XID)mode->mode_id,
wl_transform_to_xrandr (transform), wl_transform_to_xrandr (crtc_info->transform),
outputs, n_outputs); outputs, n_outputs);
meta_error_trap_pop (meta_get_display ()); meta_error_trap_pop (meta_get_display ());
if (ok != Success) if (ok != Success)
meta_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transfrom %u failed\n", meta_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transfrom %u failed\n",
(unsigned)(crtc->crtc_id), (unsigned)(mode->mode_id), (unsigned)(crtc->crtc_id), (unsigned)(mode->mode_id),
mode->width, mode->height, (float)mode->refresh_rate, x, y, transform); mode->width, mode->height, (float)mode->refresh_rate,
crtc_info->x, crtc_info->y, crtc_info->transform);
g_free (outputs); g_free (outputs);
} }
} }
while (g_variant_iter_loop (outputs, "(u@a{sv})", for (i = 0; i < n_outputs; i++)
&output_id, &properties))
{ {
gboolean primary; MetaOutputInfo *output_info = outputs[i];
if (g_variant_lookup (properties, "primary", "b", &primary) && primary) if (output_info->is_primary)
{ {
MetaOutput *output = &manager->outputs[output_id];
XRRSetOutputPrimary (manager->xdisplay, XRRSetOutputPrimary (manager->xdisplay,
DefaultRootWindow (manager->xdisplay), DefaultRootWindow (manager->xdisplay),
(XID)output->output_id); (XID)output_info->output->output_id);
} }
} }
@ -1268,23 +1259,21 @@ apply_config_xrandr (MetaMonitorManager *manager,
static void static void
apply_config_dummy (MetaMonitorManager *manager, apply_config_dummy (MetaMonitorManager *manager,
GVariantIter *crtcs, MetaCRTCInfo **crtcs,
GVariantIter *outputs) unsigned int n_crtcs,
MetaOutputInfo **outputs,
unsigned int n_outputs)
{ {
GVariant *nested_outputs, *properties;
guint crtc_id, output_id, transform;
int new_mode, x, y;
unsigned i; unsigned i;
int screen_width = 0, screen_height = 0; int screen_width = 0, screen_height = 0;
while (g_variant_iter_loop (crtcs, "(uiiiu@aua{sv})", for (i = 0; i < n_crtcs; i++)
&crtc_id, &new_mode, &x, &y,
&transform, &nested_outputs, NULL))
{ {
MetaCRTC *crtc = &manager->crtcs[crtc_id]; MetaCRTCInfo *crtc_info = crtcs[i];
MetaCRTC *crtc = crtc_info->crtc;
crtc->is_dirty = TRUE; crtc->is_dirty = TRUE;
if (new_mode == -1) if (crtc_info->mode == NULL)
{ {
crtc->rect.x = 0; crtc->rect.x = 0;
crtc->rect.y = 0; crtc->rect.y = 0;
@ -1297,12 +1286,11 @@ apply_config_dummy (MetaMonitorManager *manager,
MetaMonitorMode *mode; MetaMonitorMode *mode;
MetaOutput *output; MetaOutput *output;
int i, n_outputs; int i, n_outputs;
guint output_id;
int width, height; int width, height;
mode = &manager->modes[new_mode]; mode = crtc_info->mode;
if (meta_monitor_transform_is_rotated (transform)) if (meta_monitor_transform_is_rotated (crtc_info->transform))
{ {
width = mode->height; width = mode->height;
height = mode->width; height = mode->width;
@ -1313,22 +1301,20 @@ apply_config_dummy (MetaMonitorManager *manager,
height = mode->height; height = mode->height;
} }
crtc->rect.x = x; crtc->rect.x = crtc_info->x;
crtc->rect.y = y; crtc->rect.y = crtc_info->y;
crtc->rect.width = width; crtc->rect.width = width;
crtc->rect.height = height; crtc->rect.height = height;
crtc->current_mode = mode; crtc->current_mode = mode;
crtc->transform = transform; crtc->transform = crtc_info->transform;
screen_width = MAX (screen_width, x + width); screen_width = MAX (screen_width, crtc_info->x + width);
screen_height = MAX (screen_height, y + height); screen_height = MAX (screen_height, crtc_info->y + height);
n_outputs = g_variant_n_children (nested_outputs); n_outputs = crtc_info->outputs->len;
for (i = 0; i < n_outputs; i++) for (i = 0; i < n_outputs; i++)
{ {
g_variant_get_child (nested_outputs, i, "u", &output_id); output = ((MetaOutput**)crtc_info->outputs->pdata)[i];
output = &manager->outputs[output_id];
output->is_dirty = TRUE; output->is_dirty = TRUE;
output->crtc = crtc; output->crtc = crtc;
@ -1336,17 +1322,13 @@ apply_config_dummy (MetaMonitorManager *manager,
} }
} }
while (g_variant_iter_loop (outputs, "(u@a{sv})", for (i = 0; i < n_outputs; i++)
&output_id, &properties))
{ {
MetaOutput *output = &manager->outputs[output_id]; MetaOutputInfo *output_info = outputs[i];
gboolean primary, presentation; MetaOutput *output = output_info->output;
if (g_variant_lookup (properties, "primary", "b", &primary)) output->is_primary = output_info->is_primary;
output->is_primary = primary; output->is_presentation = output_info->is_presentation;
if (g_variant_lookup (properties, "presentation", "b", &presentation))
output->is_presentation = presentation;
} }
/* Disable CRTCs not mentioned in the list */ /* Disable CRTCs not mentioned in the list */
@ -1392,18 +1374,15 @@ apply_config_dummy (MetaMonitorManager *manager,
void void
meta_monitor_manager_apply_configuration (MetaMonitorManager *manager, meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
GVariant *crtcs, MetaCRTCInfo **crtcs,
GVariant *outputs) unsigned int n_crtcs,
MetaOutputInfo **outputs,
unsigned int n_outputs)
{ {
GVariantIter crtc_iter, output_iter;
g_variant_iter_init (&crtc_iter, crtcs);
g_variant_iter_init (&output_iter, outputs);
if (manager->backend == META_BACKEND_XRANDR) if (manager->backend == META_BACKEND_XRANDR)
apply_config_xrandr (manager, &crtc_iter, &output_iter); apply_config_xrandr (manager, crtcs, n_crtcs, outputs, n_outputs);
else else
apply_config_dummy (manager, &crtc_iter, &output_iter); apply_config_dummy (manager, crtcs, n_crtcs, outputs, n_outputs);
} }
static gboolean static gboolean
@ -1426,10 +1405,12 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
{ {
MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton); MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
GVariantIter crtc_iter, output_iter, *nested_outputs; GVariantIter crtc_iter, output_iter, *nested_outputs;
GVariant *properties;
guint crtc_id; guint crtc_id;
int new_mode, x, y; int new_mode, x, y;
guint transform; guint transform;
guint output_id; guint output_id;
GPtrArray *crtc_infos, *output_infos;
if (serial != manager->serial) if (serial != manager->serial)
{ {
@ -1439,17 +1420,26 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
return TRUE; return TRUE;
} }
crtc_infos = g_ptr_array_new_full (g_variant_n_children (crtcs),
(GDestroyNotify) meta_crtc_info_free);
output_infos = g_ptr_array_new_full (g_variant_n_children (outputs),
(GDestroyNotify) meta_output_info_free);
/* Validate all arguments */ /* Validate all arguments */
g_variant_iter_init (&crtc_iter, crtcs); g_variant_iter_init (&crtc_iter, crtcs);
while (g_variant_iter_loop (&crtc_iter, "(uiiiuaua{sv})", while (g_variant_iter_loop (&crtc_iter, "(uiiiuaua{sv})",
&crtc_id, &new_mode, &x, &y, &transform, &crtc_id, &new_mode, &x, &y, &transform,
&nested_outputs, NULL)) &nested_outputs, NULL))
{ {
MetaCRTCInfo *crtc_info;
MetaOutput *first_output; MetaOutput *first_output;
MetaCRTC *crtc; MetaCRTC *crtc;
MetaMonitorMode *mode; MetaMonitorMode *mode;
guint output_id; guint output_id;
crtc_info = g_slice_new (MetaCRTCInfo);
crtc_info->outputs = g_ptr_array_new ();
if (crtc_id >= manager->n_crtcs) if (crtc_id >= manager->n_crtcs)
{ {
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@ -1458,6 +1448,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
return TRUE; return TRUE;
} }
crtc = &manager->crtcs[crtc_id]; crtc = &manager->crtcs[crtc_id];
crtc_info->crtc = crtc;
if (new_mode != -1 && (new_mode < 0 || (unsigned)new_mode >= manager->n_modes)) if (new_mode != -1 && (new_mode < 0 || (unsigned)new_mode >= manager->n_modes))
{ {
@ -1467,6 +1458,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
return TRUE; return TRUE;
} }
mode = new_mode != -1 ? &manager->modes[new_mode] : NULL; mode = new_mode != -1 ? &manager->modes[new_mode] : NULL;
crtc_info->mode = mode;
if (mode) if (mode)
{ {
@ -1494,6 +1486,8 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
return TRUE; return TRUE;
} }
} }
crtc_info->x = x;
crtc_info->y = y;
if (transform < WL_OUTPUT_TRANSFORM_NORMAL || if (transform < WL_OUTPUT_TRANSFORM_NORMAL ||
transform > WL_OUTPUT_TRANSFORM_FLIPPED_270 || transform > WL_OUTPUT_TRANSFORM_FLIPPED_270 ||
@ -1504,6 +1498,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
"Invalid transform"); "Invalid transform");
return TRUE; return TRUE;
} }
crtc_info->transform = transform;
first_output = NULL; first_output = NULL;
while (g_variant_iter_loop (nested_outputs, "u", &output_id)) while (g_variant_iter_loop (nested_outputs, "u", &output_id))
@ -1526,6 +1521,7 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
"Output cannot be assigned to this CRTC or mode"); "Output cannot be assigned to this CRTC or mode");
return TRUE; return TRUE;
} }
g_ptr_array_add (crtc_info->outputs, output);
if (first_output) if (first_output)
{ {
@ -1551,8 +1547,11 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
} }
g_variant_iter_init (&output_iter, outputs); g_variant_iter_init (&output_iter, outputs);
while (g_variant_iter_loop (&output_iter, "(ua{sv})", &output_id, NULL)) while (g_variant_iter_loop (&output_iter, "(u@a{sv})", &output_id, &properties))
{ {
MetaOutputInfo *output_info;
gboolean primary, presentation;
if (output_id >= manager->n_outputs) if (output_id >= manager->n_outputs)
{ {
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@ -1560,6 +1559,15 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
"Invalid output id"); "Invalid output id");
return TRUE; return TRUE;
} }
output_info = g_slice_new0 (MetaOutputInfo);
output_info->output = &manager->outputs[output_id];
if (g_variant_lookup (properties, "primary", "b", &primary))
output_info->is_primary = primary;
if (g_variant_lookup (properties, "presentation", "b", &presentation))
output_info->is_presentation = presentation;
} }
/* If we were in progress of making a persistent change and we see a /* If we were in progress of making a persistent change and we see a
@ -1572,7 +1580,14 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
manager->persistent_timeout_id = 0; manager->persistent_timeout_id = 0;
} }
meta_monitor_manager_apply_configuration (manager, crtcs, outputs); meta_monitor_manager_apply_configuration (manager,
(MetaCRTCInfo**)crtc_infos->pdata,
crtc_infos->len,
(MetaOutputInfo**)output_infos->pdata,
output_infos->len);
g_ptr_array_unref (crtc_infos);
g_ptr_array_unref (output_infos);
/* Update MetaMonitorConfig data structures immediately so that we /* Update MetaMonitorConfig data structures immediately so that we
don't revert the change at the next XRandR event, then wait 20 don't revert the change at the next XRandR event, then wait 20
@ -1671,6 +1686,23 @@ meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
return manager->outputs; return manager->outputs;
} }
void
meta_monitor_manager_get_resources (MetaMonitorManager *manager,
MetaMonitorMode **modes,
unsigned int *n_modes,
MetaCRTC **crtcs,
unsigned int *n_crtcs,
MetaOutput **outputs,
unsigned int *n_outputs)
{
*modes = manager->modes;
*n_modes = manager->n_modes;
*crtcs = manager->crtcs;
*n_crtcs = manager->n_crtcs;
*outputs = manager->outputs;
*n_outputs = manager->n_outputs;
}
int int
meta_monitor_manager_get_primary_index (MetaMonitorManager *manager) meta_monitor_manager_get_primary_index (MetaMonitorManager *manager)
{ {