Merge lp:~gerboland/webbrowser-app/formFactor-support into lp:webbrowser-app

Proposed by Gerry Boland on 2016-02-22
Status: Needs review
Proposed branch: lp:~gerboland/webbrowser-app/formFactor-support
Merge into: lp:webbrowser-app
Diff against target: 298 lines (+99/-67)
5 files modified
src/Ubuntu/Components/Extras/Browser/CMakeLists.txt (+2/-0)
src/Ubuntu/Web/CMakeLists.txt (+2/-0)
src/Ubuntu/Web/UbuntuWebContext.qml (+3/-2)
src/Ubuntu/Web/UserAgent02.qml (+2/-6)
src/Ubuntu/Web/plugin.cpp (+90/-59)
To merge this branch: bzr merge lp:~gerboland/webbrowser-app/formFactor-support
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing on 2016-02-22
Ubuntu Phablet Team 2016-02-22 Pending
Review via email: mp+286790@code.launchpad.net

Commit message

Use formFactor property supplied by ubuntumirclient QPA where possible. Remove smallScreen heuristics

DO NOT LAND YET. This is (a) something for MWC, and (b) a request for comments if this approach looks reasonable to you

To post a comment you must log in.
Olivier Tilloy (osomon) wrote :

I’m not seeing any formFactor property defined on UserAgent02, so I doubt the onFormFactorChanged handler in UbuntuWebContext.qml would work.

Note that I’m currently working on a branch that removes the 'formFactor' property from the Ubuntu.Web plugin’s context object¹, so it’s kind of ironical that you’re adding it back in another branch. I really don’t think the default user agent (and corresponding overrides) should be tied to the "form factor" (whatever that means in a world of convergence). How does mir determine whether a device is a phone or a desktop, or a tablet? Is that a solid API that we are going to support and publicize?

Even if that was a sensible thing to do, we most probably don’t want to get a mobile UX on a tablet. Well, at least not a 10" tablet. On a 7" tablet maybe. See where the screenDiagonal property comes from?

As a side note, the dependency on Qt5Gui_PRIVATE is not very welcome, given that we’ve been steadily working towards entirely removing the dependencies on private Qt packages (ask Mirv about it).

¹ https://code.launchpad.net/~osomon/webbrowser-app/remove-formFactor/+merge/285539

Gerry Boland (gerboland) wrote :

> I’m not seeing any formFactor property defined on UserAgent02, so I doubt the
> onFormFactorChanged handler in UbuntuWebContext.qml would work.

Code untested. Was struggling to cross compile & deploy, sbuild unhappy with me today.

> Note that I’m currently working on a branch that removes the 'formFactor'
> property from the Ubuntu.Web plugin’s context object¹, so it’s kind of
> ironical that you’re adding it back in another branch. I really don’t think
> the default user agent (and corresponding overrides) should be tied to the
> "form factor" (whatever that means in a world of convergence). How does mir
> determine whether a device is a phone or a desktop, or a tablet? Is that a
> solid API that we are going to support and publicize?

I obviously have no idea of your plans, this was just an attempt at replacing your screen heuristic with something more concrete.

Form Factor will be a hint to the application to tell it what mode the shell is in, on each screen. Mir supports it, shell will do its best to set it correctly. I would hope the average app author has no need for such a property, any form factor specific behaviour would be encapsulated in the UITK.

> Even if that was a sensible thing to do, we most probably don’t want to get a
> mobile UX on a tablet. Well, at least not a 10" tablet. On a 7" tablet maybe.
> See where the screenDiagonal property comes from?

Is your call. The goal of this was to indicate that you can learn if the app is running on a tablet or a desktop UI at the time.

> As a side note, the dependency on Qt5Gui_PRIVATE is not very welcome, given
> that we’ve been steadily working towards entirely removing the dependencies on
> private Qt packages (ask Mirv about it).

Qt doesn't have a nice way to export it to apps yet, hence having to resort to private Qt headers. As I mentioned in a comment, a better solution is for the UITK to do that for you. This isn't the final solution.
Thanks for the comments!

1359. By Gerry Boland on 2016-02-22

formFactor not in scope, fix

Olivier Tilloy (osomon) wrote :

> > Even if that was a sensible thing to do, we most probably don’t want
> > to get a mobile UX on a tablet. Well, at least not a 10" tablet. On
> > a 7" tablet maybe. See where the screenDiagonal property comes from?
>
> Is your call. The goal of this was to indicate that you can learn if
> the app is running on a tablet or a desktop UI at the time.

Thanks, and that’s useful, but I’m not convinced that (or at least that *alone*) is enough to decide what the default UA string should be. I have started a conversation with design about that, we need to come to a consensus. Until that happens, I’d rather keep the current implementation based on screen size (I’m not against refining it though).

Chris Coulson (chrisccoulson) wrote :

> > I’m not seeing any formFactor property defined on UserAgent02, so I doubt
> the
> > onFormFactorChanged handler in UbuntuWebContext.qml would work.
>
> Code untested. Was struggling to cross compile & deploy, sbuild unhappy with
> me today.
>
> > Note that I’m currently working on a branch that removes the 'formFactor'
> > property from the Ubuntu.Web plugin’s context object¹, so it’s kind of
> > ironical that you’re adding it back in another branch. I really don’t think
> > the default user agent (and corresponding overrides) should be tied to the
> > "form factor" (whatever that means in a world of convergence). How does mir
> > determine whether a device is a phone or a desktop, or a tablet? Is that a
> > solid API that we are going to support and publicize?
>
> I obviously have no idea of your plans, this was just an attempt at replacing
> your screen heuristic with something more concrete.
>
> Form Factor will be a hint to the application to tell it what mode the shell
> is in, on each screen. Mir supports it, shell will do its best to set it
> correctly. I would hope the average app author has no need for such a
> property, any form factor specific behaviour would be encapsulated in the
> UITK.
>

It sounds like this might be useful for bug 1545088, bug 1547145 and bug 1547102. How does the shell determine what the hint is?

> > Even if that was a sensible thing to do, we most probably don’t want to get
> a
> > mobile UX on a tablet. Well, at least not a 10" tablet. On a 7" tablet
> maybe.
> > See where the screenDiagonal property comes from?
>
> Is your call. The goal of this was to indicate that you can learn if the app
> is running on a tablet or a desktop UI at the time.
>
> > As a side note, the dependency on Qt5Gui_PRIVATE is not very welcome, given
> > that we’ve been steadily working towards entirely removing the dependencies
> on
> > private Qt packages (ask Mirv about it).
>
> Qt doesn't have a nice way to export it to apps yet, hence having to resort to
> private Qt headers. As I mentioned in a comment, a better solution is for the
> UITK to do that for you. This isn't the final solution.
> Thanks for the comments!

Unmerged revisions

1359. By Gerry Boland on 2016-02-22

formFactor not in scope, fix

1358. By Gerry Boland on 2016-02-22

Use formFactor property supplied by ubuntumirclient QPA where possible. Remove smallScreen heuristics

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Ubuntu/Components/Extras/Browser/CMakeLists.txt'
2--- src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2015-06-22 10:29:20 +0000
3+++ src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2016-02-22 12:16:23 +0000
4@@ -10,6 +10,8 @@
5
6 set(PLUGIN_SRC plugin.cpp)
7
8+include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
9+
10 add_library(${PLUGIN} MODULE ${PLUGIN_SRC})
11 target_link_libraries(${PLUGIN}
12 Qt5::Core
13
14=== modified file 'src/Ubuntu/Web/CMakeLists.txt'
15--- src/Ubuntu/Web/CMakeLists.txt 2015-08-25 13:56:58 +0000
16+++ src/Ubuntu/Web/CMakeLists.txt 2016-02-22 12:16:23 +0000
17@@ -10,6 +10,8 @@
18
19 set(PLUGIN_SRC plugin.cpp)
20
21+include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
22+
23 add_library(${PLUGIN} MODULE ${PLUGIN_SRC})
24 target_link_libraries(${PLUGIN}
25 Qt5::Core
26
27=== modified file 'src/Ubuntu/Web/UbuntuWebContext.qml'
28--- src/Ubuntu/Web/UbuntuWebContext.qml 2015-12-11 10:30:42 +0000
29+++ src/Ubuntu/Web/UbuntuWebContext.qml 2016-02-22 12:16:23 +0000
30@@ -70,13 +70,14 @@
31 ]
32
33 property QtObject __ua: UserAgent02 {
34- onSmallScreenChanged: reloadOverrides()
35+ readonly property string formFactor: formFactor
36+ onFormFactorChanged: reloadOverrides()
37 Component.onCompleted: reloadOverrides()
38
39 property string _target: ""
40
41 function reloadOverrides() {
42- var target = smallScreen ? "mobile" : "desktop"
43+ var target = formFactor === "MOBILE" ? "mobile" : "desktop"
44 if (target == _target) return
45 _target = target
46 var script = "ua-overrides-%1.js".arg(target)
47
48=== modified file 'src/Ubuntu/Web/UserAgent02.qml'
49--- src/Ubuntu/Web/UserAgent02.qml 2015-12-10 10:43:04 +0000
50+++ src/Ubuntu/Web/UserAgent02.qml 2016-02-22 12:16:23 +0000
51@@ -28,10 +28,6 @@
52 */
53
54 QtObject {
55- // Empirical value: screens smaller than 19cm are considered small enough that a
56- // mobile UA string is used, screens bigger than that will get desktop content.
57- readonly property bool smallScreen: screenDiagonal < 190
58-
59 // %1: Ubuntu version, e.g. "14.04"
60 // %2: optional token to specify further attributes of the platform, e.g. "like Android"
61 // %3: optional hardware ID token
62@@ -50,7 +46,7 @@
63 // FIXME: compute at build time (using lsb_release)
64 readonly property string _ubuntuVersion: "14.04"
65
66- readonly property string _attributes: smallScreen ? "like Android 4.4" : ""
67+ readonly property string _attributes: formFactor === "MOBILE" ? "like Android 4.4" : ""
68
69 readonly property string _hardwareID: ""
70
71@@ -63,7 +59,7 @@
72 // every time we rebase on a newer chromium.
73 readonly property string _chromiumVersion: "35.0.1870.2"
74
75- readonly property string _formFactor: smallScreen ? "Mobile" : ""
76+ readonly property string _formFactor: formFactor === "MOBILE" ? "Mobile" : ""
77
78 readonly property string _more: ""
79
80
81=== modified file 'src/Ubuntu/Web/plugin.cpp'
82--- src/Ubuntu/Web/plugin.cpp 2015-12-10 22:01:05 +0000
83+++ src/Ubuntu/Web/plugin.cpp 2016-02-22 12:16:23 +0000
84@@ -34,14 +34,15 @@
85 #include <QtQml>
86 #include <QtQml/QQmlInfo>
87
88+#include <QtGui/qpa/qplatformnativeinterface.h>
89+
90 class UbuntuWebPluginContext : public QObject
91 {
92 Q_OBJECT
93
94 Q_PROPERTY(QString cacheLocation READ cacheLocation NOTIFY cacheLocationChanged)
95 Q_PROPERTY(QString dataLocation READ dataLocation NOTIFY dataLocationChanged)
96- Q_PROPERTY(QString formFactor READ formFactor CONSTANT)
97- Q_PROPERTY(qreal screenDiagonal READ screenDiagonal NOTIFY screenDiagonalChanged)
98+ Q_PROPERTY(QString formFactor READ formFactor NOTIFY formFactorChanged)
99 Q_PROPERTY(int cacheSizeHint READ cacheSizeHint NOTIFY cacheSizeHintChanged)
100 Q_PROPERTY(QString webviewDevtoolsDebugHost READ devtoolsHost CONSTANT)
101 Q_PROPERTY(int webviewDevtoolsDebugPort READ devtoolsPort CONSTANT)
102@@ -53,7 +54,6 @@
103 QString cacheLocation() const;
104 QString dataLocation() const;
105 QString formFactor();
106- qreal screenDiagonal() const;
107 int cacheSizeHint() const;
108 QString devtoolsHost();
109 int devtoolsPort();
110@@ -62,15 +62,15 @@
111 Q_SIGNALS:
112 void cacheLocationChanged() const;
113 void dataLocationChanged() const;
114- void screenDiagonalChanged() const;
115+ void formFactorChanged() const;
116 void cacheSizeHintChanged() const;
117
118 private Q_SLOTS:
119- void onFocusWindowChanged(QWindow* window);
120- void updateScreen();
121+ void onWindowPropertyChanged(QPlatformWindow* window, const QString &property);
122
123 private:
124- qreal m_screenDiagonal; // in millimeters
125+ void prepareFormFactor();
126+ QString readFormFactorFromPlatform(QPlatformWindow *window);
127 QString m_formFactor;
128 QString m_devtoolsHost;
129 int m_devtoolsPort;
130@@ -80,30 +80,57 @@
131
132 UbuntuWebPluginContext::UbuntuWebPluginContext(QObject* parent)
133 : QObject(parent)
134- , m_screenDiagonal(0)
135 , m_devtoolsPort(-2)
136 , m_hostMappingRulesQueried(false)
137 {
138 connect(qApp, SIGNAL(applicationNameChanged()), SIGNAL(cacheLocationChanged()));
139 connect(qApp, SIGNAL(applicationNameChanged()), SIGNAL(dataLocationChanged()));
140 connect(qApp, SIGNAL(applicationNameChanged()), SIGNAL(cacheSizeHintChanged()));
141- updateScreen();
142- connect(qApp, SIGNAL(focusWindowChanged(QWindow*)), SLOT(onFocusWindowChanged(QWindow*)));
143+ prepareFormFactor();
144 }
145
146-void UbuntuWebPluginContext::updateScreen()
147+namespace {
148+ // This implementation only considers two possible form factors: desktop,
149+ // and mobile (which includes phones and tablets).
150+ // XXX: do we need to consider other form factors, such as tablet?
151+ const char* DESKTOP = "desktop";
152+ const char* MOBILE = "mobile";
153+} // anonymous namespace
154+
155+void UbuntuWebPluginContext::prepareFormFactor()
156 {
157- QWindow* window = qApp->focusWindow();
158- if (window) {
159- QScreen* screen = window->screen();
160- if (screen) {
161- QSizeF size = screen->physicalSize();
162- qreal diagonal = qSqrt(size.width() * size.width() + size.height() * size.height());
163- if (diagonal != m_screenDiagonal) {
164- m_screenDiagonal = diagonal;
165- Q_EMIT screenDiagonalChanged();
166+ // The "DESKTOP_MODE" environment variable can be used to force the form
167+ // factor to desktop, when set to any valid value other than 0.
168+ const char* DESKTOP_MODE_ENV_VAR = "DESKTOP_MODE";
169+ if (qEnvironmentVariableIsSet(DESKTOP_MODE_ENV_VAR)) {
170+ QByteArray stringValue = qgetenv(DESKTOP_MODE_ENV_VAR);
171+ bool ok = false;
172+ int value = stringValue.toInt(&ok);
173+ if (ok) {
174+ m_formFactor = (value == 0) ? MOBILE : DESKTOP;
175+ return;
176+ }
177+ }
178+
179+ // If using QtUbuntu, try fetch formFactor property, falling back to assumption of mobile if that fails
180+ QString platform = QGuiApplication::platformName();
181+ if (platform != "ubuntumirclient") {
182+ m_formFactor = DESKTOP;
183+ } else { // We will get notifications of a "formFactor" property changing from the QPA for all windows
184+ auto nativeInterface = qGuiApp->platformNativeInterface();
185+ connect(nativeInterface,
186+ SIGNAL(windowPropertyChanged(QPlatformWindow*, const QString&)),
187+ SLOT(onWindowPropertyChanged(QPlatformWindow*, const QString&)));
188+
189+ auto window = qGuiApp->allWindows().first(); // FIXME: context property not suitable for per-window formFactor
190+ if (window) {
191+ auto formFactor = readFormFactorFromPlatform(window->handle());
192+ if (!formFactor.isEmpty()) {
193+ m_formFactor = formFactor;
194+ return;
195 }
196 }
197+ m_formFactor = MOBILE; // fallback position
198 }
199 }
200
201@@ -131,43 +158,9 @@
202
203 QString UbuntuWebPluginContext::formFactor()
204 {
205- if (m_formFactor.isEmpty()) {
206- // This implementation only considers two possible form factors: desktop,
207- // and mobile (which includes phones and tablets).
208- // XXX: do we need to consider other form factors, such as tablet?
209- const char* DESKTOP = "desktop";
210- const char* MOBILE = "mobile";
211-
212- // The "DESKTOP_MODE" environment variable can be used to force the form
213- // factor to desktop, when set to any valid value other than 0.
214- const char* DESKTOP_MODE_ENV_VAR = "DESKTOP_MODE";
215- if (qEnvironmentVariableIsSet(DESKTOP_MODE_ENV_VAR)) {
216- QByteArray stringValue = qgetenv(DESKTOP_MODE_ENV_VAR);
217- bool ok = false;
218- int value = stringValue.toInt(&ok);
219- if (ok) {
220- m_formFactor = (value == 0) ? MOBILE : DESKTOP;
221- return m_formFactor;
222- }
223- }
224-
225- // XXX: Assume that QtUbuntu means mobile, which is currently the case,
226- // but may not remain true forever.
227- QString platform = QGuiApplication::platformName();
228- if ((platform == "ubuntu") || (platform == "ubuntumirclient")) {
229- m_formFactor = MOBILE;
230- } else {
231- m_formFactor = DESKTOP;
232- }
233- }
234 return m_formFactor;
235 }
236
237-qreal UbuntuWebPluginContext::screenDiagonal() const
238-{
239- return m_screenDiagonal;
240-}
241-
242 int UbuntuWebPluginContext::cacheSizeHint() const
243 {
244 if (QCoreApplication::applicationName() == "webbrowser-app") {
245@@ -242,11 +235,49 @@
246 return m_devtoolsPort;
247 }
248
249-void UbuntuWebPluginContext::onFocusWindowChanged(QWindow* window)
250-{
251- updateScreen();
252- if (window) {
253- connect(window, SIGNAL(screenChanged(QScreen*)), SLOT(updateScreen()));
254+void UbuntuWebPluginContext::onWindowPropertyChanged(QPlatformWindow *window, const QString &property)
255+{
256+ if (property != QStringLiteral("formFactor")) {
257+ return;
258+ }
259+
260+ auto formFactor = readFormFactorFromPlatform(window);
261+ if (!formFactor.isEmpty()) {
262+ m_formFactor = formFactor;
263+ Q_EMIT formFactorChanged();
264+ }
265+}
266+
267+// FIXME: this should be a per-window/screen property nicely wrapped by the UITK
268+QString UbuntuWebPluginContext::readFormFactorFromPlatform(QPlatformWindow *window)
269+{
270+ auto nativeInterface = qGuiApp->platformNativeInterface();
271+ QVariant formFactorVal = nativeInterface->windowProperty(window, QStringLiteral("formFactor"));
272+ if (!formFactorVal.isValid()) {
273+ return QString();
274+ }
275+
276+ // taken from MirFormFactor enum in mirclient/common.h
277+ typedef enum MirFormFactor
278+ {
279+ mir_form_factor_unknown,
280+ mir_form_factor_phone,
281+ mir_form_factor_tablet,
282+ mir_form_factor_monitor,
283+ mir_form_factor_tv,
284+ mir_form_factor_projector,
285+ } MirFormFactor;
286+
287+ bool ok;
288+ auto formFactor = static_cast<MirFormFactor>(formFactorVal.toInt(&ok));
289+ if (!ok) {
290+ return QString();
291+ }
292+
293+ if (formFactor == mir_form_factor_phone || formFactor == mir_form_factor_tablet) {
294+ return MOBILE;
295+ } else {
296+ return DESKTOP;
297 }
298 }
299

Subscribers

People subscribed via source and target branches

to status/vote changes: