diff --git a/src/Objects/MonitorManager.vala b/src/Objects/MonitorManager.vala index 2c253beb..41e663c3 100644 --- a/src/Objects/MonitorManager.vala +++ b/src/Objects/MonitorManager.vala @@ -23,6 +23,7 @@ public class Display.MonitorManager : GLib.Object { public Gee.LinkedList virtual_monitors { get; construct; } public Gee.LinkedList monitors { get; construct; } + public bool fractional_scale_enabled { get; private set; } public bool global_scale_required { get; private set; } public bool mirroring_supported { get; private set; } public int max_width { get; private set; } @@ -103,6 +104,13 @@ public class Display.MonitorManager : GLib.Object { global_scale_required = false; } + uint layout_mode = 1; // Absence of "layout-mode" means logical (= 1) according to the documentation. + var layout_mode_variant = properties.lookup ("layout-mode"); + if (layout_mode_variant != null) { + layout_mode = layout_mode_variant.get_uint32 (); + } + fractional_scale_enabled = layout_mode == 1; + var max_screen_size_variant = properties.lookup ("max-screen-size"); if (max_screen_size_variant != null) { max_width = max_screen_size_variant.get_child_value (0).get_int32 (); diff --git a/src/Views/DisplaysView.vala b/src/Views/DisplaysView.vala index 1485a827..722cebf1 100644 --- a/src/Views/DisplaysView.vala +++ b/src/Views/DisplaysView.vala @@ -67,7 +67,12 @@ public class Display.DisplaysView : Gtk.Box { var action_bar = new Gtk.ActionBar (); action_bar.add_css_class (Granite.STYLE_CLASS_FLAT); - action_bar.pack_start (dpi_box); + + unowned Display.MonitorManager monitor_manager = Display.MonitorManager.get_default (); + if (monitor_manager.global_scale_required) { + action_bar.pack_start (dpi_box); + } + action_bar.pack_start (mirror_box); var schema_source = GLib.SettingsSchemaSource.get_default (); @@ -99,7 +104,6 @@ public class Display.DisplaysView : Gtk.Box { apply_button.sensitive = changed; }); - unowned Display.MonitorManager monitor_manager = Display.MonitorManager.get_default (); mirror_box.sensitive = monitor_manager.monitors.size > 1; monitor_manager.notify["monitor-number"].connect (() => { mirror_box.sensitive = monitor_manager.monitors.size > 1; diff --git a/src/Widgets/DisplayWidget.vala b/src/Widgets/DisplayWidget.vala index 32330320..82a10b1e 100644 --- a/src/Widgets/DisplayWidget.vala +++ b/src/Widgets/DisplayWidget.vala @@ -27,6 +27,23 @@ public struct Display.Resolution { } public class Display.DisplayWidget : Gtk.Box { + private static double[] scales; + private static string[] string_scales; + + static construct { + unowned var monitor_manager = MonitorManager.get_default (); + + if (monitor_manager.fractional_scale_enabled) { + scales = { 0.75, 1.00, 1.25, 1.50, 1.75, 2.00 }; + } else { + scales = { 1.00, 2.00 }; + } + + foreach (var scale in scales) { + string_scales += "%d %%".printf ((int) (scale * 100)); + } + } + public signal void set_as_primary (); public signal void check_position (); public signal void configuration_changed (); @@ -52,6 +69,8 @@ public class Display.DisplayWidget : Gtk.Box { private Gtk.ComboBox refresh_combobox; private Gtk.ListStore refresh_list_store; + private Gtk.DropDown scale_drop_down; + private int real_width = 0; private int real_height = 0; @@ -237,6 +256,15 @@ public class Display.DisplayWidget : Gtk.Box { populate_refresh_rates (); + scale_drop_down = new Gtk.DropDown.from_strings (string_scales) { + margin_start = 12, + margin_end = 12 + }; + + var scale_label = new Granite.HeaderLabel (_("Scaling factor")) { + mnemonic_widget = scale_drop_down + }; + var popover_box = new Gtk.Box (VERTICAL, 0) { margin_top = 6, margin_bottom = 12 @@ -249,6 +277,11 @@ public class Display.DisplayWidget : Gtk.Box { popover_box.append (refresh_label); popover_box.append (refresh_combobox); + if (!MonitorManager.get_default ().global_scale_required) { + popover_box.append (scale_label); + popover_box.append (scale_drop_down); + } + var popover = new Gtk.Popover () { child = popover_box, position = BOTTOM @@ -275,6 +308,7 @@ public class Display.DisplayWidget : Gtk.Box { use_switch.bind_property ("active", resolution_combobox, "sensitive"); use_switch.bind_property ("active", rotation_combobox, "sensitive"); use_switch.bind_property ("active", refresh_combobox, "sensitive"); + use_switch.bind_property ("active", scale_drop_down, "sensitive"); use_switch.notify["active"].connect (() => { if (rotation_combobox.active == -1) rotation_combobox.set_active (0); @@ -398,6 +432,24 @@ public class Display.DisplayWidget : Gtk.Box { } }); + virtual_monitor.notify["scale"].connect (update_selected_scale); + update_selected_scale (); + scale_drop_down.notify["selected-item"].connect ((drop_down, param_spec) => { + // Prevent breaking autohide by closing popover + popover.popdown (); + + var i = ((Gtk.DropDown) drop_down).selected; + + if (i < 0 || i > scales.length) { + warning ("Invalid scale selected."); + return; + } + + virtual_monitor.scale = scales[i]; + + configuration_changed (); + }); + rotation_combobox.set_active ((int) virtual_monitor.transform); on_vm_transform_changed (); @@ -408,6 +460,14 @@ public class Display.DisplayWidget : Gtk.Box { check_position (); } + private void update_selected_scale () { + for (uint i = 0; i < scales.length; i++) { + if (scales[i] == virtual_monitor.scale) { + scale_drop_down.selected = i; + } + } + } + private void populate_refresh_rates () { refresh_list_store.clear ();