1
0
Fork 0

monitor-config-store: Detect unkown layout modes based on the configuration

When there is no layout mode set in a logical monitor config, we currently just
assume the configuration matches the mode that the system expects. This blows
up when the layout mode expected by the system changes (eg. by turning on
"scale-monitor-framebuffers" in mutter): Suddenly configs fail the validation
check and get thrown away.

Since we now can add one configuration for each layout mode to the config store,
we can do better here: Let's only add configurations to the store where we
verified beforehand that the monitor layout is compatible with that mode, either
because we set it ourselves using the <layout_mode> key, or by detecting which
modes the layout is compatible with.

Also update monitor config ifiles to adjust for the new layout_mode, as
they all are assumed to be "logical".

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3596>
This commit is contained in:
Jonas Dreßler 2024-02-16 21:37:21 +01:00 committed by Marge Bot
parent becee89fb9
commit bbb34c2a80

View file

@ -25,6 +25,7 @@
#include <string.h>
#include "backends/meta-monitor-config-manager.h"
#include "backends/meta-monitor-config-utils.h"
#define MONITORS_CONFIG_XML_FORMAT_VERSION 2
@ -651,69 +652,6 @@ handle_start_element (GMarkupParseContext *context,
}
}
static gboolean
derive_logical_monitor_layout (MetaLogicalMonitorConfig *logical_monitor_config,
MetaLogicalMonitorLayoutMode layout_mode,
GError **error)
{
MetaMonitorConfig *monitor_config;
int mode_width, mode_height;
int width = 0, height = 0;
float scale;
GList *l;
monitor_config = logical_monitor_config->monitor_configs->data;
mode_width = monitor_config->mode_spec->width;
mode_height = monitor_config->mode_spec->height;
for (l = logical_monitor_config->monitor_configs->next; l; l = l->next)
{
monitor_config = l->data;
if (monitor_config->mode_spec->width != mode_width ||
monitor_config->mode_spec->height != mode_height)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Monitors in logical monitor incompatible");
return FALSE;
}
}
if (mtk_monitor_transform_is_rotated (logical_monitor_config->transform))
{
width = mode_height;
height = mode_width;
}
else
{
width = mode_width;
height = mode_height;
}
scale = logical_monitor_config->scale;
switch (layout_mode)
{
case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL:
width = (int) roundf (width / scale);
height = (int) roundf (height / scale);
break;
case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL:
if (!G_APPROX_VALUE (scale, roundf (scale), FLT_EPSILON))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"A fractional scale with physical layout mode not allowed");
return FALSE;
}
break;
}
logical_monitor_config->layout.width = width;
logical_monitor_config->layout.height = height;
return TRUE;
}
static void
finish_monitor_spec (ConfigParser *parser)
{
@ -742,6 +680,107 @@ finish_monitor_spec (ConfigParser *parser)
}
}
static void
get_monitor_size_with_rotation (MetaLogicalMonitorConfig *logical_monitor_config,
unsigned int *width_out,
unsigned int *height_out)
{
MetaMonitorConfig *monitor_config =
logical_monitor_config->monitor_configs->data;
if (mtk_monitor_transform_is_rotated (logical_monitor_config->transform))
{
*width_out = monitor_config->mode_spec->height;
*height_out = monitor_config->mode_spec->width;
}
else
{
*width_out = monitor_config->mode_spec->width;
*height_out = monitor_config->mode_spec->height;
}
}
static void
derive_logical_monitor_layouts (GList *logical_monitor_configs,
MetaLogicalMonitorLayoutMode layout_mode)
{
GList *l;
for (l = logical_monitor_configs; l; l = l->next)
{
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
unsigned int width, height;
get_monitor_size_with_rotation (logical_monitor_config, &width, &height);
if (layout_mode == META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL)
{
width = (int) roundf (width / logical_monitor_config->scale);
height = (int) roundf (height / logical_monitor_config->scale);
}
logical_monitor_config->layout.width = width;
logical_monitor_config->layout.height = height;
}
}
static gboolean
detect_layout_mode_configs (MetaMonitorManager *monitor_manager,
GList *logical_monitor_configs,
GList *disabled_monitor_specs,
MetaMonitorsConfigFlag config_flags,
MetaMonitorsConfig **physical_layout_mode_config,
MetaMonitorsConfig **logical_layout_mode_config,
GError **error)
{
GList *logical_monitor_configs_copy, *disabled_monitor_specs_copy;
MetaMonitorsConfig *physical_config, *logical_config;
g_autoptr (GError) local_error_physical = NULL;
g_autoptr (GError) local_error_logical = NULL;
logical_monitor_configs_copy =
meta_clone_logical_monitor_config_list (logical_monitor_configs);
disabled_monitor_specs_copy =
g_list_copy_deep (disabled_monitor_specs, (GCopyFunc) meta_monitor_spec_clone, NULL);
derive_logical_monitor_layouts (logical_monitor_configs,
META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL);
physical_config =
meta_monitors_config_new_full (g_steal_pointer (&logical_monitor_configs),
g_steal_pointer (&disabled_monitor_specs),
META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL,
config_flags);
if (!meta_verify_monitors_config (physical_config, monitor_manager,
&local_error_physical))
g_clear_object (&physical_config);
derive_logical_monitor_layouts (logical_monitor_configs_copy,
META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL);
logical_config =
meta_monitors_config_new_full (g_steal_pointer (&logical_monitor_configs_copy),
g_steal_pointer (&disabled_monitor_specs_copy),
META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL,
config_flags);
if (!meta_verify_monitors_config (logical_config, monitor_manager,
&local_error_logical))
g_clear_object (&logical_config);
if (!physical_config && !logical_config)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Detected neither physical (%s) nor logical (%s) layout mode",
local_error_physical->message, local_error_logical->message);
return FALSE;
}
*physical_layout_mode_config = physical_config;
*logical_layout_mode_config = logical_config;
return TRUE;
}
static void
handle_end_element (GMarkupParseContext *context,
const char *element_name,
@ -917,51 +956,72 @@ handle_end_element (GMarkupParseContext *context,
{
MetaMonitorConfigStore *store = parser->config_store;
MetaMonitorsConfig *config;
GList *l;
MetaLogicalMonitorLayoutMode layout_mode = parser->current_layout_mode;
MetaMonitorsConfigFlag config_flags = META_MONITORS_CONFIG_FLAG_NONE;
g_assert (g_str_equal (element_name, "configuration"));
if (!parser->is_current_layout_mode_valid)
layout_mode = meta_monitor_manager_get_default_layout_mode (store->monitor_manager);
for (l = parser->current_logical_monitor_configs; l; l = l->next)
{
MetaLogicalMonitorConfig *logical_monitor_config = l->data;
if (!derive_logical_monitor_layout (logical_monitor_config,
layout_mode,
error))
return;
if (!meta_verify_logical_monitor_config (logical_monitor_config,
layout_mode,
store->monitor_manager,
error))
return;
}
config_flags |= parser->extra_config_flags;
config =
meta_monitors_config_new_full (parser->current_logical_monitor_configs,
parser->current_disabled_monitor_specs,
layout_mode,
config_flags);
parser->current_logical_monitor_configs = NULL;
parser->current_disabled_monitor_specs = NULL;
if (!meta_verify_monitors_config (config, store->monitor_manager,
error))
if (!parser->is_current_layout_mode_valid)
{
g_object_unref (config);
return;
}
MetaMonitorsConfig *physical_layout_mode_config;
MetaMonitorsConfig *logical_layout_mode_config;
g_hash_table_replace (parser->pending_configs,
config->key, config);
if (!detect_layout_mode_configs (store->monitor_manager,
parser->current_logical_monitor_configs,
parser->current_disabled_monitor_specs,
config_flags,
&physical_layout_mode_config,
&logical_layout_mode_config,
error))
{
parser->current_logical_monitor_configs = NULL;
parser->current_disabled_monitor_specs = NULL;
return;
}
parser->current_logical_monitor_configs = NULL;
parser->current_disabled_monitor_specs = NULL;
if (physical_layout_mode_config)
{
g_hash_table_replace (parser->pending_configs,
physical_layout_mode_config->key,
physical_layout_mode_config);
}
if (logical_layout_mode_config)
{
g_hash_table_replace (parser->pending_configs,
logical_layout_mode_config->key,
logical_layout_mode_config);
}
}
else
{
derive_logical_monitor_layouts (parser->current_logical_monitor_configs,
layout_mode);
config =
meta_monitors_config_new_full (parser->current_logical_monitor_configs,
parser->current_disabled_monitor_specs,
layout_mode,
config_flags);
parser->current_logical_monitor_configs = NULL;
parser->current_disabled_monitor_specs = NULL;
if (!meta_verify_monitors_config (config, store->monitor_manager,
error))
{
g_object_unref (config);
return;
}
g_hash_table_replace (parser->pending_configs,
config->key, config);
}
parser->state = STATE_MONITORS;
return;