diff --git a/data/org.gnome.mutter.gschema.xml.in b/data/org.gnome.mutter.gschema.xml.in index 56f16cb48..0f2cd4db9 100644 --- a/data/org.gnome.mutter.gschema.xml.in +++ b/data/org.gnome.mutter.gschema.xml.in @@ -112,7 +112,14 @@ available, or configurable. Don't expect adding anything in this setting to be future proof. - Currently possible keywords: (none) + Currently possible keywords: + + * "scale-monitor-framebuffer" - makes mutter default to layout logical + monitors in a logical pixel coordinate + space, while scaling monitor + framebuffers instead of window content, + to manage HiDPI monitors. Does not + require a restart. diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h index c8d618e3f..9c1f2a0b4 100644 --- a/src/backends/meta-backend-private.h +++ b/src/backends/meta-backend-private.h @@ -100,6 +100,7 @@ struct _MetaBackendClass typedef enum _MetaExperimentalFeature { META_EXPERIMENTAL_FEATURE_NONE = 0, + META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER = (1 << 0) } MetaExperimentalFeature; void meta_init_backend (GType backend_gtype); @@ -161,6 +162,8 @@ void meta_backend_enable_experimental_feature (MetaBackend *backend, gboolean meta_is_stage_views_enabled (void); +gboolean meta_is_stage_views_scaled (void); + MetaInputSettings *meta_backend_get_input_settings (MetaBackend *backend); #endif /* META_BACKEND_PRIVATE_H */ diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 0360e327f..822ddc066 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -428,7 +428,10 @@ experimental_features_handler (GVariant *features_variant, while (g_variant_iter_loop (&features_iter, "s", &feature)) { /* So far no experimental features defined. */ - g_info ("Unknown experimental feature '%s'\n", feature); + if (g_str_equal (feature, "scale-monitor-framebuffer")) + features |= META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER; + else + g_info ("Unknown experimental feature '%s'\n", feature); } if (features != priv->experimental_features) @@ -968,6 +971,22 @@ meta_is_stage_views_enabled (void) return !g_str_equal (mutter_stage_views, "0"); } +gboolean +meta_is_stage_views_scaled (void) +{ + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaLogicalMonitorLayoutMode layout_mode; + + if (!meta_is_stage_views_enabled ()) + return FALSE; + + layout_mode = monitor_manager->layout_mode; + + return layout_mode == META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL; +} + MetaInputSettings * meta_backend_get_input_settings (MetaBackend *backend) { diff --git a/src/backends/meta-logical-monitor.c b/src/backends/meta-logical-monitor.c index d69f5c4b3..f1e2a0fd5 100644 --- a/src/backends/meta-logical-monitor.c +++ b/src/backends/meta-logical-monitor.c @@ -78,7 +78,7 @@ meta_logical_monitor_new (MetaMonitorManager *monitor_manager, logical_monitor->number = monitor_number; logical_monitor->winsys_id = main_output->winsys_id; - logical_monitor->scale = logical_monitor_config->scale, + logical_monitor->scale = logical_monitor_config->scale; logical_monitor->in_fullscreen = -1; logical_monitor->rect = logical_monitor_config->layout; diff --git a/src/backends/meta-logical-monitor.h b/src/backends/meta-logical-monitor.h index de1af1bd0..f9f99cf91 100644 --- a/src/backends/meta-logical-monitor.h +++ b/src/backends/meta-logical-monitor.h @@ -60,9 +60,9 @@ G_DECLARE_FINAL_TYPE (MetaLogicalMonitor, meta_logical_monitor, META, LOGICAL_MONITOR, GObject) -MetaLogicalMonitor * meta_logical_monitor_new (MetaMonitorManager *monitor_manager, - MetaLogicalMonitorConfig *logical_monitor_config, - int monitor_number); +MetaLogicalMonitor * meta_logical_monitor_new (MetaMonitorManager *monitor_manager, + MetaLogicalMonitorConfig *logical_monitor_config, + int monitor_number); MetaLogicalMonitor * meta_logical_monitor_new_derived (MetaMonitorManager *monitor_manager, MetaMonitor *monitor, diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c index d64c700d2..71652962a 100644 --- a/src/backends/meta-monitor-config-manager.c +++ b/src/backends/meta-monitor-config-manager.c @@ -51,8 +51,8 @@ meta_monitor_config_manager_new (MetaMonitorManager *monitor_manager) config_manager = g_object_new (META_TYPE_MONITOR_CONFIG_MANAGER, NULL); config_manager->monitor_manager = monitor_manager; - config_manager->config_store = g_object_new (META_TYPE_MONITOR_CONFIG_STORE, - NULL); + config_manager->config_store = + meta_monitor_config_store_new (monitor_manager); return config_manager; } @@ -461,10 +461,11 @@ create_monitor_config (MetaMonitor *monitor, } static MetaLogicalMonitorConfig * -create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager, - MetaMonitor *monitor, - int x, - int y) +create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager, + MetaMonitor *monitor, + int x, + int y, + MetaLogicalMonitorLayoutMode layout_mode) { MetaMonitorMode *mode; int width, height; @@ -478,6 +479,16 @@ create_preferred_logical_monitor_config (MetaMonitorManager *monitor_manager, monitor, mode); + switch (layout_mode) + { + case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL: + width /= scale; + height /= scale; + break; + case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL: + break; + } + monitor_config = create_monitor_config (monitor, mode); logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1); @@ -501,6 +512,7 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana MetaMonitorManager *monitor_manager = config_manager->monitor_manager; GList *logical_monitor_configs; MetaMonitor *primary_monitor; + MetaLogicalMonitorLayoutMode layout_mode; MetaLogicalMonitorConfig *primary_logical_monitor_config; int x; GList *monitors; @@ -510,10 +522,13 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana if (!primary_monitor) return NULL; + layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager); + primary_logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager, primary_monitor, - 0, 0); + 0, 0, + layout_mode); primary_logical_monitor_config->is_primary = TRUE; logical_monitor_configs = g_list_append (NULL, primary_logical_monitor_config); @@ -535,14 +550,15 @@ meta_monitor_config_manager_create_linear (MetaMonitorConfigManager *config_mana logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager, monitor, - x, 0); + x, 0, + layout_mode); logical_monitor_configs = g_list_append (logical_monitor_configs, logical_monitor_config); x += logical_monitor_config->layout.width; } - return meta_monitors_config_new (logical_monitor_configs); + return meta_monitors_config_new (logical_monitor_configs, layout_mode); } MetaMonitorsConfig * @@ -551,21 +567,25 @@ meta_monitor_config_manager_create_fallback (MetaMonitorConfigManager *config_ma MetaMonitorManager *monitor_manager = config_manager->monitor_manager; MetaMonitor *primary_monitor; GList *logical_monitor_configs; + MetaLogicalMonitorLayoutMode layout_mode; MetaLogicalMonitorConfig *primary_logical_monitor_config; primary_monitor = find_primary_monitor (monitor_manager); if (!primary_monitor) return NULL; + layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager); + primary_logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager, primary_monitor, - 0, 0); + 0, 0, + layout_mode); primary_logical_monitor_config->is_primary = TRUE; logical_monitor_configs = g_list_append (NULL, primary_logical_monitor_config); - return meta_monitors_config_new (logical_monitor_configs); + return meta_monitors_config_new (logical_monitor_configs, layout_mode); } MetaMonitorsConfig * @@ -574,6 +594,7 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m MetaMonitorManager *monitor_manager = config_manager->monitor_manager; MetaLogicalMonitorConfig *primary_logical_monitor_config = NULL; MetaMonitor *primary_monitor; + MetaLogicalMonitorLayoutMode layout_mode; GList *logical_monitor_configs; GList *region; GList *monitors; @@ -583,6 +604,8 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m if (!primary_monitor) return NULL; + layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager); + logical_monitor_configs = NULL; region = NULL; monitors = meta_monitor_manager_get_monitors (monitor_manager); @@ -598,7 +621,8 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m logical_monitor_config = create_preferred_logical_monitor_config (monitor_manager, monitor, - x, y); + x, y, + layout_mode); logical_monitor_configs = g_list_append (logical_monitor_configs, logical_monitor_config); @@ -629,7 +653,7 @@ meta_monitor_config_manager_create_suggested (MetaMonitorConfigManager *config_m primary_logical_monitor_config->is_primary = TRUE; - return meta_monitors_config_new (logical_monitor_configs); + return meta_monitors_config_new (logical_monitor_configs, layout_mode); } void @@ -774,13 +798,15 @@ meta_monitors_config_key_equal (gconstpointer data_a, } MetaMonitorsConfig * -meta_monitors_config_new (GList *logical_monitor_configs) +meta_monitors_config_new (GList *logical_monitor_configs, + MetaLogicalMonitorLayoutMode layout_mode) { MetaMonitorsConfig *config; config = g_object_new (META_TYPE_MONITORS_CONFIG, NULL); config->logical_monitor_configs = logical_monitor_configs; config->key = meta_monitors_config_key_new (logical_monitor_configs); + config->layout_mode = layout_mode; return config; } @@ -862,12 +888,13 @@ meta_verify_monitor_config (MetaMonitorConfig *monitor_config, } gboolean -meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config, - GError **error) +meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config, + MetaLogicalMonitorLayoutMode layout_mode, + GError **error) { GList *l; - int layout_width; - int layout_height; + int expected_mode_width = 0; + int expected_mode_height = 0; if (logical_monitor_config->scale < 1) { @@ -894,14 +921,26 @@ meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_co return FALSE; } - layout_width = logical_monitor_config->layout.width; - layout_height = logical_monitor_config->layout.height; + switch (layout_mode) + { + case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL: + expected_mode_width = (logical_monitor_config->layout.width * + logical_monitor_config->scale); + expected_mode_height = (logical_monitor_config->layout.height * + logical_monitor_config->scale); + break; + case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL: + expected_mode_width = logical_monitor_config->layout.width; + expected_mode_height = logical_monitor_config->layout.height; + break; + } + for (l = logical_monitor_config->monitor_configs; l; l = l->next) { MetaMonitorConfig *monitor_config = l->data; - if (monitor_config->mode_spec->width != layout_width || - monitor_config->mode_spec->height != layout_height) + if (monitor_config->mode_spec->width != expected_mode_width || + monitor_config->mode_spec->height != expected_mode_height) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Monitor modes in logical monitor conflict"); diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h index baa119e0c..de7911413 100644 --- a/src/backends/meta-monitor-config-manager.h +++ b/src/backends/meta-monitor-config-manager.h @@ -56,6 +56,8 @@ struct _MetaMonitorsConfig MetaMonitorsConfigKey *key; GList *logical_monitor_configs; + + MetaLogicalMonitorLayoutMode layout_mode; }; #define META_TYPE_MONITORS_CONFIG (meta_monitors_config_get_type ()) @@ -85,7 +87,8 @@ void meta_monitor_config_manager_set_current (MetaMonitorConfigManager *config_m MetaMonitorsConfig * meta_monitor_config_manager_get_current (MetaMonitorConfigManager *config_manager); -MetaMonitorsConfig * meta_monitors_config_new (GList *logical_monitor_configs); +MetaMonitorsConfig * meta_monitors_config_new (GList *logical_monitor_configs, + MetaLogicalMonitorLayoutMode layout_mode); unsigned int meta_monitors_config_key_hash (gconstpointer config_key); @@ -107,8 +110,9 @@ gboolean meta_verify_monitor_spec (MetaMonitorSpec *monitor_spec, gboolean meta_verify_monitor_config (MetaMonitorConfig *monitor_config, GError **error); -gboolean meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config, - GError **error); +gboolean meta_verify_logical_monitor_config (MetaLogicalMonitorConfig *logical_monitor_config, + MetaLogicalMonitorLayoutMode layout_mode, + GError **error); gboolean meta_verify_monitors_config (MetaMonitorsConfig *config, GError **error); diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c index 44bdce7ea..9b02bc0c9 100644 --- a/src/backends/meta-monitor-config-store.c +++ b/src/backends/meta-monitor-config-store.c @@ -81,6 +81,8 @@ struct _MetaMonitorConfigStore { GObject parent; + MetaMonitorManager *monitor_manager; + GHashTable *configs; }; @@ -355,11 +357,13 @@ handle_start_element (GMarkupParseContext *context, } static gboolean -derive_logical_monitor_layout (MetaLogicalMonitorConfig *logical_monitor_config, - GError **error) +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; GList *l; monitor_config = logical_monitor_config->monitor_configs->data; @@ -379,8 +383,19 @@ derive_logical_monitor_layout (MetaLogicalMonitorConfig *logical_monitor_config, } } - logical_monitor_config->layout.width = mode_width; - logical_monitor_config->layout.height = mode_height; + switch (layout_mode) + { + case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL: + width = mode_width / logical_monitor_config->scale; + height = mode_height / logical_monitor_config->scale; + break; + case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL: + width = mode_width; + height = mode_height; + } + + logical_monitor_config->layout.width = width; + logical_monitor_config->layout.height = height; return TRUE; } @@ -491,12 +506,6 @@ handle_end_element (GMarkupParseContext *context, if (logical_monitor_config->scale == 0) logical_monitor_config->scale = 1; - if (!derive_logical_monitor_layout (logical_monitor_config, error)) - return; - - if (!meta_verify_logical_monitor_config (logical_monitor_config, error)) - return; - parser->current_logical_monitor_configs = g_list_append (parser->current_logical_monitor_configs, logical_monitor_config); @@ -508,12 +517,34 @@ handle_end_element (GMarkupParseContext *context, case STATE_CONFIGURATION: { + MetaMonitorConfigStore *store = parser->config_store; MetaMonitorsConfig *config; + GList *l; + MetaLogicalMonitorLayoutMode layout_mode; g_assert (g_str_equal (element_name, "configuration")); + 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, + error)) + return; + } + config = - meta_monitors_config_new (parser->current_logical_monitor_configs); + meta_monitors_config_new (parser->current_logical_monitor_configs, + layout_mode); if (!meta_verify_monitors_config (config, error)) { @@ -852,6 +883,17 @@ meta_monitor_config_store_get_config_count (MetaMonitorConfigStore *config_store return (int) g_hash_table_size (config_store->configs); } +MetaMonitorConfigStore * +meta_monitor_config_store_new (MetaMonitorManager *monitor_manager) +{ + MetaMonitorConfigStore *store; + + store = g_object_new (META_TYPE_MONITOR_CONFIG_STORE, NULL); + store->monitor_manager = monitor_manager; + + return store; +} + static void meta_monitor_config_store_dispose (GObject *object) { diff --git a/src/backends/meta-monitor-config-store.h b/src/backends/meta-monitor-config-store.h index 3dc94dbfd..7451fc11e 100644 --- a/src/backends/meta-monitor-config-store.h +++ b/src/backends/meta-monitor-config-store.h @@ -30,6 +30,8 @@ G_DECLARE_FINAL_TYPE (MetaMonitorConfigStore, meta_monitor_config_store, META, MONITOR_CONFIG_STORE, GObject) +MetaMonitorConfigStore * meta_monitor_config_store_new (MetaMonitorManager *monitor_manager); + MetaMonitorsConfig * meta_monitor_config_store_lookup (MetaMonitorConfigStore *config_store, MetaMonitorsConfigKey *key); diff --git a/src/backends/meta-monitor-manager-dummy.c b/src/backends/meta-monitor-manager-dummy.c index 8c8134bcc..2c31d62b1 100644 --- a/src/backends/meta-monitor-manager-dummy.c +++ b/src/backends/meta-monitor-manager-dummy.c @@ -605,10 +605,30 @@ meta_monitor_manager_dummy_get_supported_scales (MetaMonitorManager *manager, *n_scales = G_N_ELEMENTS (supported_scales_dummy); } +static gboolean +is_monitor_framebuffers_scaled (void) +{ + MetaBackend *backend = meta_get_backend (); + + return meta_backend_is_experimental_feature_enabled ( + backend, + META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER); +} + static MetaMonitorManagerCapability meta_monitor_manager_dummy_get_capabilities (MetaMonitorManager *manager) { - return META_MONITOR_MANAGER_CAPABILITY_MIRRORING; + MetaMonitorManagerCapability capabilities = + META_MONITOR_MANAGER_CAPABILITY_NONE; + + capabilities |= META_MONITOR_MANAGER_CAPABILITY_MIRRORING; + + if (meta_backend_is_experimental_feature_enabled ( + meta_get_backend (), + META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER)) + capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE; + + return capabilities; } static gboolean @@ -625,6 +645,18 @@ meta_monitor_manager_dummy_get_max_screen_size (MetaMonitorManager *manager, return TRUE; } +static MetaLogicalMonitorLayoutMode +meta_monitor_manager_dummy_get_default_layout_mode (MetaMonitorManager *manager) +{ + if (!meta_is_stage_views_enabled ()) + return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; + + if (is_monitor_framebuffers_scaled ()) + return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL; + else + return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; +} + static void meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass) { @@ -639,6 +671,7 @@ meta_monitor_manager_dummy_class_init (MetaMonitorManagerDummyClass *klass) manager_class->get_supported_scales = meta_monitor_manager_dummy_get_supported_scales; manager_class->get_capabilities = meta_monitor_manager_dummy_get_capabilities; manager_class->get_max_screen_size = meta_monitor_manager_dummy_get_max_screen_size; + manager_class->get_default_layout_mode = meta_monitor_manager_dummy_get_default_layout_mode; } static void diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index 1e0e61171..4dc113984 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -71,7 +71,8 @@ typedef struct _MetaTileInfo MetaTileInfo; typedef enum _MetaMonitorManagerCapability { META_MONITOR_MANAGER_CAPABILITY_NONE = 0, - META_MONITOR_MANAGER_CAPABILITY_MIRRORING = (1 << 0) + META_MONITOR_MANAGER_CAPABILITY_MIRRORING = (1 << 0), + META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE = (1 << 1) } MetaMonitorManagerCapability; /* Equivalent to the 'method' enum in org.gnome.Mutter.DisplayConfig */ @@ -82,6 +83,13 @@ typedef enum _MetaMonitorsConfigMethod META_MONITORS_CONFIG_METHOD_PERSISTENT = 2 } MetaMonitorsConfigMethod; +/* Equivalent to the 'layout-mode' enum in org.gnome.Mutter.DisplayConfig */ +typedef enum _MetaLogicalMonitorLayoutMode +{ + META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL = 1, + META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL = 2 +} MetaLogicalMonitorLayoutMode; + typedef enum { META_MONITOR_TRANSFORM_NORMAL, @@ -274,6 +282,8 @@ struct _MetaMonitorManager MetaPowerSave power_save_mode; + MetaLogicalMonitorLayoutMode layout_mode; + int screen_width; int screen_height; @@ -376,6 +386,8 @@ struct _MetaMonitorManagerClass gboolean (*get_max_screen_size) (MetaMonitorManager *, int *, int *); + + MetaLogicalMonitorLayoutMode (*get_default_layout_mode) (MetaMonitorManager *); }; void meta_monitor_manager_rebuild (MetaMonitorManager *manager, @@ -479,6 +491,9 @@ gboolean meta_monitor_manager_get_max_screen_size (MetaMonitorManager int *max_width, int *max_height); +MetaLogicalMonitorLayoutMode + meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager); + void meta_monitor_manager_clear_output (MetaOutput *output); void meta_monitor_manager_clear_mode (MetaCrtcMode *mode); void meta_monitor_manager_clear_crtc (MetaCrtc *crtc); diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 0af01f1d7..4cd65c38a 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -319,6 +319,16 @@ meta_monitor_manager_get_max_screen_size (MetaMonitorManager *manager, return manager_class->get_max_screen_size (manager, max_width, max_height); } + +MetaLogicalMonitorLayoutMode +meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager) +{ + MetaMonitorManagerClass *manager_class = + META_MONITOR_MANAGER_GET_CLASS (manager); + + return manager_class->get_default_layout_mode (manager); +} + static void meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager) { @@ -1397,6 +1407,13 @@ meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton, g_variant_new_boolean (FALSE)); } + if (capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE) + { + g_variant_builder_add (&properties_builder, "{sv}", + "layout-mode", + g_variant_new_uint32 (manager->layout_mode)); + } + if (meta_monitor_manager_get_max_screen_size (manager, &max_screen_width, &max_screen_height)) @@ -1593,10 +1610,12 @@ create_monitor_config_from_variant (MetaMonitorManager *manager, } static gboolean -derive_logical_monitor_size (GList *monitor_configs, - int *width, - int *height, - GError **error) +derive_logical_monitor_size (GList *monitor_configs, + int *width, + int *height, + double scale, + MetaLogicalMonitorLayoutMode layout_mode, + GError **error) { MetaMonitorConfig *monitor_config; @@ -1608,16 +1627,27 @@ derive_logical_monitor_size (GList *monitor_configs, } monitor_config = monitor_configs->data; - *width = monitor_config->mode_spec->width; - *height = monitor_config->mode_spec->height; - return TRUE; + switch (layout_mode) + { + case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL: + *width = monitor_config->mode_spec->width / scale; + *height = monitor_config->mode_spec->height / scale; + return TRUE; + case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL: + *width = monitor_config->mode_spec->width; + *height = monitor_config->mode_spec->height; + return TRUE; + } + + g_assert_not_reached (); } static MetaLogicalMonitorConfig * -create_logical_monitor_config_from_variant (MetaMonitorManager *manager, - GVariant *logical_monitor_config_variant, - GError **error) +create_logical_monitor_config_from_variant (MetaMonitorManager *manager, + GVariant *logical_monitor_config_variant, + MetaLogicalMonitorLayoutMode layout_mode, + GError **error) { MetaLogicalMonitorConfig *logical_monitor_config; int x, y, width, height; @@ -1658,7 +1688,8 @@ create_logical_monitor_config_from_variant (MetaMonitorManager *manager, } g_variant_iter_free (monitor_configs_iter); - if (!derive_logical_monitor_size (monitor_configs, &width, &height, error)) + if (!derive_logical_monitor_size (monitor_configs, &width, &height, + scale, layout_mode, error)) goto err; logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1); @@ -1674,7 +1705,9 @@ create_logical_monitor_config_from_variant (MetaMonitorManager *manager, .monitor_configs = monitor_configs }; - if (!meta_verify_logical_monitor_config (logical_monitor_config, error)) + if (!meta_verify_logical_monitor_config (logical_monitor_config, + layout_mode, + error)) { meta_logical_monitor_config_free (logical_monitor_config); return NULL; @@ -1687,6 +1720,19 @@ err: return NULL; } +static gboolean +is_valid_layout_mode (MetaLogicalMonitorLayoutMode layout_mode) +{ + switch (layout_mode) + { + case META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL: + case META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL: + return TRUE; + } + + return FALSE; +} + static gboolean meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skeleton, GDBusMethodInvocation *invocation, @@ -1696,6 +1742,9 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet GVariant *properties_variant) { MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton); + MetaMonitorManagerCapability capabilities; + GVariant *layout_mode_variant = NULL; + MetaLogicalMonitorLayoutMode layout_mode; GVariantIter logical_monitor_configs_iter; MetaMonitorsConfig *config; GList *logical_monitor_configs = NULL; @@ -1717,6 +1766,39 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet return TRUE; } + capabilities = meta_monitor_manager_get_capabilities (manager); + + if (properties_variant) + layout_mode_variant = g_variant_lookup_value (properties_variant, + "layout-mode", + G_VARIANT_TYPE ("u")); + + if (layout_mode_variant && + capabilities & META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE) + { + g_variant_get (layout_mode_variant, "u", &layout_mode); + } + else if (!layout_mode_variant) + { + layout_mode = + meta_monitor_manager_get_default_layout_mode (manager); + } + else + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Can't set layout mode"); + return TRUE; + } + + if (!is_valid_layout_mode (layout_mode)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "Invalid layout mode specified"); + return TRUE; + } + g_variant_iter_init (&logical_monitor_configs_iter, logical_monitor_configs_variant); while (TRUE) @@ -1731,6 +1813,7 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet logical_monitor_config = create_logical_monitor_config_from_variant (manager, logical_monitor_config_variant, + layout_mode, &error); if (!logical_monitor_config) { @@ -1747,7 +1830,7 @@ meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skelet logical_monitor_config); } - config = meta_monitors_config_new (logical_monitor_configs); + config = meta_monitors_config_new (logical_monitor_configs, layout_mode); if (!meta_verify_monitors_config (config, &error)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, @@ -2416,6 +2499,12 @@ void meta_monitor_manager_update_logical_state (MetaMonitorManager *manager, MetaMonitorsConfig *config) { + if (config) + manager->layout_mode = config->layout_mode; + else + manager->layout_mode = + meta_monitor_manager_get_default_layout_mode (manager); + meta_monitor_manager_rebuild_logical_monitors (manager, config); } @@ -2455,6 +2544,8 @@ meta_monitor_manager_update_monitor_modes_derived (MetaMonitorManager *manager) void meta_monitor_manager_update_logical_state_derived (MetaMonitorManager *manager) { + manager->layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; + meta_monitor_manager_rebuild_logical_monitors_derived (manager); } diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c index 70289975a..5dbfadb8e 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -35,6 +35,8 @@ #include #include "backends/meta-backend-private.h" +#include "backends/meta-logical-monitor.h" +#include "backends/meta-monitor.h" #include "backends/meta-monitor-manager-private.h" #include "backends/native/meta-renderer-native.h" #include "meta/boxes.h" @@ -214,50 +216,125 @@ set_crtc_cursor (MetaCursorRendererNative *native, } } +typedef struct +{ + MetaCursorRendererNative *in_cursor_renderer_native; + MetaLogicalMonitor *in_logical_monitor; + MetaRectangle in_local_cursor_rect; + MetaCursorSprite *in_cursor_sprite; + + gboolean out_painted; +} UpdateCrtcCursorData; + +static gboolean +update_monitor_crtc_cursor (MetaMonitor *monitor, + MetaMonitorMode *monitor_mode, + MetaMonitorCrtcMode *monitor_crtc_mode, + gpointer user_data, + GError **error) +{ + UpdateCrtcCursorData *data = user_data; + MetaCursorRendererNative *cursor_renderer_native = + data->in_cursor_renderer_native; + MetaCursorRendererNativePrivate *priv = + meta_cursor_renderer_native_get_instance_private (cursor_renderer_native); + MetaRectangle scaled_crtc_rect; + int scale; + + if (meta_is_stage_views_scaled ()) + scale = meta_logical_monitor_get_scale (data->in_logical_monitor); + else + scale = 1; + + scaled_crtc_rect = (MetaRectangle) { + .x = monitor_crtc_mode->x / scale, + .y = monitor_crtc_mode->y / scale, + .width = monitor_crtc_mode->crtc_mode->width / scale, + .height = monitor_crtc_mode->crtc_mode->height / scale + }; + + if (priv->has_hw_cursor && + meta_rectangle_overlap (&scaled_crtc_rect, + &data->in_local_cursor_rect)) + { + int crtc_cursor_x, crtc_cursor_y; + + set_crtc_cursor (data->in_cursor_renderer_native, + monitor_crtc_mode->output->crtc, + data->in_cursor_sprite); + + crtc_cursor_x = (data->in_local_cursor_rect.x - scaled_crtc_rect.x) * scale; + crtc_cursor_y = (data->in_local_cursor_rect.y - scaled_crtc_rect.y) * scale; + drmModeMoveCursor (priv->drm_fd, + monitor_crtc_mode->output->crtc->crtc_id, + crtc_cursor_x, + crtc_cursor_y); + + data->out_painted = data->out_painted || TRUE; + } + else + { + set_crtc_cursor (data->in_cursor_renderer_native, + monitor_crtc_mode->output->crtc, NULL); + } + + return TRUE; +} + static void update_hw_cursor (MetaCursorRendererNative *native, MetaCursorSprite *cursor_sprite) { MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native); MetaCursorRenderer *renderer = META_CURSOR_RENDERER (native); - MetaMonitorManager *monitors; - MetaCrtc *crtcs; - unsigned int i, n_crtcs; + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + GList *logical_monitors; + GList *l; MetaRectangle rect; gboolean painted = FALSE; - monitors = meta_monitor_manager_get (); - meta_monitor_manager_get_resources (monitors, NULL, NULL, &crtcs, &n_crtcs, NULL, NULL); - if (cursor_sprite) rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite); else rect = (MetaRectangle) { 0 }; - for (i = 0; i < n_crtcs; i++) + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + for (l = logical_monitors; l; l = l->next) { - gboolean crtc_should_use_cursor; - MetaCursorSprite *crtc_cursor; - MetaRectangle *crtc_rect; + MetaLogicalMonitor *logical_monitor = l->data; + UpdateCrtcCursorData data; + GList *monitors; + GList *k; - crtc_rect = &crtcs[i].rect; + data = (UpdateCrtcCursorData) { + .in_cursor_renderer_native = native, + .in_logical_monitor = logical_monitor, + .in_local_cursor_rect = (MetaRectangle) { + .x = rect.x - logical_monitor->rect.x, + .y = rect.y - logical_monitor->rect.y, + .width = rect.width, + .height = rect.height + }, + .in_cursor_sprite = cursor_sprite + }; - crtc_should_use_cursor = (priv->has_hw_cursor && - meta_rectangle_overlap (&rect, crtc_rect)); - if (crtc_should_use_cursor) - crtc_cursor = cursor_sprite; - else - crtc_cursor = NULL; - - set_crtc_cursor (native, &crtcs[i], crtc_cursor); - - if (crtc_cursor) + monitors = meta_logical_monitor_get_monitors (logical_monitor); + for (k = monitors; k; k = k->next) { - drmModeMoveCursor (priv->drm_fd, crtcs[i].crtc_id, - rect.x - crtc_rect->x, - rect.y - crtc_rect->y); - painted = TRUE; + MetaMonitor *monitor = k->data; + MetaMonitorMode *monitor_mode; + + monitor_mode = meta_monitor_get_current_mode (monitor); + meta_monitor_mode_foreach_crtc (monitor, monitor_mode, + update_monitor_crtc_cursor, + &data, + NULL); } + + painted = painted || data.out_painted; } priv->hw_state_invalidated = FALSE; @@ -316,6 +393,55 @@ cursor_over_transformed_crtc (MetaCursorRenderer *renderer, return FALSE; } +static float +calculate_cursor_crtc_sprite_scale (MetaCursorSprite *cursor_sprite, + MetaLogicalMonitor *logical_monitor) +{ + return (meta_logical_monitor_get_scale (logical_monitor) * + meta_cursor_sprite_get_texture_scale (cursor_sprite)); +} + +static gboolean +can_draw_cursor_unscaled (MetaCursorRenderer *renderer, + MetaCursorSprite *cursor_sprite) +{ + MetaBackend *backend; + MetaMonitorManager *monitor_manager; + MetaRectangle cursor_rect; + GList *logical_monitors; + GList *l; + gboolean has_visible_crtc_sprite = FALSE; + + if (!meta_is_stage_views_scaled ()) + return meta_cursor_sprite_get_texture_scale (cursor_sprite) == 1.0; + + backend = meta_get_backend (); + monitor_manager = meta_backend_get_monitor_manager (backend); + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + + if (!logical_monitors) + return FALSE; + + cursor_rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite); + + for (l = logical_monitors; l; l = l->next) + { + MetaLogicalMonitor *logical_monitor = l->data; + + if (!meta_rectangle_overlap (&cursor_rect, &logical_monitor->rect)) + continue; + + if (calculate_cursor_crtc_sprite_scale (cursor_sprite, + logical_monitor) != 1.0) + return FALSE; + + has_visible_crtc_sprite = TRUE; + } + + return has_visible_crtc_sprite; +} + static gboolean should_have_hw_cursor (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite) @@ -337,7 +463,7 @@ should_have_hw_cursor (MetaCursorRenderer *renderer, if (!texture) return FALSE; - if (meta_cursor_sprite_get_texture_scale (cursor_sprite) != 1) + if (!can_draw_cursor_unscaled (renderer, cursor_sprite)) return FALSE; if (!has_valid_cursor_sprite_gbm_bo (cursor_sprite)) diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index a000a7e39..78930b854 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -1937,6 +1937,11 @@ meta_monitor_manager_kms_get_capabilities (MetaMonitorManager *manager) MetaMonitorManagerCapability capabilities = META_MONITOR_MANAGER_CAPABILITY_NONE; + if (meta_backend_is_experimental_feature_enabled ( + backend, + META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER)) + capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE; + switch (meta_renderer_native_get_mode (renderer_native)) { case META_RENDERER_NATIVE_MODE_GBM: @@ -1967,6 +1972,20 @@ meta_monitor_manager_kms_get_max_screen_size (MetaMonitorManager *manager, return TRUE; } +static MetaLogicalMonitorLayoutMode +meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager) +{ + if (!meta_is_stage_views_enabled ()) + return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; + + if (meta_backend_is_experimental_feature_enabled ( + meta_get_backend (), + META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER)) + return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL; + else + return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; +} + static void meta_monitor_manager_kms_dispose (GObject *object) { @@ -2011,4 +2030,5 @@ meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass) manager_class->get_supported_scales = meta_monitor_manager_kms_get_supported_scales; manager_class->get_capabilities = meta_monitor_manager_kms_get_capabilities; manager_class->get_max_screen_size = meta_monitor_manager_kms_get_max_screen_size; + manager_class->get_default_layout_mode = meta_monitor_manager_kms_get_default_layout_mode; } diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 9dae6dcd5..ae3381bd8 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -1707,16 +1707,26 @@ meta_renderer_native_create_view (MetaRenderer *renderer, MetaMonitorTransform view_transform; CoglOnscreen *onscreen = NULL; CoglOffscreen *offscreen = NULL; + int scale; + int width, height; MetaRendererView *view; GError *error = NULL; view_transform = calculate_view_transform (monitor_manager, logical_monitor); + if (meta_is_stage_views_scaled ()) + scale = logical_monitor->scale; + else + scale = 1; + + width = logical_monitor->rect.width * scale; + height = logical_monitor->rect.height * scale; + onscreen = meta_renderer_native_create_onscreen (META_RENDERER_NATIVE (renderer), cogl_context, view_transform, - logical_monitor->rect.width, - logical_monitor->rect.height); + width, + height); if (!onscreen) meta_fatal ("Failed to allocate onscreen framebuffer\n"); @@ -1725,14 +1735,15 @@ meta_renderer_native_create_view (MetaRenderer *renderer, offscreen = meta_renderer_native_create_offscreen (META_RENDERER_NATIVE (renderer), cogl_context, view_transform, - logical_monitor->rect.width, - logical_monitor->rect.height); + width, + height); if (!offscreen) meta_fatal ("Failed to allocate back buffer texture\n"); } view = g_object_new (META_TYPE_RENDERER_VIEW, "layout", &logical_monitor->rect, + "scale", scale, "framebuffer", onscreen, "offscreen", offscreen, "logical-monitor", logical_monitor, diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 4083e08db..fd044c8f5 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -1623,6 +1623,16 @@ meta_monitor_manager_xrandr_get_max_screen_size (MetaMonitorManager *manager, return TRUE; } +static MetaLogicalMonitorLayoutMode +meta_monitor_manager_xrandr_get_default_layout_mode (MetaMonitorManager *manager) +{ + /* + * Under X11, we still use the 'logical' layout mode, but it is + * eqivalent to 'physical' as the scale is always 1. + */ + return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL; +} + static void meta_monitor_manager_xrandr_init (MetaMonitorManagerXrandr *manager_xrandr) { @@ -1703,6 +1713,7 @@ meta_monitor_manager_xrandr_class_init (MetaMonitorManagerXrandrClass *klass) manager_class->get_supported_scales = meta_monitor_manager_xrandr_get_supported_scales; manager_class->get_capabilities = meta_monitor_manager_xrandr_get_capabilities; manager_class->get_max_screen_size = meta_monitor_manager_xrandr_get_max_screen_size; + manager_class->get_default_layout_mode = meta_monitor_manager_xrandr_get_default_layout_mode; quark_meta_monitor_xrandr_data = g_quark_from_static_string ("-meta-monitor-xrandr-data"); diff --git a/src/backends/x11/meta-renderer-x11.c b/src/backends/x11/meta-renderer-x11.c index da0613390..5eb81dd39 100644 --- a/src/backends/x11/meta-renderer-x11.c +++ b/src/backends/x11/meta-renderer-x11.c @@ -122,6 +122,7 @@ meta_renderer_x11_create_view (MetaRenderer *renderer, ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); MetaMonitorTransform view_transform; + int view_scale; int width, height; CoglTexture2D *texture_2d; CoglOffscreen *fake_onscreen; @@ -130,11 +131,16 @@ meta_renderer_x11_create_view (MetaRenderer *renderer, g_assert (meta_is_wayland_compositor ()); - width = logical_monitor->rect.width; - height = logical_monitor->rect.height; - view_transform = calculate_view_transform (monitor_manager, logical_monitor); + if (meta_is_stage_views_scaled ()) + view_scale = logical_monitor->scale; + else + view_scale = 1; + + width = logical_monitor->rect.width * view_scale; + height = logical_monitor->rect.height * view_scale; + texture_2d = cogl_texture_2d_new_with_size (cogl_context, width, height); fake_onscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture_2d)); @@ -158,6 +164,7 @@ meta_renderer_x11_create_view (MetaRenderer *renderer, "framebuffer", COGL_FRAMEBUFFER (fake_onscreen), "offscreen", COGL_FRAMEBUFFER (offscreen), "transform", view_transform, + "scale", view_scale, NULL); } diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c index 8fc4b9e9d..0dfc427ef 100644 --- a/src/compositor/meta-surface-actor-wayland.c +++ b/src/compositor/meta-surface-actor-wayland.c @@ -35,6 +35,7 @@ #include "wayland/meta-wayland-private.h" #include "wayland/meta-window-wayland.h" +#include "backends/meta-backend-private.h" #include "compositor/region-utils.h" enum { @@ -104,9 +105,12 @@ meta_surface_actor_wayland_get_scale (MetaSurfaceActorWayland *self) window = meta_wayland_surface_get_toplevel_window (surface); - /* XXX: We do not handle x11 clients yet */ - if (window && window->client_type != META_WINDOW_CLIENT_TYPE_X11) - geometry_scale = meta_window_wayland_get_geometry_scale (window); + if (!meta_is_stage_views_scaled ()) + { + /* XXX: We do not handle x11 clients yet */ + if (window && window->client_type != META_WINDOW_CLIENT_TYPE_X11) + geometry_scale = meta_window_wayland_get_geometry_scale (window); + } return (double) geometry_scale / (double) surface->scale; } diff --git a/src/core/screen.c b/src/core/screen.c index dfc499c7b..d6b5eac53 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -1279,6 +1279,37 @@ update_num_workspaces (MetaScreen *screen, g_object_notify (G_OBJECT (screen), "n-workspaces"); } +static int +find_highest_logical_monitor_scale (MetaBackend *backend, + MetaCursorSprite *cursor_sprite) +{ + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + MetaRectangle cursor_rect; + GList *logical_monitors; + GList *l; + int highest_scale = 0.0; + + cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer, + cursor_sprite); + + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + for (l = logical_monitors; l; l = l->next) + { + MetaLogicalMonitor *logical_monitor = l->data; + + if (!meta_rectangle_overlap (&cursor_rect, &logical_monitor->rect)) + continue; + + highest_scale = MAX (highest_scale, logical_monitor->scale); + } + + return highest_scale; +} + static void root_cursor_prepare_at (MetaCursorSprite *cursor_sprite, int x, @@ -1286,16 +1317,35 @@ root_cursor_prepare_at (MetaCursorSprite *cursor_sprite, MetaScreen *screen) { MetaBackend *backend = meta_get_backend (); - MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (backend); - MetaLogicalMonitor *logical_monitor; - logical_monitor = - meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y); + if (meta_is_stage_views_scaled ()) + { + int scale; - /* Reload the cursor texture if the scale has changed. */ - if (logical_monitor) - meta_cursor_sprite_set_theme_scale (cursor_sprite, logical_monitor->scale); + scale = find_highest_logical_monitor_scale (backend, cursor_sprite); + if (scale != 0.0) + { + meta_cursor_sprite_set_theme_scale (cursor_sprite, scale); + meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0 / scale); + } + } + else + { + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaLogicalMonitor *logical_monitor; + + logical_monitor = + meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y); + + /* Reload the cursor texture if the scale has changed. */ + if (logical_monitor) + { + meta_cursor_sprite_set_theme_scale (cursor_sprite, + logical_monitor->scale); + meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0); + } + } } static void @@ -2206,6 +2256,9 @@ static void on_monitors_changed (MetaMonitorManager *manager, MetaScreen *screen) { + MetaBackend *backend; + MetaCursorRenderer *cursor_renderer; + meta_monitor_manager_get_screen_size (manager, &screen->rect.width, &screen->rect.height); @@ -2237,6 +2290,10 @@ on_monitors_changed (MetaMonitorManager *manager, meta_screen_queue_check_fullscreen (screen); + backend = meta_get_backend (); + cursor_renderer = meta_backend_get_cursor_renderer (backend); + meta_cursor_renderer_force_update (cursor_renderer); + g_signal_emit (screen, screen_signals[MONITORS_CHANGED], 0); } diff --git a/src/org.gnome.Mutter.DisplayConfig.xml b/src/org.gnome.Mutter.DisplayConfig.xml index 2c623c65b..bb48768d3 100644 --- a/src/org.gnome.Mutter.DisplayConfig.xml +++ b/src/org.gnome.Mutter.DisplayConfig.xml @@ -344,10 +344,34 @@ scale factors of logical monitors supported by the display server. + @layout_mode current layout mode represents the way logical monitors + are layed out on the screen. Possible modes include: + + 1 : physical + 2 : logical + + With physical layout mode, each logical monitor has the same dimensions + an the monitor modes of the associated monitors assigned to it, no + matter what scale is in use. + + With logical mode, the dimension of a logical monitor is the dimension + of the monitor mode, divided by the logical monitor scale. + + Possible @properties are: * "supports-mirroring" (b): FALSE if mirroring not supported; TRUE or not present if mirroring is supported. + * "layout-mode" (u): Represents in what way logical monitors are laid + out on the screen. The layout mode can be either + of the ones listed below. Absence of this property + means the layout mode cannot be changed, and that + "logical" mode is assumed to be used. + * 1 : logical - the dimension of a logical monitor is derived from + the monitor modes associated with it, then scaled + using the logical monitor scale. + * 2 : physical - the dimension of a logical monitor is derived from + the monitor modes associated with it. --> @@ -386,6 +410,13 @@ - "enable_underscanning" (b): enable monitor underscanning; may only be set when underscanning is supported (see GetCurrentState). + + @properties may effect the global monitor configuration state. Possible + properties are: + + * "layout-mode" (u): layout mode the passed configuration is in; may + only be set when changing the layout mode is + supported (see GetCurrentState). --> diff --git a/src/tests/meta-monitor-manager-test.c b/src/tests/meta-monitor-manager-test.c index 6925365ed..cc88dfe9c 100644 --- a/src/tests/meta-monitor-manager-test.c +++ b/src/tests/meta-monitor-manager-test.c @@ -380,10 +380,28 @@ meta_monitor_manager_test_get_supported_scales (MetaMonitorManager *manager, *n_scales = G_N_ELEMENTS (supported_scales_test); } +static gboolean +is_monitor_framebuffer_scaled (void) +{ + MetaBackend *backend = meta_get_backend (); + + return meta_backend_is_experimental_feature_enabled ( + backend, + META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER); +} + static MetaMonitorManagerCapability meta_monitor_manager_test_get_capabilities (MetaMonitorManager *manager) { - return META_MONITOR_MANAGER_CAPABILITY_MIRRORING; + MetaMonitorManagerCapability capabilities = + META_MONITOR_MANAGER_CAPABILITY_NONE; + + capabilities |= META_MONITOR_MANAGER_CAPABILITY_MIRRORING; + + if (is_monitor_framebuffer_scaled ()) + capabilities |= META_MONITOR_MANAGER_CAPABILITY_LAYOUT_MODE; + + return capabilities; } static gboolean @@ -400,6 +418,18 @@ meta_monitor_manager_test_get_max_screen_size (MetaMonitorManager *manager, return TRUE; } +static MetaLogicalMonitorLayoutMode +meta_monitor_manager_test_get_default_layout_mode (MetaMonitorManager *manager) +{ + if (!meta_is_stage_views_enabled ()) + return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; + + if (is_monitor_framebuffer_scaled ()) + return META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL; + else + return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; +} + static void meta_monitor_manager_test_dispose (GObject *object) { @@ -436,4 +466,5 @@ meta_monitor_manager_test_class_init (MetaMonitorManagerTestClass *klass) manager_class->get_supported_scales = meta_monitor_manager_test_get_supported_scales; manager_class->get_capabilities = meta_monitor_manager_test_get_capabilities; manager_class->get_max_screen_size = meta_monitor_manager_test_get_max_screen_size; + manager_class->get_default_layout_mode = meta_monitor_manager_test_get_default_layout_mode; } diff --git a/src/tests/monitor-store-unit-tests.c b/src/tests/monitor-store-unit-tests.c index 37bd22161..60aa872b5 100644 --- a/src/tests/monitor-store-unit-tests.c +++ b/src/tests/monitor-store-unit-tests.c @@ -472,8 +472,8 @@ meta_test_monitor_store_scale (void) .layout = { .x = 0, .y = 0, - .width = 1920, - .height = 1080 + .width = 960, + .height = 540 }, .scale = 2, .is_primary = TRUE, diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c index 1eb384120..3abcc7601 100644 --- a/src/tests/monitor-unit-tests.c +++ b/src/tests/monitor-unit-tests.c @@ -1354,13 +1354,13 @@ meta_test_monitor_hidpi_linear_config (void) { .monitors = { 0 }, .n_monitors = 1, - .layout = { .x = 0, .y = 0, .width = 1280, .height = 720 }, + .layout = { .x = 0, .y = 0, .width = 640, .height = 360 }, .scale = 2 }, { .monitors = { 1 }, .n_monitors = 1, - .layout = { .x = 1280, .y = 0, .width = 1024, .height = 768 }, + .layout = { .x = 640, .y = 0, .width = 1024, .height = 768 }, .scale = 1 } }, @@ -1376,12 +1376,18 @@ meta_test_monitor_hidpi_linear_config (void) } }, .n_crtcs = 2, - .screen_width = 1280 + 1024, + .screen_width = 640 + 1024, .screen_height = 768 } }; MetaMonitorTestSetup *test_setup; + if (!is_using_monitor_config_manager ()) + { + g_test_skip ("Not using MetaMonitorConfigManager"); + return; + } + test_setup = create_monitor_test_setup (&test_case, MONITOR_TEST_FLAG_NO_STORED); emulate_hotplug (test_setup); @@ -2689,7 +2695,7 @@ meta_test_monitor_custom_scale_config (void) { .monitors = { 0 }, .n_monitors = 1, - .layout = { .x = 0, .y = 0, .width = 1920, .height = 1080 }, + .layout = { .x = 0, .y = 0, .width = 960, .height = 540 }, .scale = 2 } }, @@ -2703,8 +2709,8 @@ meta_test_monitor_custom_scale_config (void) }, .n_crtcs = 1, .n_tiled_monitors = 0, - .screen_width = 1920, - .screen_height = 1080 + .screen_width = 960, + .screen_height = 540 } }; MetaMonitorTestSetup *test_setup; @@ -2824,7 +2830,7 @@ meta_test_monitor_custom_tiled_config (void) { .monitors = { 0 }, .n_monitors = 1, - .layout = { .x = 0, .y = 0, .width = 800, .height = 600 }, + .layout = { .x = 0, .y = 0, .width = 400, .height = 300 }, .scale = 2 } }, @@ -2841,8 +2847,8 @@ meta_test_monitor_custom_tiled_config (void) }, .n_crtcs = 2, .n_tiled_monitors = 1, - .screen_width = 800, - .screen_height = 600 + .screen_width = 400, + .screen_height = 300 } }; MetaMonitorTestSetup *test_setup; diff --git a/src/tests/unit-tests.c b/src/tests/unit-tests.c index 7e5a1e8d2..efd56f142 100644 --- a/src/tests/unit-tests.c +++ b/src/tests/unit-tests.c @@ -214,8 +214,15 @@ meta_test_adjecent_to (void) static gboolean run_tests (gpointer data) { + MetaBackend *backend = meta_get_backend (); gboolean ret; + meta_backend_override_experimental_features (backend); + + meta_backend_enable_experimental_feature ( + backend, + META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER); + ret = g_test_run (); meta_quit (ret != 0); diff --git a/src/wayland/meta-wayland-surface-role-cursor.c b/src/wayland/meta-wayland-surface-role-cursor.c index 6b6c0a002..18b4fe9d3 100644 --- a/src/wayland/meta-wayland-surface-role-cursor.c +++ b/src/wayland/meta-wayland-surface-role-cursor.c @@ -112,7 +112,11 @@ cursor_sprite_prepare_at (MetaCursorSprite *cursor_sprite, { float texture_scale; - texture_scale = (float) logical_monitor->scale / surface->scale; + if (meta_is_stage_views_scaled ()) + texture_scale = 1.0 / surface->scale; + else + texture_scale = (float) logical_monitor->scale / surface->scale; + meta_cursor_sprite_set_texture_scale (cursor_sprite, texture_scale); } } diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c index 9a21388d1..a1b239b82 100644 --- a/src/wayland/meta-window-wayland.c +++ b/src/wayland/meta-window-wayland.c @@ -38,11 +38,14 @@ #include "backends/meta-backend-private.h" #include "backends/meta-logical-monitor.h" #include "compositor/meta-surface-actor-wayland.h" +#include "backends/meta-backend-private.h" struct _MetaWindowWayland { MetaWindow parent; + int geometry_scale; + MetaWaylandSerial pending_configure_serial; gboolean has_pending_move; int pending_move_x; @@ -61,11 +64,24 @@ struct _MetaWindowWaylandClass G_DEFINE_TYPE (MetaWindowWayland, meta_window_wayland, META_TYPE_WINDOW) +static int +get_window_geometry_scale_for_logical_monitor (MetaLogicalMonitor *logical_monitor) +{ + if (meta_is_stage_views_scaled ()) + return 1; + else + return logical_monitor->scale; +} + static void meta_window_wayland_manage (MetaWindow *window) { + MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window); MetaDisplay *display = window->display; + wl_window->geometry_scale = + get_window_geometry_scale_for_logical_monitor (window->monitor); + meta_display_register_wayland_window (display, window); { @@ -375,6 +391,12 @@ meta_window_wayland_update_main_monitor (MetaWindow *window) return; } + if (meta_is_stage_views_scaled ()) + { + window->monitor = to; + return; + } + /* To avoid a window alternating between two main monitors because scaling * changes the main monitor, wait until both the current and the new scale * will result in the same main monitor. */ @@ -393,16 +415,24 @@ static void meta_window_wayland_main_monitor_changed (MetaWindow *window, const MetaLogicalMonitor *old) { + MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window); + int old_geometry_scale = wl_window->geometry_scale; + int geometry_scale; float scale_factor; MetaWaylandSurface *surface; + if (!window->monitor) + return; + + geometry_scale = meta_window_wayland_get_geometry_scale (window); + /* This function makes sure that window geometry, window actor geometry and * surface actor geometry gets set according the old and current main monitor * scale. If there either is no past or current main monitor, or if the scale * didn't change, there is nothing to do. */ if (old == NULL || window->monitor == NULL || - old->scale == window->monitor->scale) + old_geometry_scale == geometry_scale) return; /* MetaWindow keeps its rectangles in the physical pixel coordinate space. @@ -410,7 +440,7 @@ meta_window_wayland_main_monitor_changed (MetaWindow *window, * window surfaces to be scaled given the monitor scale, so we need to scale * the rectangles in MetaWindow accordingly. */ - scale_factor = (float)window->monitor->scale / old->scale; + scale_factor = (float) geometry_scale / old_geometry_scale; /* Window size. */ scale_rect_size (&window->rect, scale_factor); @@ -419,7 +449,6 @@ meta_window_wayland_main_monitor_changed (MetaWindow *window, scale_size (&window->size_hints.min_width, &window->size_hints.min_height, scale_factor); scale_size (&window->size_hints.max_width, &window->size_hints.max_height, scale_factor); - /* Window geometry offset (XXX: Need a better place, see * meta_window_wayland_move_resize). */ window->custom_frame_extents.left = @@ -449,6 +478,8 @@ meta_window_wayland_main_monitor_changed (MetaWindow *window, meta_surface_actor_wayland_sync_state_recursive (actor); } + wl_window->geometry_scale = geometry_scale; + meta_window_emit_size_changed (window); } @@ -477,6 +508,8 @@ meta_window_wayland_init (MetaWindowWayland *wl_window) { MetaWindow *window = META_WINDOW (wl_window); + wl_window->geometry_scale = 1; + g_signal_connect (window, "notify::appears-focused", G_CALLBACK (appears_focused_changed), NULL); } @@ -571,7 +604,7 @@ should_do_pending_move (MetaWindowWayland *wl_window, int meta_window_wayland_get_geometry_scale (MetaWindow *window) { - return window->monitor->scale; + return get_window_geometry_scale_for_logical_monitor (window->monitor); } /**