Merge lp:~osomon/webbrowser-app/remove-formFactor into lp:webbrowser-app
- remove-formFactor
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Olivier Tilloy | ||||||||
Approved revision: | 1367 | ||||||||
Merged at revision: | 1361 | ||||||||
Proposed branch: | lp:~osomon/webbrowser-app/remove-formFactor | ||||||||
Merge into: | lp:webbrowser-app | ||||||||
Diff against target: |
1105 lines (+475/-141) 22 files modified
README (+0/-5) debian/control (+1/-0) src/Ubuntu/Web/UbuntuWebView02.qml (+2/-2) src/Ubuntu/Web/plugin.cpp (+1/-38) src/app/BrowserView.qml (+2/-0) src/app/CMakeLists.txt (+7/-1) src/app/browserapplication.cpp (+42/-14) src/app/meminfo.cpp (+137/-0) src/app/meminfo.h (+65/-0) src/app/webbrowser/Browser.qml (+69/-31) src/app/webbrowser/BrowserTab.qml (+3/-0) src/app/webbrowser/Chrome.qml (+3/-1) src/app/webbrowser/SettingsPage.qml (+1/-20) src/app/webbrowser/TabItem.qml (+9/-8) src/app/webbrowser/TabsBar.qml (+4/-1) src/app/webbrowser/webbrowser-app.cpp (+2/-0) src/app/webcontainer/WebApp.qml (+3/-2) src/app/webcontainer/WebViewImplOxide.qml (+6/-11) tests/autopilot/webbrowser_app/tests/__init__.py (+2/-7) tests/unittests/CMakeLists.txt (+1/-0) tests/unittests/meminfo/CMakeLists.txt (+15/-0) tests/unittests/meminfo/tst_MemInfoTests.cpp (+100/-0) |
||||||||
To merge this branch: | bzr merge lp:~osomon/webbrowser-app/remove-formFactor | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandre Abreu (community) | Approve | ||
PS Jenkins bot | continuous-integration | Needs Fixing | |
Review via email: mp+285539@code.launchpad.net |
Commit message
Remove the 'formFactor' context property, and replace all its uses by more meaningful conditions.
Description of the change
Note: as of 2016-02-07, there are 7 applications in the store that import Ubuntu.Web and have at least one reference to the 'formFactor' context property. Those are:
com.nokia.heremaps 1.0.7
com.ubuntu.
googleapps.mattirn 1.0.1
mynewsapps.mattirn 1.0.4
mywebsites.mattirn 1.0.1
ubuntu.mattirn 1.0.1
wikifoundation
Canonical is responsible for the first two, we need to update them. I’m going to reach out to mattirn to suggest how to fix his apps so they don’t refer to 'formFactor'.
In any case, I don’t expect any important functionality to suddenly break even if the property was removed without updating those apps.
UPDATE: as of 2016-02-18, the last five apps in the above list (all by mattirn) have been updated, they don’t have references to 'formFactor' any longer. com.ubuntu.
Chris Coulson (chrisccoulson) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1362
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1363. By Olivier Tilloy
-
Verify that a geolocation permission request originates from the webapp’s domain before silently accepting it.
- 1364. By Olivier Tilloy
-
When low on memory, the current public tab might have been unloaded, so reload it when exiting incognito mode.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1363
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1364
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alexandre Abreu (abreu-alexandre) wrote : | # |
Overall looks good, a few questions below
Olivier Tilloy (osomon) wrote : | # |
Thanks for your thorough review, I’ve replied to your questions (with more questions!) inline.
Alexandre Abreu (abreu-alexandre) wrote : | # |
See replies
- 1365. By Olivier Tilloy
-
Document the value of the lowOnMemory threshold.
Olivier Tilloy (osomon) wrote : | # |
Updated.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1365
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1366. By Olivier Tilloy
-
Do not try to load an non existent tab.
- 1367. By Olivier Tilloy
-
Raise the threshold for which a system is considered low on memory, from tests run on a MX4.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1367
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'README' |
2 | --- README 2015-04-01 05:57:42 +0000 |
3 | +++ README 2016-02-23 11:14:53 +0000 |
4 | @@ -86,11 +86,6 @@ |
5 | the OpenSearch document description format |
6 | (http://www.opensearch.org/Specifications/OpenSearch/1.1) |
7 | |
8 | - - 'allowOpenInBackgroundTab': whether to offer an option to open a link in a |
9 | - new background tab in the contextual menu. Possible values are "true", |
10 | - "false", and "default" (which resolves to true on desktop and false on |
11 | - mobile). |
12 | - |
13 | - restoreSession: whether to restore the previous browsing session at startup |
14 | (defaults to true) |
15 | |
16 | |
17 | === modified file 'debian/control' |
18 | --- debian/control 2016-01-28 16:23:17 +0000 |
19 | +++ debian/control 2016-02-23 11:14:53 +0000 |
20 | @@ -10,6 +10,7 @@ |
21 | dh-apparmor, |
22 | dh-translations, |
23 | hardening-wrapper, |
24 | + libapparmor-dev, |
25 | libevdev-dev, |
26 | liboxideqt-qmlplugin (>= 1.9), |
27 | libqt5sql5-sqlite, |
28 | |
29 | === modified file 'src/Ubuntu/Web/UbuntuWebView02.qml' |
30 | --- src/Ubuntu/Web/UbuntuWebView02.qml 2016-01-05 08:35:58 +0000 |
31 | +++ src/Ubuntu/Web/UbuntuWebView02.qml 2016-02-23 11:14:53 +0000 |
32 | @@ -1,5 +1,5 @@ |
33 | /* |
34 | - * Copyright 2013-2015 Canonical Ltd. |
35 | + * Copyright 2013-2016 Canonical Ltd. |
36 | * |
37 | * This file is part of webbrowser-app. |
38 | * |
39 | @@ -51,7 +51,7 @@ |
40 | navigationRequestedDelegate(request); |
41 | } |
42 | |
43 | - preferences.passwordEchoEnabled: formFactor === "mobile" |
44 | + preferences.passwordEchoEnabled: Qt.inputMethod.visible |
45 | |
46 | popupMenu: ItemSelector02 { |
47 | automaticOrientation: false |
48 | |
49 | === modified file 'src/Ubuntu/Web/plugin.cpp' |
50 | --- src/Ubuntu/Web/plugin.cpp 2015-12-10 22:01:05 +0000 |
51 | +++ src/Ubuntu/Web/plugin.cpp 2016-02-23 11:14:53 +0000 |
52 | @@ -1,5 +1,5 @@ |
53 | /* |
54 | - * Copyright 2013-2015 Canonical Ltd. |
55 | + * Copyright 2013-2016 Canonical Ltd. |
56 | * |
57 | * This file is part of webbrowser-app. |
58 | * |
59 | @@ -40,7 +40,6 @@ |
60 | |
61 | Q_PROPERTY(QString cacheLocation READ cacheLocation NOTIFY cacheLocationChanged) |
62 | Q_PROPERTY(QString dataLocation READ dataLocation NOTIFY dataLocationChanged) |
63 | - Q_PROPERTY(QString formFactor READ formFactor CONSTANT) |
64 | Q_PROPERTY(qreal screenDiagonal READ screenDiagonal NOTIFY screenDiagonalChanged) |
65 | Q_PROPERTY(int cacheSizeHint READ cacheSizeHint NOTIFY cacheSizeHintChanged) |
66 | Q_PROPERTY(QString webviewDevtoolsDebugHost READ devtoolsHost CONSTANT) |
67 | @@ -52,7 +51,6 @@ |
68 | |
69 | QString cacheLocation() const; |
70 | QString dataLocation() const; |
71 | - QString formFactor(); |
72 | qreal screenDiagonal() const; |
73 | int cacheSizeHint() const; |
74 | QString devtoolsHost(); |
75 | @@ -71,7 +69,6 @@ |
76 | |
77 | private: |
78 | qreal m_screenDiagonal; // in millimeters |
79 | - QString m_formFactor; |
80 | QString m_devtoolsHost; |
81 | int m_devtoolsPort; |
82 | QStringList m_hostMappingRules; |
83 | @@ -129,40 +126,6 @@ |
84 | return location.absolutePath(); |
85 | } |
86 | |
87 | -QString UbuntuWebPluginContext::formFactor() |
88 | -{ |
89 | - if (m_formFactor.isEmpty()) { |
90 | - // This implementation only considers two possible form factors: desktop, |
91 | - // and mobile (which includes phones and tablets). |
92 | - // XXX: do we need to consider other form factors, such as tablet? |
93 | - const char* DESKTOP = "desktop"; |
94 | - const char* MOBILE = "mobile"; |
95 | - |
96 | - // The "DESKTOP_MODE" environment variable can be used to force the form |
97 | - // factor to desktop, when set to any valid value other than 0. |
98 | - const char* DESKTOP_MODE_ENV_VAR = "DESKTOP_MODE"; |
99 | - if (qEnvironmentVariableIsSet(DESKTOP_MODE_ENV_VAR)) { |
100 | - QByteArray stringValue = qgetenv(DESKTOP_MODE_ENV_VAR); |
101 | - bool ok = false; |
102 | - int value = stringValue.toInt(&ok); |
103 | - if (ok) { |
104 | - m_formFactor = (value == 0) ? MOBILE : DESKTOP; |
105 | - return m_formFactor; |
106 | - } |
107 | - } |
108 | - |
109 | - // XXX: Assume that QtUbuntu means mobile, which is currently the case, |
110 | - // but may not remain true forever. |
111 | - QString platform = QGuiApplication::platformName(); |
112 | - if ((platform == "ubuntu") || (platform == "ubuntumirclient")) { |
113 | - m_formFactor = MOBILE; |
114 | - } else { |
115 | - m_formFactor = DESKTOP; |
116 | - } |
117 | - } |
118 | - return m_formFactor; |
119 | -} |
120 | - |
121 | qreal UbuntuWebPluginContext::screenDiagonal() const |
122 | { |
123 | return m_screenDiagonal; |
124 | |
125 | === modified file 'src/app/BrowserView.qml' |
126 | --- src/app/BrowserView.qml 2016-01-12 09:37:08 +0000 |
127 | +++ src/app/BrowserView.qml 2016-02-23 11:14:53 +0000 |
128 | @@ -32,6 +32,8 @@ |
129 | |
130 | property var osk: _osk |
131 | |
132 | + property bool hasTouchScreen: false |
133 | + |
134 | // See http://design.canonical.com/2015/05/to-converge-onto-mobile-tablet-and-desktop-think-grid-units/ |
135 | readonly property bool wide: width >= units.gu(90) |
136 | |
137 | |
138 | === modified file 'src/app/CMakeLists.txt' |
139 | --- src/app/CMakeLists.txt 2016-01-28 18:54:35 +0000 |
140 | +++ src/app/CMakeLists.txt 2016-02-23 11:14:53 +0000 |
141 | @@ -7,6 +7,9 @@ |
142 | find_package(Qt5Quick REQUIRED) |
143 | find_package(Qt5Widgets REQUIRED) |
144 | |
145 | +include(FindPkgConfig) |
146 | +pkg_check_modules(LIBAPPARMOR REQUIRED libapparmor) |
147 | + |
148 | add_subdirectory(unity8) |
149 | |
150 | configure_file( |
151 | @@ -19,6 +22,7 @@ |
152 | set(COMMONLIB_SRC |
153 | browserapplication.cpp |
154 | favicon-fetcher.cpp |
155 | + meminfo.cpp |
156 | mime-database.cpp |
157 | session-storage.cpp |
158 | single-instance-manager.cpp |
159 | @@ -28,7 +32,8 @@ |
160 | add_library(${COMMONLIB} STATIC ${COMMONLIB_SRC}) |
161 | |
162 | include_directories(${unity8_SOURCE_DIR}/libs/UbuntuGestures |
163 | - ${unity8_SOURCE_DIR}/plugins) |
164 | + ${unity8_SOURCE_DIR}/plugins |
165 | + ${LIBAPPARMOR_INCLUDE_DIRS}) |
166 | target_link_libraries(${COMMONLIB} |
167 | Qt5::Core |
168 | Qt5::Gui |
169 | @@ -38,6 +43,7 @@ |
170 | Qt5::Widgets |
171 | UbuntuGesturesQml |
172 | InputInfo |
173 | + ${LIBAPPARMOR_LDFLAGS} |
174 | ) |
175 | |
176 | file(GLOB QML_FILES *.qml) |
177 | |
178 | === modified file 'src/app/browserapplication.cpp' |
179 | --- src/app/browserapplication.cpp 2016-01-28 18:54:35 +0000 |
180 | +++ src/app/browserapplication.cpp 2016-02-23 11:14:53 +0000 |
181 | @@ -16,9 +16,15 @@ |
182 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
183 | */ |
184 | |
185 | +// system |
186 | +#include <cerrno> |
187 | +#include <cstring> |
188 | +#include <sys/apparmor.h> |
189 | + |
190 | // Qt |
191 | #include <QtCore/QMetaObject> |
192 | #include <QtCore/QtGlobal> |
193 | +#include <QtGui/QTouchDevice> |
194 | #include <QtNetwork/QNetworkInterface> |
195 | #include <QtQml/QQmlComponent> |
196 | #include <QtQml/QQmlContext> |
197 | @@ -30,6 +36,7 @@ |
198 | #include "browserapplication.h" |
199 | #include "config.h" |
200 | #include "favicon-fetcher.h" |
201 | +#include "meminfo.h" |
202 | #include "mime-database.h" |
203 | #include "session-storage.h" |
204 | #include "webbrowser-window.h" |
205 | @@ -100,19 +107,17 @@ |
206 | return QString(); |
207 | } |
208 | |
209 | -static QObject* MimeDatabase_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine) |
210 | -{ |
211 | - Q_UNUSED(engine); |
212 | - Q_UNUSED(scriptEngine); |
213 | - return new MimeDatabase(); |
214 | -} |
215 | - |
216 | -static QObject* Direction_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine) |
217 | -{ |
218 | - Q_UNUSED(engine); |
219 | - Q_UNUSED(scriptEngine); |
220 | - return new Direction(); |
221 | -} |
222 | +#define MAKE_SINGLETON_FACTORY(type) \ |
223 | + static QObject* type##_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine) { \ |
224 | + Q_UNUSED(engine); \ |
225 | + Q_UNUSED(scriptEngine); \ |
226 | + return new type(); \ |
227 | + } |
228 | + |
229 | +MAKE_SINGLETON_FACTORY(MemInfo) |
230 | +MAKE_SINGLETON_FACTORY(MimeDatabase) |
231 | +MAKE_SINGLETON_FACTORY(Direction) |
232 | + |
233 | |
234 | bool BrowserApplication::initialize(const QString& qmlFileSubPath) |
235 | { |
236 | @@ -149,6 +154,18 @@ |
237 | return false; |
238 | } |
239 | |
240 | + bool runningConfined = true; |
241 | + char* label; |
242 | + char* mode; |
243 | + if (aa_getcon(&label, &mode) != -1) { |
244 | + if (strcmp(label, "unconfined") == 0) { |
245 | + runningConfined = false; |
246 | + } |
247 | + free(label); |
248 | + } else if (errno == EINVAL) { |
249 | + runningConfined = false; |
250 | + } |
251 | + |
252 | QString devtoolsPort = inspectorPort(); |
253 | QString devtoolsHost = inspectorHost(); |
254 | bool inspectorEnabled = !devtoolsPort.isEmpty(); |
255 | @@ -159,6 +176,7 @@ |
256 | |
257 | const char* uri = "webbrowsercommon.private"; |
258 | qmlRegisterType<FaviconFetcher>(uri, 0, 1, "FaviconFetcher"); |
259 | + qmlRegisterSingletonType<MemInfo>(uri, 0, 1, "MemInfo", MemInfo_singleton_factory); |
260 | qmlRegisterSingletonType<MimeDatabase>(uri, 0, 1, "MimeDatabase", MimeDatabase_singleton_factory); |
261 | qmlRegisterType<SessionStorage>(uri, 0, 1, "SessionStorage"); |
262 | |
263 | @@ -179,6 +197,9 @@ |
264 | qmlEngineCreated(m_engine); |
265 | |
266 | QQmlContext* context = m_engine->rootContext(); |
267 | + context->setContextProperty("__runningConfined", runningConfined); |
268 | + context->setContextProperty("unversionedAppId", unversionedAppId); |
269 | + |
270 | m_component = new QQmlComponent(m_engine); |
271 | m_component->loadUrl(QUrl::fromLocalFile(UbuntuBrowserDirectory() + "/" + qmlFileSubPath)); |
272 | if (!m_component->isReady()) { |
273 | @@ -187,7 +208,6 @@ |
274 | } |
275 | m_webbrowserWindowProxy = new WebBrowserWindow(); |
276 | context->setContextProperty("webbrowserWindowProxy", m_webbrowserWindowProxy); |
277 | - context->setContextProperty("unversionedAppId", unversionedAppId); |
278 | |
279 | QObject* browser = m_component->beginCreate(context); |
280 | m_window = qobject_cast<QQuickWindow*>(browser); |
281 | @@ -198,6 +218,14 @@ |
282 | browser->setProperty("developerExtrasEnabled", inspectorEnabled); |
283 | browser->setProperty("forceFullscreen", m_arguments.contains("--fullscreen")); |
284 | |
285 | + bool hasTouchScreen = false; |
286 | + Q_FOREACH(const QTouchDevice* device, QTouchDevice::devices()) { |
287 | + if (device->type() == QTouchDevice::TouchScreen) { |
288 | + hasTouchScreen = true; |
289 | + } |
290 | + } |
291 | + browser->setProperty("hasTouchScreen", hasTouchScreen); |
292 | + |
293 | return true; |
294 | } |
295 | |
296 | |
297 | === added file 'src/app/meminfo.cpp' |
298 | --- src/app/meminfo.cpp 1970-01-01 00:00:00 +0000 |
299 | +++ src/app/meminfo.cpp 2016-02-23 11:14:53 +0000 |
300 | @@ -0,0 +1,137 @@ |
301 | +/* |
302 | + * Copyright 2016 Canonical Ltd. |
303 | + * |
304 | + * This file is part of webbrowser-app. |
305 | + * |
306 | + * webbrowser-app is free software; you can redistribute it and/or modify |
307 | + * it under the terms of the GNU General Public License as published by |
308 | + * the Free Software Foundation; version 3. |
309 | + * |
310 | + * webbrowser-app is distributed in the hope that it will be useful, |
311 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
312 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
313 | + * GNU General Public License for more details. |
314 | + * |
315 | + * You should have received a copy of the GNU General Public License |
316 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
317 | + */ |
318 | + |
319 | +#include "meminfo.h" |
320 | + |
321 | +// Qt |
322 | +#include <QtCore/QByteArray> |
323 | +#include <QtCore/QFile> |
324 | +#include <QtCore/QRegExp> |
325 | +#include <QtCore/QString> |
326 | +#include <QtCore/QtGlobal> |
327 | + |
328 | +MemInfo::MemInfo(QObject* parent) |
329 | + : QObject(parent) |
330 | + , m_total(0) |
331 | + , m_free(0) |
332 | +{ |
333 | + // Default interval: 5000 ms |
334 | + m_timer.setInterval(5000); |
335 | + connect(&m_timer, SIGNAL(timeout()), SLOT(update())); |
336 | + // Active by default |
337 | + m_timer.start(); |
338 | +} |
339 | + |
340 | +MemInfo::~MemInfo() |
341 | +{} |
342 | + |
343 | +const bool MemInfo::active() const |
344 | +{ |
345 | + return m_timer.isActive(); |
346 | +} |
347 | + |
348 | +void MemInfo::setActive(bool active) |
349 | +{ |
350 | + if (active != m_timer.isActive()) { |
351 | + if (active) { |
352 | + m_timer.start(); |
353 | + } else { |
354 | + m_timer.stop(); |
355 | + } |
356 | + Q_EMIT activeChanged(); |
357 | + } |
358 | +} |
359 | + |
360 | +const int MemInfo::interval() const |
361 | +{ |
362 | + return m_timer.interval(); |
363 | +} |
364 | + |
365 | +void MemInfo::setInterval(int interval) |
366 | +{ |
367 | + if (interval != m_timer.interval()) { |
368 | + m_timer.setInterval(interval); |
369 | + Q_EMIT intervalChanged(); |
370 | + } |
371 | +} |
372 | + |
373 | +const int MemInfo::total() const |
374 | +{ |
375 | + return m_total; |
376 | +} |
377 | + |
378 | +const int MemInfo::free() const |
379 | +{ |
380 | + return m_free; |
381 | +} |
382 | + |
383 | +void MemInfo::update() |
384 | +{ |
385 | +#if defined(Q_OS_LINUX) |
386 | + // Inspired by glibtop_get_mem_s() |
387 | + QFile meminfo(QStringLiteral("/proc/meminfo")); |
388 | + if (!meminfo.open(QIODevice::ReadOnly)) { |
389 | + return; |
390 | + } |
391 | + static QRegExp memTotalRegexp(QStringLiteral("MemTotal:\\s*(\\d+) kB\\n")); |
392 | + static QRegExp memFreeRegexp(QStringLiteral("MemFree:\\s*(\\d+) kB\\n")); |
393 | + static QRegExp buffersRegexp(QStringLiteral("Buffers:\\s*(\\d+) kB\\n")); |
394 | + static QRegExp cachedRegexp(QStringLiteral("Cached:\\s*(\\d+) kB\\n")); |
395 | + int parsedTotal = -1; |
396 | + int parsedFree = -1; |
397 | + int parsedBuffers = -1; |
398 | + int parsedCached = -1; |
399 | + while ((parsedTotal == -1) || (parsedFree == -1) || |
400 | + (parsedBuffers == -1) || (parsedCached == -1)) { |
401 | + QByteArray line = meminfo.readLine(); |
402 | + if (line.isEmpty()) { |
403 | + break; |
404 | + } |
405 | + if (memTotalRegexp.exactMatch(line)) { |
406 | + parsedTotal = memTotalRegexp.cap(1).toInt(); |
407 | + } else if (memFreeRegexp.exactMatch(line)) { |
408 | + parsedFree = memFreeRegexp.cap(1).toInt(); |
409 | + } else if (buffersRegexp.exactMatch(line)) { |
410 | + parsedBuffers = buffersRegexp.cap(1).toInt(); |
411 | + } else if (cachedRegexp.exactMatch(line)) { |
412 | + parsedCached = cachedRegexp.cap(1).toInt(); |
413 | + } |
414 | + } |
415 | + meminfo.close(); |
416 | + if ((parsedTotal != -1) && (parsedFree != -1) && |
417 | + (parsedBuffers != -1) && (parsedCached != -1)) { |
418 | + bool totalUpdated = false; |
419 | + if (parsedTotal != m_total) { |
420 | + m_total = parsedTotal; |
421 | + totalUpdated = true; |
422 | + } |
423 | + bool freeUpdated = false; |
424 | + int newFree = parsedFree + parsedCached + parsedBuffers; |
425 | + if (newFree != m_free) { |
426 | + m_free = newFree; |
427 | + freeUpdated = true; |
428 | + } |
429 | + if (totalUpdated) { |
430 | + Q_EMIT totalChanged(); |
431 | + } |
432 | + if (freeUpdated) { |
433 | + Q_EMIT freeChanged(); |
434 | + } |
435 | + } |
436 | +#endif // Q_OS_LINUX |
437 | +} |
438 | |
439 | === added file 'src/app/meminfo.h' |
440 | --- src/app/meminfo.h 1970-01-01 00:00:00 +0000 |
441 | +++ src/app/meminfo.h 2016-02-23 11:14:53 +0000 |
442 | @@ -0,0 +1,65 @@ |
443 | +/* |
444 | + * Copyright 2016 Canonical Ltd. |
445 | + * |
446 | + * This file is part of webbrowser-app. |
447 | + * |
448 | + * webbrowser-app is free software; you can redistribute it and/or modify |
449 | + * it under the terms of the GNU General Public License as published by |
450 | + * the Free Software Foundation; version 3. |
451 | + * |
452 | + * webbrowser-app is distributed in the hope that it will be useful, |
453 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
454 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
455 | + * GNU General Public License for more details. |
456 | + * |
457 | + * You should have received a copy of the GNU General Public License |
458 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
459 | + */ |
460 | + |
461 | +#ifndef __MEMINFO_H__ |
462 | +#define __MEMINFO_H__ |
463 | + |
464 | +// Qt |
465 | +#include <QtCore/QObject> |
466 | +#include <QtCore/QTimer> |
467 | + |
468 | +class MemInfo : public QObject |
469 | +{ |
470 | + Q_OBJECT |
471 | + |
472 | + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) |
473 | + Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged) |
474 | + |
475 | + // Expressed in kB |
476 | + Q_PROPERTY(int total READ total NOTIFY totalChanged) |
477 | + Q_PROPERTY(int free READ free NOTIFY freeChanged) |
478 | + |
479 | +public: |
480 | + MemInfo(QObject* parent=nullptr); |
481 | + ~MemInfo(); |
482 | + |
483 | + const bool active() const; |
484 | + void setActive(bool active); |
485 | + |
486 | + const int interval() const; |
487 | + void setInterval(int interval); |
488 | + |
489 | + const int total() const; |
490 | + const int free() const; |
491 | + |
492 | +Q_SIGNALS: |
493 | + void activeChanged() const; |
494 | + void intervalChanged() const; |
495 | + void totalChanged() const; |
496 | + void freeChanged() const; |
497 | + |
498 | +private Q_SLOTS: |
499 | + void update(); |
500 | + |
501 | +private: |
502 | + QTimer m_timer; |
503 | + int m_total; |
504 | + int m_free; |
505 | +}; |
506 | + |
507 | +#endif // __MEMINFO_H__ |
508 | |
509 | === modified file 'src/app/webbrowser/Browser.qml' |
510 | --- src/app/webbrowser/Browser.qml 2016-02-15 13:33:11 +0000 |
511 | +++ src/app/webbrowser/Browser.qml 2016-02-23 11:14:53 +0000 |
512 | @@ -47,10 +47,6 @@ |
513 | |
514 | readonly property var tabsModel: incognito ? privateTabsModelLoader.item : publicTabsModel |
515 | |
516 | - // XXX: we might want to tweak this value depending |
517 | - // on the form factor and/or the available memory |
518 | - readonly property int maxLiveWebviews: 2 |
519 | - |
520 | // Restore only the n most recent tabs at startup, |
521 | // to limit the overhead of instantiating too many |
522 | // tab objects (see http://pad.lv/1376433). |
523 | @@ -59,6 +55,10 @@ |
524 | onTabsModelChanged: { |
525 | if (incognito && privateTabsModelLoader.item) { |
526 | browser.openUrlInNewTab("", true) |
527 | + } else if (!incognito && tabsModel.currentTab) { |
528 | + // If the system is low on memory, the current public tab might |
529 | + // have been unloaded while browsing incognito, so reload it. |
530 | + tabsModel.currentTab.load() |
531 | } |
532 | } |
533 | |
534 | @@ -106,6 +106,11 @@ |
535 | deviceFilter: InputInfo.TouchPad |
536 | } |
537 | |
538 | + InputDeviceModel { |
539 | + id: touchScreenModel |
540 | + deviceFilter: InputInfo.TouchScreen |
541 | + } |
542 | + |
543 | Component { |
544 | id: mediaAccessDialogComponent |
545 | MediaAccessDialog { } |
546 | @@ -151,7 +156,6 @@ |
547 | |
548 | property url homepage: settingsDefaults.homepage |
549 | property string searchEngine: settingsDefaults.searchEngine |
550 | - property string allowOpenInBackgroundTab: settingsDefaults.allowOpenInBackgroundTab |
551 | property bool restoreSession: settingsDefaults.restoreSession |
552 | property int newTabDefaultSection: settingsDefaults.newTabDefaultSection |
553 | property string defaultAudioDevice |
554 | @@ -160,7 +164,6 @@ |
555 | function restoreDefaults() { |
556 | homepage = settingsDefaults.homepage |
557 | searchEngine = settingsDefaults.searchEngine |
558 | - allowOpenInBackgroundTab = settingsDefaults.allowOpenInBackgroundTab |
559 | restoreSession = settingsDefaults.restoreSession |
560 | newTabDefaultSection = settingsDefaults.newTabDefaultSection |
561 | defaultAudioDevice = settingsDefaults.defaultAudioDevice |
562 | @@ -173,7 +176,6 @@ |
563 | |
564 | readonly property url homepage: "http://start.ubuntu.com" |
565 | readonly property string searchEngine: "google" |
566 | - readonly property string allowOpenInBackgroundTab: "default" |
567 | readonly property bool restoreSession: true |
568 | readonly property int newTabDefaultSection: 0 |
569 | readonly property string defaultAudioDevice: "" |
570 | @@ -461,8 +463,9 @@ |
571 | webview: browser.currentWebview |
572 | forceHide: browser.fullscreen |
573 | forceShow: recentView.visible |
574 | - defaultMode: (formFactor == "desktop") ? Oxide.LocationBarController.ModeShown |
575 | - : Oxide.LocationBarController.ModeAuto |
576 | + defaultMode: (internal.hasMouse && !internal.hasTouchScreen) |
577 | + ? Oxide.LocationBarController.ModeShown |
578 | + : Oxide.LocationBarController.ModeAuto |
579 | } |
580 | |
581 | Chrome { |
582 | @@ -480,6 +483,8 @@ |
583 | |
584 | availableHeight: tabContainer.height - height - y |
585 | |
586 | + touchEnabled: internal.hasTouchScreen |
587 | + |
588 | property bool hidden: false |
589 | y: hidden ? -height : webview ? webview.locationBarController.offset : 0 |
590 | Behavior on y { |
591 | @@ -1080,10 +1085,7 @@ |
592 | } |
593 | Actions.OpenLinkInNewBackgroundTab { |
594 | objectName: "OpenLinkInNewBackgroundTabContextualAction" |
595 | - enabled: contextModel && contextModel.linkUrl.toString() && |
596 | - ((settings.allowOpenInBackgroundTab === "true") || |
597 | - ((settings.allowOpenInBackgroundTab === "default") && |
598 | - (formFactor === "desktop"))) |
599 | + enabled: contextModel && contextModel.linkUrl.toString() |
600 | onTriggered: browser.openUrlInNewTab(contextModel.linkUrl, false) |
601 | } |
602 | Actions.BookmarkLink { |
603 | @@ -1112,7 +1114,7 @@ |
604 | } |
605 | Actions.Share { |
606 | objectName: "ShareContextualAction" |
607 | - enabled: (formFactor == "mobile") && contextModel && |
608 | + enabled: (contentHandlerLoader.status == Loader.Ready) && contextModel && |
609 | (contextModel.linkUrl.toString() || contextModel.selectionText) |
610 | onTriggered: { |
611 | if (contextModel.linkUrl.toString()) { |
612 | @@ -1339,9 +1341,9 @@ |
613 | color: "white" |
614 | font.weight: Font.Light |
615 | anchors.centerIn: parent |
616 | - text: (formFactor == "mobile") ? |
617 | - i18n.tr("Swipe Up To Exit Full Screen") : |
618 | - i18n.tr("Press ESC To Exit Full Screen") |
619 | + text: bottomEdgeHandle.enabled |
620 | + ? i18n.tr("Swipe Up To Exit Full Screen") |
621 | + : i18n.tr("Press ESC To Exit Full Screen") |
622 | } |
623 | |
624 | Timer { |
625 | @@ -1453,6 +1455,15 @@ |
626 | } |
627 | |
628 | readonly property bool hasMouse: (miceModel.count + touchPadModel.count) > 0 |
629 | + readonly property bool hasTouchScreen: touchScreenModel.count > 0 |
630 | + |
631 | + readonly property real freeMemRatio: (MemInfo.total > 0) ? (MemInfo.free / MemInfo.total) : 1.0 |
632 | + // Under that threshold, available memory is considered "low", and the |
633 | + // browser is going to try and free up memory from unused tabs. This |
634 | + // value was chosen empirically, it is subject to change to better |
635 | + // reflect what a system under memory pressure might look like. |
636 | + readonly property real lowOnMemoryThreshold: 0.3 |
637 | + readonly property bool lowOnMemory: freeMemRatio < lowOnMemoryThreshold |
638 | |
639 | function getOpenPages() { |
640 | var urls = [] |
641 | @@ -1765,11 +1776,12 @@ |
642 | session.save() |
643 | } |
644 | if (browser.currentWebview) { |
645 | - // Workaround for a desktop bug where changing volume causes the app to |
646 | - // briefly lose focus to notify-osd, and therefore exit fullscreen mode. |
647 | - // We prevent this by exiting fullscreen only if the focus remains lost |
648 | - // for longer than a certain threshold. See: http://pad.lv/1477308 |
649 | - if (formFactor == "desktop") exitFullscreenOnLostFocus.start() |
650 | + // Workaround for a desktop bug where changing volume causes |
651 | + // the app to briefly lose focus to notify-osd, and therefore |
652 | + // exit fullscreen mode. We prevent this by exiting fullscreen |
653 | + // only if the focus remains lost for longer than a certain |
654 | + // threshold. See: https://launchpad.net/bugs/694224. |
655 | + if (__platformName == "xcb") exitFullscreenOnLostFocus.start() |
656 | else browser.currentWebview.fullscreen = false |
657 | } |
658 | } else exitFullscreenOnLostFocus.stop() |
659 | @@ -1838,15 +1850,41 @@ |
660 | } |
661 | |
662 | Connections { |
663 | - // On mobile, ensure that at most n webviews are instantiated at all |
664 | - // times, to reduce memory consumption (see http://pad.lv/1376418). |
665 | - // Note: this works only in narrow mode, where the list of tabs is a |
666 | - // stack. Switching from wide mode to narrow mode will result in |
667 | - // undefined behaviour (tabs previously loaded won’t be unloaded). |
668 | - target: ((formFactor == "mobile") && !browser.wide) ? tabsModel : null |
669 | - onCurrentTabChanged: { |
670 | - if (tabsModel.count > browser.maxLiveWebviews) { |
671 | - tabsModel.get(browser.maxLiveWebviews).unload() |
672 | + target: internal |
673 | + onFreeMemRatioChanged: { |
674 | + if (internal.lowOnMemory) { |
675 | + // Unload an inactive tab to (hopefully) free up some memory |
676 | + function getCandidate(model) { |
677 | + // Naive implementation that only takes into account the |
678 | + // last time a tab was current. In the future we might |
679 | + // want to take into account other parameters such as |
680 | + // whether the tab is currently playing audio/video. |
681 | + var candidate = null |
682 | + for (var i = 0; i < model.count; ++i) { |
683 | + var tab = model.get(i) |
684 | + if (tab.current || !tab.webview) { |
685 | + continue |
686 | + } |
687 | + if (!candidate || (candidate.lastCurrent > tab.lastCurrent)) { |
688 | + candidate = tab |
689 | + } |
690 | + } |
691 | + return candidate |
692 | + } |
693 | + var candidate = getCandidate(publicTabsModel) |
694 | + if (candidate) { |
695 | + console.warn("Unloading background tab (%1) to free up some memory".arg(candidate.url)) |
696 | + candidate.unload() |
697 | + return |
698 | + } else if (browser.incognito) { |
699 | + candidate = getCandidate(privateTabsModelLoader.item) |
700 | + if (candidate) { |
701 | + console.warn("Unloading a background incognito tab to free up some memory") |
702 | + candidate.unload() |
703 | + return |
704 | + } |
705 | + } |
706 | + console.warn("System low on memory, but unable to pick a tab to unload") |
707 | } |
708 | } |
709 | } |
710 | |
711 | === modified file 'src/app/webbrowser/BrowserTab.qml' |
712 | --- src/app/webbrowser/BrowserTab.qml 2016-02-11 10:38:44 +0000 |
713 | +++ src/app/webbrowser/BrowserTab.qml 2016-02-23 11:14:53 +0000 |
714 | @@ -39,6 +39,7 @@ |
715 | readonly property url icon: webview ? webview.icon : initialIcon |
716 | property url preview |
717 | property bool current: false |
718 | + readonly property int lastCurrent: internal.lastCurrent |
719 | property bool incognito |
720 | visible: false |
721 | |
722 | @@ -126,6 +127,7 @@ |
723 | id: internal |
724 | property bool hiding: false |
725 | property var incubator: null |
726 | + property int lastCurrent: 0 |
727 | } |
728 | |
729 | // When current is set to false, delay hiding the tab contents to give it |
730 | @@ -133,6 +135,7 @@ |
731 | // only if embedders do not set the 'visible' property directly or |
732 | // indirectly on instances of a BrowserTab. |
733 | onCurrentChanged: { |
734 | + internal.lastCurrent = Date.now() |
735 | if (current) { |
736 | internal.hiding = false |
737 | z = 1 |
738 | |
739 | === modified file 'src/app/webbrowser/Chrome.qml' |
740 | --- src/app/webbrowser/Chrome.qml 2016-01-26 17:44:49 +0000 |
741 | +++ src/app/webbrowser/Chrome.qml 2016-02-23 11:14:53 +0000 |
742 | @@ -40,6 +40,7 @@ |
743 | property alias showFaviconInAddressBar: navigationBar.showFaviconInAddressBar |
744 | property alias availableHeight: navigationBar.availableHeight |
745 | readonly property alias bookmarkTogglePlaceHolder: navigationBar.bookmarkTogglePlaceHolder |
746 | + property bool touchEnabled: true |
747 | |
748 | signal switchToTab(int index) |
749 | signal requestNewTab(int index, bool makeCurrent) |
750 | @@ -72,6 +73,7 @@ |
751 | model: tabsModel |
752 | incognito: chrome.incognito |
753 | fgColor: navigationBar.fgColor |
754 | + touchEnabled: chrome.touchEnabled |
755 | onSwitchToTab: chrome.switchToTab(index) |
756 | onRequestNewTab: chrome.requestNewTab(index, makeCurrent) |
757 | onTabClosed: chrome.tabClosed(index) |
758 | @@ -82,7 +84,7 @@ |
759 | left: parent.left |
760 | right: parent.right |
761 | } |
762 | - height: active ? (formFactor == "desktop" ? units.gu(3) : units.gu(4)) : 0 |
763 | + height: active ? (touchEnabled ? units.gu(4) : units.gu(3)) : 0 |
764 | } |
765 | |
766 | NavigationBar { |
767 | |
768 | === modified file 'src/app/webbrowser/SettingsPage.qml' |
769 | --- src/app/webbrowser/SettingsPage.qml 2015-11-30 09:38:08 +0000 |
770 | +++ src/app/webbrowser/SettingsPage.qml 2016-02-23 11:14:53 +0000 |
771 | @@ -1,5 +1,5 @@ |
772 | /* |
773 | - * Copyright 2015 Canonical Ltd. |
774 | + * Copyright 2015-2016 Canonical Ltd. |
775 | * |
776 | * This file is part of webbrowser-app. |
777 | * |
778 | @@ -113,25 +113,6 @@ |
779 | } |
780 | |
781 | ListItems.Standard { |
782 | - objectName: "backgroundTabs" |
783 | - |
784 | - text: i18n.tr("Allow opening new tabs in background") |
785 | - highlightWhenPressed: false |
786 | - |
787 | - control: CheckBox { |
788 | - id: allowOpenInBackgroundTabCheckbox |
789 | - onTriggered: settingsObject.allowOpenInBackgroundTab = checked ? 'true' : 'false' |
790 | - } |
791 | - |
792 | - Binding { |
793 | - target: allowOpenInBackgroundTabCheckbox |
794 | - property: "checked" |
795 | - value: settingsObject.allowOpenInBackgroundTab === 'true' || |
796 | - (settingsObject.allowOpenInBackgroundTab === 'default' && formFactor === "desktop") |
797 | - } |
798 | - } |
799 | - |
800 | - ListItems.Standard { |
801 | objectName: "privacy" |
802 | |
803 | text: i18n.tr("Privacy & permissions") |
804 | |
805 | === modified file 'src/app/webbrowser/TabItem.qml' |
806 | --- src/app/webbrowser/TabItem.qml 2016-01-26 17:44:49 +0000 |
807 | +++ src/app/webbrowser/TabItem.qml 2016-02-23 11:14:53 +0000 |
808 | @@ -37,6 +37,8 @@ |
809 | |
810 | property color fgColor: Theme.palette.normal.baseText |
811 | |
812 | + property bool touchEnabled: true |
813 | + |
814 | signal selected() |
815 | signal closed() |
816 | signal contextMenu() |
817 | @@ -47,7 +49,7 @@ |
818 | anchors.rightMargin: tabItem.rightMargin |
819 | source: "assets/tab-%1%2.sci".arg((active) ? "active" : |
820 | (hoverArea.containsMouse ? "hover" : "non-active")) |
821 | - .arg(formFactor == "desktop" ? "-desktop" : "") |
822 | + .arg(touchEnabled ? "" : "-desktop") |
823 | |
824 | Favicon { |
825 | id: favicon |
826 | @@ -121,15 +123,14 @@ |
827 | id: closeButton |
828 | objectName: "closeButton" |
829 | |
830 | - // On mobile the tap area to close the tab occupies the whole right |
831 | + // On touch the tap area to close the tab occupies the whole right |
832 | // hand side of the tab, while it covers only the close icon in |
833 | // other form factors |
834 | - readonly property bool mobile: formFactor == "mobile" |
835 | - anchors.fill: mobile ? undefined : closeIcon |
836 | - anchors.top: mobile ? parent.top : undefined |
837 | - anchors.bottom: mobile ? parent.bottom : undefined |
838 | - anchors.right: mobile ? parent.right : undefined |
839 | - width: mobile ? units.gu(4) : closeIcon.width |
840 | + anchors.fill: touchEnabled ? undefined : closeIcon |
841 | + anchors.top: touchEnabled ? parent.top : undefined |
842 | + anchors.bottom: touchEnabled ? parent.bottom : undefined |
843 | + anchors.right: touchEnabled ? parent.right : undefined |
844 | + width: touchEnabled ? units.gu(4) : closeIcon.width |
845 | |
846 | onClicked: closed() |
847 | |
848 | |
849 | === modified file 'src/app/webbrowser/TabsBar.qml' |
850 | --- src/app/webbrowser/TabsBar.qml 2016-01-26 17:44:49 +0000 |
851 | +++ src/app/webbrowser/TabsBar.qml 2016-02-23 11:14:53 +0000 |
852 | @@ -34,6 +34,8 @@ |
853 | |
854 | property color fgColor: Theme.palette.normal.baseText |
855 | |
856 | + property bool touchEnabled: true |
857 | + |
858 | signal switchToTab(int index) |
859 | signal requestNewTab(int index, bool makeCurrent) |
860 | signal tabClosed(int index) |
861 | @@ -111,7 +113,6 @@ |
862 | anchors { |
863 | top: parent.top |
864 | bottom: parent.bottom |
865 | - bottomMargin: tabsContainer.verticalGap |
866 | left: parent.left |
867 | } |
868 | width: tabWidth * root.model.count |
869 | @@ -153,6 +154,8 @@ |
870 | icon: model.icon |
871 | fgColor: root.fgColor |
872 | |
873 | + touchEnabled: root.touchEnabled |
874 | + |
875 | rightMargin: tabDelegate.rightMargin |
876 | |
877 | onClosed: root.tabClosed(index) |
878 | |
879 | === modified file 'src/app/webbrowser/webbrowser-app.cpp' |
880 | --- src/app/webbrowser/webbrowser-app.cpp 2016-01-22 10:23:29 +0000 |
881 | +++ src/app/webbrowser/webbrowser-app.cpp 2016-02-23 11:14:53 +0000 |
882 | @@ -82,6 +82,8 @@ |
883 | searchEnginesSearchPaths << UbuntuBrowserDirectory() + "/webbrowser/searchengines"; |
884 | m_engine->rootContext()->setContextProperty("searchEnginesSearchPaths", searchEnginesSearchPaths); |
885 | |
886 | + m_engine->rootContext()->setContextProperty("__platformName", platformName()); |
887 | + |
888 | m_window->setProperty("newSession", m_arguments.contains("--new-session")); |
889 | |
890 | QVariantList urls; |
891 | |
892 | === modified file 'src/app/webcontainer/WebApp.qml' |
893 | --- src/app/webcontainer/WebApp.qml 2016-01-08 16:09:01 +0000 |
894 | +++ src/app/webcontainer/WebApp.qml 2016-02-23 11:14:53 +0000 |
895 | @@ -250,8 +250,9 @@ |
896 | ChromeController { |
897 | webview: webapp.currentWebview |
898 | forceHide: webapp.chromeless |
899 | - defaultMode: (formFactor == "desktop") ? Oxide.LocationBarController.ModeShown |
900 | - : Oxide.LocationBarController.ModeAuto |
901 | + defaultMode: webapp.hasTouchScreen |
902 | + ? Oxide.LocationBarController.ModeAuto |
903 | + : Oxide.LocationBarController.ModeShown |
904 | } |
905 | } |
906 | |
907 | |
908 | === modified file 'src/app/webcontainer/WebViewImplOxide.qml' |
909 | --- src/app/webcontainer/WebViewImplOxide.qml 2016-01-08 16:09:01 +0000 |
910 | +++ src/app/webcontainer/WebViewImplOxide.qml 2016-02-23 11:14:53 +0000 |
911 | @@ -1,5 +1,5 @@ |
912 | /* |
913 | - * Copyright 2014-2015 Canonical Ltd. |
914 | + * Copyright 2014-2016 Canonical Ltd. |
915 | * |
916 | * This file is part of webbrowser-app. |
917 | * |
918 | @@ -207,10 +207,6 @@ |
919 | samlRequestUrlPatternReceived(urlPattern) |
920 | } |
921 | |
922 | - function shouldOpenPopupsInDefaultBrowser() { |
923 | - return formFactor !== "desktop"; |
924 | - } |
925 | - |
926 | function isRunningAsANamedWebapp() { |
927 | return webview.webappName && typeof(webview.webappName) === 'string' && webview.webappName.length != 0 |
928 | } |
929 | @@ -328,13 +324,12 @@ |
930 | } |
931 | |
932 | onGeolocationPermissionRequested: { |
933 | - if (formFactor == "desktop") { |
934 | + if (__runningConfined && (request.origin == request.embedder)) { |
935 | + // When running confined, querying the location service will trigger |
936 | + // a system prompt (trust store), so no need for a custom one. |
937 | + request.accept() |
938 | + } else { |
939 | requestGeolocationPermission(request) |
940 | - } else { |
941 | - // On devices where webapps are confined, trying to access the |
942 | - // location service will trigger a system prompt from the trust |
943 | - // store, so we don’t need a custom prompt. |
944 | - request.accept() |
945 | } |
946 | } |
947 | |
948 | |
949 | === modified file 'tests/autopilot/webbrowser_app/tests/__init__.py' |
950 | --- tests/autopilot/webbrowser_app/tests/__init__.py 2016-02-03 11:56:56 +0000 |
951 | +++ tests/autopilot/webbrowser_app/tests/__init__.py 2016-02-23 11:14:53 +0000 |
952 | @@ -158,16 +158,11 @@ |
953 | toolbar.click_action("newTabButton") |
954 | tabs_view.visible.wait_for(False) |
955 | |
956 | - if self.main_window.wide or (model() == 'Desktop'): |
957 | - new_count = count + 1 |
958 | - else: |
959 | - max_webviews = self.main_window.maxLiveWebviews |
960 | - new_count = (count + 1) if (count < max_webviews) else max_webviews |
961 | if (self.main_window.incognito): |
962 | - self.assert_number_incognito_webviews_eventually(new_count) |
963 | + self.assert_number_incognito_webviews_eventually(count + 1) |
964 | new_tab_view = self.main_window.get_new_private_tab_view() |
965 | else: |
966 | - self.assert_number_webviews_eventually(new_count) |
967 | + self.assert_number_webviews_eventually(count + 1) |
968 | new_tab_view = self.main_window.get_new_tab_view() |
969 | |
970 | if self.main_window.wide: |
971 | |
972 | === modified file 'tests/unittests/CMakeLists.txt' |
973 | --- tests/unittests/CMakeLists.txt 2016-01-18 14:45:12 +0000 |
974 | +++ tests/unittests/CMakeLists.txt 2016-02-23 11:14:53 +0000 |
975 | @@ -22,3 +22,4 @@ |
976 | add_subdirectory(text-search-filter-model) |
977 | add_subdirectory(downloads-model) |
978 | add_subdirectory(single-instance-manager) |
979 | +add_subdirectory(meminfo) |
980 | |
981 | === added directory 'tests/unittests/meminfo' |
982 | === added file 'tests/unittests/meminfo/CMakeLists.txt' |
983 | --- tests/unittests/meminfo/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
984 | +++ tests/unittests/meminfo/CMakeLists.txt 2016-02-23 11:14:53 +0000 |
985 | @@ -0,0 +1,15 @@ |
986 | +find_package(Qt5Core REQUIRED) |
987 | +find_package(Qt5Test REQUIRED) |
988 | +set(TEST tst_MemInfoTests) |
989 | +set(SOURCES |
990 | + ${webbrowser-common_SOURCE_DIR}/meminfo.cpp |
991 | + tst_MemInfoTests.cpp |
992 | +) |
993 | +add_executable(${TEST} ${SOURCES}) |
994 | +include_directories(${webbrowser-common_SOURCE_DIR}) |
995 | +target_link_libraries(${TEST} |
996 | + Qt5::Core |
997 | + Qt5::Test |
998 | +) |
999 | +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml) |
1000 | +set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal") |
1001 | |
1002 | === added file 'tests/unittests/meminfo/tst_MemInfoTests.cpp' |
1003 | --- tests/unittests/meminfo/tst_MemInfoTests.cpp 1970-01-01 00:00:00 +0000 |
1004 | +++ tests/unittests/meminfo/tst_MemInfoTests.cpp 2016-02-23 11:14:53 +0000 |
1005 | @@ -0,0 +1,100 @@ |
1006 | +/* |
1007 | + * Copyright 2016 Canonical Ltd. |
1008 | + * |
1009 | + * This file is part of webbrowser-app. |
1010 | + * |
1011 | + * webbrowser-app is free software; you can redistribute it and/or modify |
1012 | + * it under the terms of the GNU General Public License as published by |
1013 | + * the Free Software Foundation; version 3. |
1014 | + * |
1015 | + * webbrowser-app is distributed in the hope that it will be useful, |
1016 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1017 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1018 | + * GNU General Public License for more details. |
1019 | + * |
1020 | + * You should have received a copy of the GNU General Public License |
1021 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1022 | + */ |
1023 | + |
1024 | +// Qt |
1025 | +#include <QtCore/QObject> |
1026 | +#include <QtTest/QSignalSpy> |
1027 | +#include <QtTest/QtTest> |
1028 | + |
1029 | +// local |
1030 | +#include "meminfo.h" |
1031 | + |
1032 | +class MemInfoTests : public QObject |
1033 | +{ |
1034 | + Q_OBJECT |
1035 | + |
1036 | +private: |
1037 | + MemInfo* meminfo; |
1038 | + |
1039 | +private Q_SLOTS: |
1040 | + void init() |
1041 | + { |
1042 | + meminfo = new MemInfo(this); |
1043 | + } |
1044 | + |
1045 | + void cleanup() |
1046 | + { |
1047 | + delete meminfo; |
1048 | + } |
1049 | + |
1050 | + void test_active_property() |
1051 | + { |
1052 | + QVERIFY(meminfo->active()); |
1053 | + QSignalSpy spy(meminfo, SIGNAL(activeChanged())); |
1054 | + |
1055 | + meminfo->setActive(true); |
1056 | + QVERIFY(spy.isEmpty()); |
1057 | + |
1058 | + meminfo->setActive(false); |
1059 | + QCOMPARE(spy.count(), 1); |
1060 | + QVERIFY(!meminfo->active()); |
1061 | + spy.clear(); |
1062 | + |
1063 | + meminfo->setActive(false); |
1064 | + QVERIFY(spy.isEmpty()); |
1065 | + |
1066 | + meminfo->setActive(true); |
1067 | + QCOMPARE(spy.count(), 1); |
1068 | + QVERIFY(meminfo->active()); |
1069 | + } |
1070 | + |
1071 | + void test_interval_property() |
1072 | + { |
1073 | + QCOMPARE(meminfo->interval(), 5000); |
1074 | + QSignalSpy spy(meminfo, SIGNAL(intervalChanged())); |
1075 | + |
1076 | + meminfo->setInterval(5000); |
1077 | + QVERIFY(spy.isEmpty()); |
1078 | + |
1079 | + meminfo->setInterval(1500); |
1080 | + QCOMPARE(spy.count(), 1); |
1081 | + QCOMPARE(meminfo->interval(), 1500); |
1082 | + } |
1083 | + |
1084 | + void test_initial_values() |
1085 | + { |
1086 | + QCOMPARE(meminfo->total(), 0); |
1087 | + QCOMPARE(meminfo->free(), 0); |
1088 | + } |
1089 | + |
1090 | + void test_update() |
1091 | + { |
1092 | + QSignalSpy totalSpy(meminfo, SIGNAL(totalChanged())); |
1093 | + QSignalSpy freeSpy(meminfo, SIGNAL(freeChanged())); |
1094 | + meminfo->setInterval(100); |
1095 | + totalSpy.wait(); |
1096 | + freeSpy.wait(); |
1097 | + QVERIFY(meminfo->total() > 0); |
1098 | + QVERIFY(meminfo->free() > 0); |
1099 | + QVERIFY(meminfo->total() > meminfo->free()); |
1100 | + } |
1101 | +}; |
1102 | + |
1103 | +QTEST_MAIN(MemInfoTests) |
1104 | + |
1105 | +#include "tst_MemInfoTests.moc" |
I've added a comment inline to this