Merge lp:~aacid/qtmir/make_sure_surface_not_null into lp:qtmir

Proposed by Albert Astals Cid
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
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, onWindowFocusChanged, etc so no reason to not do it in onWindowRemoved

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

To post a comment you must log in.
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Ok

review: Approve
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:609
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/544/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/4281/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4309
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4143
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4143/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4143
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4143/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4143/console
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4143/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4143
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4143/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4143
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4143/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4143
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4143/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/544/rebuild

review: Needs Fixing (continuous-integration)
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 isBeingDisplayedChanged 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, onWindowFocusChanged, 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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches