Skip to content

monitor-config-manager: Fallback to closed laptop lid configuration

When closing the lid of a laptop, we reconfigure all the monitors in order to update the CRTCs and (if enabled) the global UI scaling factor.

To do this, we try first to reuse the current configuration for the usable monitors, but if we have only monitor enabled and this one is on the laptop lid we just end up creating a new configuration where the primary monitor is the laptop one (as per find_primary_monitor() in MetaMonitorConfigManager), but ignoring the user parameters.

In case the user selected a different resolution / scaling compared to the default one, while the laptop lid is closed we might change the monitors layout, causing applications to rescale or reposition.

To avoid this, when creating the monitors configuration from the current current state, in case we have only one monitor available and that one is the laptop panel, let's just reuse this configuration.


This fixes an issue we noticed when the user with a laptop with a native resolution that would be using 2x (or more) scaling, disabled the scaling in g-c-c, in such scenario while the laptop lid is closed the scaling goes back to 1 before being set again to 2, causing windows re-layouting.

Can be watched easily in X11 with, when launching xprop just before closing the lid:

xprop -root -spy RESOURCE_MANAGER
RESOURCE_MANAGER(STRING) = "Xft.dpi:\t96\nXft.antialias:\t1\nXft.hinting:\t1\nXft.hintstyle:\thintslight\nXft.rgba:\tnone\nXcursor.size:\t24\nXcursor.theme:\tAdwaita\n
# Now closing the lid
RESOURCE_MANAGER(STRING) = "Xft.dpi:\t192\nXft.antialias:\t1\nXft.hinting:\t1\nXft.hintstyle:\thintslight\nXft.rgba:\tnone\nXcursor.size:\t48\nXcursor.theme:\tAdwaita\n"
# Reopened
RESOURCE_MANAGER(STRING) = "Xft.dpi:\t96\nXft.antialias:\t1\nXft.hinting:\t1\nXft.hintstyle:\thintslight\nXft.rgba:\tnone\nXcursor.size:\t24\nXcursor.theme:\tAdwaita\n"

Now, something similar could be done achieved also by just ignoring the monitors configuration on lid-closed in case we have just one monitor (as below), but I wanted to be a bit more conservative, so let me know what you prefer.

--- a/src/backends/meta-monitor-manager.c
+++ b/src/backends/meta-monitor-manager.c
@@ -383,7 +383,8 @@ power_save_mode_changed (MetaMonitorManager *manager,
 void
 meta_monitor_manager_lid_is_closed_changed (MetaMonitorManager *manager)
 {
-  meta_monitor_manager_ensure_configured (manager);
+  if (manager->monitors && manager->monitors->next)
+    meta_monitor_manager_ensure_configured (manager);
 }

 static void
Some debugging info

Thread 1 "gnome-shell" hit Breakpoint 1, update_ui_scaling_factor (settings=settings@entry=0x560080393360) at ../../mutter/src/backends/meta-settings.c:103
103     ../../mutter/src/backends/meta-settings.c: No such file or directory.
(gdb) bt
#0  update_ui_scaling_factor (settings=settings@entry=0x560080393360) at ../../mutter/src/backends/meta-settings.c:103
#1  0x00007f841c64cee6 in meta_settings_update_ui_scaling_factor (settings=0x560080393360) at ../../mutter/src/backends/meta-settings.c:119
#2  0x00007f841d340912 in g_closure_invoke (closure=0x5600806a1830, return_value=0x0, n_param_values=1, param_values=0x7ffd1cad2ba0, invocation_hint=0x7ffd1cad2b20) at ../../glib/gobject/gclosure.c:810
#3  0x00007f841d354603 in signal_emit_unlocked_R (node=node@entry=0x5600803e7c00, detail=detail@entry=0, instance=instance@entry=0x5600803abb20, emission_return=emission_return@entry=0x0, 
    instance_and_params=instance_and_params@entry=0x7ffd1cad2ba0) at ../../glib/gobject/gsignal.c:3808
#4  0x00007f841d36027e in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7ffd1cad2d50) at ../../glib/gobject/gsignal.c:3494
#5  0x00007f841d3607b3 in g_signal_emit (instance=instance@entry=0x5600803abb20, signal_id=<optimized out>, detail=detail@entry=0) at ../../glib/gobject/gsignal.c:3550
#6  0x00007f841c6464b7 in meta_monitor_manager_notify_monitors_changed (manager=manager@entry=0x5600803abb20) at ../../mutter/src/backends/meta-monitor-manager.c:2745
#7  0x00007f841c648d60 in meta_monitor_manager_rebuild_derived (manager=0x5600803abb20, config=0x560083065e40) at ../../mutter/src/backends/meta-monitor-manager.c:2879
#8  0x00007f841c659c7a in meta_monitor_manager_xrandr_rebuild_derived (manager=<optimized out>, config=<optimized out>) at ../../mutter/src/backends/x11/meta-monitor-manager-xrandr.c:584
#9  0x00007f841c65a1f3 in meta_monitor_manager_xrandr_apply_monitors_config (manager=<optimized out>, config=<optimized out>, method=<optimized out>, error=<optimized out>)
    at ../../mutter/src/backends/x11/meta-monitor-manager-xrandr.c:632
#10 0x00007f841c646511 in meta_monitor_manager_apply_monitors_config (manager=0x5600803abb20, config=0x560083065e40, method=META_MONITORS_CONFIG_METHOD_PERSISTENT, error=<optimized out>)
    at ../../mutter/src/backends/meta-monitor-manager.c:499
#11 0x00007f841c6477b0 in meta_monitor_manager_ensure_configured (manager=0x5600803abb20) at ../../mutter/src/backends/meta-monitor-manager.c:626
#12 0x00007f841d342e42 in g_cclosure_marshal_VOID__BOOLEANv (closure=<optimized out>, return_value=<optimized out>, instance=<optimized out>, args=<optimized out>, marshal_data=<optimized out>, 
    n_params=<optimized out>, param_types=0x56008036bcb0) at ../../glib/gobject/gmarshal.c:272
#13 0x00007f841d340b66 in _g_closure_invoke_va (closure=0x5600803ee160, return_value=0x0, instance=0x56008037d170, args=0x7ffd1cad3220, n_params=1, param_types=0x56008036bcb0) at ../../glib/gobject/gclosure.c:873
#14 0x00007f841d360208 in g_signal_emit_valist (instance=0x56008037d170, signal_id=<optimized out>, detail=0, var_args=var_args@entry=0x7ffd1cad3220) at ../../glib/gobject/gsignal.c:3403
#15 0x00007f841d3607b3 in g_signal_emit (instance=instance@entry=0x56008037d170, signal_id=<optimized out>, detail=detail@entry=0) at ../../glib/gobject/gsignal.c:3550
#16 0x00007f841c6303c2 in upower_properties_changed (proxy=<optimized out>, changed_properties=<optimized out>, invalidated_properties=<optimized out>, user_data=0x56008037d170)
    at ../../mutter/src/backends/meta-backend.c:638
#17 0x00007f841d340912 in g_closure_invoke (closure=0x560082d53dc0, return_value=0x0, n_param_values=3, param_values=0x7ffd1cad34f0, invocation_hint=0x7ffd1cad3470) at ../../glib/gobject/gclosure.c:810
#18 0x00007f841d354bd4 in signal_emit_unlocked_R (node=node@entry=0x56008039c7a0, detail=detail@entry=0, instance=instance@entry=0x5600828ed9b0, emission_return=emission_return@entry=0x0, 
    instance_and_params=instance_and_params@entry=0x7ffd1cad34f0) at ../../glib/gobject/gsignal.c:3738
#19 0x00007f841d36027e in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7ffd1cad36d0) at ../../glib/gobject/gsignal.c:3494
#20 0x00007f841d3607b3 in g_signal_emit (instance=instance@entry=0x5600828ed9b0, signal_id=<optimized out>, detail=detail@entry=0) at ../../glib/gobject/gsignal.c:3550
#21 0x00007f841d4a847b in on_properties_changed (connection=<optimized out>, sender_name=<optimized out>, object_path=<optimized out>, interface_name=<optimized out>, signal_name=<optimized out>, 
    parameters=<optimized out>, user_data=0x560082415480) at ../../glib/gio/gdbusproxy.c:1096
#22 0x00007f841d495c0f in emit_signal_instance_in_idle_cb (data=0x560080cbb100) at ../../glib/gio/gdbusconnection.c:3777
#23 0x00007f841d2531ee in g_main_dispatch (context=0x56008037b510) at ../../glib/glib/gmain.c:3309
#24 g_main_context_dispatch (context=context@entry=0x56008037b510) at ../../glib/glib/gmain.c:3974
#25 0x00007f841d2535a0 in g_main_context_iterate (context=0x56008037b510, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../../glib/glib/gmain.c:4047
#26 0x00007f841d253893 in g_main_loop_run (loop=0x56008069a4e0) at ../../glib/glib/gmain.c:4241
#27 0x00007f841c68aa60 in meta_run () at ../../mutter/src/core/main.c:676
#28 0x000056007eb36729 in main (argc=1, argv=0x7ffd1cad3b38) at ../../gnome-shell/src/main.c:634
(gdb) list
98      in ../../mutter/src/backends/meta-settings.c
(gdb) print ui_scaling_factor
$1 = 2
(gdb) call meta_monitor_manager_get_primary_logical_monitor (meta_backend_get_monitor_manager (settings->backend))
$3 = (MetaLogicalMonitor *) 0x560081249320
(gdb) print *$3
$4 = {parent = {g_type_instance = {g_class = 0x560080676900}, ref_count = 1, qdata = 0x0}, number = 0, rect = {x = 0, y = 0, width = 2560, height = 1440}, is_primary = 1, is_presentation = 0, in_fullscreen = -1, 
  scale = 2, transform = META_MONITOR_TRANSFORM_NORMAL, winsys_id = 66, monitors = 0x560080907400}
(gdb) 


#10 0x00007f841c646511 in meta_monitor_manager_apply_monitors_config (manager=0x5600803abb20, config=0x560083065e40, method=META_MONITORS_CONFIG_METHOD_PERSISTENT, error=<optimized out>)
    at ../../mutter/src/backends/meta-monitor-manager.c:499
499     ../../mutter/src/backends/meta-monitor-manager.c: No such file or directory.
(gdb) print config
$16 = (MetaMonitorsConfig *) 0x560083065e40
(gdb) print config->
disabled_monitor_specs   flags                    key                      layout_mode              logical_monitor_configs  parent                   switch_config            
(gdb) print config->layout_mode 
$17 = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL
(gdb) print config->logical_monitor_configs 
$18 = (GList *) 0x5600809c6f40
(gdb) print config->logical_monitor_configs->data 
$19 = (gpointer) 0x560080ef4a40
(gdb) print config->logical_monitor_configs->next
$20 = (GList *) 0x0
(gdb) print config->logical_monitor_configs->data
$21 = (gpointer) 0x560080ef4a40
(gdb) print *(MetaLogicalMonitorConfig*) config->logical_monitor_configs->data
$22 = {layout = {x = 0, y = 0, width = 2560, height = 1440}, monitor_configs = 0x5600809c02e0, transform = META_MONITOR_TRANSFORM_NORMAL, scale = 2, is_primary = 1, is_presentation = 0}
(gdb) call meta_backend_is_lid_closed (meta_monitor_manager_get_backend(manager))
Edited by Marco Trevisan

Merge request reports