Merge lp:~osomon/webbrowser-app/xenial-sru-1 into lp:webbrowser-app/xenial

Proposed by Olivier Tilloy
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 1427
Merged at revision: 1418
Proposed branch: lp:~osomon/webbrowser-app/xenial-sru-1
Merge into: lp:webbrowser-app/xenial
Diff against target: 905 lines (+274/-86)
27 files modified
debian/changelog (+15/-0)
debian/control (+2/-1)
src/Ubuntu/CMakeLists.txt (+4/-0)
src/Ubuntu/Web/UserAgent02.qml (+4/-10)
src/Ubuntu/Web/plugin.cpp (+7/-0)
src/Ubuntu/Web/ua-overrides-desktop.js (+5/-0)
src/Ubuntu/Web/ua-overrides-mobile.js (+6/-1)
src/app/browserapplication.cpp (+32/-24)
src/app/browserapplication.h (+1/-2)
src/app/config.h.in (+0/-1)
src/app/single-instance-manager.cpp (+39/-3)
src/app/single-instance-manager.h (+1/-1)
src/app/webbrowser/Browser.qml (+21/-15)
src/app/webbrowser/BrowserTab.qml (+3/-2)
src/app/webbrowser/NavigationBar.qml (+1/-2)
src/app/webbrowser/webbrowser-app.cpp (+1/-1)
src/app/webcontainer/WebApp.qml (+1/-0)
src/app/webcontainer/WebViewImplOxide.qml (+28/-14)
src/app/webcontainer/WebappContainerWebview.qml (+3/-1)
src/app/webcontainer/webapp-container.cpp (+32/-1)
src/app/webcontainer/webapp-container.h (+1/-0)
src/app/webcontainer/webapp-container.qml (+2/-0)
tests/autopilot/webapp_container/tests/__init__.py (+4/-0)
tests/autopilot/webapp_container/tests/fake_servers.py (+29/-0)
tests/autopilot/webapp_container/tests/test_popup_webview_overlay.py (+19/-0)
tests/autopilot/webapp_container/tests/test_saml_url_patterns.py (+9/-3)
tests/unittests/single-instance-manager/tst_SingleInstanceManagerTests.cpp (+4/-4)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/xenial-sru-1
Reviewer Review Type Date Requested Status
Ubuntu Phablet Team Pending
Review via email: mp+299522@code.launchpad.net

Commit message

SRU for selected bug fixes:
 - LP #1565055: support for google hangouts
 - LP #1573017: SAML detection logic broken in webapp container
 - LP #1572673: invalid variable access error in webapp container
 - LP #1466427: dynamic Ubuntu version in default UA string
 - LP #1576639: fine-tune the custom memory-pressure handler
 - LP #1581025: secure connection icon not showing
 - LP #1580290: only load the current tab when the session is restored
 - LP #1577806: browser and container open under the same instance
 - LP #1565063: dynamic Chromium version in default UA string

To post a comment you must log in.
1427. By Olivier Tilloy

Add a custom changelog entry.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2016-04-13 15:22:11 +0000
3+++ debian/changelog 2016-08-18 09:28:41 +0000
4@@ -1,3 +1,18 @@
5+webbrowser-app (0.23+16.04.20160818-0ubuntu1) UNRELEASED; urgency=medium
6+
7+ * SRU for selected bug fixes:
8+ - LP #1565055: support for google hangouts
9+ - LP #1573017: SAML detection logic broken in webapp container
10+ - LP #1572673: invalid variable access error in webapp container
11+ - LP #1466427: dynamic Ubuntu version in default UA string
12+ - LP #1576639: fine-tune the custom memory-pressure handler
13+ - LP #1581025: secure connection icon not showing
14+ - LP #1580290: only load the current tab when the session is restored
15+ - LP #1577806: browser and container open under the same instance
16+ - LP #1565063: dynamic Chromium version in default UA string
17+
18+ -- Olivier Tilloy <olivier.tilloy@canonical.com> Thu, 18 Aug 2016 11:25:10 +0200
19+
20 webbrowser-app (0.23+16.04.20160413-0ubuntu1) xenial; urgency=medium
21
22 * Do not handle backspace as a window-level shortcut, as it would take
23
24=== modified file 'debian/control'
25--- debian/control 2016-04-08 17:06:09 +0000
26+++ debian/control 2016-08-18 09:28:41 +0000
27@@ -15,6 +15,7 @@
28 liboxideqt-qmlplugin (>= 1.12),
29 libqt5sql5-sqlite,
30 libudev-dev,
31+ lsb-release,
32 pkg-config,
33 python3-all,
34 python3-flake8,
35@@ -115,7 +116,7 @@
36 Pre-Depends: ${misc:Pre-Depends}
37 Depends: ${misc:Depends},
38 ${shlibs:Depends},
39- liboxideqt-qmlplugin (>= 1.12),
40+ liboxideqt-qmlplugin (>= 1.15),
41 qml-module-qtquick2 (>= 5.4),
42 qml-module-qtquick-window2 (>= 5.3),
43 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3),
44
45=== modified file 'src/Ubuntu/CMakeLists.txt'
46--- src/Ubuntu/CMakeLists.txt 2014-05-29 17:03:44 +0000
47+++ src/Ubuntu/CMakeLists.txt 2016-08-18 09:28:41 +0000
48@@ -19,5 +19,9 @@
49 set(QT_INSTALL_QML "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt5/qml")
50 endif()
51
52+execute_process(COMMAND lsb_release --short --release
53+ OUTPUT_VARIABLE UBUNTU_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
54+add_definitions(-DUBUNTU_VERSION="${UBUNTU_VERSION}")
55+
56 add_subdirectory(Components)
57 add_subdirectory(Web)
58
59=== modified file 'src/Ubuntu/Web/UserAgent02.qml'
60--- src/Ubuntu/Web/UserAgent02.qml 2015-12-10 10:43:04 +0000
61+++ src/Ubuntu/Web/UserAgent02.qml 2016-08-18 09:28:41 +0000
62@@ -1,5 +1,5 @@
63 /*
64- * Copyright 2013-2015 Canonical Ltd.
65+ * Copyright 2013-2016 Canonical Ltd.
66 *
67 * This file is part of webbrowser-app.
68 *
69@@ -17,6 +17,7 @@
70 */
71
72 import QtQml 2.0
73+import com.canonical.Oxide 1.15
74
75 /*
76 * Useful documentation:
77@@ -47,9 +48,6 @@
78 // difference in the content served by certain sites (e.g. gmail.com)
79 readonly property string _template: "Mozilla/5.0 (Linux; Ubuntu %1%2%3) AppleWebKit/%4 Chromium/%5 %6Safari/%7%8"
80
81- // FIXME: compute at build time (using lsb_release)
82- readonly property string _ubuntuVersion: "14.04"
83-
84 readonly property string _attributes: smallScreen ? "like Android 4.4" : ""
85
86 readonly property string _hardwareID: ""
87@@ -57,11 +55,7 @@
88 // See chromium/src/content/webkit_version.h.in in oxide’s source tree.
89 readonly property string _webkitVersion: "537.36"
90
91- // See chromium/src/chrome/VERSION in oxide’s source tree.
92- // Note: the actual version number probably doesn’t matter that much,
93- // however its format does, so we probably don’t need to bump it
94- // every time we rebase on a newer chromium.
95- readonly property string _chromiumVersion: "35.0.1870.2"
96+ readonly property string _chromiumVersion: Oxide.chromiumVersion
97
98 readonly property string _formFactor: smallScreen ? "Mobile" : ""
99
100@@ -69,7 +63,7 @@
101
102 property string defaultUA: {
103 var ua = _template
104- ua = ua.arg(_ubuntuVersion) // %1
105+ ua = ua.arg(ubuntuVersion) // %1
106 ua = ua.arg((_attributes !== "") ? " %1".arg(_attributes) : "") // %2
107 ua = ua.arg((_hardwareID !== "") ? "; %1".arg(_hardwareID) : "") // %3
108 ua = ua.arg(_webkitVersion) // %4
109
110=== modified file 'src/Ubuntu/Web/plugin.cpp'
111--- src/Ubuntu/Web/plugin.cpp 2016-02-09 21:56:55 +0000
112+++ src/Ubuntu/Web/plugin.cpp 2016-08-18 09:28:41 +0000
113@@ -45,6 +45,7 @@
114 Q_PROPERTY(QString webviewDevtoolsDebugHost READ devtoolsHost CONSTANT)
115 Q_PROPERTY(int webviewDevtoolsDebugPort READ devtoolsPort CONSTANT)
116 Q_PROPERTY(QStringList webviewHostMappingRules READ hostMappingRules CONSTANT)
117+ Q_PROPERTY(QString ubuntuVersion READ ubuntuVersion CONSTANT)
118
119 public:
120 UbuntuWebPluginContext(QObject* parent = 0);
121@@ -56,6 +57,7 @@
122 QString devtoolsHost();
123 int devtoolsPort();
124 QStringList hostMappingRules();
125+ QString ubuntuVersion() const;
126
127 Q_SIGNALS:
128 void cacheLocationChanged() const;
129@@ -205,6 +207,11 @@
130 return m_devtoolsPort;
131 }
132
133+QString UbuntuWebPluginContext::ubuntuVersion() const
134+{
135+ return QStringLiteral(UBUNTU_VERSION);
136+}
137+
138 void UbuntuWebPluginContext::onFocusWindowChanged(QWindow* window)
139 {
140 updateScreen();
141
142=== modified file 'src/Ubuntu/Web/ua-overrides-desktop.js'
143--- src/Ubuntu/Web/ua-overrides-desktop.js 2016-03-21 10:29:07 +0000
144+++ src/Ubuntu/Web/ua-overrides-desktop.js 2016-08-18 09:28:41 +0000
145@@ -24,4 +24,9 @@
146 ["^https?:\/\/(www\.)?youtube\.com\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/35.0.1870.2 Safari/537.36"], // http://pad.lv/1412880
147 ["^https?:\/\/(www\.)?google\..+\/maps", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/35.0.1870.2 Safari/537.36"], // http://pad.lv/1503506, http://pad.lv/1551649
148 ["^https?:\/\/mail\.google\.com\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/47.0.2526.106 Safari/537.36"], // http://pad.lv/1452616
149+
150+ // Google hangouts (https://launchpad.net/bugs/1565055)
151+ ["^https?:\/\/hangouts\.google\.com\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/49.0.2623.87 Safari/537.36"],
152+ ["^https?:\/\/talkgadget\.google\.com\/hangouts\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/49.0.2623.87 Safari/537.36"],
153+ ["^https?:\/\/plus\.google\.com\/hangouts\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/49.0.2623.87 Safari/537.36"],
154 ];
155
156=== modified file 'src/Ubuntu/Web/ua-overrides-mobile.js'
157--- src/Ubuntu/Web/ua-overrides-mobile.js 2015-09-28 15:23:56 +0000
158+++ src/Ubuntu/Web/ua-overrides-mobile.js 2016-08-18 09:28:41 +0000
159@@ -1,5 +1,5 @@
160 /*
161- * Copyright 2014-2015 Canonical Ltd.
162+ * Copyright 2014-2016 Canonical Ltd.
163 *
164 * This file is part of webbrowser-app.
165 *
166@@ -24,4 +24,9 @@
167 ["^http:\/\/chrome\.angrybirds\.com\/", "Mozilla/5.0 (Linux; Ubuntu 14.04 like Android 4.4;) AppleWebKit/537.36 Chrome/35.0.1870.2 Mobile Safari/537.36"], // http://pad.lv/1284158
168 ["^https?:\/\/(\w+\.)*hsbc\.com\.br\/", "Mozilla/5.0 (Linux; Ubuntu 14.04 like Android 4.4;) AppleWebKit/537.36 Chrome/35.0.1870.2 Mobile Safari/537.36"], // http://pad.lv/1380657
169 ["^http:\/\/(\w+\.)*espn\.(go\.)?com\/", "Mozilla/5.0 (Linux; Ubuntu 14.04 like Android 4.4;) AppleWebKit/537.36 Chrome/35.0.1870.2 Mobile Safari/537.36"], // http://pad.lv/1316259
170+
171+ // Google hangouts (https://launchpad.net/bugs/1565055)
172+ ["^https?:\/\/hangouts\.google\.com\/", "Mozilla/5.0 (Linux; Ubuntu 14.04 like Android 4.4;) AppleWebKit/537.36 Chrome/49.0.2623.87 Mobile Safari/537.36"],
173+ ["^https?:\/\/talkgadget\.google\.com\/hangouts\/", "Mozilla/5.0 (Linux; Ubuntu 14.04 like Android 4.4;) AppleWebKit/537.36 Chrome/49.0.2623.87 Mobile Safari/537.36"],
174+ ["^https?:\/\/plus\.google\.com\/hangouts\/", "Mozilla/5.0 (Linux; Ubuntu 14.04 like Android 4.4;) AppleWebKit/537.36 Chrome/49.0.2623.87 Mobile Safari/537.36"],
175 ];
176
177=== modified file 'src/app/browserapplication.cpp'
178--- src/app/browserapplication.cpp 2016-03-29 11:01:18 +0000
179+++ src/app/browserapplication.cpp 2016-08-18 09:28:41 +0000
180@@ -98,16 +98,6 @@
181 return host;
182 }
183
184-QString BrowserApplication::appId() const
185-{
186- Q_FOREACH(const QString& argument, m_arguments) {
187- if (argument.startsWith("--app-id=")) {
188- return argument.split("--app-id=")[1];
189- }
190- }
191- return QString();
192-}
193-
194 #define MAKE_SINGLETON_FACTORY(type) \
195 static QObject* type##_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine) { \
196 Q_UNUSED(engine); \
197@@ -119,36 +109,54 @@
198 MAKE_SINGLETON_FACTORY(MimeDatabase)
199 MAKE_SINGLETON_FACTORY(Direction)
200
201-
202-bool BrowserApplication::initialize(const QString& qmlFileSubPath)
203+bool BrowserApplication::initialize(const QString& qmlFileSubPath
204+ , const QString& appId)
205 {
206 Q_ASSERT(m_window == 0);
207
208+ if (appId.isEmpty()) {
209+ qCritical() << "Cannot initialize the runtime environment: "
210+ "no application id detected.";
211+ return false;
212+ }
213+
214 if (m_arguments.contains("--help") || m_arguments.contains("-h")) {
215 printUsage();
216 return false;
217 }
218
219- // Handle legacy platforms (i.e. current desktop versions, where
220- // applications are not started by the Ubuntu ApplicationManager).
221- if (qgetenv("APP_ID").isEmpty()) {
222- QString id = appId();
223- if (id.isEmpty()) {
224- id = QStringLiteral(APP_ID);
225- }
226- qputenv("APP_ID", id.toUtf8());
227- }
228 // Ensure that application-specific data is written where it ought to.
229- QStringList appIdParts =
230- QString::fromUtf8(qgetenv("APP_ID")).split('_');
231+ QStringList appIdParts = appId.split('_');
232+
233 QCoreApplication::setApplicationName(appIdParts.first());
234 QCoreApplication::setOrganizationDomain(QCoreApplication::applicationName());
235+
236 // Get also the the first two components of the app ID: <package>_<app>,
237 // which is needed by Online Accounts.
238 QString unversionedAppId = QStringList(appIdParts.mid(0, 2)).join('_');
239
240 // Ensure only one instance of the app is running.
241- if (m_singleton.run(m_arguments)) {
242+ // For webapps using the container as a launcher, the predicate that
243+ // is used to determine if this running instance is a duplicate of
244+ // a running one, is based on the current APP_ID.
245+ // The app id is formed as: <package name>_<app name>_<version>
246+
247+ // Where the <package name> is specified in the the manifest.json as
248+ // "appName" and is specific for the whole click package.
249+
250+ // The <app name> portion is based on the desktop file name and is a short
251+ // app name. This name is meaningful when more than one desktop file is
252+ // found in a given click package.
253+
254+ // IMPORTANT:
255+ // 1. When a click application contains more than one desktop file
256+ // the bundle is considered a single app from the point of view of the
257+ // cache and resource file locations. THOSE FILES ARE THEN SHARED between
258+ // the instances.
259+ // 2. To make sure that if more than one desktop file is found in a click package,
260+ // those apps are not considered the same instance, the instance existance predicate
261+ // is based on the <package name> AND the <app name> detailed above.
262+ if (m_singleton.run(m_arguments, appId)) {
263 connect(&m_singleton, SIGNAL(newInstanceLaunched(const QStringList&)),
264 SLOT(onNewInstanceLaunched(const QStringList&)));
265 } else {
266
267=== modified file 'src/app/browserapplication.h'
268--- src/app/browserapplication.h 2016-01-15 09:29:22 +0000
269+++ src/app/browserapplication.h 2016-08-18 09:28:41 +0000
270@@ -45,7 +45,7 @@
271 BrowserApplication(int& argc, char** argv);
272 ~BrowserApplication();
273
274- bool initialize(const QString& qmlFileSubPath);
275+ bool initialize(const QString& qmlFileSubPath, const QString& appId);
276 int run();
277
278 protected:
279@@ -63,7 +63,6 @@
280 void onNewInstanceLaunched(const QStringList& arguments) const;
281
282 private:
283- QString appId() const;
284 QString inspectorPort() const;
285 QString inspectorHost() const;
286
287
288=== modified file 'src/app/config.h.in'
289--- src/app/config.h.in 2015-05-14 05:57:01 +0000
290+++ src/app/config.h.in 2016-08-18 09:28:41 +0000
291@@ -23,7 +23,6 @@
292 #include <QtCore/QDir>
293 #include <QtCore/QString>
294
295-#define APP_ID "webbrowser-app"
296 #define REMOTE_INSPECTOR_PORT 9221
297
298 inline bool isRunningInstalled()
299
300=== modified file 'src/app/single-instance-manager.cpp'
301--- src/app/single-instance-manager.cpp 2016-04-08 13:49:25 +0000
302+++ src/app/single-instance-manager.cpp 2016-08-18 09:28:41 +0000
303@@ -33,12 +33,48 @@
304 #include "single-instance-manager.h"
305
306 namespace {
307+
308 const int kWaitForRunningInstanceToRespondMs = 1000;
309 const int kWaitForRunningInstanceToAckMs = 1000;
310 const int kDataStreamVersion = QDataStream::Qt_5_0;
311 const QString kHeaderToken = QStringLiteral("MESSAGE");
312 const QString kAckToken = QStringLiteral("ACK");
313-}
314+
315+QString getProfilePathFromAppId(const QString& appId)
316+{
317+ QString profilePath =
318+ QStandardPaths::writableLocation(QStandardPaths::DataLocation);
319+
320+ QStringList appIdParts = appId.split('_', QString::SkipEmptyParts);
321+
322+ QString appDesktopName;
323+
324+ // We try to get the "short app name" to try to uniquely identify
325+ // the single instance profile path.
326+
327+ // In cases where you have a single click with multiple apps in it,
328+ // the "app name" as defined in the click manifest.json file will be
329+ // a proper way to distinguish a unique instance, it needs to take
330+ // the desktop name into account.
331+
332+ // At the moment there is no clean way to get those click app name
333+ // paths, see:
334+ // https://launchpad.net/bugs/1555542
335+
336+ if (appIdParts.size() >= 3) {
337+ // Assume that we have a APP_ID that corresponds to:
338+ // <manifest app name>_<desktop app name>_<version>
339+ appDesktopName = appIdParts[1];
340+ } else {
341+ // We either run on desktop or as the webbrowser
342+ appDesktopName = appIdParts.first();
343+ }
344+
345+ return profilePath + QDir::separator() + appDesktopName;
346+}
347+
348+}
349+
350
351 SingleInstanceManager::SingleInstanceManager(QObject* parent)
352 : QObject(parent)
353@@ -54,13 +90,13 @@
354 return false;
355 }
356
357-bool SingleInstanceManager::run(const QStringList& arguments)
358+bool SingleInstanceManager::run(const QStringList& arguments, const QString& appId)
359 {
360 if (m_server.isListening()) {
361 return false;
362 }
363
364- QDir profile(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
365+ QDir profile(getProfilePathFromAppId(appId));
366 if (!profile.exists()) {
367 if (!QDir::root().mkpath(profile.absolutePath())) {
368 qCritical() << "Failed to create profile directory,"
369
370=== modified file 'src/app/single-instance-manager.h'
371--- src/app/single-instance-manager.h 2016-01-15 10:06:31 +0000
372+++ src/app/single-instance-manager.h 2016-08-18 09:28:41 +0000
373@@ -33,7 +33,7 @@
374 public:
375 SingleInstanceManager(QObject* parent=nullptr);
376
377- bool run(const QStringList& arguments);
378+ bool run(const QStringList& arguments, const QString& appId);
379
380 Q_SIGNALS:
381 void newInstanceLaunched(const QStringList& arguments) const;
382
383=== modified file 'src/app/webbrowser/Browser.qml'
384--- src/app/webbrowser/Browser.qml 2016-04-13 15:17:37 +0000
385+++ src/app/webbrowser/Browser.qml 2016-08-18 09:28:41 +0000
386@@ -1470,14 +1470,6 @@
387 readonly property bool hasMouse: (miceModel.count + touchPadModel.count) > 0
388 readonly property bool hasTouchScreen: touchScreenModel.count > 0
389
390- readonly property real freeMemRatio: (MemInfo.total > 0) ? (MemInfo.free / MemInfo.total) : 1.0
391- // Under that threshold, available memory is considered "low", and the
392- // browser is going to try and free up memory from unused tabs. This
393- // value was chosen empirically, it is subject to change to better
394- // reflect what a system under memory pressure might look like.
395- readonly property real lowOnMemoryThreshold: 0.3
396- readonly property bool lowOnMemory: freeMemRatio < lowOnMemoryThreshold
397-
398 function getOpenPages() {
399 var urls = []
400 for (var i = 0; i < tabsModel.count; i++) {
401@@ -1699,7 +1691,13 @@
402 store(JSON.stringify({tabs: tabs, currentIndex: publicTabsModel.currentIndex}))
403 }
404
405+ property bool restoring: false
406 function restore() {
407+ restoring = true
408+ _doRestore()
409+ restoring = false
410+ }
411+ function _doRestore() {
412 if (!locked) {
413 return
414 }
415@@ -1714,11 +1712,11 @@
416 if (tabs) {
417 for (var i = 0; i < Math.min(tabs.length, browser.maxTabsToRestore); ++i) {
418 var tab = createTabFromState(tabs[i])
419- internal.addTab(tab, i == 0)
420+ internal.addTab(tab, false)
421 }
422 }
423 if ('currentIndex' in state) {
424- internal.switchToTab(state.currentIndex, true)
425+ internal.switchToTab(state.currentIndex, false)
426 }
427 }
428 }
429@@ -1838,7 +1836,9 @@
430 if (tabsModel.count == 0) {
431 browser.openUrlInNewTab(settings.homepage, true, false)
432 }
433- tabsModel.currentTab.load()
434+ if (!delayedTabSwitcher.running) {
435+ tabsModel.currentTab.load()
436+ }
437 if (!tabsModel.currentTab.url.toString() && !tabsModel.currentTab.restoreState) {
438 internal.maybeFocusAddressBar()
439 }
440@@ -1854,9 +1854,15 @@
441 }
442
443 Connections {
444- target: internal
445- onFreeMemRatioChanged: {
446- if (internal.lowOnMemory) {
447+ target: MemInfo
448+ onFreeChanged: {
449+ var freeMemRatio = (MemInfo.total > 0) ? (MemInfo.free / MemInfo.total) : 1.0
450+ // Under that threshold, available memory is considered "low", and the
451+ // browser is going to try and free up memory from unused tabs. This
452+ // value was chosen empirically, it is subject to change to better
453+ // reflect what a system under memory pressure might look like.
454+ var lowOnMemory = (freeMemRatio < 0.2)
455+ if (lowOnMemory) {
456 // Unload an inactive tab to (hopefully) free up some memory
457 function getCandidate(model) {
458 // Naive implementation that only takes into account the
459@@ -1894,7 +1900,7 @@
460 }
461
462 Connections {
463- target: tabsModel
464+ target: session.restoring ? null : tabsModel
465 onCurrentIndexChanged: {
466 // In narrow mode, the tabslist is a stack:
467 // the current tab is always at the top.
468
469=== modified file 'src/app/webbrowser/BrowserTab.qml'
470--- src/app/webbrowser/BrowserTab.qml 2016-02-23 11:24:26 +0000
471+++ src/app/webbrowser/BrowserTab.qml 2016-08-18 09:28:41 +0000
472@@ -39,7 +39,7 @@
473 readonly property url icon: webview ? webview.icon : initialIcon
474 property url preview
475 property bool current: false
476- readonly property int lastCurrent: internal.lastCurrent
477+ readonly property real lastCurrent: internal.lastCurrent
478 property bool incognito
479 visible: false
480
481@@ -105,6 +105,7 @@
482 restoreState = webview.currentState
483 restoreType = Oxide.WebView.RestoreCurrentSession
484 webview.destroy()
485+ gc()
486 }
487 }
488
489@@ -127,7 +128,7 @@
490 id: internal
491 property bool hiding: false
492 property var incubator: null
493- property int lastCurrent: 0
494+ property real lastCurrent: 0
495 }
496
497 // When current is set to false, delay hiding the tab contents to give it
498
499=== modified file 'src/app/webbrowser/NavigationBar.qml'
500--- src/app/webbrowser/NavigationBar.qml 2016-04-08 17:06:32 +0000
501+++ src/app/webbrowser/NavigationBar.qml 2016-08-18 09:28:41 +0000
502@@ -107,6 +107,7 @@
503
504 findInPageMode: findInPageMode
505 findController: internal.webview ? internal.webview.findController : null
506+ securityStatus: internal.webview ? internal.webview.securityStatus : null
507
508 anchors {
509 left: parent.left
510@@ -226,13 +227,11 @@
511 onTabChanged: {
512 if (tab) {
513 addressbar.actualUrl = tab.url
514- addressbar.securityStatus = (tab.webview ? tab.webview.securityStatus : null)
515 if (!tab.url.toString() && editing) {
516 addressbar.text = ""
517 }
518 } else {
519 addressbar.actualUrl = ""
520- addressbar.securityStatus = null
521 }
522 }
523
524
525=== modified file 'src/app/webbrowser/webbrowser-app.cpp'
526--- src/app/webbrowser/webbrowser-app.cpp 2016-02-05 15:20:10 +0000
527+++ src/app/webbrowser/webbrowser-app.cpp 2016-08-18 09:28:41 +0000
528@@ -76,7 +76,7 @@
529 qmlRegisterSingletonType<DownloadsModel>(uri, 0, 1, "DownloadsModel", DownloadsModel_singleton_factory);
530 qmlRegisterType<TextSearchFilterModel>(uri, 0, 1, "TextSearchFilterModel");
531
532- if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml")) {
533+ if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml", QStringLiteral("webbrowser-app"))) {
534 QStringList searchEnginesSearchPaths;
535 searchEnginesSearchPaths << QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/searchengines";
536 searchEnginesSearchPaths << UbuntuBrowserDirectory() + "/webbrowser/searchengines";
537
538=== modified file 'src/app/webcontainer/WebApp.qml'
539--- src/app/webcontainer/WebApp.qml 2016-04-05 15:42:53 +0000
540+++ src/app/webcontainer/WebApp.qml 2016-08-18 09:28:41 +0000
541@@ -46,6 +46,7 @@
542 property alias dataPath: containerWebView.dataPath
543 property alias runningLocalApplication: containerWebView.runningLocalApplication
544 property alias openExternalUrlInOverlay: containerWebView.openExternalUrlInOverlay
545+ property alias popupBlockerEnabled: containerWebView.popupBlockerEnabled
546
547 property string webappName: ""
548
549
550=== modified file 'src/app/webcontainer/WebViewImplOxide.qml'
551--- src/app/webcontainer/WebViewImplOxide.qml 2016-03-24 14:57:11 +0000
552+++ src/app/webcontainer/WebViewImplOxide.qml 2016-08-18 09:28:41 +0000
553@@ -38,6 +38,7 @@
554 property var overlayViewsParent: webview.parent
555 property var mediaAccessDialogComponent
556 property bool openExternalUrlInOverlay: false
557+ property bool popupBlockerEnabled: true
558
559 // Mostly used for testing & avoid external urls to
560 // "leak" in the default browser. External URLs corresponds
561@@ -54,6 +55,14 @@
562 signal gotRedirectionUrl(string url)
563 property bool runningLocalApplication: false
564
565+ onLoadEvent: {
566+ var url = event.url.toString()
567+ if (event.type === Oxide.LoadEvent.TypeRedirected
568+ && url.indexOf("SAMLRequest") > 0) {
569+ handleSamlRequestNavigation(url)
570+ }
571+ }
572+
573 function openOverlayForUrl(overlayUrl) {
574 if (popupController) {
575 popupController.createPopupViewForUrl(
576@@ -70,6 +79,8 @@
577 dataPath: webview.dataPath
578 userAgent: localUserAgentOverride ? localUserAgentOverride : defaultUserAgent
579
580+ popupBlockerEnabled: webview.popupBlockerEnabled
581+
582 userScripts: [
583 Oxide.UserScript {
584 context: "oxide://webapp-specific-page-metadata-collector/"
585@@ -176,6 +187,18 @@
586 return false;
587 }
588
589+ function handleSamlRequestNavigation(url) {
590+ var urlRegExp = new RegExp("https?://([^?/]+)")
591+ var match = urlRegExp.exec(url)
592+ var host = match[1]
593+ var escapeDotsRegExp = new RegExp("\\.", "g")
594+ var hostPattern = "https?://" + host.replace(escapeDotsRegExp, "\\.") + "/*"
595+
596+ console.log("SAML request detected. Adding host pattern: " + hostPattern)
597+
598+ handleSAMLRequestPattern(hostPattern)
599+ }
600+
601 function navigationRequestedDelegate(request) {
602 var url = request.url.toString()
603 if (runningLocalApplication && url.indexOf("file://") !== 0) {
604@@ -186,13 +209,13 @@
605
606 request.action = Oxide.NavigationRequest.ActionReject
607 if (isNewForegroundWebViewDisposition(request.disposition)) {
608- request.action = Oxide.NavigationRequest.ActionAccept
609 var shouldAcceptRequest =
610- popupWindowController.handleNewForegroundNavigationRequest(
611+ popupController.handleNewForegroundNavigationRequest(
612 url, request, true);
613 if (shouldAcceptRequest) {
614 request.action = Oxide.NavigationRequest.ActionAccept
615 }
616+ return
617 }
618
619 // Pass-through if we are not running as a named webapp (--webapp='Gmail')
620@@ -211,18 +234,9 @@
621 // query parameter called "SAMLRequest".
622 // Besides letting the request through, we must also add the SAML
623 // domain to the list of the allowed hosts.
624- if (request.disposition === Oxide.NavigationRequest.DispositionCurrentTab &&
625- url.indexOf("SAMLRequest") > 0) {
626- var urlRegExp = new RegExp("https?://([^?/]+)")
627- var match = urlRegExp.exec(url)
628- var host = match[1]
629- var escapeDotsRegExp = new RegExp("\\.", "g")
630- var hostPattern = "https?://" + host.replace(escapeDotsRegExp, "\\.") + "/*"
631-
632- console.log("SAML request detected. Adding host pattern: " + hostPattern)
633-
634- handleSAMLRequestPattern(hostPattern)
635-
636+ if (request.disposition === Oxide.NavigationRequest.DispositionCurrentTab
637+ && url.indexOf("SAMLRequest") > 0) {
638+ handleSamlRequestNavigation(url)
639 request.action = Oxide.NavigationRequest.ActionAccept
640 }
641
642
643=== modified file 'src/app/webcontainer/WebappContainerWebview.qml'
644--- src/app/webcontainer/WebappContainerWebview.qml 2016-03-24 14:06:22 +0000
645+++ src/app/webcontainer/WebappContainerWebview.qml 2016-08-18 09:28:41 +0000
646@@ -41,6 +41,7 @@
647 property bool runningLocalApplication: false
648 property bool wide: false
649 property bool openExternalUrlInOverlay: false
650+ property bool popupBlockerEnabled: true
651
652 signal samlRequestUrlPatternReceived(string urlPattern)
653 signal themeColorMetaInformationDetected(string theme_color)
654@@ -126,7 +127,8 @@
655 , overlayViewsParent: containerWebview.parent
656 , wide: containerWebview.wide
657 , mediaAccessDialogComponent: mediaAccessDialogComponent
658- , openExternalUrlInOverlay: containerWebview.openExternalUrlInOverlay})
659+ , openExternalUrlInOverlay: containerWebview.openExternalUrlInOverlay
660+ , popupBlockerEnabled: containerWebview.popupBlockerEnabled})
661 }
662 }
663
664
665=== modified file 'src/app/webcontainer/webapp-container.cpp'
666--- src/app/webcontainer/webapp-container.cpp 2016-02-29 13:32:17 +0000
667+++ src/app/webcontainer/webapp-container.cpp 2016-08-18 09:28:41 +0000
668@@ -92,12 +92,38 @@
669 {
670 }
671
672+QString WebappContainer::appId() const
673+{
674+ Q_FOREACH(const QString& argument, m_arguments) {
675+ if (argument.startsWith("--app-id=")) {
676+ return argument.split("--app-id=")[1];
677+ }
678+ }
679+ return QString();
680+}
681
682 bool WebappContainer::initialize()
683 {
684 earlyEnvironment();
685
686- if (BrowserApplication::initialize("webcontainer/webapp-container.qml")) {
687+ if (qgetenv("APP_ID").isEmpty()) {
688+ QString id = appId();
689+ if (id.isEmpty()) {
690+ qCritical() << "The application has been launched with no "
691+ "explicit or system provided app id. "
692+ "An application id can be set by using the --app-id "
693+ "command line parameter and setting it to a unique "
694+ "application specific value or using the APP_ID environment "
695+ "variable.";
696+ return false;
697+ }
698+ qputenv("APP_ID", id.toUtf8());
699+ }
700+
701+ if (BrowserApplication::initialize(
702+ "webcontainer/webapp-container.qml",
703+ QString::fromUtf8(qgetenv("APP_ID")))) {
704+
705 parseCommandLine();
706 parseExtraConfiguration();
707
708@@ -197,6 +223,11 @@
709 // Handle an optional scheme handler filter. The default *catch all* filter does nothing.
710 setupLocalSchemeFilterIfAny(context, m_webappModelSearchPath);
711
712+ if (qEnvironmentVariableIsSet("WEBAPP_CONTAINER_BLOCKER_DISABLED")
713+ && QString(qgetenv("WEBAPP_CONTAINER_BLOCKER_DISABLED")) == "1") {
714+ m_window->setProperty("popupBlockerEnabled", false);
715+ }
716+
717 m_component->completeCreate();
718
719 return true;
720
721=== modified file 'src/app/webcontainer/webapp-container.h'
722--- src/app/webcontainer/webapp-container.h 2016-02-27 21:45:57 +0000
723+++ src/app/webcontainer/webapp-container.h 2016-08-18 09:28:41 +0000
724@@ -54,6 +54,7 @@
725 bool shouldNotValidateCommandLineUrls() const;
726 bool isValidLocalIntentFilterFile(const QString& filename) const;
727 void setupLocalSchemeFilterIfAny(QQmlContext* context, const QString& webappSearchPath);
728+ QString appId() const;
729
730 private:
731 QString m_webappName;
732
733=== modified file 'src/app/webcontainer/webapp-container.qml'
734--- src/app/webcontainer/webapp-container.qml 2016-03-24 14:06:22 +0000
735+++ src/app/webcontainer/webapp-container.qml 2016-08-18 09:28:41 +0000
736@@ -46,6 +46,7 @@
737 property string localUserAgentOverride: ""
738 property bool blockOpenExternalUrls: false
739 property bool openExternalUrlInOverlay: false
740+ property bool popupBlockerEnabled: true
741
742 currentWebview: webappViewLoader.item ? webappViewLoader.item.currentWebview : null
743
744@@ -89,6 +90,7 @@
745 webappUrlPatterns: root.webappUrlPatterns
746 blockOpenExternalUrls: root.blockOpenExternalUrls
747 openExternalUrlInOverlay: root.openExternalUrlInOverlay
748+ popupBlockerEnabled: root.popupBlockerEnabled
749
750 popupRedirectionUrlPrefixPattern: root.popupRedirectionUrlPrefixPattern
751
752
753=== modified file 'tests/autopilot/webapp_container/tests/__init__.py'
754--- tests/autopilot/webapp_container/tests/__init__.py 2016-01-22 10:19:34 +0000
755+++ tests/autopilot/webapp_container/tests/__init__.py 2016-08-18 09:28:41 +0000
756@@ -57,6 +57,10 @@
757 args.append(
758 '--desktop_file_hint=/usr/share/applications/'
759 'webbrowser-app.desktop')
760+
761+ if next(filter(lambda e: e.startswith('--appid'), args), None) is None:
762+ args.append('--app-id=running.test')
763+
764 if envvars:
765 for envvar_key in envvars:
766 self.useFixture(fixtures.EnvironmentVariable(
767
768=== modified file 'tests/autopilot/webapp_container/tests/fake_servers.py'
769--- tests/autopilot/webapp_container/tests/fake_servers.py 2016-04-04 15:28:22 +0000
770+++ tests/autopilot/webapp_container/tests/fake_servers.py 2016-08-18 09:28:41 +0000
771@@ -218,6 +218,28 @@
772 </html>
773 """
774
775+ def timer_based_window_open_content(self, count):
776+ return """
777+<html>
778+<head>
779+<title>open-close</title>
780+<script>
781+var idx = 0;
782+var count = %s;
783+window.setInterval(function() {
784+ if (idx < count) {
785+ window.open('/open-close-content')
786+ }
787+ ++idx
788+}, 1000);
789+</script>
790+</head>
791+<body>
792+ Test
793+</body>
794+</html>
795+""" % count
796+
797 base64_png_data = \
798 "iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAACXBIWXMAAAsTAAALEwE" \
799 "AmpwYAAAAOUlEQVRYw+3OAQ0AAAgDoGv/zlpDN0hATS7qaGlpaWlpaWlpaWlpaWlpaW" \
800@@ -317,6 +339,13 @@
801 self.send_response(200)
802 self.serve_content(
803 self.external_href_with_link_content(qs['path'][0]))
804+ elif self.path.startswith('/timer-window-open-content'):
805+ qs = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
806+ count = 1
807+ if 'count' in qs:
808+ count = int(qs['count'][0])
809+ self.send_response(200)
810+ self.serve_content(self.timer_based_window_open_content(count))
811 else:
812 self.send_error(404)
813
814
815=== modified file 'tests/autopilot/webapp_container/tests/test_popup_webview_overlay.py'
816--- tests/autopilot/webapp_container/tests/test_popup_webview_overlay.py 2015-09-22 14:11:09 +0000
817+++ tests/autopilot/webapp_container/tests/test_popup_webview_overlay.py 2016-08-18 09:28:41 +0000
818@@ -168,3 +168,22 @@
819 self.assertThat(
820 lambda: external_open_watcher.was_emitted,
821 Eventually(Equals(True)))
822+
823+ def test_multiple_window_open_from_webview(self):
824+ args = []
825+ overlay_opened_from_main_view_count = 3
826+ self.launch_webcontainer_app_with_local_http_server(
827+ args,
828+ '/timer-window-open-content?count={}'.format(
829+ overlay_opened_from_main_view_count),
830+ {'WEBAPP_CONTAINER_BLOCKER_DISABLED': '1'})
831+ self.get_webcontainer_window().visible.wait_for(True)
832+
833+ webview = self.get_oxide_webview()
834+ self.assertThat(
835+ lambda: webview.visible,
836+ Eventually(Equals(True)))
837+
838+ self.assertThat(
839+ lambda: len(self.get_popup_overlay_views()),
840+ Eventually(Equals(overlay_opened_from_main_view_count)))
841
842=== modified file 'tests/autopilot/webapp_container/tests/test_saml_url_patterns.py'
843--- tests/autopilot/webapp_container/tests/test_saml_url_patterns.py 2015-06-03 14:50:14 +0000
844+++ tests/autopilot/webapp_container/tests/test_saml_url_patterns.py 2016-08-18 09:28:41 +0000
845@@ -26,9 +26,10 @@
846 args = ["--webappUrlPatterns=\
847 http://www.test.com/saml/*,{}/saml/*".format(self.base_url)]
848
849- samlRequestRedirectsCount = 1
850+ expectedSamlRequestRedirectPatternsCount = 1
851+ samlRequestNavigationCount = 3
852 target_path = '/saml/?\
853-loopcount={}'.format(str(samlRequestRedirectsCount))
854+loopcount={}'.format(str(samlRequestNavigationCount))
855
856 self.launch_webcontainer_app_with_local_http_server(
857 args,
858@@ -38,6 +39,8 @@
859 self.get_webcontainer_window().visible.wait_for(True)
860 self.assert_page_eventually_loaded(self.base_url+target_path)
861
862+ saml_url_navigations_detected_watcher = self.get_webview(
863+ ).watch_signal('samlRequestUrlPatternReceived(QString)')
864 webcontainer_webview = self.get_webcontainer_webview()
865 url_patterns_settings_watcher = webcontainer_webview.watch_signal(
866 'generatedUrlPatternsChanged()')
867@@ -55,7 +58,10 @@
868 Eventually(Equals(True)))
869 self.assertThat(
870 lambda: url_patterns_settings_watcher.num_emissions,
871- Eventually(Equals(samlRequestRedirectsCount)))
872+ Eventually(Equals(expectedSamlRequestRedirectPatternsCount)))
873+ self.assertThat(
874+ lambda: saml_url_navigations_detected_watcher.num_emissions,
875+ Eventually(Equals(samlRequestNavigationCount+1)))
876
877 saved_patterns = webcontainer_webview.generatedUrlPatterns
878
879
880=== modified file 'tests/unittests/single-instance-manager/tst_SingleInstanceManagerTests.cpp'
881--- tests/unittests/single-instance-manager/tst_SingleInstanceManagerTests.cpp 2016-01-18 14:45:12 +0000
882+++ tests/unittests/single-instance-manager/tst_SingleInstanceManagerTests.cpp 2016-08-18 09:28:41 +0000
883@@ -50,18 +50,18 @@
884
885 void test_cannot_run_twice_same_instance()
886 {
887- QVERIFY(singleton->run(QStringList()));
888- QVERIFY(!singleton->run(QStringList()));
889+ QVERIFY(singleton->run(QStringList(), "appid"));
890+ QVERIFY(!singleton->run(QStringList(), "appid"));
891 QVERIFY(newInstanceSpy->isEmpty());
892 }
893
894 void test_arguments_passed_to_already_running_instance()
895 {
896- QVERIFY(singleton->run(QStringList()));
897+ QVERIFY(singleton->run(QStringList(), "appid"));
898 SingleInstanceManager other;
899 QStringList args;
900 args << QStringLiteral("foo") << QStringLiteral("bar") << QStringLiteral("baz");
901- QVERIFY(!other.run(args));
902+ QVERIFY(!other.run(args, "appid"));
903 newInstanceSpy->wait();
904 QCOMPARE(newInstanceSpy->first().at(0).toStringList(), args);
905 }

Subscribers

People subscribed via source and target branches