on xenial help sign in
Merge in shell_chrome
28988b8Michael Terry
qml/Components/InputMethod.qml+4−1
@@ -51,7 +51,10 @@ Item {
51 }
51 }
52
52
53 state: {
53 state: {
54+ if (surfaceItem.surface &&
55+ surfaceItem.surfaceState != Mir.HiddenState &&
54− if (surfaceItem.surface && surfaceItem.surfaceState != Mir.MinimizedState && root.enabled) {
56+ surfaceItem.surfaceState != Mir.MinimizedState &&
57+ root.enabled) {
55 return "shown";
58 return "shown";
56 } else {
59 } else {
57 return "hidden";
60 return "hidden";
qml/Shell.qml+5−1
@@ -247,7 +247,7 @@ Item {
247 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
247 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
248 ? "phone"
248 ? "phone"
249 : shell.usageScenario
249 : shell.usageScenario
250− source: {
250+ readonly property string qmlComponent: {
251 if(shell.mode === "greeter") {
251 if(shell.mode === "greeter") {
252 return "Stages/ShimStage.qml"
252 return "Stages/ShimStage.qml"
253 } else if (applicationsDisplayLoader.usageScenario === "phone") {
253 } else if (applicationsDisplayLoader.usageScenario === "phone") {
@@ -258,6 +258,10 @@ Item {
258 return "Stages/DesktopStage.qml";
258 return "Stages/DesktopStage.qml";
259 }
259 }
260 }
260 }
261+ onQmlComponentChanged: {
262+ if (item) item.stageAboutToBeUnloaded();
263+ source = qmlComponent;
264+ }
261
265
262 property bool interactive: (!greeter || !greeter.shown)
266 property bool interactive: (!greeter || !greeter.shown)
263 && panel.indicators.fullyClosed
267 && panel.indicators.fullyClosed
qml/Stages/AbstractStage.qml+2
@@ -52,6 +52,8 @@ Rectangle {
52 | Qt.InvertedPortraitOrientation
52 | Qt.InvertedPortraitOrientation
53 | Qt.InvertedLandscapeOrientation
53 | Qt.InvertedLandscapeOrientation
54
54
55+ signal stageAboutToBeUnloaded
56+
55 // Shared code for use in stage implementations
57 // Shared code for use in stage implementations
56 GSettings {
58 GSettings {
57 id: lifecycleExceptions
59 id: lifecycleExceptions
qml/Stages/DesktopStage.qml+61−9
@@ -255,8 +255,8 @@ AbstractStage {
255 focus: appId === priv.focusedAppId
255 focus: appId === priv.focusedAppId
256 width: decoratedWindow.width
256 width: decoratedWindow.width
257 height: decoratedWindow.height
257 height: decoratedWindow.height
258− property alias requestedWidth: decoratedWindow.requestedWidth
258+ property int requestedWidth: -1
259− property alias requestedHeight: decoratedWindow.requestedHeight
259+ property int requestedHeight: -1
260 property alias minimumWidth: decoratedWindow.minimumWidth
260 property alias minimumWidth: decoratedWindow.minimumWidth
261 property alias minimumHeight: decoratedWindow.minimumHeight
261 property alias minimumHeight: decoratedWindow.minimumHeight
262 property alias maximumWidth: decoratedWindow.maximumWidth
262 property alias maximumWidth: decoratedWindow.maximumWidth
@@ -388,20 +388,40 @@ AbstractStage {
388 PropertyChanges {
388 PropertyChanges {
389 target: appDelegate;
389 target: appDelegate;
390 x: root.leftMargin; y: 0;
390 x: root.leftMargin; y: 0;
391− requestedWidth: appContainer.width - root.leftMargin; requestedHeight: appContainer.height;
392 visuallyMinimized: false;
391 visuallyMinimized: false;
393 visuallyMaximized: true
392 visuallyMaximized: true
394 }
393 }
394+ PropertyChanges {
395+ target: decoratedWindow
396+ requestedWidth: root.width;
397+ requestedHeight: root.height;
398+ }
395 },
399 },
396 State {
400 State {
397 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
401 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
402+ PropertyChanges {
403+ target: appDelegate
404+ x: root.leftMargin
398− PropertyChanges { target: appDelegate; x: root.leftMargin; y: PanelState.panelHeight;
405+ y: PanelState.panelHeight
406+ }
407+ PropertyChanges {
408+ target: decoratedWindow
409+ requestedWidth: (appContainer.width - root.leftMargin)/2
399− requestedWidth: (appContainer.width - root.leftMargin)/2; requestedHeight: appContainer.height - PanelState.panelHeight }
410+ requestedHeight: appContainer.height - PanelState.panelHeight
411+ }
400 },
412 },
401 State {
413 State {
402 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
414 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
415+ PropertyChanges {
416+ target: appDelegate;
403− PropertyChanges { target: appDelegate; x: (appContainer.width + root.leftMargin)/2; y: PanelState.panelHeight;
417+ x: (appContainer.width + root.leftMargin)/2
418+ y: PanelState.panelHeight
419+ }
420+ PropertyChanges {
421+ target: decoratedWindow
422+ requestedWidth: (appContainer.width - root.leftMargin)/2
404− requestedWidth: (appContainer.width - root.leftMargin)/2; requestedHeight: appContainer.height - PanelState.panelHeight }
423+ requestedHeight: appContainer.height - PanelState.panelHeight
424+ }
405 },
425 },
406 State {
426 State {
407 name: "minimized"; when: appDelegate.minimized
427 name: "minimized"; when: appDelegate.minimized
@@ -421,13 +441,17 @@ AbstractStage {
421 enabled: appDelegate.animationsEnabled
441 enabled: appDelegate.animationsEnabled
422 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
442 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
423 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
443 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
444+ UbuntuNumberAnimation { target: decoratedWindow; properties: "requestedWidth,requestedHeight"; duration: UbuntuAnimation.FastDuration }
424 },
445 },
425 Transition {
446 Transition {
426 to: "minimized"
447 to: "minimized"
427 enabled: appDelegate.animationsEnabled
448 enabled: appDelegate.animationsEnabled
428 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
449 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
429 SequentialAnimation {
450 SequentialAnimation {
451+ ParallelAnimation {
452+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,scale"; duration: UbuntuAnimation.FastDuration }
430− UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
453+ UbuntuNumberAnimation { target: decoratedWindow; properties: "requestedWidth,requestedHeight"; duration: UbuntuAnimation.FastDuration }
454+ }
431 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
455 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
432 ScriptAction {
456 ScriptAction {
433 script: {
457 script: {
@@ -443,7 +467,10 @@ AbstractStage {
443 enabled: appDelegate.animationsEnabled
467 enabled: appDelegate.animationsEnabled
444 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
468 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
445 SequentialAnimation {
469 SequentialAnimation {
470+ ParallelAnimation {
471+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,scale"; duration: UbuntuAnimation.FastDuration }
446− UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
472+ UbuntuNumberAnimation { target: decoratedWindow; properties: "requestedWidth,requestedHeight"; duration: UbuntuAnimation.FastDuration }
473+ }
447 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
474 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
448 }
475 }
449 }
476 }
@@ -458,6 +485,7 @@ AbstractStage {
458 }
485 }
459
486
460 WindowResizeArea {
487 WindowResizeArea {
488+ id: resizeArea
461 objectName: "windowResizeArea"
489 objectName: "windowResizeArea"
462 target: appDelegate
490 target: appDelegate
463 minWidth: units.gu(10)
491 minWidth: units.gu(10)
@@ -469,6 +497,21 @@ AbstractStage {
469 leftMargin: root.leftMargin
497 leftMargin: root.leftMargin
470
498
471 onPressed: { ApplicationManager.focusApplication(model.appId) }
499 onPressed: { ApplicationManager.focusApplication(model.appId) }
500+
501+ property bool saveStateOnDestruction: true
502+ Connections {
503+ target: root
504+ onStageAboutToBeUnloaded: {
505+ resizeArea.saveWindowState();
506+ resizeArea.saveStateOnDestruction = false;
507+ fullscreenPolicy.active = false;
508+ }
509+ }
510+ Component.onDestruction: {
511+ if (saveStateOnDestruction) {
512+ saveWindowState();
513+ }
514+ }
472 }
515 }
473
516
474 DecoratedWindow {
517 DecoratedWindow {
@@ -480,12 +523,21 @@ AbstractStage {
480 active: ApplicationManager.focusedApplicationId === model.appId
523 active: ApplicationManager.focusedApplicationId === model.appId
481 focus: true
524 focus: true
482
525
526+ requestedWidth: appDelegate.requestedWidth
527+ requestedHeight: appDelegate.requestedHeight
528+
483 onClose: ApplicationManager.stopApplication(model.appId)
529 onClose: ApplicationManager.stopApplication(model.appId)
484 onMaximize: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
530 onMaximize: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
485 ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
531 ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
486 onMinimize: appDelegate.minimize()
532 onMinimize: appDelegate.minimize()
487 onDecorationPressed: { ApplicationManager.focusApplication(model.appId) }
533 onDecorationPressed: { ApplicationManager.focusApplication(model.appId) }
488 }
534 }
535+
536+ WindowedFullscreenPolicy {
537+ id: fullscreenPolicy
538+ active: true
539+ application: decoratedWindow.application
540+ }
489 }
541 }
490 }
542 }
491 }
543 }
qml/Stages/PhoneStage.qml+9
@@ -626,6 +626,15 @@ AbstractStage {
626 property: "focusedAppOrientationChangesEnabled"
626 property: "focusedAppOrientationChangesEnabled"
627 value: orientationChangesEnabled
627 value: orientationChangesEnabled
628 }
628 }
629+
630+ StagedFullscreenPolicy {
631+ id: fullscreenPolicy
632+ application: appDelegate.application
633+ }
634+ Connections {
635+ target: root
636+ onStageAboutToBeUnloaded: fullscreenPolicy.active = false
637+ }
629 }
638 }
630 }
639 }
631 }
640 }
qml/Stages/StagedFullscreenPolicy.qmlnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Unity.Application 0.1
19+
20+// This component will change the state of the surface based on the surface
21+// state and shell chrome.
22+//
23+// Chrome changed to LowChrome -> server sets client window state to "fullscreen"
24+// Chrome changed to NormalChrome -> server sets client window to "restored" state.
25+// Chrome set and state change to restored -> server RESETS client window state to "fullscreen"
26+// Chrome not set and state change to restored -> client window stays "restored"
27+// Chrome not set and state change to fulscreen -> client window stays "fullscreen"
28+QtObject {
29+ property bool active: true
30+ property QtObject application: null
31+
32+ readonly property var lastSurface: application && application.session ?
33+ application.session.lastSurface : null
34+ onLastSurfaceChanged: {
35+ if (!active || !lastSurface) return;
36+ if (lastSurface.shellChrome === Mir.LowChrome) {
37+ lastSurface.state = Mir.FullscreenState;
38+ }
39+ }
40+
41+ property var _connections: Connections {
42+ target: lastSurface
43+ onShellChromeChanged: {
44+ if (!active || !lastSurface) return;
45+ if (lastSurface.shellChrome === Mir.LowChrome) {
46+ lastSurface.state = Mir.FullscreenState;
47+ } else {
48+ lastSurface.state = Mir.RestoredState;
49+ }
50+ }
51+ onStateChanged: {
52+ if (!active) return;
53+ if (lastSurface.state === Mir.RestoredState && lastSurface.shellChrome === Mir.LowChrome) {
54+ lastSurface.state = Mir.FullscreenState;
55+ }
56+ }
57+ }
58+}
qml/Stages/TabletStage.qml+9
@@ -954,6 +954,15 @@ AbstractStage {
954 period: (spreadView.positionMarker2 - spreadView.positionMarker1) / 3
954 period: (spreadView.positionMarker2 - spreadView.positionMarker1) / 3
955 progress: spreadTile.progress - spreadView.positionMarker1
955 progress: spreadTile.progress - spreadView.positionMarker1
956 }
956 }
957+
958+ StagedFullscreenPolicy {
959+ id: fullscreenPolicy
960+ application: spreadTile.application
961+ }
962+ Connections {
963+ target: root
964+ onStageAboutToBeUnloaded: fullscreenPolicy.active = false
965+ }
957 }
966 }
958 }
967 }
959 }
968 }
qml/Stages/WindowResizeArea.qml+1−1
@@ -87,7 +87,7 @@ MouseArea {
87 priv.updateNormalGeometry();
87 priv.updateNormalGeometry();
88 }
88 }
89
89
90− Component.onDestruction: {
90+ function saveWindowState() {
91 windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal)
91 windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal)
92 windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight))
92 windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight))
93 }
93 }
qml/Stages/WindowedFullscreenPolicy.qmlnew file+41
@@ -0,0 +1,41 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQml 2.2
18+import Unity.Application 0.1
19+
20+// This component will change the state of the surface when the stage is loaded.
21+//
22+// On first surface load; if the surface is set to low chrome & fullscreen, the
23+// state of the window is returned to restored.
24+QtObject {
25+ property bool active: true
26+ property QtObject application: null
27+
28+ readonly property var lastSurface: application && application.session ?
29+ application.session.lastSurface : null
30+ property bool _firstTimeSurface: true
31+
32+ onLastSurfaceChanged: {
33+ if (!active || !lastSurface) return;
34+ if (!_firstTimeSurface) return;
35+ _firstTimeSurface = false;
36+
37+ if (lastSurface.state === Mir.FullscreenState && lastSurface.shellChrome === Mir.LowChrome) {
38+ lastSurface.state = Mir.RestoredState;
39+ }
40+ }
41+}
tests/mocks/Unity/Application/ApplicationInfo.cpp+21−3
@@ -44,6 +44,7 @@ ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
44 , m_isTouchApp(true)
44 , m_isTouchApp(true)
45 , m_exemptFromLifecycle(false)
45 , m_exemptFromLifecycle(false)
46 , m_manualSurfaceCreation(false)
46 , m_manualSurfaceCreation(false)
47+ , m_shellChrome(Mir::NormalChrome)
47{
48{
48}
49}
49
50
@@ -63,6 +64,7 @@ ApplicationInfo::ApplicationInfo(QObject *parent)
63 , m_isTouchApp(true)
64 , m_isTouchApp(true)
64 , m_exemptFromLifecycle(false)
65 , m_exemptFromLifecycle(false)
65 , m_manualSurfaceCreation(false)
66 , m_manualSurfaceCreation(false)
67+ , m_shellChrome(Mir::NormalChrome)
66{
68{
67}
69}
68
70
@@ -102,9 +104,11 @@ void ApplicationInfo::setSession(Session* session)
102 if (m_session) {
104 if (m_session) {
103 m_session->setApplication(this);
105 m_session->setApplication(this);
104 m_session->setParent(this);
106 m_session->setParent(this);
107+ m_session->setFullscreen(m_fullscreen);
105 SessionManager::singleton()->registerSession(m_session);
108 SessionManager::singleton()->registerSession(m_session);
106 connect(m_session, &Session::surfaceAdded,
109 connect(m_session, &Session::surfaceAdded,
107 this, &ApplicationInfo::onSessionSurfaceAdded);
110 this, &ApplicationInfo::onSessionSurfaceAdded);
111+ connect(m_session, &Session::fullscreenChanged, this, &ApplicationInfo::fullscreenChanged);
108
112
109 if (!m_manualSurfaceCreation) {
113 if (!m_manualSurfaceCreation) {
110 QTimer::singleShot(500, m_session, &Session::createSurface);
114 QTimer::singleShot(500, m_session, &Session::createSurface);
@@ -191,12 +195,17 @@ void ApplicationInfo::setFocused(bool value)
191
195
192void ApplicationInfo::setFullscreen(bool value)
196void ApplicationInfo::setFullscreen(bool value)
193{
197{
194− if (value != m_fullscreen) {
198+ m_fullscreen = value;
195− m_fullscreen = value;
199+ if (m_session) {
196− Q_EMIT fullscreenChanged(value);
200+ m_session->setFullscreen(value);
197 }
201 }
198}
202}
199
203
204+bool ApplicationInfo::fullscreen() const
205+{
206+ return m_session ? m_session->fullscreen() : false;
207+}
208+
200void ApplicationInfo::setManualSurfaceCreation(bool value)
209void ApplicationInfo::setManualSurfaceCreation(bool value)
201{
210{
202 if (value != m_manualSurfaceCreation) {
211 if (value != m_manualSurfaceCreation) {
@@ -262,6 +271,7 @@ void ApplicationInfo::onSessionSurfaceAdded(MirSurface* surface)
262 } else {
271 } else {
263 setState(Suspended);
272 setState(Suspended);
264 }
273 }
274+ surface->setShellChrome(m_shellChrome);
265 }
275 }
266}
276}
267
277
@@ -291,3 +301,11 @@ void ApplicationInfo::setInitialSurfaceSize(const QSize &size)
291 Q_EMIT initialSurfaceSizeChanged(m_initialSurfaceSize);
301 Q_EMIT initialSurfaceSizeChanged(m_initialSurfaceSize);
292 }
302 }
293}
303}
304+
305+void ApplicationInfo::setShellChrome(Mir::ShellChrome shellChrome)
306+{
307+ m_shellChrome = shellChrome;
308+ if (m_session && m_session->lastSurface()) {
309+ m_session->lastSurface()->setShellChrome(shellChrome);
310+ }
311+}
tests/mocks/Unity/Application/ApplicationInfo.h+5−1
@@ -24,6 +24,7 @@ class Session;
24
24
25// unity-api
25// unity-api
26#include <unity/shell/application/ApplicationInfoInterface.h>
26#include <unity/shell/application/ApplicationInfoInterface.h>
27+#include <unity/shell/application/Mir.h>
27
28
28using namespace unity::shell::application;
29using namespace unity::shell::application;
29
30
@@ -78,7 +79,7 @@ public:
78 QString screenshot() const { return m_screenshotFileName; }
79 QString screenshot() const { return m_screenshotFileName; }
79
80
80 void setFullscreen(bool value);
81 void setFullscreen(bool value);
81− bool fullscreen() const { return m_fullscreen; }
82+ bool fullscreen() const;
82
83
83 Qt::ScreenOrientations supportedOrientations() const override;
84 Qt::ScreenOrientations supportedOrientations() const override;
84 void setSupportedOrientations(Qt::ScreenOrientations orientations);
85 void setSupportedOrientations(Qt::ScreenOrientations orientations);
@@ -97,6 +98,8 @@ public:
97
98
98 QSize initialSurfaceSize() const override;
99 QSize initialSurfaceSize() const override;
99 void setInitialSurfaceSize(const QSize &size) override;
100 void setInitialSurfaceSize(const QSize &size) override;
101+
102+ Q_INVOKABLE void setShellChrome(Mir::ShellChrome shellChrome);
100public:
103public:
101 void setSession(Session* session);
104 void setSession(Session* session);
102 Session* session() const { return m_session; }
105 Session* session() const { return m_session; }
@@ -134,6 +137,7 @@ private:
134 QSize m_initialSurfaceSize;
137 QSize m_initialSurfaceSize;
135
138
136 bool m_manualSurfaceCreation;
139 bool m_manualSurfaceCreation;
140+ Mir::ShellChrome m_shellChrome;
137};
141};
138
142
139Q_DECLARE_METATYPE(ApplicationInfo*)
143Q_DECLARE_METATYPE(ApplicationInfo*)
tests/mocks/Unity/Application/ApplicationManager.cpp+6−4
@@ -328,6 +328,7 @@ void ApplicationManager::buildListOfAvailableApplications()
328 application->setName("Camera");
328 application->setName("Camera");
329 application->setScreenshotId("camera");
329 application->setScreenshotId("camera");
330 application->setIconId("camera");
330 application->setIconId("camera");
331+ application->setShellChrome(Mir::LowChrome);
331 application->setFullscreen(true);
332 application->setFullscreen(true);
332 application->setSupportedOrientations(Qt::PortraitOrientation
333 application->setSupportedOrientations(Qt::PortraitOrientation
333 | Qt::LandscapeOrientation
334 | Qt::LandscapeOrientation
@@ -341,7 +342,8 @@ void ApplicationManager::buildListOfAvailableApplications()
341 application->setName("Gallery");
342 application->setName("Gallery");
342 application->setScreenshotId("gallery");
343 application->setScreenshotId("gallery");
343 application->setIconId("gallery");
344 application->setIconId("gallery");
344− application->setFullscreen(true);
345+ application->setShellChrome(Mir::LowChrome);
346+ application->setStage(ApplicationInfo::MainStage);
345 m_availableApplications.append(application);
347 m_availableApplications.append(application);
346
348
347 application = new ApplicationInfo(this);
349 application = new ApplicationInfo(this);
@@ -353,7 +355,7 @@ void ApplicationManager::buildListOfAvailableApplications()
353
355
354 application = new ApplicationInfo(this);
356 application = new ApplicationInfo(this);
355 application->setAppId("webbrowser-app");
357 application->setAppId("webbrowser-app");
356− application->setFullscreen(true);
358+ application->setShellChrome(Mir::LowChrome);
357 application->setName("Browser");
359 application->setName("Browser");
358 application->setScreenshotId("browser");
360 application->setScreenshotId("browser");
359 application->setIconId("browser");
361 application->setIconId("browser");
@@ -378,7 +380,7 @@ void ApplicationManager::buildListOfAvailableApplications()
378 application->setName("GMail");
380 application->setName("GMail");
379 application->setIconId("gmail");
381 application->setIconId("gmail");
380 application->setScreenshotId("gmail-webapp.svg");
382 application->setScreenshotId("gmail-webapp.svg");
381− application->setFullscreen(false);
383+ application->setStage(ApplicationInfo::MainStage);
382 application->setSupportedOrientations(Qt::PortraitOrientation
384 application->setSupportedOrientations(Qt::PortraitOrientation
383 | Qt::LandscapeOrientation
385 | Qt::LandscapeOrientation
384 | Qt::InvertedPortraitOrientation
386 | Qt::InvertedPortraitOrientation
@@ -390,7 +392,7 @@ void ApplicationManager::buildListOfAvailableApplications()
390 application->setName("Music");
392 application->setName("Music");
391 application->setIconId("soundcloud");
393 application->setIconId("soundcloud");
392 application->setScreenshotId("music");
394 application->setScreenshotId("music");
393− application->setFullscreen(false);
395+ application->setStage(ApplicationInfo::MainStage);
394 application->setSupportedOrientations(Qt::PortraitOrientation
396 application->setSupportedOrientations(Qt::PortraitOrientation
395 | Qt::LandscapeOrientation
397 | Qt::LandscapeOrientation
396 | Qt::InvertedPortraitOrientation
398 | Qt::InvertedPortraitOrientation
tests/mocks/Unity/Application/MirSurface.cpp+16
@@ -38,6 +38,7 @@ MirSurface::MirSurface(const QString& name,
38 , m_width(-1)
38 , m_width(-1)
39 , m_height(-1)
39 , m_height(-1)
40 , m_slowToResize(false)
40 , m_slowToResize(false)
41+ , m_shellChrome(Mir::NormalChrome)
41{
42{
42// qDebug() << "MirSurface::MirSurface() " << name;
43// qDebug() << "MirSurface::MirSurface() " << name;
43 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
44 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
@@ -134,6 +135,21 @@ void MirSurface::setOrientationAngle(Mir::OrientationAngle angle)
134}
135}
135
136
136
137
138+Mir::ShellChrome MirSurface::shellChrome() const
139+{
140+ return m_shellChrome;
141+}
142+
143+void MirSurface::setShellChrome(Mir::ShellChrome shellChrome)
144+{
145+ if (shellChrome == m_shellChrome)
146+ return;
147+
148+ m_shellChrome = shellChrome;
149+ Q_EMIT shellChromeChanged(shellChrome);
150+}
151+
152+
137
153
138void MirSurface::registerView(qintptr viewId)
154void MirSurface::registerView(qintptr viewId)
139{
155{
tests/mocks/Unity/Application/MirSurface.h+5−3
@@ -74,10 +74,13 @@ public:
74 int widthIncrement() const override { return m_widthIncrement; }
74 int widthIncrement() const override { return m_widthIncrement; }
75 int heightIncrement() const override { return m_heightIncrement; }
75 int heightIncrement() const override { return m_heightIncrement; }
76
76
77+ Mir::ShellChrome shellChrome() const override;
78+
77 ////
79 ////
78 // API for tests
80 // API for tests
79
81
80 Q_INVOKABLE void setLive(bool live);
82 Q_INVOKABLE void setLive(bool live);
83+ Q_INVOKABLE void setShellChrome(Mir::ShellChrome shellChrome);
81
84
82 void registerView(qintptr viewId);
85 void registerView(qintptr viewId);
83 void unregisterView(qintptr viewId);
86 void unregisterView(qintptr viewId);
@@ -109,9 +112,6 @@ public:
109 void setActiveFocus(bool);
112 void setActiveFocus(bool);
110
113
111Q_SIGNALS:
114Q_SIGNALS:
112− void stateChanged(Mir::State);
113− void liveChanged(bool live);
114− void orientationAngleChanged(Mir::OrientationAngle angle);
115 void widthChanged();
115 void widthChanged();
116 void heightChanged();
116 void heightChanged();
117 void slowToResizeChanged();
117 void slowToResizeChanged();
@@ -152,6 +152,8 @@ private:
152 QSize m_delayedResize;
152 QSize m_delayedResize;
153 QSize m_pendingResize;
153 QSize m_pendingResize;
154
154
155+ Mir::ShellChrome m_shellChrome;
156+
155 struct View {
157 struct View {
156 bool visible;
158 bool visible;
157 };
159 };
tests/mocks/Unity/Application/MirSurfaceItem.cpp+9
@@ -100,6 +100,15 @@ bool MirSurfaceItem::live() const
100 }
100 }
101}
101}
102
102
103+Mir::ShellChrome MirSurfaceItem::shellChrome() const
104+{
105+ if (m_qmlSurface) {
106+ return m_qmlSurface->shellChrome();
107+ } else {
108+ return Mir::NormalChrome;
109+ }
110+}
111+
103Mir::OrientationAngle MirSurfaceItem::orientationAngle() const
112Mir::OrientationAngle MirSurfaceItem::orientationAngle() const
104{
113{
105 if (m_qmlSurface) {
114 if (m_qmlSurface) {
tests/mocks/Unity/Application/MirSurfaceItem.h+1
@@ -47,6 +47,7 @@ public:
47 Mir::Type type() const override;
47 Mir::Type type() const override;
48 QString name() const override;
48 QString name() const override;
49 bool live() const override;
49 bool live() const override;
50+ Mir::ShellChrome shellChrome() const override;
50
51
51 Mir::State surfaceState() const override;
52 Mir::State surfaceState() const override;
52 void setSurfaceState(Mir::State) override {}
53 void setSurfaceState(Mir::State) override {}
tests/mocks/Unity/Application/Session.cpp+26−1
@@ -34,6 +34,7 @@ Session::Session(const QString &name,
34 , m_surface(nullptr)
34 , m_surface(nullptr)
35 , m_parentSession(nullptr)
35 , m_parentSession(nullptr)
36 , m_children(new SessionModel(this))
36 , m_children(new SessionModel(this))
37+ , m_fullscreen(false)
37{
38{
38// qDebug() << "Session::Session() " << this->name();
39// qDebug() << "Session::Session() " << this->name();
39
40
@@ -71,6 +72,25 @@ void Session::release()
71 deleteLater();
72 deleteLater();
72}
73}
73
74
75+void Session::updateFullscreenProperty()
76+{
77+ if (m_surfaces.rowCount() > 0) {
78+ // TODO: Figure out something better
79+ setFullscreen(lastSurface()->state() == Mir::FullscreenState);
80+ } else {
81+ // Keep the current value of the fullscreen property until we get a new
82+ // surface
83+ }
84+}
85+
86+void Session::setFullscreen(bool fullscreen)
87+{
88+ if (m_fullscreen != fullscreen) {
89+ m_fullscreen = fullscreen;
90+ Q_EMIT fullscreenChanged(m_fullscreen);
91+ }
92+}
93+
74void Session::setApplication(ApplicationInfo* application)
94void Session::setApplication(ApplicationInfo* application)
75{
95{
76 if (m_application == application)
96 if (m_application == application)
@@ -82,15 +102,18 @@ void Session::setApplication(ApplicationInfo* application)
82
102
83void Session::appendSurface(MirSurface* surface)
103void Session::appendSurface(MirSurface* surface)
84{
104{
85− // qDebug() << "Session::appendSurface - session=" << name() << "surface=" << surface;
105+ qDebug() << "Session::appendSurface - session=" << name() << "surface=" << surface;
86
106
87 m_surfaces.insert(m_surfaces.rowCount(), surface);
107 m_surfaces.insert(m_surfaces.rowCount(), surface);
88
108
109+ connect(surface, &MirSurfaceInterface::stateChanged, this, &Session::updateFullscreenProperty);
89 connect(surface, &QObject::destroyed,
110 connect(surface, &QObject::destroyed,
90 this, [this, surface]() { this->removeSurface(surface); });
111 this, [this, surface]() { this->removeSurface(surface); });
91
112
92 Q_EMIT lastSurfaceChanged(surface);
113 Q_EMIT lastSurfaceChanged(surface);
93 Q_EMIT surfaceAdded(surface);
114 Q_EMIT surfaceAdded(surface);
115+
116+ updateFullscreenProperty();
94}
117}
95
118
96void Session::removeSurface(MirSurface* surface)
119void Session::removeSurface(MirSurface* surface)
@@ -99,6 +122,8 @@ void Session::removeSurface(MirSurface* surface)
99 if (m_surfaces.contains(surface)) {
122 if (m_surfaces.contains(surface)) {
100 m_surfaces.remove(surface);
123 m_surfaces.remove(surface);
101 }
124 }
125+
126+ updateFullscreenProperty();
102}
127}
103
128
104void Session::setScreenshot(const QUrl& screenshot)
129void Session::setScreenshot(const QUrl& screenshot)
tests/mocks/Unity/Application/Session.h+7
@@ -47,6 +47,7 @@ public:
47 //getters
47 //getters
48 QString name() const { return m_name; }
48 QString name() const { return m_name; }
49 bool live() const { return m_live; }
49 bool live() const { return m_live; }
50+ bool fullscreen() const { return m_fullscreen; }
50 ApplicationInfo* application() const { return m_application; }
51 ApplicationInfo* application() const { return m_application; }
51 MirSurface *lastSurface() const;
52 MirSurface *lastSurface() const;
52 ObjectListModel<MirSurface>* surfaces() const;
53 ObjectListModel<MirSurface>* surfaces() const;
@@ -57,6 +58,7 @@ public:
57 void removeSurface(MirSurface* surface);
58 void removeSurface(MirSurface* surface);
58 void setScreenshot(const QUrl& m_screenshot);
59 void setScreenshot(const QUrl& m_screenshot);
59 void setLive(bool live);
60 void setLive(bool live);
61+ void setFullscreen(bool fullscreen);
60
62
61 Q_INVOKABLE void addChildSession(Session* session);
63 Q_INVOKABLE void addChildSession(Session* session);
62 void insertChildSession(uint index, Session* session);
64 void insertChildSession(uint index, Session* session);
@@ -68,6 +70,7 @@ Q_SIGNALS:
68 void liveChanged(bool live);
70 void liveChanged(bool live);
69 void surfaceAdded(MirSurface *surface);
71 void surfaceAdded(MirSurface *surface);
70 void lastSurfaceChanged(MirSurface *surface);
72 void lastSurfaceChanged(MirSurface *surface);
73+ void fullscreenChanged(bool fullscreen);
71
74
72 // internal mock use
75 // internal mock use
73 void deregister();
76 void deregister();
@@ -75,6 +78,9 @@ Q_SIGNALS:
75public Q_SLOTS:
78public Q_SLOTS:
76 Q_INVOKABLE void createSurface();
79 Q_INVOKABLE void createSurface();
77
80
81+private Q_SLOTS:
82+ void updateFullscreenProperty();
83+
78private:
84private:
79 SessionModel* childSessions() const;
85 SessionModel* childSessions() const;
80 void setParentSession(Session* session);
86 void setParentSession(Session* session);
@@ -87,6 +93,7 @@ private:
87 Session* m_parentSession;
93 Session* m_parentSession;
88 SessionModel* m_children;
94 SessionModel* m_children;
89 ObjectListModel<MirSurface> m_surfaces;
95 ObjectListModel<MirSurface> m_surfaces;
96+ bool m_fullscreen;
90
97
91 friend class ApplicationTestInterface;
98 friend class ApplicationTestInterface;
92};
99};
tests/qmltests/tst_Shell.qml+62
@@ -131,6 +131,9 @@ Rectangle {
131 anchors.right: root.right
131 anchors.right: root.right
132 width: units.gu(30)
132 width: units.gu(30)
133
133
134+ property var focusedApp: ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
135+ property var focusedSurface: focusedApp && focusedApp.session ? focusedApp.session.lastSurface : null
136+
134 Rectangle {
137 Rectangle {
135 id: controlRect
138 id: controlRect
136 anchors { left: parent.left; right: parent.right }
139 anchors { left: parent.left; right: parent.right }
@@ -251,6 +254,65 @@ Rectangle {
251 appId: modelData
254 appId: modelData
252 }
255 }
253 }
256 }
257+
258+ Label { text: "Focused Application"; font.bold: true }
259+
260+ Row {
261+ CheckBox {
262+ id: fullscreeAppCheck
263+
264+ onTriggered: {
265+ if (!controls.focusedSurface) return;
266+ if (controls.focusedSurface.state == Mir.FullscreenState) {
267+ controls.focusedSurface.state = Mir.RestoredState;
268+ } else {
269+ controls.focusedSurface.state = Mir.FullscreenState;
270+ }
271+ }
272+
273+ Binding {
274+ target: fullscreeAppCheck
275+ when: controls.focusedSurface
276+ property: "checked"
277+ value: {
278+ if (!controls.focusedSurface) return false;
279+ return controls.focusedSurface.state === Mir.FullscreenState
280+ }
281+ }
282+ }
283+ Label {
284+ text: "Fullscreen"
285+ }
286+ }
287+
288+ Row {
289+ CheckBox {
290+ id: chromeAppCheck
291+
292+ onTriggered: {
293+ if (!controls.focusedSurface) return;
294+ if (controls.focusedSurface.shellChrome == Mir.LowChrome) {
295+ controls.focusedSurface.setShellChrome(Mir.NormalChrome);
296+ } else {
297+ controls.focusedSurface.setShellChrome(Mir.LowChrome);
298+ }
299+ }
300+
301+ Binding {
302+ target: chromeAppCheck
303+ when: controls.focusedSurface !== null
304+ property: "checked"
305+ value: {
306+ if (!controls.focusedSurface) return false;
307+ controls.focusedSurface.shellChrome === Mir.LowChrome
308+ }
309+ }
310+ }
311+ Label {
312+ text: "Low Chrome"
313+ }
314+ }
315+
254 }
316 }
255 }
317 }
256 }
318 }