Merge lp:~kaihengfeng/unity/set-hidpi-scale-factor into lp:unity

Proposed by Kai-Heng Feng on 2016-07-07
Status: Merged
Approved by: Andrea Azzarone on 2016-11-24
Approved revision: 4133
Merged at revision: 4212
Proposed branch: lp:~kaihengfeng/unity/set-hidpi-scale-factor
Merge into: lp:unity
Diff against target: 153 lines (+64/-2)
3 files modified
unity-shared/UScreen.cpp (+10/-0)
unity-shared/UScreen.h (+2/-0)
unity-shared/UnitySettings.cpp (+52/-2)
To merge this branch: bzr merge lp:~kaihengfeng/unity/set-hidpi-scale-factor
Reviewer Review Type Date Requested Status
Andrea Azzarone 2016-07-07 Approve on 2016-11-24
Review via email: mp+299380@code.launchpad.net

This proposal supersedes a proposal from 2016-07-04.

Commit Message

UnitySettings: If scale-factor is not set, find and set right scale for HiDPI displays.

To post a comment you must log in.
Kai-Heng Feng (kaihengfeng) wrote : Posted in a previous version of this proposal

Set gsettings value is needed, otherwise Unity Control Center's Display will reset it because scale-factor is empty.

Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

Mh, this is something I always wanted to do, so thanks.

However I'm not sure is something that should be done at unity level, since it could cause to override the user setting.
Maybe this should be done only if the value is not the default one, I guess.

The preferred way to do this, would be using a migration script though. You can write it in python and follow the same we do for ./tools/migration-scripts/*.

I'd like to discuss about the algorithm to find the proper scaling value. Since we also support non-integer values, it would be nicer to define a scaling to be proportional to display size by using some thresholds.

Kai-Heng Feng (kaihengfeng) wrote : Posted in a previous version of this proposal

I think this won't override user setting, as long as it's greater than 0.

With this algorithm, a 27 inches 4K display will have scale factor 1.
So yes, I think if the scale can be proportional to display size would be great.

Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

Ok, overriding a 0 value is fine then.

As for the thresholds calculations, can we do some testing?

Kai-Heng Feng (kaihengfeng) wrote : Posted in a previous version of this proposal

Sure.

I think we can make the scale factor being proportional to the DPI, if the DPI is in range of DEFAULT_DPI to DEFAULT_DPI * 2. Your thought?

Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

Yeah, I agree.

Kai-Heng Feng (kaihengfeng) wrote : Posted in a previous version of this proposal

I choose 140 DPI as a base because it's the DPI on a 15" FHD screen. And both 15" UHD screen and 13" QHD+ screen has roughly 280 DPI, both of them look great with scale factor 2.

Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

We're there, just a few style fixes.

Kai-Heng Feng (kaihengfeng) wrote :

Since the value eventually set into scale-factor is an integer, I use the same type for DPI_SCALING_STEP.

Andrea Azzarone (azzar1) wrote :

Can you explain why the check on the sizes as per diff comment?

review: Needs Information
Kai-Heng Feng (kaihengfeng) wrote :

It's from Unity Settings Daemon [1].
I believe this size check is cherry-picked from Gnome Settings Daemon.

[1] https://bazaar.launchpad.net/~unity-settings-daemon-team/unity-settings-daemon/trunk/view/head:/plugins/xsettings/gsd-xsettings-manager.c#L491

Kai-Heng Feng (kaihengfeng) wrote :

Any chance to merge this patch? :)

Kai-Heng Feng (kaihengfeng) wrote :

Currently our team has several high-end machines with UHD/QHD display need to be enabled, so auto-scale will be great if it can work out of the box.

Is there any improvement for this patch I can make?

Andrea Azzarone (azzar1) wrote :

Code looks good to me and it works fine on my 4k monitor.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'unity-shared/UScreen.cpp'
2--- unity-shared/UScreen.cpp 2014-12-18 18:43:36 +0000
3+++ unity-shared/UScreen.cpp 2016-07-07 07:45:15 +0000
4@@ -88,6 +88,11 @@
5 return monitors_[monitor];
6 }
7
8+nux::Size const& UScreen::GetMonitorPhysicalSize(int monitor) const
9+{
10+ return physical_monitors_[monitor];
11+}
12+
13 std::vector<nux::Geometry> const& UScreen::GetMonitors() const
14 {
15 return monitors_;
16@@ -154,6 +159,7 @@
17
18 nux::Geometry last_geo;
19 monitors_.clear();
20+ physical_monitors_.clear();
21 primary_ = gdk_screen_get_primary_monitor(screen_);
22 int monitors = gdk_screen_get_n_monitors(screen_);
23
24@@ -164,6 +170,9 @@
25
26 float scale = gdk_screen_get_monitor_scale_factor(screen_, i);
27 nux::Geometry geo(rect.x, rect.y, rect.width, rect.height);
28+
29+ nux::Size physical_size(gdk_screen_get_monitor_width_mm(screen_, i),
30+ gdk_screen_get_monitor_height_mm(screen_, i));
31
32 if (scale != 1.0)
33 geo = geo * scale;
34@@ -174,6 +183,7 @@
35
36 last_geo = geo;
37 monitors_.push_back(geo);
38+ physical_monitors_.push_back(physical_size);
39
40 LOG_DEBUG(logger) << "Monitor " << i << " has geometry " << geo.x << "x"
41 << geo.y << "x" << geo.width << "x" << geo.height;
42
43=== modified file 'unity-shared/UScreen.h'
44--- unity-shared/UScreen.h 2014-10-21 15:43:16 +0000
45+++ unity-shared/UScreen.h 2016-07-07 07:45:15 +0000
46@@ -45,6 +45,7 @@
47 int GetMonitorWithMouse() const;
48 int GetMonitorAtPosition(int x, int y) const;
49 nux::Geometry const& GetMonitorGeometry(int monitor) const;
50+ nux::Size const& GetMonitorPhysicalSize(int monitor) const;
51
52 std::vector<nux::Geometry> const& GetMonitors() const;
53 nux::Geometry GetScreenGeometry() const;
54@@ -63,6 +64,7 @@
55 protected:
56 static UScreen* default_screen_;
57 std::vector<nux::Geometry> monitors_;
58+ std::vector<nux::Size> physical_monitors_;
59 int primary_;
60
61 private:
62
63=== modified file 'unity-shared/UnitySettings.cpp'
64--- unity-shared/UnitySettings.cpp 2016-07-04 14:21:00 +0000
65+++ unity-shared/UnitySettings.cpp 2016-07-07 07:45:15 +0000
66@@ -76,6 +76,8 @@
67 const int MINIMUM_DESKTOP_HEIGHT = 800;
68 const int GNOME_SETTINGS_CHANGED_WAIT_SECONDS = 1;
69 const double DEFAULT_DPI = 96.0f;
70+const double DPI_SCALING_LIMIT = 140.0f;
71+const int DPI_SCALING_STEP = 8;
72 }
73
74 //
75@@ -322,6 +324,34 @@
76 return em_converters_[monitor];
77 }
78
79+ int FindOptimalScale(const UScreen* uscreen, const int monitor)
80+ {
81+ auto const& geo = uscreen->GetMonitorGeometry(monitor);
82+ auto const& size = uscreen->GetMonitorPhysicalSize(monitor);
83+ auto scale = DPI_SCALING_STEP;
84+
85+ if ((size.width == 160 && size.height == 90) ||
86+ (size.width == 160 && size.height == 100) ||
87+ (size.width == 16 && size.height == 9) ||
88+ (size.width == 16 && size.height == 10))
89+ {
90+ return scale;
91+ }
92+
93+ if (size.width > 0 && size.height > 0)
94+ {
95+ const double dpi_x = static_cast<double>(geo.width) / (size.width / 25.4);
96+ const double dpi_y = static_cast<double>(geo.height) / (size.height / 25.4);
97+
98+ const auto dpi = std::max(dpi_x, dpi_y);
99+
100+ if (dpi > DPI_SCALING_LIMIT)
101+ scale = static_cast<int>(std::lround(scale * dpi / DPI_SCALING_LIMIT));
102+ }
103+
104+ return scale;
105+ }
106+
107 void UpdateDPI()
108 {
109 auto* uscreen = UScreen::GetDefault();
110@@ -332,6 +362,10 @@
111 glib::Variant dict;
112 g_settings_get(ubuntu_ui_settings_, SCALE_FACTOR.c_str(), "@a{si}", &dict);
113
114+ bool dict_changed = false;
115+ GVariantBuilder builder;
116+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{si}"));
117+
118 glib::String app_target_monitor(g_settings_get_string(ui_settings_, APP_SCALE_MONITOR.c_str()));
119 double app_target_scale = 0;
120
121@@ -345,8 +379,18 @@
122 double ui_scale = 1.0f;
123 int value;
124
125- if (g_variant_lookup(dict, monitor_name.c_str(), "i", &value) && value > 0)
126- ui_scale = static_cast<double>(value)/8.0f;
127+ if (g_variant_lookup(dict, monitor_name.c_str(), "i", &value))
128+ {
129+ if (value > 0)
130+ ui_scale = static_cast<double>(value)/DPI_SCALING_STEP;
131+ }
132+ else
133+ {
134+ value = FindOptimalScale(uscreen, monitor);
135+ ui_scale = static_cast<double>(value)/DPI_SCALING_STEP;
136+ dict_changed = true;
137+ }
138+ g_variant_builder_add(&builder, "{si}", monitor_name.c_str(), value);
139
140 if (app_target_monitor.Str() == monitor_name)
141 app_target_scale = ui_scale;
142@@ -360,6 +404,12 @@
143 any_changed = true;
144 }
145
146+ glib::Variant new_dict(g_variant_builder_end(&builder));
147+ if (dict_changed)
148+ {
149+ g_settings_set_value(ubuntu_ui_settings_, SCALE_FACTOR.c_str(), new_dict);
150+ }
151+
152 if (app_target_scale == 0)
153 app_target_scale = (g_settings_get_boolean(ui_settings_, APP_USE_MAX_SCALE.c_str())) ? max_scale : min_scale;
154