mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
MonitorConfig: add support for default configurations
Activate the presentation bit on new hotplugged monitors, while making a fully extended setup when running for the first time.
This commit is contained in:
parent
7764e1f3ff
commit
25f82424b8
@ -740,16 +740,21 @@ init_key_from_output (MetaOutputKey *key,
|
||||
static void
|
||||
make_config_key (MetaConfiguration *key,
|
||||
MetaOutput *outputs,
|
||||
unsigned n_outputs)
|
||||
unsigned n_outputs,
|
||||
unsigned skip)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int o, i;
|
||||
|
||||
key->n_outputs = n_outputs;
|
||||
key->outputs = NULL;
|
||||
key->keys = g_new0 (MetaOutputKey, n_outputs);
|
||||
|
||||
for (i = 0; i < key->n_outputs; i++)
|
||||
init_key_from_output (&key->keys[i], &outputs[i]);
|
||||
for (o = 0, i = 0; i < n_outputs; o++, i++)
|
||||
if (i == skip)
|
||||
o--;
|
||||
else
|
||||
init_key_from_output (&key->keys[o], &outputs[i]);
|
||||
|
||||
key->n_outputs = o;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -766,7 +771,7 @@ meta_monitor_config_match_current (MetaMonitorConfig *self,
|
||||
|
||||
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
|
||||
|
||||
make_config_key (&key, outputs, n_outputs);
|
||||
make_config_key (&key, outputs, n_outputs, -1);
|
||||
ok = config_equal (&key, self->current);
|
||||
|
||||
config_clear (&key);
|
||||
@ -781,7 +786,7 @@ meta_monitor_config_get_stored (MetaMonitorConfig *self,
|
||||
MetaConfiguration key;
|
||||
MetaConfiguration *stored;
|
||||
|
||||
make_config_key (&key, outputs, n_outputs);
|
||||
make_config_key (&key, outputs, n_outputs, -1);
|
||||
stored = g_hash_table_lookup (self->configs, &key);
|
||||
|
||||
config_clear (&key);
|
||||
@ -840,12 +845,220 @@ meta_monitor_config_apply_stored (MetaMonitorConfig *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static MetaConfiguration *
|
||||
make_default_config (MetaOutput *outputs,
|
||||
/*
|
||||
* Tries to find the primary output according to the current layout,
|
||||
* or failing that, an output that is good to be a primary (LVDS or eDP,
|
||||
* which are internal monitors), or failing that, the one with the
|
||||
* best resolution
|
||||
*
|
||||
* Input assertions: there is at least one output
|
||||
*/
|
||||
static MetaOutput *
|
||||
find_primary_output (MetaOutput *outputs,
|
||||
unsigned n_outputs)
|
||||
{
|
||||
/* FIXME */
|
||||
return NULL;
|
||||
unsigned i;
|
||||
MetaOutput *best;
|
||||
int best_width, best_height;
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
if (outputs[i].is_primary)
|
||||
return &outputs[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
if (g_str_has_prefix (outputs[i].name, "LVDS") ||
|
||||
g_str_has_prefix (outputs[i].name, "eDP"))
|
||||
return &outputs[i];
|
||||
}
|
||||
|
||||
best = NULL;
|
||||
best_width = 0; best_height = 0;
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
if (outputs[i].preferred_mode->width * outputs[i].preferred_mode->height >
|
||||
best_width * best_height)
|
||||
{
|
||||
best = &outputs[i];
|
||||
best_width = outputs[i].preferred_mode->width;
|
||||
best_height = outputs[i].preferred_mode->height;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
static MetaConfiguration *
|
||||
make_default_config (MetaMonitorConfig *self,
|
||||
MetaOutput *outputs,
|
||||
unsigned n_outputs,
|
||||
int max_width,
|
||||
int max_height)
|
||||
{
|
||||
unsigned i, j;
|
||||
int x, y;
|
||||
MetaConfiguration *ret;
|
||||
MetaOutput *primary;
|
||||
|
||||
ret = g_slice_new (MetaConfiguration);
|
||||
make_config_key (ret, outputs, n_outputs, -1);
|
||||
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
|
||||
|
||||
/* Special case the simple case: one output, primary at preferred mode,
|
||||
nothing else to do */
|
||||
if (n_outputs == 1)
|
||||
{
|
||||
ret->outputs[0].enabled = TRUE;
|
||||
ret->outputs[0].rect.x = 0;
|
||||
ret->outputs[0].rect.y = 0;
|
||||
ret->outputs[0].rect.width = outputs[0].preferred_mode->width;
|
||||
ret->outputs[0].rect.height = outputs[0].preferred_mode->height;
|
||||
ret->outputs[0].refresh_rate = outputs[0].preferred_mode->refresh_rate;
|
||||
ret->outputs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret->outputs[0].is_primary = TRUE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If we reach this point, this is either the first time mutter runs
|
||||
on this system ever, or we just hotplugged a new screen.
|
||||
In the latter case, search for a configuration that includes one
|
||||
less screen, then add the new one as a presentation screen
|
||||
in preferred mode.
|
||||
*/
|
||||
x = 0;
|
||||
y = 0;
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
MetaConfiguration key;
|
||||
MetaConfiguration *ref;
|
||||
|
||||
make_config_key (&key, outputs, n_outputs, i);
|
||||
ref = g_hash_table_lookup (self->configs, &key);
|
||||
config_clear (&key);
|
||||
|
||||
if (ref)
|
||||
{
|
||||
for (j = 0; j < n_outputs; j++)
|
||||
{
|
||||
if (j < i)
|
||||
{
|
||||
g_assert (output_key_equal (&ret->keys[j], &ref->keys[j]));
|
||||
ret->outputs[j] = ref->outputs[j];
|
||||
x = MAX (x, ref->outputs[j].rect.x + ref->outputs[j].rect.width);
|
||||
y = MAX (y, ref->outputs[j].rect.y + ref->outputs[j].rect.height);
|
||||
}
|
||||
else if (j > i)
|
||||
{
|
||||
g_assert (output_key_equal (&ret->keys[i], &ref->keys[j - 1]));
|
||||
ret->outputs[j] = ref->outputs[j - 1];
|
||||
x = MAX (x, ref->outputs[j - 1].rect.x + ref->outputs[j - 1].rect.width);
|
||||
y = MAX (y, ref->outputs[j - 1].rect.y + ref->outputs[j - 1].rect.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret->outputs[j].enabled = TRUE;
|
||||
ret->outputs[j].rect.x = 0;
|
||||
ret->outputs[j].rect.y = 0;
|
||||
ret->outputs[j].rect.width = outputs[0].preferred_mode->width;
|
||||
ret->outputs[j].rect.height = outputs[0].preferred_mode->height;
|
||||
ret->outputs[j].refresh_rate = outputs[0].preferred_mode->refresh_rate;
|
||||
ret->outputs[j].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret->outputs[j].is_primary = FALSE;
|
||||
ret->outputs[j].is_presentation = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Place the new output at the right end of the screen, if it fits,
|
||||
otherwise below it, otherwise disable it (or apply_configuration will fail) */
|
||||
if (x + ret->outputs[i].rect.width <= max_width)
|
||||
ret->outputs[i].rect.x = x;
|
||||
else if (y + ret->outputs[i].rect.height <= max_height)
|
||||
ret->outputs[i].rect.y = y;
|
||||
else
|
||||
ret->outputs[i].enabled = FALSE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* No previous configuration found, try with a really default one, which
|
||||
is one primary that goes first and the rest to the right of it, extended.
|
||||
*/
|
||||
primary = find_primary_output (outputs, n_outputs);
|
||||
|
||||
x = primary->preferred_mode->width;
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
MetaOutput *output = &outputs[i];
|
||||
|
||||
ret->outputs[i].enabled = TRUE;
|
||||
ret->outputs[i].rect.x = (output == primary) ? 0 : x;
|
||||
ret->outputs[i].rect.y = 0;
|
||||
ret->outputs[i].rect.width = output->preferred_mode->width;
|
||||
ret->outputs[i].rect.height = output->preferred_mode->height;
|
||||
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
|
||||
ret->outputs[i].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret->outputs[i].is_primary = (output == primary);
|
||||
|
||||
/* Disable outputs that would go beyond framebuffer limits */
|
||||
if (ret->outputs[i].rect.x + ret->outputs[i].rect.width > max_width)
|
||||
ret->outputs[i].enabled = FALSE;
|
||||
else if (output != primary)
|
||||
x += output->preferred_mode->width;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ensure_at_least_one_output (MetaMonitorConfig *self,
|
||||
MetaMonitorManager *manager,
|
||||
MetaOutput *outputs,
|
||||
unsigned n_outputs)
|
||||
{
|
||||
MetaConfiguration *ret;
|
||||
MetaOutput *primary;
|
||||
unsigned i;
|
||||
|
||||
/* Check that we have at least one active output */
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
if (outputs[i].crtc != NULL)
|
||||
return TRUE;
|
||||
|
||||
/* Oh no, we don't! Activate the primary one and disable everything else */
|
||||
|
||||
ret = g_slice_new (MetaConfiguration);
|
||||
make_config_key (ret, outputs, n_outputs, -1);
|
||||
ret->outputs = g_new0 (MetaOutputConfig, n_outputs);
|
||||
|
||||
primary = find_primary_output (outputs, n_outputs);
|
||||
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
MetaOutput *output = &outputs[i];
|
||||
|
||||
if (output == primary)
|
||||
{
|
||||
ret->outputs[i].enabled = TRUE;
|
||||
ret->outputs[i].rect.x = 0;
|
||||
ret->outputs[i].rect.y = 0;
|
||||
ret->outputs[i].rect.width = output->preferred_mode->width;
|
||||
ret->outputs[i].rect.height = output->preferred_mode->height;
|
||||
ret->outputs[i].refresh_rate = output->preferred_mode->refresh_rate;
|
||||
ret->outputs[i].transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
ret->outputs[i].is_primary = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret->outputs[i].enabled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
apply_configuration (self, ret, manager, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
@ -855,15 +1068,23 @@ meta_monitor_config_make_default (MetaMonitorConfig *self,
|
||||
MetaOutput *outputs;
|
||||
MetaConfiguration *default_config;
|
||||
unsigned n_outputs;
|
||||
gboolean ok;
|
||||
int max_width, max_height;
|
||||
|
||||
outputs = meta_monitor_manager_get_outputs (manager, &n_outputs);
|
||||
default_config = make_default_config (outputs, n_outputs);
|
||||
meta_monitor_manager_get_screen_limits (manager, &max_width, &max_height);
|
||||
|
||||
default_config = make_default_config (self, outputs, n_outputs, max_width, max_height);
|
||||
|
||||
if (default_config != NULL)
|
||||
apply_configuration (self, default_config, manager, FALSE);
|
||||
ok = apply_configuration (self, default_config, manager, FALSE);
|
||||
else
|
||||
ok = FALSE;
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
meta_warning ("Could not make default configuration for current output layout, leaving unconfigured\n");
|
||||
if (ensure_at_least_one_output (self, manager, outputs, n_outputs))
|
||||
meta_monitor_config_update_current (self, manager);
|
||||
}
|
||||
}
|
||||
@ -1297,9 +1518,6 @@ real_assign_crtcs (CrtcAssignment *assignment,
|
||||
}
|
||||
|
||||
out:
|
||||
if (!success)
|
||||
meta_warning ("Could not assign CRTC to outputs, ignoring configuration\n");
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@ -1323,6 +1541,8 @@ meta_monitor_config_assign_crtcs (MetaConfiguration *config,
|
||||
|
||||
if (!real_assign_crtcs (&assignment, 0))
|
||||
{
|
||||
meta_warning ("Could not assign CRTC to outputs, ignoring configuration\n");
|
||||
|
||||
g_hash_table_destroy (assignment.info);
|
||||
return FALSE;
|
||||
}
|
||||
@ -1341,10 +1561,10 @@ meta_monitor_config_assign_crtcs (MetaConfiguration *config,
|
||||
for (i = 0; i < n_outputs; i++)
|
||||
{
|
||||
MetaOutputInfo *output_info = g_slice_new (MetaOutputInfo);
|
||||
MetaOutputConfig *output_config = &config->outputs[0];
|
||||
MetaOutputConfig *output_config = &config->outputs[i];
|
||||
|
||||
output_info->output = find_output_by_key (all_outputs, n_outputs,
|
||||
&config->keys[0]);
|
||||
&config->keys[i]);
|
||||
output_info->is_primary = output_config->is_primary;
|
||||
output_info->is_presentation = output_config->is_presentation;
|
||||
|
||||
|
@ -229,6 +229,10 @@ void meta_monitor_manager_get_screen_size (MetaMonitorManager *
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
void meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
void meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
|
||||
MetaCRTCInfo **crtcs,
|
||||
unsigned int n_crtcs,
|
||||
|
@ -64,6 +64,7 @@ struct _MetaMonitorManager
|
||||
packed, but I like the logical organization
|
||||
of fields */
|
||||
|
||||
gboolean in_init;
|
||||
unsigned int serial;
|
||||
|
||||
MetaPowerSave power_save_mode;
|
||||
@ -501,6 +502,9 @@ read_monitor_infos_from_xrandr (MetaMonitorManager *manager)
|
||||
}
|
||||
meta_output->preferred_mode = meta_output->modes[0];
|
||||
|
||||
if (meta_output->preferred_mode == NULL)
|
||||
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++)
|
||||
@ -739,6 +743,7 @@ meta_monitor_manager_new (Display *display)
|
||||
|
||||
manager = g_object_new (META_TYPE_MONITOR_MANAGER, NULL);
|
||||
|
||||
manager->in_init = TRUE;
|
||||
manager->xdisplay = display;
|
||||
|
||||
manager->backend = make_debug_config (manager);
|
||||
@ -808,6 +813,8 @@ meta_monitor_manager_new (Display *display)
|
||||
}
|
||||
|
||||
make_logical_config (manager);
|
||||
|
||||
manager->in_init = FALSE;
|
||||
return manager;
|
||||
}
|
||||
|
||||
@ -1529,6 +1536,8 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
|
||||
"Mode specified without outputs?");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_ptr_array_add (crtc_infos, crtc_info);
|
||||
}
|
||||
|
||||
g_variant_iter_init (&output_iter, outputs);
|
||||
@ -1553,6 +1562,8 @@ meta_monitor_manager_handle_apply_configuration (MetaDBusDisplayConfig *skeleto
|
||||
|
||||
if (g_variant_lookup (properties, "presentation", "b", &presentation))
|
||||
output_info->is_presentation = presentation;
|
||||
|
||||
g_ptr_array_add (output_infos, output_info);
|
||||
}
|
||||
|
||||
/* If we were in progress of making a persistent change and we see a
|
||||
@ -1703,6 +1714,15 @@ meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
|
||||
*height = manager->screen_height;
|
||||
}
|
||||
|
||||
void
|
||||
meta_monitor_manager_get_screen_limits (MetaMonitorManager *manager,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
*width = manager->max_screen_width;
|
||||
*height = manager->max_screen_height;
|
||||
}
|
||||
|
||||
static void
|
||||
invalidate_logical_config (MetaMonitorManager *manager)
|
||||
{
|
||||
@ -1710,6 +1730,9 @@ invalidate_logical_config (MetaMonitorManager *manager)
|
||||
|
||||
old_monitor_infos = manager->monitor_infos;
|
||||
|
||||
if (manager->in_init)
|
||||
return;
|
||||
|
||||
make_logical_config (manager);
|
||||
|
||||
g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
|
||||
|
Loading…
Reference in New Issue
Block a user