Merge lp:~aacid/qtmir/make_sure_surface_not_null into lp:qtmir
- make_sure_surface_not_null
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~aacid/qtmir/make_sure_surface_not_null |
Merge into: | lp:qtmir |
Diff against target: |
1210 lines (+785/-131) 19 files modified
src/modules/Unity/Application/CMakeLists.txt (+0/-2) src/modules/Unity/Application/mirbuffersgtexture.cpp (+4/-17) src/modules/Unity/Application/mirbuffersgtexture.h (+2/-2) src/modules/Unity/Application/mirsurface.cpp (+0/-14) src/modules/Unity/Application/mirsurface.h (+0/-1) src/modules/Unity/Application/sessionmanager.cpp (+4/-0) src/modules/Unity/Application/sessionmanager.h (+3/-2) src/modules/Unity/Application/surfacemanager.cpp (+36/-29) src/modules/Unity/Application/surfacemanager.h (+8/-3) src/platforms/mirserver/CMakeLists.txt (+1/-0) src/platforms/mirserver/mirbuffer.cpp (+70/-0) src/platforms/mirserver/mirbuffer.h (+48/-0) tests/framework/CMakeLists.txt (+2/-0) tests/framework/mock_session_manager.h (+33/-0) tests/framework/mock_window_controller.h (+43/-0) tests/modules/CMakeLists.txt (+2/-1) tests/modules/SurfaceManager/CMakeLists.txt (+40/-0) tests/modules/SurfaceManager/surface_manager_test.cpp (+489/-0) tests/modules/WindowManager/mirsurface_test.cpp (+0/-60) |
To merge this branch: | bzr merge lp:~aacid/qtmir/make_sure_surface_not_null |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity8 CI Bot (community) | continuous-integration | Needs Fixing | |
Daniel d'Andrada (community) | Approve | ||
Review via email: mp+318744@code.launchpad.net |
This proposal has been superseded by a proposal from 2017-03-10.
Commit message
Check for find() result not being null before using it
We do it in onWindowReady, onWindowMoved, onWindowFocusCh
Description of the change
* Are there any related MPs required for this MP to build/function as expected?
No
* Did you perform an exploratory manual test run of your code change and any related functionality?
N/A
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:609
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 613. By Alan Griffiths
-
Simplify and remove dead code
- 614. By Alan Griffiths
-
Put const where "we" like it
- 615. By Alan Griffiths
-
Move const to the left
- 616. By Alan Griffiths
-
merge :parent
- 620. By Gerry Boland
-
Small SurfaceManager Test improvements
- 621. By Gerry Boland
-
Remove tests for the old delete-self behaviour of MirSurface
- 622. By Gerry Boland
-
Stop MirSurface deleting itself, ensure SurfaceManager alone manages MirSurface lifetimes
This fixes bugs where a MirSurface would call deleteLater on itself, but SurfaceManager would have no idea and keep a pointer to that MirSurface in its internal list.
Instead SurfaceManager listens for signals from MirSurface and decides when to delete it.
- 623. By Gerry Boland
-
Cleanup: no need to pass MirSurface out in isBeingDisplaye
dChanged signal - 624. By Gerry Boland
-
Make self-triggered MirSurface deletion happen later, makes code more robust
- 625. By Gerry Boland
-
Remnant of bad rebase, delete SessionManager reference
- 626. By Albert Astals Cid
-
Check for find() result not being null before using it
We do it in onWindowReady, onWindowMoved, onWindowFocusCh
anged, etc so no reason to not do it in onWindowRemoved - 627. By Albert Astals Cid
-
Merge
- 628. By Albert Astals Cid
-
Wrong merge
Unmerged revisions
Preview Diff
1 | === modified file 'src/modules/Unity/Application/CMakeLists.txt' |
2 | --- src/modules/Unity/Application/CMakeLists.txt 2017-02-08 12:19:14 +0000 |
3 | +++ src/modules/Unity/Application/CMakeLists.txt 2017-03-10 12:23:14 +0000 |
4 | @@ -74,8 +74,6 @@ |
5 | # Frig for files that still rely on mirserver-dev |
6 | string(REPLACE ";" " -I" QTMIR_ADD_MIRSERVER "-I ${MIRSERVER_INCLUDE_DIRS}") |
7 | set_source_files_properties(mirsurface.cpp PROPERTIES COMPILE_FLAGS "${CMAKE_CXXFLAGS} ${QTMIR_ADD_MIRSERVER}") |
8 | -set_source_files_properties(mirbuffersgtexture.cpp PROPERTIES COMPILE_FLAGS "${CMAKE_CXXFLAGS} ${QTMIR_ADD_MIRSERVER}") |
9 | -set_source_files_properties(surfacemanager.cpp PROPERTIES COMPILE_FLAGS "${CMAKE_CXXFLAGS} ${QTMIR_ADD_MIRSERVER}") |
10 | |
11 | target_link_libraries( |
12 | unityapplicationplugin |
13 | |
14 | === modified file 'src/modules/Unity/Application/mirbuffersgtexture.cpp' |
15 | --- src/modules/Unity/Application/mirbuffersgtexture.cpp 2015-12-14 09:05:06 +0000 |
16 | +++ src/modules/Unity/Application/mirbuffersgtexture.cpp 2017-03-10 12:23:14 +0000 |
17 | @@ -17,12 +17,9 @@ |
18 | #include "mirbuffersgtexture.h" |
19 | |
20 | // Mir |
21 | -#include <mir/graphics/buffer.h> |
22 | #include <mir/geometry/size.h> |
23 | -#include <mir/renderer/gl/texture_source.h> |
24 | |
25 | namespace mg = mir::geometry; |
26 | -namespace mrg = mir::renderer::gl; |
27 | |
28 | MirBufferSGTexture::MirBufferSGTexture() |
29 | : QSGTexture() |
30 | @@ -54,14 +51,14 @@ |
31 | void MirBufferSGTexture::setBuffer(const std::shared_ptr<mir::graphics::Buffer>& buffer) |
32 | { |
33 | m_mirBuffer = buffer; |
34 | - mg::Size size = buffer->size(); |
35 | + mg::Size size = m_mirBuffer.size(); |
36 | m_height = size.height.as_int(); |
37 | m_width = size.width.as_int(); |
38 | } |
39 | |
40 | bool MirBufferSGTexture::hasBuffer() const |
41 | { |
42 | - return !!m_mirBuffer; |
43 | + return m_mirBuffer.hasBuffer(); |
44 | } |
45 | |
46 | int MirBufferSGTexture::textureId() const |
47 | @@ -76,12 +73,7 @@ |
48 | |
49 | bool MirBufferSGTexture::hasAlphaChannel() const |
50 | { |
51 | - if (hasBuffer()) { |
52 | - return m_mirBuffer->pixel_format() == mir_pixel_format_abgr_8888 |
53 | - || m_mirBuffer->pixel_format() == mir_pixel_format_argb_8888; |
54 | - } else { |
55 | - return false; |
56 | - } |
57 | + return m_mirBuffer.hasAlphaChannel(); |
58 | } |
59 | |
60 | void MirBufferSGTexture::bind() |
61 | @@ -90,10 +82,5 @@ |
62 | glBindTexture(GL_TEXTURE_2D, m_textureId); |
63 | updateBindOptions(true/* force */); |
64 | |
65 | - auto const texture_source = |
66 | - dynamic_cast<mrg::TextureSource*>(m_mirBuffer->native_buffer_base()); |
67 | - if (!texture_source) |
68 | - throw std::logic_error("Buffer does not support GL rendering"); |
69 | - |
70 | - texture_source->gl_bind_to_texture(); |
71 | + m_mirBuffer.glBindToTexture(); |
72 | } |
73 | |
74 | === modified file 'src/modules/Unity/Application/mirbuffersgtexture.h' |
75 | --- src/modules/Unity/Application/mirbuffersgtexture.h 2015-10-28 13:45:07 +0000 |
76 | +++ src/modules/Unity/Application/mirbuffersgtexture.h 2017-03-10 12:23:14 +0000 |
77 | @@ -17,7 +17,7 @@ |
78 | #ifndef MIRBUFFERSGTEXTURE_H |
79 | #define MIRBUFFERSGTEXTURE_H |
80 | |
81 | -#include <memory> |
82 | +#include "mirbuffer.h" |
83 | |
84 | #include <QSGTexture> |
85 | |
86 | @@ -44,7 +44,7 @@ |
87 | void bind() override; |
88 | |
89 | private: |
90 | - std::shared_ptr<mir::graphics::Buffer> m_mirBuffer; |
91 | + qtmir::MirBuffer m_mirBuffer; |
92 | int m_width; |
93 | int m_height; |
94 | GLuint m_textureId; |
95 | |
96 | === modified file 'src/modules/Unity/Application/mirsurface.cpp' |
97 | --- src/modules/Unity/Application/mirsurface.cpp 2017-02-09 11:01:37 +0000 |
98 | +++ src/modules/Unity/Application/mirsurface.cpp 2017-03-10 12:23:14 +0000 |
99 | @@ -169,7 +169,6 @@ |
100 | connect(m_surfaceObserver.get(), &SurfaceObserver::confinesMousePointerChanged, this, &MirSurface::confinesMousePointerChanged); |
101 | m_surfaceObserver->setListener(this); |
102 | |
103 | - //connect(session, &QObject::destroyed, this, &MirSurface::onSessionDestroyed); // TODO try using Shared pointer for lifecycle |
104 | connect(session, &SessionInterface::stateChanged, this, [this]() { |
105 | if (clientIsRunning() && m_pendingResize.isValid()) { |
106 | resize(m_pendingResize.width(), m_pendingResize.height()); |
107 | @@ -585,9 +584,6 @@ |
108 | DEBUG_MSG << "(" << value << ")"; |
109 | m_live = value; |
110 | Q_EMIT liveChanged(value); |
111 | - if (m_views.isEmpty() && !m_live) { |
112 | - deleteLater(); |
113 | - } |
114 | } |
115 | } |
116 | |
117 | @@ -712,9 +708,6 @@ |
118 | DEBUG_MSG << "(" << viewId << ")" << " after=" << m_views.count() << " live=" << m_live; |
119 | if (m_views.count() == 0) { |
120 | Q_EMIT isBeingDisplayedChanged(); |
121 | - if (m_session.isNull() || !m_live) { |
122 | - deleteLater(); |
123 | - } |
124 | } |
125 | updateExposure(); |
126 | setViewActiveFocus(viewId, false); |
127 | @@ -759,13 +752,6 @@ |
128 | return m_currentFrameNumber; |
129 | } |
130 | |
131 | -void MirSurface::onSessionDestroyed() |
132 | -{ |
133 | - if (m_views.isEmpty()) { |
134 | - deleteLater(); |
135 | - } |
136 | -} |
137 | - |
138 | void MirSurface::emitSizeChanged() |
139 | { |
140 | Q_EMIT sizeChanged(m_size); |
141 | |
142 | === modified file 'src/modules/Unity/Application/mirsurface.h' |
143 | --- src/modules/Unity/Application/mirsurface.h 2017-02-02 09:17:48 +0000 |
144 | +++ src/modules/Unity/Application/mirsurface.h 2017-03-10 12:23:14 +0000 |
145 | @@ -188,7 +188,6 @@ |
146 | void dropPendingBuffer(); |
147 | void onAttributeChanged(const MirWindowAttrib, const int); |
148 | void onFramesPostedObserved(); |
149 | - void onSessionDestroyed(); |
150 | void emitSizeChanged(); |
151 | void setCursor(const QCursor &cursor); |
152 | void onCloseTimedOut(); |
153 | |
154 | === modified file 'src/modules/Unity/Application/sessionmanager.cpp' |
155 | --- src/modules/Unity/Application/sessionmanager.cpp 2016-11-03 20:17:46 +0000 |
156 | +++ src/modules/Unity/Application/sessionmanager.cpp 2017-03-10 12:23:14 +0000 |
157 | @@ -90,6 +90,10 @@ |
158 | setObjectName(QStringLiteral("qtmir::SessionManager")); |
159 | } |
160 | |
161 | +SessionManager::SessionManager() // for test use only |
162 | + : m_applicationManager(nullptr) |
163 | +{} |
164 | + |
165 | SessionManager::~SessionManager() |
166 | { |
167 | qCDebug(QTMIR_SESSIONS) << "SessionManager::~SessionManager - this=" << this; |
168 | |
169 | === modified file 'src/modules/Unity/Application/sessionmanager.h' |
170 | --- src/modules/Unity/Application/sessionmanager.h 2016-11-03 20:17:46 +0000 |
171 | +++ src/modules/Unity/Application/sessionmanager.h 2017-03-10 12:23:14 +0000 |
172 | @@ -56,11 +56,11 @@ |
173 | ApplicationManager* applicationManager, |
174 | QObject *parent = 0 |
175 | ); |
176 | - ~SessionManager(); |
177 | + virtual ~SessionManager(); |
178 | |
179 | static SessionManager* singleton(); |
180 | |
181 | - SessionInterface *findSession(const mir::scene::Session* session) const; |
182 | + virtual SessionInterface *findSession(const mir::scene::Session* session) const; |
183 | |
184 | Q_SIGNALS: |
185 | void sessionStarting(SessionInterface* session); |
186 | @@ -76,6 +76,7 @@ |
187 | void onPromptProviderRemoved(const qtmir::PromptSession &promptSession, const std::shared_ptr<mir::scene::Session> &); |
188 | |
189 | protected: |
190 | + SessionManager(); // for test purposes only |
191 | |
192 | private: |
193 | const std::shared_ptr<PromptSessionManager> m_promptSessionManager; |
194 | |
195 | === modified file 'src/modules/Unity/Application/surfacemanager.cpp' |
196 | --- src/modules/Unity/Application/surfacemanager.cpp 2017-02-15 13:21:07 +0000 |
197 | +++ src/modules/Unity/Application/surfacemanager.cpp 2017-03-10 12:23:14 +0000 |
198 | @@ -27,9 +27,6 @@ |
199 | #include <debughelpers.h> |
200 | #include <mirqtconversion.h> |
201 | |
202 | -// Mir |
203 | -#include <mir/scene/surface.h> |
204 | - |
205 | // Qt |
206 | #include <QGuiApplication> |
207 | |
208 | @@ -41,7 +38,8 @@ |
209 | using namespace qtmir; |
210 | namespace unityapi = unity::shell::application; |
211 | |
212 | -SurfaceManager::SurfaceManager(QObject *) |
213 | + |
214 | +SurfaceManager::SurfaceManager() |
215 | { |
216 | DEBUG_MSG << "()"; |
217 | |
218 | @@ -59,6 +57,16 @@ |
219 | m_sessionManager = SessionManager::singleton(); |
220 | } |
221 | |
222 | +SurfaceManager::SurfaceManager(WindowControllerInterface *windowController, |
223 | + WindowModelNotifier *windowModel, |
224 | + SessionManager *sessionManager) |
225 | + : m_windowController(windowController) |
226 | + , m_sessionManager(sessionManager) |
227 | +{ |
228 | + DEBUG_MSG << "()"; |
229 | + connectToWindowModelNotifier(windowModel); |
230 | +} |
231 | + |
232 | void SurfaceManager::connectToWindowModelNotifier(WindowModelNotifier *notifier) |
233 | { |
234 | connect(notifier, &WindowModelNotifier::windowAdded, this, &SurfaceManager::onWindowAdded, Qt::QueuedConnection); |
235 | @@ -90,27 +98,32 @@ |
236 | |
237 | void SurfaceManager::onWindowAdded(const NewWindow &window) |
238 | { |
239 | + const auto &windowInfo = window.windowInfo; |
240 | { |
241 | - std::shared_ptr<mir::scene::Surface> surface = window.surface; |
242 | - DEBUG_MSG << " mir::scene::Surface[type=" << mirSurfaceTypeToStr(surface->type()) |
243 | - << ",parent=" << (void*)(surface->parent().get()) |
244 | - << ",state=" << mirSurfaceStateToStr(surface->state()) |
245 | - << ",top_left=" << toQPoint(surface->top_left()) |
246 | + DEBUG_MSG << " mir::scene::Surface[type=" << mirSurfaceTypeToStr(windowInfo.type()) |
247 | + << ",parent=" << (void*)(std::shared_ptr<mir::scene::Surface>{windowInfo.parent()}.get()) |
248 | + << ",state=" << mirSurfaceStateToStr(windowInfo.state()) |
249 | + << ",top_left=" << toQPoint(windowInfo.window().top_left()) |
250 | << "]"; |
251 | } |
252 | |
253 | - auto mirSession = window.windowInfo.window().application(); |
254 | + auto mirSession = windowInfo.window().application(); |
255 | + |
256 | SessionInterface* session = m_sessionManager->findSession(mirSession.get()); |
257 | |
258 | - MirSurface *parentSurface; |
259 | - { |
260 | - std::shared_ptr<mir::scene::Surface> surface = window.windowInfo.window(); |
261 | - parentSurface = find(surface->parent()); |
262 | - } |
263 | - |
264 | - auto surface = new MirSurface(window, m_windowController, session, parentSurface); |
265 | + const auto parentSurface = find(windowInfo.parent()); |
266 | + const auto surface = new MirSurface(window, m_windowController, session, parentSurface); |
267 | rememberMirSurface(surface); |
268 | |
269 | + connect(surface, &MirSurface::isBeingDisplayedChanged, this, [this, surface]() { |
270 | + if ((!surface->live() || !surface->session()) |
271 | + && !surface->isBeingDisplayed()) { |
272 | + forgetMirSurface(static_cast<MirSurface*>(surface)->window()); |
273 | + surface->deleteLater(); // don't delete immediately, slot may be directly connected |
274 | + tracepoint(qtmir, surfaceDestroyed); |
275 | + } |
276 | + }); |
277 | + |
278 | if (parentSurface) { |
279 | static_cast<MirSurfaceListModel*>(parentSurface->childSurfaceList())->prependSurface(surface); |
280 | } |
281 | @@ -126,8 +139,12 @@ |
282 | { |
283 | MirSurface *surface = find(windowInfo); |
284 | forgetMirSurface(windowInfo.window()); |
285 | - surface->setLive(false); |
286 | - tracepoint(qtmir, surfaceDestroyed); |
287 | + if (surface && surface->isBeingDisplayed()) { |
288 | + surface->setLive(false); |
289 | + } else { |
290 | + delete surface; |
291 | + tracepoint(qtmir, surfaceDestroyed); |
292 | + } |
293 | } |
294 | |
295 | MirSurface *SurfaceManager::find(const miral::WindowInfo &needle) const |
296 | @@ -145,16 +162,6 @@ |
297 | return nullptr; |
298 | } |
299 | |
300 | -MirSurface *SurfaceManager::find(const std::shared_ptr<mir::scene::Surface> &needle) const |
301 | -{ |
302 | - Q_FOREACH(const auto surface, m_allSurfaces) { |
303 | - if (surface->window() == needle) { |
304 | - return surface; |
305 | - } |
306 | - } |
307 | - return nullptr; |
308 | -} |
309 | - |
310 | void SurfaceManager::onWindowReady(const miral::WindowInfo &windowInfo) |
311 | { |
312 | if (auto mirSurface = find(windowInfo)) { |
313 | |
314 | === modified file 'src/modules/Unity/Application/surfacemanager.h' |
315 | --- src/modules/Unity/Application/surfacemanager.h 2017-02-02 09:17:48 +0000 |
316 | +++ src/modules/Unity/Application/surfacemanager.h 2017-03-10 12:23:14 +0000 |
317 | @@ -39,12 +39,19 @@ |
318 | Q_OBJECT |
319 | |
320 | public: |
321 | - explicit SurfaceManager(QObject *parent = 0); |
322 | + explicit SurfaceManager(); |
323 | virtual ~SurfaceManager() {} |
324 | |
325 | void raise(unity::shell::application::MirSurfaceInterface *surface) override; |
326 | void activate(unity::shell::application::MirSurfaceInterface *surface) override; |
327 | |
328 | +protected: |
329 | + // for testing purposes |
330 | + SurfaceManager(WindowControllerInterface *windowController, |
331 | + WindowModelNotifier *windowModel, |
332 | + SessionManager *sessionManager); |
333 | + MirSurface* find(const miral::WindowInfo &needle) const; |
334 | + |
335 | private Q_SLOTS: |
336 | void onWindowAdded(const qtmir::NewWindow &windowInfo); |
337 | void onWindowRemoved(const miral::WindowInfo &windowInfo); |
338 | @@ -59,9 +66,7 @@ |
339 | void connectToWindowModelNotifier(WindowModelNotifier *notifier); |
340 | void rememberMirSurface(MirSurface *surface); |
341 | void forgetMirSurface(const miral::Window &window); |
342 | - MirSurface* find(const miral::WindowInfo &needle) const; |
343 | MirSurface* find(const miral::Window &needle) const; |
344 | - MirSurface* find(const std::shared_ptr<mir::scene::Surface> &needle) const; |
345 | |
346 | QVector<MirSurface*> m_allSurfaces; |
347 | |
348 | |
349 | === modified file 'src/platforms/mirserver/CMakeLists.txt' |
350 | --- src/platforms/mirserver/CMakeLists.txt 2017-02-15 13:21:50 +0000 |
351 | +++ src/platforms/mirserver/CMakeLists.txt 2017-03-10 12:23:14 +0000 |
352 | @@ -88,6 +88,7 @@ |
353 | setqtcompositor.cpp setqtcompositor.h |
354 | eventdispatch.cpp eventdispatch.h |
355 | promptsessionmanager.cpp promptsessionmanager.h promptsession.h |
356 | + mirbuffer.cpp mirbuffer.h |
357 | ) |
358 | |
359 | # These files get entangled by automoc so they need to go together. And some depend on mirserver-dev |
360 | |
361 | === added file 'src/platforms/mirserver/mirbuffer.cpp' |
362 | --- src/platforms/mirserver/mirbuffer.cpp 1970-01-01 00:00:00 +0000 |
363 | +++ src/platforms/mirserver/mirbuffer.cpp 2017-03-10 12:23:14 +0000 |
364 | @@ -0,0 +1,70 @@ |
365 | +/* |
366 | + * Copyright © 2017 Canonical Ltd. |
367 | + * |
368 | + * This program is free software: you can redistribute it and/or modify it |
369 | + * under the terms of the GNU General Public License version 3, |
370 | + * as published by the Free Software Foundation. |
371 | + * |
372 | + * This program is distributed in the hope that it will be useful, |
373 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
374 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
375 | + * GNU General Public License for more details. |
376 | + * |
377 | + * You should have received a copy of the GNU General Public License |
378 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
379 | + */ |
380 | + |
381 | +#include "mirbuffer.h" |
382 | + |
383 | +#include <mir/graphics/buffer.h> |
384 | +#include <mir/renderer/gl/texture_source.h> |
385 | + |
386 | +#include <stdexcept> |
387 | + |
388 | +qtmir::MirBuffer::MirBuffer() = default; |
389 | +qtmir::MirBuffer::~MirBuffer() = default; |
390 | +qtmir::MirBuffer::MirBuffer(std::shared_ptr<mir::graphics::Buffer> const &buffer) : |
391 | + m_mirBuffer(buffer) |
392 | +{ |
393 | +} |
394 | + |
395 | +qtmir::MirBuffer& qtmir::MirBuffer::operator=(std::shared_ptr<mir::graphics::Buffer> const &buffer) |
396 | +{ |
397 | + m_mirBuffer = buffer; |
398 | + return *this; |
399 | +} |
400 | + |
401 | +bool qtmir::MirBuffer::hasBuffer() const |
402 | +{ |
403 | + return !!m_mirBuffer; |
404 | +} |
405 | + |
406 | +bool qtmir::MirBuffer::hasAlphaChannel() const |
407 | +{ |
408 | + return hasBuffer() && |
409 | + (m_mirBuffer->pixel_format() == mir_pixel_format_abgr_8888 |
410 | + || m_mirBuffer->pixel_format() == mir_pixel_format_argb_8888); |
411 | +} |
412 | + |
413 | +mir::geometry::Size qtmir::MirBuffer::size() const |
414 | +{ |
415 | + return m_mirBuffer->size(); |
416 | +} |
417 | + |
418 | +void qtmir::MirBuffer::reset() |
419 | +{ |
420 | + m_mirBuffer.reset(); |
421 | +} |
422 | + |
423 | +void qtmir::MirBuffer::glBindToTexture() |
424 | +{ |
425 | + namespace mrg = mir::renderer::gl; |
426 | + |
427 | + auto const texture_source = |
428 | + dynamic_cast<mrg::TextureSource*>(m_mirBuffer->native_buffer_base()); |
429 | + if (!texture_source) |
430 | + throw std::logic_error("Buffer does not support GL rendering"); |
431 | + |
432 | + texture_source->gl_bind_to_texture(); |
433 | +} |
434 | + |
435 | |
436 | === added file 'src/platforms/mirserver/mirbuffer.h' |
437 | --- src/platforms/mirserver/mirbuffer.h 1970-01-01 00:00:00 +0000 |
438 | +++ src/platforms/mirserver/mirbuffer.h 2017-03-10 12:23:14 +0000 |
439 | @@ -0,0 +1,48 @@ |
440 | +/* |
441 | + * Copyright © 2017 Canonical Ltd. |
442 | + * |
443 | + * This program is free software: you can redistribute it and/or modify it |
444 | + * under the terms of the GNU General Public License version 3, |
445 | + * as published by the Free Software Foundation. |
446 | + * |
447 | + * This program is distributed in the hope that it will be useful, |
448 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
449 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
450 | + * GNU General Public License for more details. |
451 | + * |
452 | + * You should have received a copy of the GNU General Public License |
453 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
454 | + */ |
455 | + |
456 | +#ifndef QTMIR_MIR_BUFFER_H |
457 | +#define QTMIR_MIR_BUFFER_H |
458 | + |
459 | +#include <mir/geometry/size.h> |
460 | + |
461 | +#include <memory> |
462 | + |
463 | +namespace mir { namespace graphics { class Buffer; }} |
464 | + |
465 | +namespace qtmir |
466 | +{ |
467 | +class MirBuffer |
468 | +{ |
469 | +public: |
470 | + MirBuffer(); |
471 | + ~MirBuffer(); |
472 | + explicit MirBuffer(std::shared_ptr<mir::graphics::Buffer> const &buffer); |
473 | + MirBuffer& operator=(std::shared_ptr<mir::graphics::Buffer> const &buffer); |
474 | + |
475 | + bool hasBuffer() const; |
476 | + bool hasAlphaChannel() const; |
477 | + mir::geometry::Size size() const; |
478 | + |
479 | + void reset(); |
480 | + void glBindToTexture(); |
481 | + |
482 | +private: |
483 | + std::shared_ptr<mir::graphics::Buffer> m_mirBuffer; |
484 | +}; |
485 | +} |
486 | + |
487 | +#endif //QTMIR_MIR_BUFFER_H |
488 | |
489 | === modified file 'tests/framework/CMakeLists.txt' |
490 | --- tests/framework/CMakeLists.txt 2016-12-02 16:22:45 +0000 |
491 | +++ tests/framework/CMakeLists.txt 2017-03-10 12:23:14 +0000 |
492 | @@ -46,6 +46,8 @@ |
493 | target_link_libraries( |
494 | qtmir-test-framework-static |
495 | |
496 | + unityapplicationplugin |
497 | + |
498 | ${GTEST_BOTH_LIBRARIES} |
499 | ${GMOCK_LIBRARIES} |
500 | ) |
501 | |
502 | === added file 'tests/framework/mock_session_manager.h' |
503 | --- tests/framework/mock_session_manager.h 1970-01-01 00:00:00 +0000 |
504 | +++ tests/framework/mock_session_manager.h 2017-03-10 12:23:14 +0000 |
505 | @@ -0,0 +1,33 @@ |
506 | +/* |
507 | + * Copyright (C) 2017 Canonical, Ltd. |
508 | + * |
509 | + * This program is free software: you can redistribute it and/or modify it under |
510 | + * the terms of the GNU Lesser General Public License version 3, as published by |
511 | + * the Free Software Foundation. |
512 | + * |
513 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
514 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
515 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
516 | + * Lesser General Public License for more details. |
517 | + * |
518 | + * You should have received a copy of the GNU Lesser General Public License |
519 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
520 | + */ |
521 | + |
522 | +#ifndef MOCK_SESSION_MANAGER_H |
523 | +#define MOCK_SESSION_MANAGER_H |
524 | + |
525 | +#include <Unity/Application/sessionmanager.h> |
526 | + |
527 | +#include <gmock/gmock.h> |
528 | + |
529 | +namespace qtmir { |
530 | + |
531 | +struct MockSessionManager : public qtmir::SessionManager |
532 | +{ |
533 | + MOCK_CONST_METHOD1(findSession, qtmir::SessionInterface*(const mir::scene::Session*)); |
534 | +}; |
535 | + |
536 | +} // namespace qtmir |
537 | + |
538 | +#endif // MOCK_SESSION_MANAGER_H |
539 | |
540 | === added file 'tests/framework/mock_window_controller.h' |
541 | --- tests/framework/mock_window_controller.h 1970-01-01 00:00:00 +0000 |
542 | +++ tests/framework/mock_window_controller.h 2017-03-10 12:23:14 +0000 |
543 | @@ -0,0 +1,43 @@ |
544 | +/* |
545 | + * Copyright (C) 2017 Canonical, Ltd. |
546 | + * |
547 | + * This program is free software: you can redistribute it and/or modify it under |
548 | + * the terms of the GNU Lesser General Public License version 3, as published by |
549 | + * the Free Software Foundation. |
550 | + * |
551 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
552 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
553 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
554 | + * Lesser General Public License for more details. |
555 | + * |
556 | + * You should have received a copy of the GNU Lesser General Public License |
557 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
558 | + */ |
559 | + |
560 | +#ifndef MOCK_WINDOW_CONTROLLER_H |
561 | +#define MOCK_WINDOW_CONTROLLER_H |
562 | + |
563 | +#include "windowcontrollerinterface.h" |
564 | + |
565 | +#include <gmock/gmock.h> |
566 | + |
567 | +class MockWindowController : public qtmir::WindowControllerInterface |
568 | +{ |
569 | +public: |
570 | + MOCK_METHOD1(activate, void(const miral::Window &)); |
571 | + MOCK_METHOD1(raise, void(const miral::Window &)); |
572 | + |
573 | + MOCK_METHOD2(resize, void(const miral::Window &, const QSize &)); |
574 | + MOCK_METHOD2(move, void(const miral::Window &, const QPoint &)); |
575 | + |
576 | + MOCK_METHOD1(requestClose, void(const miral::Window &)); |
577 | + MOCK_METHOD1(forceClose, void(const miral::Window &)); |
578 | + |
579 | + MOCK_METHOD2(requestState, void(const miral::Window &, const Mir::State)); |
580 | + |
581 | + MOCK_METHOD2(deliverKeyboardEvent, void(const miral::Window &, const MirKeyboardEvent *)); |
582 | + MOCK_METHOD2(deliverTouchEvent, void(const miral::Window &, const MirTouchEvent *)); |
583 | + MOCK_METHOD2(deliverPointerEvent, void(const miral::Window &, const MirPointerEvent *)); |
584 | +}; |
585 | + |
586 | +#endif // MOCK_WINDOW_CONTROLLER_H |
587 | |
588 | === modified file 'tests/modules/CMakeLists.txt' |
589 | --- tests/modules/CMakeLists.txt 2016-11-03 20:17:46 +0000 |
590 | +++ tests/modules/CMakeLists.txt 2017-03-10 12:23:14 +0000 |
591 | @@ -1,6 +1,7 @@ |
592 | add_subdirectory(Application) |
593 | add_subdirectory(ApplicationManager) |
594 | add_subdirectory(General) |
595 | +add_subdirectory(SessionManager) |
596 | add_subdirectory(SharedWakelock) |
597 | -add_subdirectory(SessionManager) |
598 | +add_subdirectory(SurfaceManager) |
599 | add_subdirectory(WindowManager) |
600 | |
601 | === added directory 'tests/modules/SurfaceManager' |
602 | === added file 'tests/modules/SurfaceManager/CMakeLists.txt' |
603 | --- tests/modules/SurfaceManager/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
604 | +++ tests/modules/SurfaceManager/CMakeLists.txt 2017-03-10 12:23:14 +0000 |
605 | @@ -0,0 +1,40 @@ |
606 | +set( |
607 | + SURFACE_MANAGER_TEST_SOURCES |
608 | + surface_manager_test.cpp |
609 | + ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
610 | +) |
611 | + |
612 | +include_directories( |
613 | + ${CMAKE_SOURCE_DIR}/src/common |
614 | + ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
615 | + ${CMAKE_SOURCE_DIR}/src/modules |
616 | + ${CMAKE_SOURCE_DIR}/tests/framework |
617 | +) |
618 | + |
619 | +include_directories( |
620 | + SYSTEM |
621 | + ${APPLICATION_API_INCLUDE_DIRS} |
622 | + ${MIRAL_INCLUDE_DIRS} |
623 | + ${MIRTEST_INCLUDE_DIRS} |
624 | +) |
625 | + |
626 | +add_executable(surfacemanager_test ${SURFACE_MANAGER_TEST_SOURCES}) |
627 | + |
628 | +add_dependencies(surfacemanager_test qtmir-test-framework-static) |
629 | + |
630 | +target_link_libraries( |
631 | + surfacemanager_test |
632 | + |
633 | + unityapplicationplugin |
634 | + |
635 | + Qt5::Test |
636 | + |
637 | + -L${CMAKE_BINARY_DIR}/tests/framework |
638 | + qtmir-test-framework-static |
639 | + |
640 | + ${MIRTEST_LDFLAGS} |
641 | + ${GTEST_BOTH_LIBRARIES} |
642 | + ${GMOCK_LIBRARIES} |
643 | +) |
644 | + |
645 | +add_test(SurfaceManager, surfacemanager_test) |
646 | |
647 | === added file 'tests/modules/SurfaceManager/surface_manager_test.cpp' |
648 | --- tests/modules/SurfaceManager/surface_manager_test.cpp 1970-01-01 00:00:00 +0000 |
649 | +++ tests/modules/SurfaceManager/surface_manager_test.cpp 2017-03-10 12:23:14 +0000 |
650 | @@ -0,0 +1,489 @@ |
651 | +/* |
652 | + * Copyright (C) 2017 Canonical, Ltd. |
653 | + * |
654 | + * This program is free software: you can redistribute it and/or modify it under |
655 | + * the terms of the GNU Lesser General Public License version 3, as published by |
656 | + * the Free Software Foundation. |
657 | + * |
658 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
659 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
660 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
661 | + * Lesser General Public License for more details. |
662 | + * |
663 | + * You should have received a copy of the GNU Lesser General Public License |
664 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
665 | + */ |
666 | + |
667 | +#include <QLoggingCategory> |
668 | +#include <QSignalSpy> |
669 | + |
670 | +// the test subject |
671 | +#include <Unity/Application/surfacemanager.h> |
672 | +#include <Unity/Application/mirsurface.h> |
673 | + |
674 | +// miral |
675 | +#include <miral/window.h> |
676 | +#include <miral/window_info.h> |
677 | + |
678 | +// mirtest |
679 | +#include <mir/test/doubles/stub_session.h> |
680 | +#include <mir/test/doubles/stub_surface.h> |
681 | + |
682 | +// local |
683 | +#include "qtmir_test.h" |
684 | +#include "fake_session.h" |
685 | +#include "mock_session_manager.h" |
686 | +#include "mock_window_controller.h" |
687 | + |
688 | +using namespace qtmir; |
689 | +using StubSurface = mir::test::doubles::StubSurface; |
690 | +using StubSession = mir::test::doubles::StubSession; |
691 | + |
692 | +struct TestableSurfaceManager : public SurfaceManager |
693 | +{ |
694 | + // just exports the test-only protected constructor |
695 | + TestableSurfaceManager(WindowControllerInterface *windowController, |
696 | + WindowModelNotifier *windowModel, |
697 | + SessionManager *sessionManager) |
698 | + : SurfaceManager(windowController, windowModel, sessionManager) {} |
699 | + |
700 | + MirSurface* find(const miral::WindowInfo &needle) const |
701 | + { |
702 | + return SurfaceManager::find(needle); |
703 | + } |
704 | +}; |
705 | + |
706 | +class SurfaceManagerTests : public ::testing::Test |
707 | +{ |
708 | +public: |
709 | + SurfaceManagerTests() |
710 | + { |
711 | + // We don't want the logging spam cluttering the test results |
712 | + QLoggingCategory::setFilterRules(QStringLiteral("qtmir.*=false")); |
713 | + |
714 | + qRegisterMetaType<unity::shell::application::MirSurfaceInterface*>(); |
715 | + qRegisterMetaType<QVector<unity::shell::application::MirSurfaceInterface*>>(); |
716 | + } |
717 | + |
718 | + testing::NiceMock<MockSessionManager> sessionManager; |
719 | + testing::NiceMock<MockWindowController> wmController; |
720 | + WindowModelNotifier wmNotifier; |
721 | + QScopedPointer<TestableSurfaceManager> surfaceManager; |
722 | + QScopedPointer<QCoreApplication> qtApp; // need to spin event loop for queued connections |
723 | + |
724 | + // Needed to create miral::WindowInfo |
725 | + const std::shared_ptr<StubSession> stubSession{std::make_shared<StubSession>()}; |
726 | + const std::shared_ptr<StubSurface> stubSurface{std::make_shared<StubSurface>()}; |
727 | + const miral::Window window{stubSession, stubSurface}; |
728 | + const ms::SurfaceCreationParameters spec; |
729 | + const miral::WindowInfo windowInfo{window, spec}; |
730 | + FakeSession fakeSession; |
731 | + |
732 | +protected: |
733 | + void SetUp() override |
734 | + { |
735 | + int argc = 0; |
736 | + char* argv[0]; |
737 | + qtApp.reset(new QCoreApplication(argc, argv)); |
738 | + |
739 | + using namespace ::testing; |
740 | + ON_CALL(sessionManager,findSession(_)) |
741 | + .WillByDefault(Return(&fakeSession)); |
742 | + |
743 | + surfaceManager.reset(new TestableSurfaceManager(&wmController, |
744 | + &wmNotifier, &sessionManager)); |
745 | + } |
746 | +}; |
747 | + |
748 | +/* |
749 | + * Test if MirAL notifies that a window was created, SurfaceManager emits the surfaceCreated |
750 | + * signal |
751 | + */ |
752 | +TEST_F(SurfaceManagerTests, miralWindowCreationCausesSignalEmission) |
753 | +{ |
754 | + QSignalSpy newMirSurfaceSpy(surfaceManager.data(), &SurfaceManager::surfaceCreated); |
755 | + |
756 | + // Test |
757 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
758 | + qtApp->sendPostedEvents(); |
759 | + |
760 | + // Check result |
761 | + EXPECT_EQ(1, newMirSurfaceSpy.count()); |
762 | +} |
763 | + |
764 | + |
765 | +/* |
766 | + * Test if MirAL notifies that a window was created, SurfaceManager emits the surfaceCreated |
767 | + * signal with a corresponding MirSurface |
768 | + */ |
769 | +TEST_F(SurfaceManagerTests, miralWindowCreationCausesMirSurfaceCreation) |
770 | +{ |
771 | + QSignalSpy newMirSurfaceSpy(surfaceManager.data(), &SurfaceManager::surfaceCreated); |
772 | + |
773 | + // Test |
774 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
775 | + qtApp->sendPostedEvents(); |
776 | + |
777 | + // Check result |
778 | + auto mirSurface = qvariant_cast<MirSurface*>(newMirSurfaceSpy.takeFirst().at(0)); |
779 | + ASSERT_TRUE(mirSurface); |
780 | + EXPECT_EQ(window, mirSurface->window()); |
781 | +} |
782 | + |
783 | +/* |
784 | + * Test if MirAL notifies that a window was created, SurfaceManager adds the corresponding |
785 | + * MirSurface to its internal list |
786 | + */ |
787 | +TEST_F(SurfaceManagerTests, miralWindowCreationAddsMirSurfaceToItsInternalList) |
788 | +{ |
789 | + // Test |
790 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
791 | + qtApp->sendPostedEvents(); |
792 | + |
793 | + // Check result |
794 | + auto mirSurface = surfaceManager->find(windowInfo); |
795 | + ASSERT_TRUE(mirSurface); |
796 | + EXPECT_EQ(window, mirSurface->window()); |
797 | +} |
798 | + |
799 | +/* |
800 | + * Test SurfaceManager creates a MirSurface with a Session associated |
801 | + */ |
802 | +TEST_F(SurfaceManagerTests, createdMirSurfaceHasSessionSet) |
803 | +{ |
804 | + // Setup |
805 | + using namespace ::testing; |
806 | + EXPECT_CALL(sessionManager,findSession(_)) |
807 | + .WillOnce(Return(&fakeSession)); |
808 | + |
809 | + // Test |
810 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
811 | + qtApp->sendPostedEvents(); |
812 | + |
813 | + // Check result |
814 | + auto mirSurface = surfaceManager->find(windowInfo); |
815 | + ASSERT_TRUE(mirSurface); |
816 | + EXPECT_EQ(&fakeSession, mirSurface->session()); |
817 | +} |
818 | + |
819 | +/* |
820 | + * Test when MirAL creates a surface with a parent, SurfaceManager correctly associates |
821 | + * the parent MirSurface to the MirSurface |
822 | + */ |
823 | +TEST_F(SurfaceManagerTests, parentedMiralWindowGeneratesMirSurfaceWithCorrectParent) |
824 | +{ |
825 | + // Setup |
826 | + miral::Window parentWindow(stubSession, stubSurface); |
827 | + miral::Window childWindow(stubSession, stubSurface); |
828 | + miral::WindowInfo parentWindowInfo(parentWindow, spec); |
829 | + miral::WindowInfo childWindowInfo(childWindow, spec); |
830 | + childWindowInfo.parent(parentWindow); |
831 | + |
832 | + // Test |
833 | + Q_EMIT wmNotifier.windowAdded(parentWindowInfo); |
834 | + Q_EMIT wmNotifier.windowAdded(childWindowInfo); |
835 | + qtApp->sendPostedEvents(); |
836 | + |
837 | + // Check result |
838 | + auto childMirSurface = surfaceManager->find(childWindowInfo); |
839 | + auto parentMirSurface = surfaceManager->find(parentWindowInfo); |
840 | + ASSERT_TRUE(childMirSurface); |
841 | + ASSERT_TRUE(parentMirSurface); |
842 | + |
843 | + EXPECT_EQ(parentMirSurface, childMirSurface->parentSurface()); |
844 | +} |
845 | + |
846 | +/* |
847 | + * Test when MirAL creates a surface with a parent, SurfaceManager correctly associates |
848 | + * the child MirSurface to the parent MirSurface |
849 | + */ |
850 | +TEST_F(SurfaceManagerTests, miralWindowWithChildHasMirSurfaceWithCorrectChild) |
851 | +{ |
852 | + // Setup |
853 | + miral::Window parentWindow(stubSession, stubSurface); |
854 | + miral::Window childWindow(stubSession, stubSurface); |
855 | + miral::WindowInfo parentWindowInfo(parentWindow, spec); |
856 | + miral::WindowInfo childWindowInfo(childWindow, spec); |
857 | + childWindowInfo.parent(parentWindow); |
858 | + |
859 | + // Test |
860 | + Q_EMIT wmNotifier.windowAdded(parentWindowInfo); |
861 | + Q_EMIT wmNotifier.windowAdded(childWindowInfo); |
862 | + qtApp->sendPostedEvents(); |
863 | + |
864 | + // Check result |
865 | + auto childMirSurface = surfaceManager->find(childWindowInfo); |
866 | + auto parentMirSurface = surfaceManager->find(parentWindowInfo); |
867 | + ASSERT_TRUE(childMirSurface); |
868 | + ASSERT_TRUE(parentMirSurface); |
869 | + |
870 | + ASSERT_EQ(1, parentMirSurface->childSurfaceList()->count()); |
871 | + EXPECT_EQ(childMirSurface, parentMirSurface->childSurfaceList()->first()); |
872 | +} |
873 | + |
874 | +/* |
875 | + * Test if MirAL notifies that a window is ready, SurfaceManager updates the corresponding |
876 | + * MirSurface causing it to emit a ready() signal |
877 | + */ |
878 | +TEST_F(SurfaceManagerTests, miralWindowReadyUpdatesMirSurfaceState) |
879 | +{ |
880 | + // Setup: add window and get corresponding MirSurface |
881 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
882 | + qtApp->sendPostedEvents(); |
883 | + auto mirSurface = surfaceManager->find(windowInfo); |
884 | + ASSERT_TRUE(mirSurface); |
885 | + |
886 | + QSignalSpy mirSurfaceReadySpy(mirSurface, &MirSurface::ready); |
887 | + |
888 | + // Test |
889 | + Q_EMIT wmNotifier.windowReady(windowInfo); |
890 | + qtApp->sendPostedEvents(); |
891 | + |
892 | + // Check result |
893 | + EXPECT_EQ(1, mirSurfaceReadySpy.count()); |
894 | +} |
895 | + |
896 | +/* |
897 | + * Test if MirAL notifies that a window is moved, SurfaceManager updates the corresponding |
898 | + * MirSurface position |
899 | + */ |
900 | +TEST_F(SurfaceManagerTests, miralWindowMoveUpdatesMirSurfacePosition) |
901 | +{ |
902 | + QPoint newPosition(222,333); |
903 | + |
904 | + // Setup: add window and get corresponding MirSurface |
905 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
906 | + qtApp->sendPostedEvents(); |
907 | + auto mirSurface = surfaceManager->find(windowInfo); |
908 | + ASSERT_TRUE(mirSurface); |
909 | + |
910 | + QSignalSpy mirSurfacePositionSpy(mirSurface, &MirSurface::positionChanged); |
911 | + |
912 | + // Test |
913 | + Q_EMIT wmNotifier.windowMoved(windowInfo, newPosition); |
914 | + qtApp->sendPostedEvents(); |
915 | + |
916 | + // Check result |
917 | + EXPECT_EQ(1, mirSurfacePositionSpy.count()); |
918 | + EXPECT_EQ(mirSurface->position(), newPosition); |
919 | +} |
920 | + |
921 | +/* |
922 | + * Test if MirAL notifies that a window's focus state changes, SurfaceManager updates the corresponding |
923 | + * MirSurface focus state |
924 | + */ |
925 | +TEST_F(SurfaceManagerTests, miralWindowFocusChangeUpdatesMirSurfaceFocus) |
926 | +{ |
927 | + // Setup: add window and get corresponding MirSurface |
928 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
929 | + qtApp->sendPostedEvents(); |
930 | + auto mirSurface = surfaceManager->find(windowInfo); |
931 | + ASSERT_TRUE(mirSurface); |
932 | + ASSERT_FALSE(mirSurface->focused()); // false must be the initial state |
933 | + |
934 | + QSignalSpy mirSurfaceFocusSpy(mirSurface, &MirSurface::focusedChanged); |
935 | + |
936 | + // Test |
937 | + Q_EMIT wmNotifier.windowFocusChanged(windowInfo, true); |
938 | + qtApp->sendPostedEvents(); |
939 | + |
940 | + // Check result |
941 | + EXPECT_EQ(1, mirSurfaceFocusSpy.count()); |
942 | + EXPECT_EQ(mirSurface->focused(), true); |
943 | +} |
944 | + |
945 | +/* |
946 | + * Test if MirAL notifies that a window's state changes, SurfaceManager updates the corresponding |
947 | + * MirSurface state (just testing a single state, see no value in testing all possible states here) |
948 | + */ |
949 | +TEST_F(SurfaceManagerTests, miralWindowStateChangeUpdatesMirSurfaceState) |
950 | +{ |
951 | + auto newState = Mir::FullscreenState; |
952 | + |
953 | + // Setup: add window and get corresponding MirSurface |
954 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
955 | + qtApp->sendPostedEvents(); |
956 | + auto mirSurface = surfaceManager->find(windowInfo); |
957 | + ASSERT_TRUE(mirSurface); |
958 | + |
959 | + QSignalSpy mirSurfaceStateSpy(mirSurface, &MirSurface::stateChanged); |
960 | + |
961 | + // Test |
962 | + Q_EMIT wmNotifier.windowStateChanged(windowInfo, newState); |
963 | + qtApp->sendPostedEvents(); |
964 | + |
965 | + // Check result |
966 | + EXPECT_EQ(1, mirSurfaceStateSpy.count()); |
967 | + EXPECT_EQ(mirSurface->state(), newState); |
968 | +} |
969 | + |
970 | +/* |
971 | + * Test when miral raises a list of surfaces, the raise signal is fired by SurfaceManager with |
972 | + * a list of MirSurfaces in the matching order |
973 | + */ |
974 | +TEST_F(SurfaceManagerTests, miralsRaiseWindowListTransformedToVectorOfMirSurfaces) |
975 | +{ |
976 | + // Setup |
977 | + miral::Window window1(stubSession, stubSurface); |
978 | + miral::Window window2(stubSession, stubSurface); |
979 | + miral::WindowInfo windowInfo1(window1, spec); |
980 | + miral::WindowInfo windowInfo2(window2, spec); |
981 | + |
982 | + // Setup: add 2 windows and get their MirSurfaces |
983 | + Q_EMIT wmNotifier.windowAdded(windowInfo1); |
984 | + Q_EMIT wmNotifier.windowAdded(windowInfo2); |
985 | + qtApp->sendPostedEvents(); |
986 | + auto mirSurface1 = surfaceManager->find(windowInfo1); |
987 | + auto mirSurface2 = surfaceManager->find(windowInfo2); |
988 | + ASSERT_TRUE(mirSurface1); |
989 | + ASSERT_TRUE(mirSurface2); |
990 | + |
991 | + QSignalSpy mirSurfacesRaisedSpy(surfaceManager.data(), &SurfaceManager::surfacesRaised); |
992 | + |
993 | + // Test |
994 | + std::vector<miral::Window> raiseWindowList{window2, window1}; |
995 | + Q_EMIT wmNotifier.windowsRaised(raiseWindowList); |
996 | + qtApp->sendPostedEvents(); |
997 | + |
998 | + // Check results |
999 | + ASSERT_EQ(1, mirSurfacesRaisedSpy.count()); |
1000 | + auto raiseMirSurfaceList = qvariant_cast<QVector<unity::shell::application::MirSurfaceInterface*>>( |
1001 | + mirSurfacesRaisedSpy.takeFirst().at(0)); // first argument of signal |
1002 | + ASSERT_EQ(2, raiseMirSurfaceList.count()); |
1003 | + EXPECT_EQ(mirSurface1, raiseMirSurfaceList.at(1)); |
1004 | + EXPECT_EQ(mirSurface2, raiseMirSurfaceList.at(0)); |
1005 | +} |
1006 | + |
1007 | +/* |
1008 | + * Test focus requests fire focusRequested signal of the MirSurface |
1009 | + */ |
1010 | +TEST_F(SurfaceManagerTests, focusRequestCausesMirSurfaceToFireFocusRequestedSignal) |
1011 | +{ |
1012 | + // Setup: add window and get corresponding MirSurface |
1013 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
1014 | + qtApp->sendPostedEvents(); |
1015 | + auto mirSurface = surfaceManager->find(windowInfo); |
1016 | + ASSERT_TRUE(mirSurface); |
1017 | + |
1018 | + QSignalSpy mirSurfaceFocusRequestedSpy(mirSurface, &MirSurface::focusRequested); |
1019 | + |
1020 | + // Test |
1021 | + Q_EMIT wmNotifier.windowRequestedRaise(windowInfo); |
1022 | + qtApp->sendPostedEvents(); |
1023 | + |
1024 | + // Check result |
1025 | + EXPECT_EQ(1, mirSurfaceFocusRequestedSpy.count()); |
1026 | +} |
1027 | + |
1028 | +/* |
1029 | + * If MirAL notifies that a window was removed, and its corresponding MirSurface is not |
1030 | + * being displayed, test that SurfaceManager removes the corresponding MirSurface from |
1031 | + * its internal list and deletes the MirSurface |
1032 | + */ |
1033 | +TEST_F(SurfaceManagerTests, miralWindowRemovedDeletesSurfaceManagerInternalEntryAndMirSurface) |
1034 | +{ |
1035 | + // Setup: add window and get corresponding MirSurface |
1036 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
1037 | + qtApp->sendPostedEvents(); |
1038 | + auto mirSurface = surfaceManager->find(windowInfo); |
1039 | + ASSERT_TRUE(mirSurface); |
1040 | + |
1041 | + QSignalSpy mirSurfaceDestroyedSpy(mirSurface, &QObject::destroyed); |
1042 | + |
1043 | + // Test |
1044 | + Q_EMIT wmNotifier.windowRemoved(windowInfo); |
1045 | + qtApp->sendPostedEvents(); |
1046 | + |
1047 | + // Check result |
1048 | + ASSERT_EQ(2, mirSurfaceDestroyedSpy.count()); //FIXME - should be 1 |
1049 | + EXPECT_FALSE(surfaceManager->find(windowInfo)); |
1050 | +} |
1051 | + |
1052 | +/* |
1053 | + * If MirAL notifies that a window was removed, and its corresponding MirSurface *is* |
1054 | + * being displayed, test that SurfaceManager removes the corresponding MirSurface from |
1055 | + * its internal list but does *not* delete the MirSurface, but sets it as not "live" |
1056 | + */ |
1057 | +TEST_F(SurfaceManagerTests, miralWindowRemovedDeletesSurfaceManagerInternalEntryButNotMirSurface) |
1058 | +{ |
1059 | + // Setup: add window and get corresponding MirSurface |
1060 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
1061 | + qtApp->sendPostedEvents(); |
1062 | + auto mirSurface = surfaceManager->find(windowInfo); |
1063 | + ASSERT_TRUE(mirSurface); |
1064 | + |
1065 | + QSignalSpy mirSurfaceDestroyedSpy(mirSurface, &QObject::destroyed); |
1066 | + |
1067 | + mirSurface->registerView(1); |
1068 | + |
1069 | + // Test |
1070 | + Q_EMIT wmNotifier.windowRemoved(windowInfo); |
1071 | + qtApp->sendPostedEvents(); |
1072 | + |
1073 | + // Check result |
1074 | + ASSERT_EQ(0, mirSurfaceDestroyedSpy.count()); |
1075 | + EXPECT_FALSE(surfaceManager->find(windowInfo)); |
1076 | + EXPECT_FALSE(mirSurface->live()); |
1077 | +} |
1078 | + |
1079 | +/* |
1080 | + * If MirAL notifies that a window was removed, and its corresponding MirSurface *is* |
1081 | + * being displayed, SurfaceManager does *not* delete the MirSurface. Later when that |
1082 | + * MirSurface is not being displayed any more, SurfaceManager should delete it. |
1083 | + */ |
1084 | +TEST_F(SurfaceManagerTests, miralWindowRemovedSurfaceManagerDeletesMirSurfaceWhenItDoneWith) |
1085 | +{ |
1086 | + int viewId = 99; |
1087 | + |
1088 | + // Setup: add window and get corresponding MirSurface |
1089 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
1090 | + qtApp->sendPostedEvents(); |
1091 | + auto mirSurface = surfaceManager->find(windowInfo); |
1092 | + ASSERT_TRUE(mirSurface); |
1093 | + |
1094 | + QSignalSpy mirSurfaceDestroyedSpy(mirSurface, &QObject::destroyed); |
1095 | + |
1096 | + // Setup: indicate MirSurface is being displayed |
1097 | + mirSurface->registerView(viewId); |
1098 | + |
1099 | + // Setup: notify that window removed |
1100 | + Q_EMIT wmNotifier.windowRemoved(windowInfo); |
1101 | + qtApp->sendPostedEvents(); |
1102 | + |
1103 | + // Test |
1104 | + mirSurface->unregisterView(viewId); |
1105 | + // MirSurface is deleteLater()ed by SurfaceManager, so need to spin event loop. |
1106 | + // But DeferredDelete is special: likes to be called out specifically or it won't come out |
1107 | + qtApp->sendPostedEvents(mirSurface, QEvent::DeferredDelete); |
1108 | + qtApp->sendPostedEvents(); |
1109 | + |
1110 | + // Check result |
1111 | + ASSERT_EQ(2, mirSurfaceDestroyedSpy.count()); //FIXME - should be 1 |
1112 | +} |
1113 | + |
1114 | +/* |
1115 | + * Test that if a MirSurface is live, and stops being displayed, SurfaceManager does *not* |
1116 | + * delete the MirSurface. |
1117 | + */ |
1118 | +TEST_F(SurfaceManagerTests, surfaceManagerDoesNotDeleteLiveMirSurfaceWhenStopsBeingDisplayed) |
1119 | +{ |
1120 | + int viewId = 99; |
1121 | + |
1122 | + // Setup: add window and get corresponding MirSurface |
1123 | + Q_EMIT wmNotifier.windowAdded(windowInfo); |
1124 | + qtApp->sendPostedEvents(); |
1125 | + auto mirSurface = surfaceManager->find(windowInfo); |
1126 | + ASSERT_TRUE(mirSurface); |
1127 | + ASSERT_TRUE(mirSurface->live()); |
1128 | + |
1129 | + QSignalSpy mirSurfaceDestroyedSpy(mirSurface, &QObject::destroyed); |
1130 | + |
1131 | + // Setup: indicate MirSurface is being displayed |
1132 | + mirSurface->registerView(viewId); |
1133 | + |
1134 | + // Test |
1135 | + mirSurface->unregisterView(viewId); |
1136 | + |
1137 | + // Check result |
1138 | + ASSERT_EQ(0, mirSurfaceDestroyedSpy.count()); |
1139 | +} |
1140 | |
1141 | === modified file 'tests/modules/WindowManager/mirsurface_test.cpp' |
1142 | --- tests/modules/WindowManager/mirsurface_test.cpp 2017-02-02 09:29:46 +0000 |
1143 | +++ tests/modules/WindowManager/mirsurface_test.cpp 2017-03-10 12:23:14 +0000 |
1144 | @@ -110,66 +110,6 @@ |
1145 | ASSERT_TRUE(spyFrameDropped.count() > 0); |
1146 | } |
1147 | |
1148 | - |
1149 | -TEST_F(MirSurfaceTest, DeleteMirSurfaceOnLastNonLiveUnregisterView) |
1150 | -{ |
1151 | - int argc = 0; |
1152 | - char* argv[0]; |
1153 | - QCoreApplication qtApp(argc, argv); // app for deleteLater event |
1154 | - |
1155 | - miral::Window mockWindow(stubSession, stubSurface); |
1156 | - ms::SurfaceCreationParameters spec; |
1157 | - miral::WindowInfo mockWindowInfo(mockWindow, spec); |
1158 | - |
1159 | - auto surface = new MirSurface(mockWindowInfo, nullptr); // lives on the heap, as it will delete itself |
1160 | - |
1161 | - bool surfaceDeleted = false; |
1162 | - QObject::connect(surface, &QObject::destroyed, [&surfaceDeleted](){ surfaceDeleted = true; }); |
1163 | - |
1164 | - qintptr view1 = (qintptr)1; |
1165 | - qintptr view2 = (qintptr)2; |
1166 | - |
1167 | - surface->registerView(view1); |
1168 | - surface->registerView(view2); |
1169 | - surface->setLive(false); |
1170 | - EXPECT_FALSE(surfaceDeleted); |
1171 | - |
1172 | - surface->unregisterView(view1); |
1173 | - surface->unregisterView(view2); |
1174 | - |
1175 | - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
1176 | - EXPECT_TRUE(surfaceDeleted); |
1177 | -} |
1178 | - |
1179 | - |
1180 | -TEST_F(MirSurfaceTest, DISABLED_DoNotDeleteMirSurfaceOnLastLiveUnregisterView) |
1181 | -{ |
1182 | - int argc = 0; |
1183 | - char* argv[0]; |
1184 | - QCoreApplication qtApp(argc, argv); // app for deleteLater event |
1185 | - |
1186 | - miral::Window mockWindow(stubSession, stubSurface); |
1187 | - ms::SurfaceCreationParameters spec; |
1188 | - miral::WindowInfo mockWindowInfo(mockWindow, spec); |
1189 | - |
1190 | - auto surface = new MirSurface(mockWindowInfo, nullptr); // lives on the heap, as it may delete itself |
1191 | - |
1192 | - bool surfaceDeleted = false; |
1193 | - QObject::connect(surface, &QObject::destroyed, [&surfaceDeleted](){ surfaceDeleted = true; }); |
1194 | - |
1195 | - qintptr view1 = (qintptr)1; |
1196 | - qintptr view2 = (qintptr)2; |
1197 | - |
1198 | - surface->registerView(view1); |
1199 | - surface->registerView(view2); |
1200 | - |
1201 | - surface->unregisterView(view1); |
1202 | - surface->unregisterView(view2); |
1203 | - |
1204 | - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
1205 | - EXPECT_FALSE(surfaceDeleted); |
1206 | -} |
1207 | - |
1208 | /* |
1209 | * Test that MirSurface.visible is recalculated after the client swaps the first frame. |
1210 | * A surface is not considered visible unless it has a non-hidden & non-minimized state, and |
Ok