Merge lp:~lukas-kde/unity8/activateWindows into lp:unity8
- activateWindows
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~lukas-kde/unity8/activateWindows |
Merge into: | lp:unity8 |
Prerequisite: | lp:~unity-team/unity8/mousePointer |
Diff against target: |
1013 lines (+523/-77) 14 files modified
plugins/Utils/windowstatestorage.cpp (+62/-23) plugins/Utils/windowstatestorage.h (+13/-1) qml/Components/WindowControlButtons.qml (+3/-0) qml/Panel/Panel.qml (+5/-3) qml/Shell.qml (+2/-0) qml/Stages/DesktopSpreadDelegate.qml (+2/-2) qml/Stages/DesktopStage.qml (+152/-13) qml/Stages/WindowDecoration.qml (+2/-1) qml/Stages/WindowResizeArea.qml (+38/-7) tests/mocks/Utils/windowstatestorage.cpp (+11/-0) tests/mocks/Utils/windowstatestorage.h (+9/-0) tests/qmltests/Stages/tst_DesktopStage.qml (+120/-25) tests/qmltests/Stages/tst_WindowResizeArea.qml (+35/-2) tests/qmltests/tst_Shell.qml (+69/-0) |
To merge this branch: | bzr merge lp:~lukas-kde/unity8/activateWindows |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Michael Zanetti | Pending | ||
Daniel d'Andrada | Pending | ||
Review via email: mp+274903@code.launchpad.net |
This proposal supersedes a proposal from 2015-10-19.
This proposal has been superseded by a proposal from 2015-10-26.
Commit message
Restore windows when activating from the spread, maintain a focus stack
Stop displaying the "grabbing" icon when we merely click to focus the app's decoration.
Provide keyboard shortcuts for common window operations
Description of the change
Raise/restore windows when activating from the spread, maintain a focus stack in case we minimize/close an app.
Stop displaying the "grabbing" icon when we merely click to focus the app's decoration.
Provide keyboard shortcuts for common window operations
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* Did you make sure that your branch does not contain spurious tags?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Yes
* If you changed the UI, has there been a design review?
N/A
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal | # |
> Please follow the commit message format as explained here:
> https:/
Should be fine now
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
Could you please add qml tests to cover those use cases you mention (ie active focus when clicking on decoration and raise/restore when activation from spread)?
I believe we already have a test for the first one (focus when clicking decoration). We had similar problems in the past before. Should investigate why it passes now even though there's a bug there (maybe it tests only with touches and not with mouse clicks, don't know).
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
Oh, and it's worth making lp:~unity-team/unity8/mousePointer from silo 022 a prerequisite as it makes a lot of changes in this code.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> > Please follow the commit message format as explained here:
> > https:/
>
> Should be fine now
Yes, thanks!
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2005
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2020
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 2021. By Lukáš Tinkl
-
merge trunk
- 2022. By Lukáš Tinkl
- 2023. By Lukáš Tinkl
-
display the maximized window's title in the panel, next to the buttons
- 2024. By Lukáš Tinkl
-
merge prereq to fix failing tests
- 2025. By Lukáš Tinkl
-
elide the window title in the title bar
- 2026. By Lukáš Tinkl
-
silence warnings
- 2027. By Lukáš Tinkl
-
fix issues found by mzanetti
additionally properly restore windows from minimized state to the correct
previous state (maximized, maximizedLeft/Right) - 2028. By Lukáš Tinkl
-
fix restoring the apps from spread to the correct state and size
potential fix for the Alt+F4 shortcut problem
- 2029. By Lukáš Tinkl
-
fix click to focus
- 2030. By Lukáš Tinkl
-
take the panel height into account when semimaximizing windows
- 2031. By Lukáš Tinkl
-
add a test to prove smashing all the 4 cursor keys together does nothing :)
- 2032. By Lukáš Tinkl
-
make sure to play the minimized animation before switching focus to next
- 2033. By Lukáš Tinkl
-
merge trunk
- 2034. By Lukáš Tinkl
-
cleanup
- 2035. By Lukáš Tinkl
-
cleanup
Unmerged revisions
Preview Diff
1 | === modified file 'plugins/Utils/windowstatestorage.cpp' | |||
2 | --- plugins/Utils/windowstatestorage.cpp 2015-09-14 09:11:08 +0000 | |||
3 | +++ plugins/Utils/windowstatestorage.cpp 2015-10-26 13:53:58 +0000 | |||
4 | @@ -47,26 +47,38 @@ | |||
5 | 47 | m_db.close(); | 47 | m_db.close(); |
6 | 48 | } | 48 | } |
7 | 49 | 49 | ||
8 | 50 | void WindowStateStorage::saveState(const QString &windowId, WindowStateStorage::WindowState state) | ||
9 | 51 | { | ||
10 | 52 | const QString queryString = QStringLiteral("INSERT OR REPLACE INTO state (windowId, state) values ('%1', '%2');") | ||
11 | 53 | .arg(windowId) | ||
12 | 54 | .arg((int)state); | ||
13 | 55 | |||
14 | 56 | saveValue(queryString); | ||
15 | 57 | } | ||
16 | 58 | |||
17 | 59 | WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue) const | ||
18 | 60 | { | ||
19 | 61 | const QString queryString = QStringLiteral("SELECT * FROM state WHERE windowId = '%1';") | ||
20 | 62 | .arg(windowId); | ||
21 | 63 | |||
22 | 64 | QSqlQuery query = getValue(queryString); | ||
23 | 65 | |||
24 | 66 | if (!query.first()) { | ||
25 | 67 | return defaultValue; | ||
26 | 68 | } | ||
27 | 69 | return (WindowState)query.value("state").toInt(); | ||
28 | 70 | } | ||
29 | 71 | |||
30 | 50 | void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect) | 72 | void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect) |
31 | 51 | { | 73 | { |
35 | 52 | QMutexLocker mutexLocker(&s_mutex); | 74 | const QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');") |
33 | 53 | |||
34 | 54 | QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');") | ||
36 | 55 | .arg(windowId) | 75 | .arg(windowId) |
37 | 56 | .arg(rect.x()) | 76 | .arg(rect.x()) |
38 | 57 | .arg(rect.y()) | 77 | .arg(rect.y()) |
39 | 58 | .arg(rect.width()) | 78 | .arg(rect.width()) |
40 | 59 | .arg(rect.height()); | 79 | .arg(rect.height()); |
41 | 60 | 80 | ||
51 | 61 | QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString); | 81 | saveValue(queryString); |
43 | 62 | m_asyncQueries.append(future); | ||
44 | 63 | |||
45 | 64 | QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>(); | ||
46 | 65 | futureWatcher->setFuture(future); | ||
47 | 66 | connect(futureWatcher, &QFutureWatcher<void>::finished, | ||
48 | 67 | this, | ||
49 | 68 | [=](){ m_asyncQueries.removeAll(futureWatcher->future()); | ||
50 | 69 | futureWatcher->deleteLater(); }); | ||
52 | 70 | } | 82 | } |
53 | 71 | 83 | ||
54 | 72 | void WindowStateStorage::executeAsyncQuery(const QString &queryString) | 84 | void WindowStateStorage::executeAsyncQuery(const QString &queryString) |
55 | @@ -82,20 +94,13 @@ | |||
56 | 82 | } | 94 | } |
57 | 83 | } | 95 | } |
58 | 84 | 96 | ||
60 | 85 | QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue) | 97 | QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue) const |
61 | 86 | { | 98 | { |
62 | 87 | QMutexLocker l(&s_mutex); | ||
63 | 88 | QString queryString = QStringLiteral("SELECT * FROM geometry WHERE windowId = '%1';") | 99 | QString queryString = QStringLiteral("SELECT * FROM geometry WHERE windowId = '%1';") |
64 | 89 | .arg(windowId); | 100 | .arg(windowId); |
74 | 90 | QSqlQuery query; | 101 | |
75 | 91 | 102 | QSqlQuery query = getValue(queryString); | |
76 | 92 | bool ok = query.exec(queryString); | 103 | |
68 | 93 | if (!ok) { | ||
69 | 94 | qWarning() << "Error retrieving window state for" << windowId | ||
70 | 95 | << "Driver error:" << query.lastError().driverText() | ||
71 | 96 | << "Database error:" << query.lastError().databaseText(); | ||
72 | 97 | return defaultValue; | ||
73 | 98 | } | ||
77 | 99 | if (!query.first()) { | 104 | if (!query.first()) { |
78 | 100 | return defaultValue; | 105 | return defaultValue; |
79 | 101 | } | 106 | } |
80 | @@ -114,4 +119,38 @@ | |||
81 | 114 | QSqlQuery query; | 119 | QSqlQuery query; |
82 | 115 | query.exec(QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);")); | 120 | query.exec(QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);")); |
83 | 116 | } | 121 | } |
84 | 122 | |||
85 | 123 | if (!m_db.tables().contains("state")) { | ||
86 | 124 | QSqlQuery query; | ||
87 | 125 | query.exec("CREATE TABLE state(windowId TEXT UNIQUE, state INTEGER);"); | ||
88 | 126 | } | ||
89 | 127 | } | ||
90 | 128 | |||
91 | 129 | void WindowStateStorage::saveValue(const QString &queryString) | ||
92 | 130 | { | ||
93 | 131 | QMutexLocker mutexLocker(&s_mutex); | ||
94 | 132 | |||
95 | 133 | QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString); | ||
96 | 134 | m_asyncQueries.append(future); | ||
97 | 135 | |||
98 | 136 | QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>(); | ||
99 | 137 | futureWatcher->setFuture(future); | ||
100 | 138 | connect(futureWatcher, &QFutureWatcher<void>::finished, | ||
101 | 139 | this, | ||
102 | 140 | [=](){ m_asyncQueries.removeAll(futureWatcher->future()); | ||
103 | 141 | futureWatcher->deleteLater(); }); | ||
104 | 142 | } | ||
105 | 143 | |||
106 | 144 | QSqlQuery WindowStateStorage::getValue(const QString &queryString) const | ||
107 | 145 | { | ||
108 | 146 | QMutexLocker l(&s_mutex); | ||
109 | 147 | QSqlQuery query; | ||
110 | 148 | |||
111 | 149 | bool ok = query.exec(queryString); | ||
112 | 150 | if (!ok) { | ||
113 | 151 | qWarning() << "Error retrieving database query:" << queryString | ||
114 | 152 | << "Driver error:" << query.lastError().driverText() | ||
115 | 153 | << "Database error:" << query.lastError().databaseText(); | ||
116 | 154 | } | ||
117 | 155 | return query; | ||
118 | 117 | } | 156 | } |
119 | 118 | 157 | ||
120 | === modified file 'plugins/Utils/windowstatestorage.h' | |||
121 | --- plugins/Utils/windowstatestorage.h 2015-03-13 19:01:32 +0000 | |||
122 | +++ plugins/Utils/windowstatestorage.h 2015-10-26 13:53:58 +0000 | |||
123 | @@ -22,16 +22,28 @@ | |||
124 | 22 | class WindowStateStorage: public QObject | 22 | class WindowStateStorage: public QObject |
125 | 23 | { | 23 | { |
126 | 24 | Q_OBJECT | 24 | Q_OBJECT |
127 | 25 | Q_ENUMS(WindowState) | ||
128 | 25 | public: | 26 | public: |
129 | 27 | enum WindowState { | ||
130 | 28 | WindowStateNormal, | ||
131 | 29 | WindowStateMaximized | ||
132 | 30 | }; | ||
133 | 31 | |||
134 | 26 | WindowStateStorage(QObject *parent = 0); | 32 | WindowStateStorage(QObject *parent = 0); |
135 | 27 | virtual ~WindowStateStorage(); | 33 | virtual ~WindowStateStorage(); |
136 | 28 | 34 | ||
137 | 35 | Q_INVOKABLE void saveState(const QString &windowId, WindowState state); | ||
138 | 36 | Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue) const; | ||
139 | 37 | |||
140 | 29 | Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect); | 38 | Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect); |
142 | 30 | Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue); | 39 | Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue) const; |
143 | 31 | 40 | ||
144 | 32 | private: | 41 | private: |
145 | 33 | void initdb(); | 42 | void initdb(); |
146 | 34 | 43 | ||
147 | 44 | void saveValue(const QString &queryString); | ||
148 | 45 | QSqlQuery getValue(const QString &queryString) const; | ||
149 | 46 | |||
150 | 35 | static void executeAsyncQuery(const QString &queryString); | 47 | static void executeAsyncQuery(const QString &queryString); |
151 | 36 | static QMutex s_mutex; | 48 | static QMutex s_mutex; |
152 | 37 | 49 | ||
153 | 38 | 50 | ||
154 | === modified file 'qml/Components/WindowControlButtons.qml' | |||
155 | --- qml/Components/WindowControlButtons.qml 2014-11-24 11:21:38 +0000 | |||
156 | +++ qml/Components/WindowControlButtons.qml 2015-10-26 13:53:58 +0000 | |||
157 | @@ -28,6 +28,7 @@ | |||
158 | 28 | signal maximize() | 28 | signal maximize() |
159 | 29 | 29 | ||
160 | 30 | Rectangle { | 30 | Rectangle { |
161 | 31 | objectName: "closeWindowButton" | ||
162 | 31 | height: parent.height; width: height; radius: height / 2 | 32 | height: parent.height; width: height; radius: height / 2 |
163 | 32 | gradient: Gradient { | 33 | gradient: Gradient { |
164 | 33 | GradientStop { color: "#F49073"; position: 0 } | 34 | GradientStop { color: "#F49073"; position: 0 } |
165 | @@ -38,6 +39,7 @@ | |||
166 | 38 | MouseArea { anchors.fill: parent; onClicked: root.close() } | 39 | MouseArea { anchors.fill: parent; onClicked: root.close() } |
167 | 39 | } | 40 | } |
168 | 40 | Rectangle { | 41 | Rectangle { |
169 | 42 | objectName: "minimizeWindowButton" | ||
170 | 41 | height: parent.height; width: height; radius: height / 2 | 43 | height: parent.height; width: height; radius: height / 2 |
171 | 42 | gradient: Gradient { | 44 | gradient: Gradient { |
172 | 43 | GradientStop { color: "#92918C"; position: 0 } | 45 | GradientStop { color: "#92918C"; position: 0 } |
173 | @@ -48,6 +50,7 @@ | |||
174 | 48 | MouseArea { anchors.fill: parent; onClicked: root.minimize() } | 50 | MouseArea { anchors.fill: parent; onClicked: root.minimize() } |
175 | 49 | } | 51 | } |
176 | 50 | Rectangle { | 52 | Rectangle { |
177 | 53 | objectName: "maximizeWindowButton" | ||
178 | 51 | height: parent.height; width: height; radius: height / 2 | 54 | height: parent.height; width: height; radius: height / 2 |
179 | 52 | gradient: Gradient { | 55 | gradient: Gradient { |
180 | 53 | GradientStop { color: "#92918C"; position: 0 } | 56 | GradientStop { color: "#92918C"; position: 0 } |
181 | 54 | 57 | ||
182 | === modified file 'qml/Panel/Panel.qml' | |||
183 | --- qml/Panel/Panel.qml 2015-09-29 12:48:46 +0000 | |||
184 | +++ qml/Panel/Panel.qml 2015-10-26 13:53:58 +0000 | |||
185 | @@ -28,6 +28,7 @@ | |||
186 | 28 | property alias callHint: __callHint | 28 | property alias callHint: __callHint |
187 | 29 | property bool fullscreenMode: false | 29 | property bool fullscreenMode: false |
188 | 30 | property real indicatorAreaShowProgress: 1.0 | 30 | property real indicatorAreaShowProgress: 1.0 |
189 | 31 | property bool locked: false | ||
190 | 31 | 32 | ||
191 | 32 | opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0 | 33 | opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0 |
192 | 33 | 34 | ||
193 | @@ -136,7 +137,7 @@ | |||
194 | 136 | } | 137 | } |
195 | 137 | 138 | ||
196 | 138 | shown: false | 139 | shown: false |
198 | 139 | width: root.width - (PanelState.buttonsVisible ? windowControlButtons.width : 0) | 140 | width: root.width - (windowControlButtons.visible ? windowControlButtons.width : 0) |
199 | 140 | minimizedPanelHeight: units.gu(3) | 141 | minimizedPanelHeight: units.gu(3) |
200 | 141 | expandedPanelHeight: units.gu(7) | 142 | expandedPanelHeight: units.gu(7) |
201 | 142 | openedHeight: root.height - indicatorOrangeLine.height | 143 | openedHeight: root.height - indicatorOrangeLine.height |
202 | @@ -164,13 +165,14 @@ | |||
203 | 164 | 165 | ||
204 | 165 | WindowControlButtons { | 166 | WindowControlButtons { |
205 | 166 | id: windowControlButtons | 167 | id: windowControlButtons |
206 | 168 | objectName: "panelWindowControlButtons" | ||
207 | 167 | anchors { | 169 | anchors { |
208 | 168 | left: parent.left | 170 | left: parent.left |
209 | 169 | top: parent.top | 171 | top: parent.top |
210 | 170 | margins: units.gu(0.7) | 172 | margins: units.gu(0.7) |
211 | 171 | } | 173 | } |
212 | 172 | height: indicators.minimizedPanelHeight - anchors.margins * 2 | 174 | height: indicators.minimizedPanelHeight - anchors.margins * 2 |
214 | 173 | visible: PanelState.buttonsVisible | 175 | visible: PanelState.buttonsVisible && !root.locked |
215 | 174 | onClose: PanelState.close() | 176 | onClose: PanelState.close() |
216 | 175 | onMinimize: PanelState.minimize() | 177 | onMinimize: PanelState.minimize() |
217 | 176 | onMaximize: PanelState.maximize() | 178 | onMaximize: PanelState.maximize() |
218 | @@ -189,7 +191,7 @@ | |||
219 | 189 | id: __callHint | 191 | id: __callHint |
220 | 190 | anchors { | 192 | anchors { |
221 | 191 | top: parent.top | 193 | top: parent.top |
223 | 192 | left: PanelState.buttonsVisible ? windowControlButtons.right : parent.left | 194 | left: windowControlButtons.visible ? windowControlButtons.right : parent.left |
224 | 193 | } | 195 | } |
225 | 194 | height: indicators.minimizedPanelHeight | 196 | height: indicators.minimizedPanelHeight |
226 | 195 | visible: active && indicators.state == "initial" | 197 | visible: active && indicators.state == "initial" |
227 | 196 | 198 | ||
228 | === modified file 'qml/Shell.qml' | |||
229 | --- qml/Shell.qml 2015-10-16 17:11:54 +0000 | |||
230 | +++ qml/Shell.qml 2015-10-26 13:53:58 +0000 | |||
231 | @@ -57,6 +57,7 @@ | |||
232 | 57 | property bool beingResized | 57 | property bool beingResized |
233 | 58 | property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop" | 58 | property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop" |
234 | 59 | property string mode: "full-greeter" | 59 | property string mode: "full-greeter" |
235 | 60 | property bool cursorVisible: false | ||
236 | 60 | function updateFocusedAppOrientation() { | 61 | function updateFocusedAppOrientation() { |
237 | 61 | applicationsDisplayLoader.item.updateFocusedAppOrientation(); | 62 | applicationsDisplayLoader.item.updateFocusedAppOrientation(); |
238 | 62 | } | 63 | } |
239 | @@ -536,6 +537,7 @@ | |||
240 | 536 | 537 | ||
241 | 537 | fullscreenMode: (topmostApplicationIsFullscreen && !lightDM.greeter.active && launcher.progress == 0) | 538 | fullscreenMode: (topmostApplicationIsFullscreen && !lightDM.greeter.active && launcher.progress == 0) |
242 | 538 | || greeter.hasLockedApp | 539 | || greeter.hasLockedApp |
243 | 540 | locked: greeter && greeter.active | ||
244 | 539 | } | 541 | } |
245 | 540 | 542 | ||
246 | 541 | Launcher { | 543 | Launcher { |
247 | 542 | 544 | ||
248 | === modified file 'qml/Stages/DesktopSpreadDelegate.qml' | |||
249 | --- qml/Stages/DesktopSpreadDelegate.qml 2015-09-18 11:03:48 +0000 | |||
250 | +++ qml/Stages/DesktopSpreadDelegate.qml 2015-10-26 13:53:58 +0000 | |||
251 | @@ -29,8 +29,8 @@ | |||
252 | 29 | property bool highlightShown: false | 29 | property bool highlightShown: false |
253 | 30 | property real shadowOpacity: 1 | 30 | property real shadowOpacity: 1 |
254 | 31 | 31 | ||
257 | 32 | property int windowWidth: application.session && application.session.surface ? application.session.surface.size.width : 0 | 32 | property int windowWidth: application && application.session && application.session.surface ? application.session.surface.size.width : 0 |
258 | 33 | property int windowHeight: application.session && application.session.surface ? application.session.surface.size.height : 0 | 33 | property int windowHeight: application && application.session && application.session.surface ? application.session.surface.size.height : 0 |
259 | 34 | 34 | ||
260 | 35 | state: "normal" | 35 | state: "normal" |
261 | 36 | states: [ | 36 | states: [ |
262 | 37 | 37 | ||
263 | === modified file 'qml/Stages/DesktopStage.qml' | |||
264 | --- qml/Stages/DesktopStage.qml 2015-10-19 14:27:57 +0000 | |||
265 | +++ qml/Stages/DesktopStage.qml 2015-10-26 13:53:58 +0000 | |||
266 | @@ -24,6 +24,7 @@ | |||
267 | 24 | import "../Components/PanelState" | 24 | import "../Components/PanelState" |
268 | 25 | import Utils 0.1 | 25 | import Utils 0.1 |
269 | 26 | import Ubuntu.Gestures 0.1 | 26 | import Ubuntu.Gestures 0.1 |
270 | 27 | import GlobalShortcut 1.0 | ||
271 | 27 | 28 | ||
272 | 28 | Rectangle { | 29 | Rectangle { |
273 | 29 | id: root | 30 | id: root |
274 | @@ -63,7 +64,15 @@ | |||
275 | 63 | spread.state = ""; | 64 | spread.state = ""; |
276 | 64 | } | 65 | } |
277 | 65 | 66 | ||
279 | 66 | ApplicationManager.requestFocusApplication(appId) | 67 | ApplicationManager.focusApplication(appId); |
280 | 68 | } | ||
281 | 69 | |||
282 | 70 | onApplicationRemoved: { | ||
283 | 71 | priv.removeAndFocusPreviousInStack(appId); | ||
284 | 72 | } | ||
285 | 73 | |||
286 | 74 | onFocusedApplicationIdChanged: { | ||
287 | 75 | priv.addToFocusStack(priv.focusedAppId); | ||
288 | 67 | } | 76 | } |
289 | 68 | 77 | ||
290 | 69 | onFocusRequested: { | 78 | onFocusRequested: { |
291 | @@ -78,6 +87,53 @@ | |||
292 | 78 | } | 87 | } |
293 | 79 | } | 88 | } |
294 | 80 | 89 | ||
295 | 90 | GlobalShortcut { | ||
296 | 91 | id: closeWindowShortcut | ||
297 | 92 | shortcut: Qt.AltModifier|Qt.Key_F4 | ||
298 | 93 | onTriggered: ApplicationManager.stopApplication(priv.focusedAppId) | ||
299 | 94 | active: priv.focusedAppId !== "" | ||
300 | 95 | } | ||
301 | 96 | |||
302 | 97 | GlobalShortcut { | ||
303 | 98 | id: showSpreadShortcut | ||
304 | 99 | shortcut: Qt.MetaModifier|Qt.Key_W | ||
305 | 100 | onTriggered: spread.state = "altTab" | ||
306 | 101 | } | ||
307 | 102 | |||
308 | 103 | GlobalShortcut { | ||
309 | 104 | id: minimizeAllShortcut | ||
310 | 105 | shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_D | ||
311 | 106 | onTriggered: priv.minimizeAllWindows() | ||
312 | 107 | } | ||
313 | 108 | |||
314 | 109 | GlobalShortcut { | ||
315 | 110 | id: maximizeWindowShortcut | ||
316 | 111 | shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up | ||
317 | 112 | onTriggered: priv.focusedAppDelegate.minimized ? priv.focusedAppDelegate.restore() : priv.focusedAppDelegate.maximize() | ||
318 | 113 | active: priv.focusedAppDelegate !== null | ||
319 | 114 | } | ||
320 | 115 | |||
321 | 116 | GlobalShortcut { | ||
322 | 117 | id: maximizeWindowLeftShortcut | ||
323 | 118 | shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left | ||
324 | 119 | onTriggered: priv.focusedAppDelegate.maximizeLeft() | ||
325 | 120 | active: priv.focusedAppDelegate !== null | ||
326 | 121 | } | ||
327 | 122 | |||
328 | 123 | GlobalShortcut { | ||
329 | 124 | id: maximizeWindowRightShortcut | ||
330 | 125 | shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right | ||
331 | 126 | onTriggered: priv.focusedAppDelegate.maximizeRight() | ||
332 | 127 | active: priv.focusedAppDelegate !== null | ||
333 | 128 | } | ||
334 | 129 | |||
335 | 130 | GlobalShortcut { | ||
336 | 131 | id: minimizeRestoreShortcut | ||
337 | 132 | shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down | ||
338 | 133 | onTriggered: priv.focusedAppDelegate.maximized ? priv.focusedAppDelegate.restore() : priv.focusedAppDelegate.minimize() | ||
339 | 134 | active: priv.focusedAppDelegate !== null | ||
340 | 135 | } | ||
341 | 136 | |||
342 | 81 | QtObject { | 137 | QtObject { |
343 | 82 | id: priv | 138 | id: priv |
344 | 83 | 139 | ||
345 | @@ -86,6 +142,11 @@ | |||
346 | 86 | var index = indexOf(focusedAppId); | 142 | var index = indexOf(focusedAppId); |
347 | 87 | return index >= 0 && index < appRepeater.count ? appRepeater.itemAt(index) : null | 143 | return index >= 0 && index < appRepeater.count ? appRepeater.itemAt(index) : null |
348 | 88 | } | 144 | } |
349 | 145 | onFocusedAppDelegateChanged: { // restore the window from minimization when we focus it (e.g. using spread) | ||
350 | 146 | if (focusedAppDelegate && focusedAppDelegate.minimized) { | ||
351 | 147 | focusedAppDelegate.restore(); | ||
352 | 148 | } | ||
353 | 149 | } | ||
354 | 89 | 150 | ||
355 | 90 | function indexOf(appId) { | 151 | function indexOf(appId) { |
356 | 91 | for (var i = 0; i < ApplicationManager.count; i++) { | 152 | for (var i = 0; i < ApplicationManager.count; i++) { |
357 | @@ -95,6 +156,45 @@ | |||
358 | 95 | } | 156 | } |
359 | 96 | return -1; | 157 | return -1; |
360 | 97 | } | 158 | } |
361 | 159 | |||
362 | 160 | property var focusStack: [] // focus stack of appIds | ||
363 | 161 | |||
364 | 162 | function addToFocusStack(appId) { | ||
365 | 163 | var oldIndex = focusStack.indexOf(appId); | ||
366 | 164 | if (oldIndex != -1) { | ||
367 | 165 | // remove the old item | ||
368 | 166 | focusStack.splice(oldIndex, 1); | ||
369 | 167 | } | ||
370 | 168 | // insert to the top of the focus stack | ||
371 | 169 | focusStack.unshift(appId); | ||
372 | 170 | } | ||
373 | 171 | |||
374 | 172 | function removeAndFocusPreviousInStack(appId) { | ||
375 | 173 | var removedIndex = focusStack.indexOf(appId); | ||
376 | 174 | if (removedIndex != -1) { | ||
377 | 175 | focusStack.splice(removedIndex, 1); // remove one item from the focus stack | ||
378 | 176 | focusFirstInStack(); // focus the first one | ||
379 | 177 | } | ||
380 | 178 | } | ||
381 | 179 | |||
382 | 180 | function focusFirstInStack() { | ||
383 | 181 | var newHead = focusStack[0]; | ||
384 | 182 | if (newHead !== "") { | ||
385 | 183 | ApplicationManager.focusApplication(newHead); | ||
386 | 184 | } | ||
387 | 185 | } | ||
388 | 186 | |||
389 | 187 | function minimizeAllWindows() { | ||
390 | 188 | focusStack.forEach(function(appId) { | ||
391 | 189 | var appDelegate = appRepeater.itemAt(indexOf(appId)); | ||
392 | 190 | if (appDelegate && !appDelegate.minimized) { | ||
393 | 191 | // we don't want to change the focus to a different window | ||
394 | 192 | appDelegate.minimized = true; | ||
395 | 193 | } | ||
396 | 194 | }); | ||
397 | 195 | ApplicationManager.unfocusCurrentApplication(); // no app should have focus at this point | ||
398 | 196 | focusStack = []; | ||
399 | 197 | } | ||
400 | 98 | } | 198 | } |
401 | 99 | 199 | ||
402 | 100 | Connections { | 200 | Connections { |
403 | @@ -103,14 +203,15 @@ | |||
404 | 103 | ApplicationManager.stopApplication(ApplicationManager.focusedApplicationId) | 203 | ApplicationManager.stopApplication(ApplicationManager.focusedApplicationId) |
405 | 104 | } | 204 | } |
406 | 105 | onMinimize: appRepeater.itemAt(0).minimize(); | 205 | onMinimize: appRepeater.itemAt(0).minimize(); |
408 | 106 | onMaximize: appRepeater.itemAt(0).unmaximize(); | 206 | onMaximize: appRepeater.itemAt(0).restore(); |
409 | 107 | } | 207 | } |
410 | 108 | 208 | ||
411 | 109 | Binding { | 209 | Binding { |
412 | 110 | target: PanelState | 210 | target: PanelState |
413 | 111 | property: "buttonsVisible" | 211 | property: "buttonsVisible" |
415 | 112 | value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.state === "maximized" | 212 | value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized |
416 | 113 | } | 213 | } |
417 | 214 | Component.onDestruction: PanelState.buttonsVisible = false; | ||
418 | 114 | 215 | ||
419 | 115 | FocusScope { | 216 | FocusScope { |
420 | 116 | id: appContainer | 217 | id: appContainer |
421 | @@ -132,18 +233,23 @@ | |||
422 | 132 | 233 | ||
423 | 133 | delegate: FocusScope { | 234 | delegate: FocusScope { |
424 | 134 | id: appDelegate | 235 | id: appDelegate |
425 | 236 | objectName: "appDelegate_" + appId | ||
426 | 135 | z: ApplicationManager.count - index | 237 | z: ApplicationManager.count - index |
427 | 136 | y: units.gu(3) | 238 | y: units.gu(3) |
428 | 137 | width: units.gu(60) | 239 | width: units.gu(60) |
429 | 138 | height: units.gu(50) | 240 | height: units.gu(50) |
431 | 139 | focus: model.appId === priv.focusedAppId | 241 | focus: appId === priv.focusedAppId |
432 | 140 | 242 | ||
433 | 141 | property bool maximized: false | 243 | property bool maximized: false |
434 | 244 | property bool maximizedLeft: false | ||
435 | 245 | property bool maximizedRight: false | ||
436 | 142 | property bool minimized: false | 246 | property bool minimized: false |
437 | 247 | readonly property string appId: model.appId | ||
438 | 248 | property bool animationsEnabled: true | ||
439 | 143 | 249 | ||
440 | 144 | onFocusChanged: { | 250 | onFocusChanged: { |
443 | 145 | if (focus && ApplicationManager.focusedApplicationId !== model.appId) { | 251 | if (focus && ApplicationManager.focusedApplicationId !== appId) { |
444 | 146 | ApplicationManager.focusApplication(model.appId); | 252 | ApplicationManager.focusApplication(appId); |
445 | 147 | } | 253 | } |
446 | 148 | } | 254 | } |
447 | 149 | 255 | ||
448 | @@ -158,36 +264,69 @@ | |||
449 | 158 | value: ApplicationInfoInterface.RequestedRunning // Always running for now | 264 | value: ApplicationInfoInterface.RequestedRunning // Always running for now |
450 | 159 | } | 265 | } |
451 | 160 | 266 | ||
453 | 161 | function maximize() { | 267 | function maximize(animated) { |
454 | 268 | animationsEnabled = (animated === undefined) || animated; | ||
455 | 162 | minimized = false; | 269 | minimized = false; |
456 | 163 | maximized = true; | 270 | maximized = true; |
459 | 164 | } | 271 | maximizedLeft = false; |
460 | 165 | function minimize() { | 272 | maximizedRight = false; |
461 | 273 | } | ||
462 | 274 | function maximizeLeft() { | ||
463 | 275 | minimized = false; | ||
464 | 276 | maximized = false; | ||
465 | 277 | maximizedLeft = true; | ||
466 | 278 | maximizedRight = false; | ||
467 | 279 | } | ||
468 | 280 | function maximizeRight() { | ||
469 | 281 | minimized = false; | ||
470 | 282 | maximized = false; | ||
471 | 283 | maximizedLeft = false; | ||
472 | 284 | maximizedRight = true; | ||
473 | 285 | } | ||
474 | 286 | function minimize(animated) { | ||
475 | 287 | animationsEnabled = (animated === undefined) || animated; | ||
476 | 166 | maximized = false; | 288 | maximized = false; |
477 | 167 | minimized = true; | 289 | minimized = true; |
478 | 290 | maximizedLeft = false; | ||
479 | 291 | maximizedRight = false; | ||
480 | 292 | priv.removeAndFocusPreviousInStack(appId); | ||
481 | 168 | } | 293 | } |
483 | 169 | function unmaximize() { | 294 | function restore(animated) { |
484 | 295 | animationsEnabled = (animated === undefined) || animated; | ||
485 | 170 | minimized = false; | 296 | minimized = false; |
486 | 171 | maximized = false; | 297 | maximized = false; |
487 | 298 | maximizedLeft = false; | ||
488 | 299 | maximizedRight = false; | ||
489 | 300 | priv.addToFocusStack(appId); | ||
490 | 172 | } | 301 | } |
491 | 173 | 302 | ||
492 | 174 | states: [ | 303 | states: [ |
493 | 175 | State { | 304 | State { |
494 | 176 | name: "normal"; when: !appDelegate.maximized && !appDelegate.minimized | 305 | name: "normal"; when: !appDelegate.maximized && !appDelegate.minimized |
495 | 306 | && !appDelegate.maximizedLeft && !appDelegate.maximizedRight | ||
496 | 177 | }, | 307 | }, |
497 | 178 | State { | 308 | State { |
498 | 179 | name: "maximized"; when: appDelegate.maximized | 309 | name: "maximized"; when: appDelegate.maximized |
499 | 180 | PropertyChanges { target: appDelegate; x: 0; y: 0; width: root.width; height: root.height } | 310 | PropertyChanges { target: appDelegate; x: 0; y: 0; width: root.width; height: root.height } |
500 | 181 | }, | 311 | }, |
501 | 182 | State { | 312 | State { |
502 | 313 | name: "maximized_left"; when: appDelegate.maximizedLeft | ||
503 | 314 | PropertyChanges { target: appDelegate; x: 0; y: units.gu(3); width: root.width/2; height: root.height } | ||
504 | 315 | }, | ||
505 | 316 | State { | ||
506 | 317 | name: "maximized_right"; when: appDelegate.maximizedRight | ||
507 | 318 | PropertyChanges { target: appDelegate; x: root.width/2; y: units.gu(3); width: root.width/2; height: root.height } | ||
508 | 319 | }, | ||
509 | 320 | State { | ||
510 | 183 | name: "minimized"; when: appDelegate.minimized | 321 | name: "minimized"; when: appDelegate.minimized |
511 | 184 | PropertyChanges { target: appDelegate; x: -appDelegate.width / 2; scale: units.gu(5) / appDelegate.width; opacity: 0 } | 322 | PropertyChanges { target: appDelegate; x: -appDelegate.width / 2; scale: units.gu(5) / appDelegate.width; opacity: 0 } |
512 | 185 | } | 323 | } |
513 | 186 | ] | 324 | ] |
514 | 187 | transitions: [ | 325 | transitions: [ |
515 | 188 | Transition { | 326 | Transition { |
518 | 189 | from: "maximized,minimized,normal," | 327 | from: "maximized,maximized_left,maximized_right,minimized,normal," |
519 | 190 | to: "maximized,minimized,normal," | 328 | to: "maximized,maximized_left,maximized_right,minimized,normal," |
520 | 329 | enabled: appDelegate.animationsEnabled | ||
521 | 191 | PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" } | 330 | PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" } |
522 | 192 | }, | 331 | }, |
523 | 193 | Transition { | 332 | Transition { |
524 | @@ -234,7 +373,7 @@ | |||
525 | 234 | focus: true | 373 | focus: true |
526 | 235 | 374 | ||
527 | 236 | onClose: ApplicationManager.stopApplication(model.appId) | 375 | onClose: ApplicationManager.stopApplication(model.appId) |
529 | 237 | onMaximize: appDelegate.maximize() | 376 | onMaximize: appDelegate.maximized ? appDelegate.restore() : appDelegate.maximize() |
530 | 238 | onMinimize: appDelegate.minimize() | 377 | onMinimize: appDelegate.minimize() |
531 | 239 | onDecorationPressed: { ApplicationManager.focusApplication(model.appId) } | 378 | onDecorationPressed: { ApplicationManager.focusApplication(model.appId) } |
532 | 240 | } | 379 | } |
533 | 241 | 380 | ||
534 | === modified file 'qml/Stages/WindowDecoration.qml' | |||
535 | --- qml/Stages/WindowDecoration.qml 2015-10-19 19:05:23 +0000 | |||
536 | +++ qml/Stages/WindowDecoration.qml 2015-10-26 13:53:58 +0000 | |||
537 | @@ -45,14 +45,15 @@ | |||
538 | 45 | priv.distanceX = pos.x; | 45 | priv.distanceX = pos.x; |
539 | 46 | priv.distanceY = pos.y; | 46 | priv.distanceY = pos.y; |
540 | 47 | priv.dragging = true; | 47 | priv.dragging = true; |
541 | 48 | Mir.cursorName = "grabbing"; | ||
542 | 49 | } else { | 48 | } else { |
543 | 50 | priv.dragging = false; | 49 | priv.dragging = false; |
544 | 51 | Mir.cursorName = ""; | 50 | Mir.cursorName = ""; |
545 | 52 | } | 51 | } |
546 | 53 | } | 52 | } |
547 | 53 | |||
548 | 54 | onPositionChanged: { | 54 | onPositionChanged: { |
549 | 55 | if (priv.dragging) { | 55 | if (priv.dragging) { |
550 | 56 | Mir.cursorName = "grabbing"; | ||
551 | 56 | var pos = mapToItem(root.target.parent, mouseX, mouseY); | 57 | var pos = mapToItem(root.target.parent, mouseX, mouseY); |
552 | 57 | root.target.x = pos.x - priv.distanceX; | 58 | root.target.x = pos.x - priv.distanceX; |
553 | 58 | root.target.y = pos.y - priv.distanceY; | 59 | root.target.y = pos.y - priv.distanceY; |
554 | 59 | 60 | ||
555 | === modified file 'qml/Stages/WindowResizeArea.qml' | |||
556 | --- qml/Stages/WindowResizeArea.qml 2015-09-29 12:48:46 +0000 | |||
557 | +++ qml/Stages/WindowResizeArea.qml 2015-10-26 13:53:58 +0000 | |||
558 | @@ -36,18 +36,49 @@ | |||
559 | 36 | property int minWidth: 0 | 36 | property int minWidth: 0 |
560 | 37 | property int minHeight: 0 | 37 | property int minHeight: 0 |
561 | 38 | 38 | ||
562 | 39 | QtObject { | ||
563 | 40 | id: priv | ||
564 | 41 | |||
565 | 42 | property int normalX: 0 | ||
566 | 43 | property int normalY: 0 | ||
567 | 44 | property int normalWidth: 0 | ||
568 | 45 | property int normalHeight: 0 | ||
569 | 46 | |||
570 | 47 | function updateNormalGeometry() { | ||
571 | 48 | if (root.target.state == "normal") { | ||
572 | 49 | normalX = root.target.x | ||
573 | 50 | normalY = root.target.y | ||
574 | 51 | normalWidth = root.target.width | ||
575 | 52 | normalHeight = root.target.height | ||
576 | 53 | } | ||
577 | 54 | } | ||
578 | 55 | } | ||
579 | 56 | |||
580 | 57 | Connections { | ||
581 | 58 | target: root.target | ||
582 | 59 | onXChanged: priv.updateNormalGeometry(); | ||
583 | 60 | onYChanged: priv.updateNormalGeometry(); | ||
584 | 61 | onWidthChanged: priv.updateNormalGeometry(); | ||
585 | 62 | onHeightChanged: priv.updateNormalGeometry(); | ||
586 | 63 | } | ||
587 | 64 | |||
588 | 39 | Component.onCompleted: { | 65 | Component.onCompleted: { |
595 | 40 | var windowState = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height)) | 66 | var windowGeometry = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height)) |
596 | 41 | if (windowState !== undefined) { | 67 | if (windowGeometry !== undefined) { |
597 | 42 | target.x = windowState.x | 68 | target.x = windowGeometry.x |
598 | 43 | target.y = windowState.y | 69 | target.y = windowGeometry.y |
599 | 44 | target.width = windowState.width | 70 | target.width = windowGeometry.width |
600 | 45 | target.height = windowState.height | 71 | target.height = windowGeometry.height |
601 | 72 | } | ||
602 | 73 | var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal) | ||
603 | 74 | if (windowState === WindowStateStorage.WindowStateMaximized) { | ||
604 | 75 | target.maximize(false) | ||
605 | 46 | } | 76 | } |
606 | 47 | } | 77 | } |
607 | 48 | 78 | ||
608 | 49 | Component.onDestruction: { | 79 | Component.onDestruction: { |
610 | 50 | windowStateStorage.saveGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height)) | 80 | windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal) |
611 | 81 | windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight)) | ||
612 | 51 | } | 82 | } |
613 | 52 | 83 | ||
614 | 53 | QtObject { | 84 | QtObject { |
615 | 54 | 85 | ||
616 | === modified file 'tests/mocks/Utils/windowstatestorage.cpp' | |||
617 | --- tests/mocks/Utils/windowstatestorage.cpp 2015-08-24 15:39:53 +0000 | |||
618 | +++ tests/mocks/Utils/windowstatestorage.cpp 2015-10-26 13:53:58 +0000 | |||
619 | @@ -44,3 +44,14 @@ | |||
620 | 44 | if (!m_geometry.contains(windowId)) return defaultValue; | 44 | if (!m_geometry.contains(windowId)) return defaultValue; |
621 | 45 | return m_geometry.value(windowId).toRect(); | 45 | return m_geometry.value(windowId).toRect(); |
622 | 46 | } | 46 | } |
623 | 47 | |||
624 | 48 | void WindowStateStorage::saveState(const QString &windowId, WindowState state) | ||
625 | 49 | { | ||
626 | 50 | m_state[windowId] = state; | ||
627 | 51 | } | ||
628 | 52 | |||
629 | 53 | WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue) | ||
630 | 54 | { | ||
631 | 55 | if (!m_state.contains(windowId)) return defaultValue; | ||
632 | 56 | return m_state.value(windowId); | ||
633 | 57 | } | ||
634 | 47 | 58 | ||
635 | === modified file 'tests/mocks/Utils/windowstatestorage.h' | |||
636 | --- tests/mocks/Utils/windowstatestorage.h 2015-08-24 15:39:53 +0000 | |||
637 | +++ tests/mocks/Utils/windowstatestorage.h 2015-10-26 13:53:58 +0000 | |||
638 | @@ -22,9 +22,17 @@ | |||
639 | 22 | { | 22 | { |
640 | 23 | Q_OBJECT | 23 | Q_OBJECT |
641 | 24 | Q_PROPERTY(QVariantMap geometry READ geometry WRITE setGeometry NOTIFY geometryChanged) | 24 | Q_PROPERTY(QVariantMap geometry READ geometry WRITE setGeometry NOTIFY geometryChanged) |
642 | 25 | Q_ENUMS(WindowState) | ||
643 | 25 | public: | 26 | public: |
644 | 27 | enum WindowState { | ||
645 | 28 | WindowStateNormal, | ||
646 | 29 | WindowStateMaximized | ||
647 | 30 | }; | ||
648 | 26 | WindowStateStorage(QObject *parent = 0); | 31 | WindowStateStorage(QObject *parent = 0); |
649 | 27 | 32 | ||
650 | 33 | Q_INVOKABLE void saveState(const QString &windowId, WindowState state); | ||
651 | 34 | Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue); | ||
652 | 35 | |||
653 | 28 | Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect); | 36 | Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect); |
654 | 29 | Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue); | 37 | Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue); |
655 | 30 | 38 | ||
656 | @@ -35,5 +43,6 @@ | |||
657 | 35 | void setGeometry(const QVariantMap& geometry); | 43 | void setGeometry(const QVariantMap& geometry); |
658 | 36 | QVariantMap geometry() const; | 44 | QVariantMap geometry() const; |
659 | 37 | 45 | ||
660 | 46 | QHash<QString, WindowState> m_state; | ||
661 | 38 | QVariantMap m_geometry; | 47 | QVariantMap m_geometry; |
662 | 39 | }; | 48 | }; |
663 | 40 | 49 | ||
664 | === modified file 'tests/qmltests/Stages/tst_DesktopStage.qml' | |||
665 | --- tests/qmltests/Stages/tst_DesktopStage.qml 2015-09-17 12:25:29 +0000 | |||
666 | +++ tests/qmltests/Stages/tst_DesktopStage.qml 2015-10-26 13:53:58 +0000 | |||
667 | @@ -53,14 +53,10 @@ | |||
668 | 53 | 53 | ||
669 | 54 | focus: true | 54 | focus: true |
670 | 55 | 55 | ||
671 | 56 | property bool itemDestroyed: false | ||
672 | 57 | sourceComponent: Component { | 56 | sourceComponent: Component { |
673 | 58 | DesktopStage { | 57 | DesktopStage { |
674 | 59 | color: "darkblue" | 58 | color: "darkblue" |
675 | 60 | anchors.fill: parent | 59 | anchors.fill: parent |
676 | 61 | Component.onDestruction: { | ||
677 | 62 | desktopStageLoader.itemDestroyed = true; | ||
678 | 63 | } | ||
679 | 64 | } | 60 | } |
680 | 65 | } | 61 | } |
681 | 66 | } | 62 | } |
682 | @@ -95,16 +91,10 @@ | |||
683 | 95 | property Item desktopStage: desktopStageLoader.status === Loader.Ready ? desktopStageLoader.item : null | 91 | property Item desktopStage: desktopStageLoader.status === Loader.Ready ? desktopStageLoader.item : null |
684 | 96 | 92 | ||
685 | 97 | function cleanup() { | 93 | function cleanup() { |
686 | 98 | desktopStageLoader.itemDestroyed = false; | ||
687 | 99 | desktopStageLoader.active = false; | 94 | desktopStageLoader.active = false; |
688 | 100 | 95 | ||
689 | 101 | tryCompare(desktopStageLoader, "status", Loader.Null); | 96 | tryCompare(desktopStageLoader, "status", Loader.Null); |
690 | 102 | tryCompare(desktopStageLoader, "item", null); | 97 | tryCompare(desktopStageLoader, "item", null); |
691 | 103 | // Loader.status might be Loader.Null and Loader.item might be null but the Loader | ||
692 | 104 | // actually took place. Likely because Loader waits until the next event loop | ||
693 | 105 | // iteration to do its work. So to ensure the reload, we will wait until the | ||
694 | 106 | // Shell instance gets destroyed. | ||
695 | 107 | tryCompare(desktopStageLoader, "itemDestroyed", true); | ||
696 | 108 | 98 | ||
697 | 109 | killAllRunningApps(); | 99 | killAllRunningApps(); |
698 | 110 | 100 | ||
699 | @@ -117,7 +107,7 @@ | |||
700 | 117 | var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0 | 107 | var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0 |
701 | 118 | ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId); | 108 | ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId); |
702 | 119 | } | 109 | } |
704 | 120 | compare(ApplicationManager.count, 1) | 110 | compare(ApplicationManager.count, 1); |
705 | 121 | } | 111 | } |
706 | 122 | 112 | ||
707 | 123 | function waitUntilAppSurfaceShowsUp(appId) { | 113 | function waitUntilAppSurfaceShowsUp(appId) { |
708 | @@ -147,10 +137,7 @@ | |||
709 | 147 | } | 137 | } |
710 | 148 | 138 | ||
711 | 149 | function test_appFocusSwitch(data) { | 139 | function test_appFocusSwitch(data) { |
716 | 150 | var i; | 140 | data.apps.forEach(startApplication); |
713 | 151 | for (i = 0; i < data.apps.length; i++) { | ||
714 | 152 | startApplication(data.apps[i]); | ||
715 | 153 | } | ||
717 | 154 | 141 | ||
718 | 155 | ApplicationManager.requestFocusApplication(data.apps[data.focusfrom]); | 142 | ApplicationManager.requestFocusApplication(data.apps[data.focusfrom]); |
719 | 156 | tryCompare(ApplicationManager.findApplication(data.apps[data.focusfrom]).session.surface, "activeFocus", true); | 143 | tryCompare(ApplicationManager.findApplication(data.apps[data.focusfrom]).session.surface, "activeFocus", true); |
720 | @@ -167,10 +154,7 @@ | |||
721 | 167 | } | 154 | } |
722 | 168 | 155 | ||
723 | 169 | function test_tappingOnWindowChangesFocusedApp(data) { | 156 | function test_tappingOnWindowChangesFocusedApp(data) { |
728 | 170 | var i; | 157 | data.apps.forEach(startApplication); |
725 | 171 | for (i = 0; i < data.apps.length; i++) { | ||
726 | 172 | startApplication(data.apps[i]); | ||
727 | 173 | } | ||
729 | 174 | var fromAppId = data.apps[data.focusfrom]; | 158 | var fromAppId = data.apps[data.focusfrom]; |
730 | 175 | var toAppId = data.apps[data.focusTo] | 159 | var toAppId = data.apps[data.focusTo] |
731 | 176 | 160 | ||
732 | @@ -187,18 +171,37 @@ | |||
733 | 187 | compare(ApplicationManager.focusedApplicationId, toAppId); | 171 | compare(ApplicationManager.focusedApplicationId, toAppId); |
734 | 188 | } | 172 | } |
735 | 189 | 173 | ||
736 | 174 | function test_clickingOnWindowChangesFocusedApp_data() { | ||
737 | 175 | return test_tappingOnWindowChangesFocusedApp_data(); // reuse test data | ||
738 | 176 | } | ||
739 | 177 | |||
740 | 178 | function test_clickingOnWindowChangesFocusedApp(data) { | ||
741 | 179 | data.apps.forEach(startApplication); | ||
742 | 180 | var fromAppId = data.apps[data.focusfrom]; | ||
743 | 181 | var toAppId = data.apps[data.focusTo] | ||
744 | 182 | |||
745 | 183 | var fromAppWindow = findChild(desktopStage, "appWindow_" + fromAppId); | ||
746 | 184 | verify(fromAppWindow); | ||
747 | 185 | mouseClick(fromAppWindow); | ||
748 | 186 | compare(fromAppWindow.application.session.surface.activeFocus, true); | ||
749 | 187 | compare(ApplicationManager.focusedApplicationId, fromAppId); | ||
750 | 188 | |||
751 | 189 | var toAppWindow = findChild(desktopStage, "appWindow_" + toAppId); | ||
752 | 190 | verify(toAppWindow); | ||
753 | 191 | mouseClick(toAppWindow); | ||
754 | 192 | compare(toAppWindow.application.session.surface.activeFocus, true); | ||
755 | 193 | compare(ApplicationManager.focusedApplicationId, toAppId); | ||
756 | 194 | } | ||
757 | 195 | |||
758 | 190 | function test_tappingOnDecorationFocusesApplication_data() { | 196 | function test_tappingOnDecorationFocusesApplication_data() { |
759 | 191 | return [ | 197 | return [ |
762 | 192 | {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 0, focusTo: 1 }, | 198 | {tag: "dash to dialer", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 0, focusTo: 1 }, |
763 | 193 | {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 1, focusTo: 0 }, | 199 | {tag: "dialer to dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 1, focusTo: 0 }, |
764 | 194 | ] | 200 | ] |
765 | 195 | } | 201 | } |
766 | 196 | 202 | ||
767 | 197 | function test_tappingOnDecorationFocusesApplication(data) { | 203 | function test_tappingOnDecorationFocusesApplication(data) { |
772 | 198 | var i; | 204 | data.apps.forEach(startApplication); |
769 | 199 | for (i = 0; i < data.apps.length; i++) { | ||
770 | 200 | startApplication(data.apps[i]); | ||
771 | 201 | } | ||
773 | 202 | 205 | ||
774 | 203 | var fromAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusfrom]); | 206 | var fromAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusfrom]); |
775 | 204 | verify(fromAppDecoration); | 207 | verify(fromAppDecoration); |
776 | @@ -210,5 +213,97 @@ | |||
777 | 210 | tap(toAppDecoration); | 213 | tap(toAppDecoration); |
778 | 211 | tryCompare(ApplicationManager.findApplication(data.apps[data.focusTo]).session.surface, "activeFocus", true); | 214 | tryCompare(ApplicationManager.findApplication(data.apps[data.focusTo]).session.surface, "activeFocus", true); |
779 | 212 | } | 215 | } |
780 | 216 | |||
781 | 217 | function test_clickingOnDecorationFocusesApplication_data() { | ||
782 | 218 | return test_tappingOnDecorationFocusesApplication_data(); // reuse test data | ||
783 | 219 | } | ||
784 | 220 | |||
785 | 221 | function test_clickingOnDecorationFocusesApplication(data) { | ||
786 | 222 | data.apps.forEach(startApplication); | ||
787 | 223 | |||
788 | 224 | var fromAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusfrom]); | ||
789 | 225 | verify(fromAppDecoration); | ||
790 | 226 | mouseClick(fromAppDecoration); | ||
791 | 227 | tryCompare(ApplicationManager.findApplication(data.apps[data.focusfrom]).session.surface, "activeFocus", true); | ||
792 | 228 | |||
793 | 229 | var toAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusTo]); | ||
794 | 230 | verify(toAppDecoration); | ||
795 | 231 | mouseClick(toAppDecoration); | ||
796 | 232 | tryCompare(ApplicationManager.findApplication(data.apps[data.focusTo]).session.surface, "activeFocus", true); | ||
797 | 233 | } | ||
798 | 234 | |||
799 | 235 | function test_windowMaximize() { | ||
800 | 236 | var apps = ["unity8-dash", "dialer-app", "camera-app"]; | ||
801 | 237 | apps.forEach(startApplication); | ||
802 | 238 | var appName = "dialer-app"; | ||
803 | 239 | var appDelegate = findChild(desktopStage, "appDelegate_" + appName); | ||
804 | 240 | verify(appDelegate); | ||
805 | 241 | ApplicationManager.focusApplication(appName); | ||
806 | 242 | keyClick(Qt.Key_Up, Qt.MetaModifier|Qt.ControlModifier); // Ctrl+Super+Up shortcut to maximize | ||
807 | 243 | tryCompare(appDelegate, "maximized", true); | ||
808 | 244 | tryCompare(appDelegate, "minimized", false); | ||
809 | 245 | } | ||
810 | 246 | |||
811 | 247 | function test_windowMaximizeLeft() { | ||
812 | 248 | var apps = ["unity8-dash", "dialer-app", "camera-app"]; | ||
813 | 249 | apps.forEach(startApplication); | ||
814 | 250 | var appName = "dialer-app"; | ||
815 | 251 | var appDelegate = findChild(desktopStage, "appDelegate_" + appName); | ||
816 | 252 | verify(appDelegate); | ||
817 | 253 | ApplicationManager.focusApplication(appName); | ||
818 | 254 | keyClick(Qt.Key_Left, Qt.MetaModifier|Qt.ControlModifier); // Ctrl+Super+Left shortcut to maximizeLeft | ||
819 | 255 | tryCompare(appDelegate, "maximized", false); | ||
820 | 256 | tryCompare(appDelegate, "minimized", false); | ||
821 | 257 | tryCompare(appDelegate, "maximizedLeft", true); | ||
822 | 258 | tryCompare(appDelegate, "maximizedRight", false); | ||
823 | 259 | } | ||
824 | 260 | |||
825 | 261 | function test_windowMaximizeRight() { | ||
826 | 262 | var apps = ["unity8-dash", "dialer-app", "camera-app"]; | ||
827 | 263 | apps.forEach(startApplication); | ||
828 | 264 | var appName = "dialer-app"; | ||
829 | 265 | var appDelegate = findChild(desktopStage, "appDelegate_" + appName); | ||
830 | 266 | verify(appDelegate); | ||
831 | 267 | ApplicationManager.focusApplication(appName); | ||
832 | 268 | keyClick(Qt.Key_Right, Qt.MetaModifier|Qt.ControlModifier); // Ctrl+Super+Right shortcut to maximizeRight | ||
833 | 269 | tryCompare(appDelegate, "maximized", false); | ||
834 | 270 | tryCompare(appDelegate, "minimized", false); | ||
835 | 271 | tryCompare(appDelegate, "maximizedLeft", false); | ||
836 | 272 | tryCompare(appDelegate, "maximizedRight", true); | ||
837 | 273 | } | ||
838 | 274 | |||
839 | 275 | function test_windowMinimize() { | ||
840 | 276 | var apps = ["unity8-dash", "dialer-app", "camera-app"]; | ||
841 | 277 | apps.forEach(startApplication); | ||
842 | 278 | var appName = "dialer-app"; | ||
843 | 279 | var appDelegate = findChild(desktopStage, "appDelegate_" + appName); | ||
844 | 280 | verify(appDelegate); | ||
845 | 281 | ApplicationManager.focusApplication(appName); | ||
846 | 282 | keyClick(Qt.Key_Down, Qt.MetaModifier|Qt.ControlModifier); // Ctrl+Super+Down shortcut to minimize | ||
847 | 283 | tryCompare(appDelegate, "maximized", false); | ||
848 | 284 | tryCompare(appDelegate, "minimized", true); | ||
849 | 285 | verify(ApplicationManager.focusedApplicationId != ""); // verify we don't lose focus when minimizing an app | ||
850 | 286 | } | ||
851 | 287 | |||
852 | 288 | function test_windowMinimizeAll() { | ||
853 | 289 | var apps = ["unity8-dash", "dialer-app", "camera-app"]; | ||
854 | 290 | apps.forEach(startApplication); | ||
855 | 291 | verify(ApplicationManager.count == 3); | ||
856 | 292 | keyClick(Qt.Key_D, Qt.MetaModifier|Qt.ControlModifier); // Ctrl+Super+D shortcut to minimize all | ||
857 | 293 | tryCompare(ApplicationManager, "focusedApplicationId", ""); // verify no app is focused | ||
858 | 294 | } | ||
859 | 295 | |||
860 | 296 | function test_windowClose() { | ||
861 | 297 | var apps = ["unity8-dash", "dialer-app", "camera-app"]; | ||
862 | 298 | apps.forEach(startApplication); | ||
863 | 299 | verify(ApplicationManager.count == 3); | ||
864 | 300 | var appName = "dialer-app"; | ||
865 | 301 | var appDelegate = findChild(desktopStage, "appDelegate_" + appName); | ||
866 | 302 | verify(appDelegate); | ||
867 | 303 | ApplicationManager.focusApplication(appName); | ||
868 | 304 | keyClick(Qt.Key_F4, Qt.AltModifier); // Alt+F4 shortcut to close | ||
869 | 305 | verify(ApplicationManager.count == 2); // verify the app is gone | ||
870 | 306 | verify(ApplicationManager.findApplication(appName) === null); // and it's not in running apps | ||
871 | 307 | } | ||
872 | 213 | } | 308 | } |
873 | 214 | } | 309 | } |
874 | 215 | 310 | ||
875 | === modified file 'tests/qmltests/Stages/tst_WindowResizeArea.qml' | |||
876 | --- tests/qmltests/Stages/tst_WindowResizeArea.qml 2015-10-08 14:27:12 +0000 | |||
877 | +++ tests/qmltests/Stages/tst_WindowResizeArea.qml 2015-10-26 13:53:58 +0000 | |||
878 | @@ -44,8 +44,11 @@ | |||
879 | 44 | width: units.gu(20) | 44 | width: units.gu(20) |
880 | 45 | property int windowHeight: height | 45 | property int windowHeight: height |
881 | 46 | property int windowWidth: width | 46 | property int windowWidth: width |
884 | 47 | onWindowHeightChanged: height = windowHeight | 47 | state: "normal" |
885 | 48 | onWindowWidthChanged: width = windowWidth | 48 | |
886 | 49 | function maximize() { | ||
887 | 50 | state = "maximized" | ||
888 | 51 | } | ||
889 | 49 | 52 | ||
890 | 50 | WindowResizeArea { | 53 | WindowResizeArea { |
891 | 51 | id: windowResizeArea | 54 | id: windowResizeArea |
892 | @@ -195,5 +198,35 @@ | |||
893 | 195 | tryCompare(fakeWindow, "width", initialWindowWidth); | 198 | tryCompare(fakeWindow, "width", initialWindowWidth); |
894 | 196 | tryCompare(fakeWindow, "height", initialWindowHeight); | 199 | tryCompare(fakeWindow, "height", initialWindowHeight); |
895 | 197 | } | 200 | } |
896 | 201 | |||
897 | 202 | function test_saveRestoreMaximized() { | ||
898 | 203 | var initialWindowX = fakeWindow.x; | ||
899 | 204 | var initialWindowY = fakeWindow.y; | ||
900 | 205 | |||
901 | 206 | var moveDelta = units.gu(5); | ||
902 | 207 | |||
903 | 208 | fakeWindow.x = initialWindowX + moveDelta | ||
904 | 209 | fakeWindow.y = initialWindowY + moveDelta | ||
905 | 210 | |||
906 | 211 | // Now change the state to maximized. The window should not keep updating the stored values | ||
907 | 212 | fakeWindow.state = "maximized" | ||
908 | 213 | fakeWindow.x = 31415 // 0 is too risky to pass the test even when broken | ||
909 | 214 | fakeWindow.y = 31415 | ||
910 | 215 | |||
911 | 216 | // This will destroy the window and recreate it | ||
912 | 217 | windowLoader.active = false; | ||
913 | 218 | waitForRendering(root); | ||
914 | 219 | windowLoader.active = true; | ||
915 | 220 | |||
916 | 221 | // Make sure it's again where we left it in normal state before destroying | ||
917 | 222 | tryCompare(fakeWindow, "x", initialWindowX + moveDelta) | ||
918 | 223 | tryCompare(fakeWindow, "y", initialWindowX + moveDelta) | ||
919 | 224 | |||
920 | 225 | // Make sure maximize() has been called after restoring | ||
921 | 226 | tryCompare(fakeWindow, "state", "maximized") | ||
922 | 227 | |||
923 | 228 | // clean up | ||
924 | 229 | fakeWindow.state = "normal" | ||
925 | 230 | } | ||
926 | 198 | } | 231 | } |
927 | 199 | } | 232 | } |
928 | 200 | 233 | ||
929 | === modified file 'tests/qmltests/tst_Shell.qml' | |||
930 | --- tests/qmltests/tst_Shell.qml 2015-10-20 08:10:03 +0000 | |||
931 | +++ tests/qmltests/tst_Shell.qml 2015-10-26 13:53:58 +0000 | |||
932 | @@ -31,6 +31,7 @@ | |||
933 | 31 | import Wizard 0.1 as Wizard | 31 | import Wizard 0.1 as Wizard |
934 | 32 | 32 | ||
935 | 33 | import "../../qml" | 33 | import "../../qml" |
936 | 34 | import "../../qml/Components/PanelState" | ||
937 | 34 | import "Stages" | 35 | import "Stages" |
938 | 35 | 36 | ||
939 | 36 | Rectangle { | 37 | Rectangle { |
940 | @@ -1707,5 +1708,73 @@ | |||
941 | 1707 | 1708 | ||
942 | 1708 | keyRelease(Qt.Key_Control); | 1709 | keyRelease(Qt.Key_Control); |
943 | 1709 | } | 1710 | } |
944 | 1711 | |||
945 | 1712 | // regression test for http://pad.lv/1443319 | ||
946 | 1713 | function test_closeMaximizedAndRestart() { | ||
947 | 1714 | loadDesktopShellWithApps(); | ||
948 | 1715 | |||
949 | 1716 | var appRepeater = findChild(shell, "appRepeater") | ||
950 | 1717 | var appId = ApplicationManager.get(0).appId; | ||
951 | 1718 | var appDelegate = appRepeater.itemAt(0); | ||
952 | 1719 | var maximizeButton = findChild(appDelegate, "maximizeWindowButton"); | ||
953 | 1720 | |||
954 | 1721 | tryCompare(appDelegate, "state", "normal"); | ||
955 | 1722 | tryCompare(PanelState, "buttonsVisible", false) | ||
956 | 1723 | |||
957 | 1724 | mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2); | ||
958 | 1725 | tryCompare(appDelegate, "state", "maximized"); | ||
959 | 1726 | tryCompare(PanelState, "buttonsVisible", true) | ||
960 | 1727 | |||
961 | 1728 | ApplicationManager.stopApplication(appId); | ||
962 | 1729 | tryCompare(PanelState, "buttonsVisible", false) | ||
963 | 1730 | |||
964 | 1731 | ApplicationManager.startApplication(appId); | ||
965 | 1732 | tryCompare(PanelState, "buttonsVisible", true) | ||
966 | 1733 | } | ||
967 | 1734 | |||
968 | 1735 | // bug http://pad.lv/1431566 | ||
969 | 1736 | function test_switchToStagedHidesPanelButtons() { | ||
970 | 1737 | loadDesktopShellWithApps(); | ||
971 | 1738 | var appRepeater = findChild(shell, "appRepeater") | ||
972 | 1739 | var appId = ApplicationManager.get(0).appId; | ||
973 | 1740 | var appDelegate = appRepeater.itemAt(0); | ||
974 | 1741 | var panelButtons = findChild(shell, "panelWindowControlButtons") | ||
975 | 1742 | |||
976 | 1743 | tryCompare(appDelegate, "state", "normal"); | ||
977 | 1744 | tryCompare(panelButtons, "visible", false); | ||
978 | 1745 | |||
979 | 1746 | appDelegate.maximize(false); | ||
980 | 1747 | tryCompare(panelButtons, "visible", true); | ||
981 | 1748 | |||
982 | 1749 | shell.usageScenario = "phone"; | ||
983 | 1750 | waitForRendering(shell); | ||
984 | 1751 | tryCompare(panelButtons, "visible", false); | ||
985 | 1752 | |||
986 | 1753 | shell.usageScenario = "desktop"; | ||
987 | 1754 | waitForRendering(shell); | ||
988 | 1755 | tryCompare(panelButtons, "visible", true); | ||
989 | 1756 | } | ||
990 | 1757 | |||
991 | 1758 | function test_lockingGreeterHidesPanelButtons() { | ||
992 | 1759 | loadDesktopShellWithApps(); | ||
993 | 1760 | var appRepeater = findChild(shell, "appRepeater") | ||
994 | 1761 | var appId = ApplicationManager.get(0).appId; | ||
995 | 1762 | var appDelegate = appRepeater.itemAt(0); | ||
996 | 1763 | var panelButtons = findChild(shell, "panelWindowControlButtons") | ||
997 | 1764 | |||
998 | 1765 | tryCompare(appDelegate, "state", "normal"); | ||
999 | 1766 | tryCompare(panelButtons, "visible", false); | ||
1000 | 1767 | |||
1001 | 1768 | appDelegate.maximize(false); | ||
1002 | 1769 | tryCompare(panelButtons, "visible", true); | ||
1003 | 1770 | |||
1004 | 1771 | LightDM.Greeter.showGreeter(); | ||
1005 | 1772 | waitForRendering(shell); | ||
1006 | 1773 | tryCompare(panelButtons, "visible", false); | ||
1007 | 1774 | |||
1008 | 1775 | LightDM.Greeter.hideGreeter(); | ||
1009 | 1776 | waitForRendering(shell); | ||
1010 | 1777 | tryCompare(panelButtons, "visible", true); | ||
1011 | 1778 | } | ||
1012 | 1710 | } | 1779 | } |
1013 | 1711 | } | 1780 | } |
Please follow the commit message format as explained here: https:/ /wiki.ubuntu. com/Process/ Merges/ Checklists/ Unity8