on d73aca0 help sign in
unity8/tests/mocks/Unity/Application/SurfaceManager.cpp
339 lines 10 kB history raw
1/*
2 * Copyright (C) 2014-2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17#include "SurfaceManager.h"
19#include "ApplicationInfo.h"
20#include "VirtualKeyboard.h"
21#include "../../WindowManager/WindowManagementPolicy.h"
23#include <paths.h>
24#include <mirtest/mir/test/doubles/stub_surface.h>
26#define SURFACEMANAGER_DEBUG 1
28#if SURFACEMANAGER_DEBUG
29#define DEBUG_MSG(params) qDebug().nospace() << "SurfaceManager[" << (void*)this << "]::" << __func__ << params
30#else
31#define DEBUG_MSG(params) ((void)0)
32#endif
34namespace unityapi = unity::shell::application;
36uint qHash(const WindowWrapper &key, uint)
38 std::shared_ptr<mir::scene::Surface> surface = key.window;
39 return (quintptr)surface.get();
42SurfaceManager *SurfaceManager::m_instance = nullptr;
44SurfaceManager *SurfaceManager::instance()
46 return m_instance;
49SurfaceManager::SurfaceManager(QObject *)
51 DEBUG_MSG("");
53 Q_ASSERT(m_instance == nullptr);
54 m_instance = this;
56 connect(WindowManagementPolicy::instance(), &WindowManagementPolicy::windowAdded,
57 this, [this](const miral::Window& window) {
58 Q_EMIT surfaceCreated(surfaceFor(window));
59 });
61 connect(WindowManagementPolicy::instance(), &WindowManagementPolicy::windowsAddedToWorkspace,
62 this, [this](const std::shared_ptr<miral::Workspace> &workspace, const std::vector<miral::Window> &windows) {
63 Q_EMIT surfacesAddedToWorkspace(workspace, find(windows));
64 });
66 connect(WindowManagementPolicy::instance(), &WindowManagementPolicy::windowsAboutToBeRemovedFromWorkspace,
67 this, [this](const std::shared_ptr<miral::Workspace> &workspace, const std::vector<miral::Window> &windows) {
68 Q_EMIT surfacesAboutToBeRemovedFromWorkspace(workspace, find(windows));
69 });
72SurfaceManager::~SurfaceManager()
74 DEBUG_MSG("");
76 if (m_virtualKeyboard) {
77 m_virtualKeyboard->setLive(false);
78 }
80 Q_ASSERT(m_instance == this);
81 m_instance = nullptr;
86QVector<MirSurfaceInterface*> SurfaceManager::find(const std::vector<miral::Window> &windows) const
88 QVector<unityapi::MirSurfaceInterface*> surfaces;
89 for (size_t i = 0; i < windows.size(); i++) {
90 auto mirSurface = surfaceFor(windows[i]);
91 if (mirSurface) {
92 surfaces.push_back(mirSurface);
93 }
94 }
95 return surfaces;
98MirSurfaceInterface *SurfaceManager::surfaceFor(const miral::Window& window) const
100 auto iter = m_windowToSurface.find({window});
101 if (iter != m_windowToSurface.end()) {
102 return *iter;
103 }
104 return nullptr;
107MirSurface *SurfaceManager::createSurface(const QString& name,
108 Mir::Type type,
109 Mir::State state,
110 MirSurface *parentSurface,
111 const QUrl &screenshot,
112 const QUrl &qmlFilePath)
114 MirSurface* surface = new MirSurface(name, type, state, parentSurface, screenshot, qmlFilePath);
115 registerSurface(surface);
116 if (parentSurface) {
117 static_cast<MirSurfaceListModel*>(parentSurface->childSurfaceList())->addSurface(surface);
118 }
119 return surface;
122void SurfaceManager::registerSurface(MirSurface *surface)
124 auto fakeSurface = std::make_shared<mir::test::doubles::StubSurface>();
125 WindowWrapper window{miral::Window(nullptr, fakeSurface), fakeSurface};
127 m_surfaces.prepend(surface);
128 m_windowToSurface.insert(window, surface);
129 m_surfaceToWindow.insert(surface, window);
131 if (!surface->parentSurface()) {
132 surface->setMinimumWidth(m_newSurfaceMinimumWidth);
133 surface->setMaximumWidth(m_newSurfaceMaximumWidth);
134 surface->setMinimumHeight(m_newSurfaceMinimumHeight);
135 surface->setMaximumHeight(m_newSurfaceMaximumHeight);
136 surface->setWidthIncrement(m_newSurfaceWidthIncrement);
137 surface->setHeightIncrement(m_newSurfaceHeightIncrement);
138 }
140 connect(surface, &MirSurface::stateRequested, this, [=](Mir::State state) {
141 this->onStateRequested(surface, state);
142 });
144 const QString persistentId = surface->persistentId();
145 connect(surface, &QObject::destroyed, this, [=]() {
146 WindowWrapper key = m_surfaceToWindow.take(surface);
147 m_windowToSurface.remove(key);
148 this->onSurfaceDestroyed(surface, persistentId);
149 });
153void SurfaceManager::notifySurfaceCreated(unityapi::MirSurfaceInterface *surface)
155 if (Q_UNLIKELY(!m_surfaceToWindow.contains(surface))) {
156 Q_EMIT surfaceCreated(surface);
157 return;
158 }
160 WindowManagementPolicy::instance()->addWindow(m_surfaceToWindow[surface].window);
163void SurfaceManager::setNewSurfaceMinimumWidth(int value)
165 if (m_newSurfaceMinimumWidth != value) {
166 m_newSurfaceMinimumWidth = value;
167 Q_EMIT newSurfaceMinimumWidthChanged(m_newSurfaceMinimumWidth);
168 }
171void SurfaceManager::setNewSurfaceMaximumWidth(int value)
173 if (m_newSurfaceMaximumWidth != value) {
174 m_newSurfaceMaximumWidth = value;
175 Q_EMIT newSurfaceMaximumWidthChanged(m_newSurfaceMaximumWidth);
176 }
179void SurfaceManager::setNewSurfaceMinimumHeight(int value)
181 if (m_newSurfaceMinimumHeight != value) {
182 m_newSurfaceMinimumHeight = value;
183 Q_EMIT newSurfaceMinimumHeightChanged(m_newSurfaceMinimumHeight);
184 }
187void SurfaceManager::setNewSurfaceMaximumHeight(int value)
189 if (m_newSurfaceMaximumHeight != value) {
190 m_newSurfaceMaximumHeight = value;
191 Q_EMIT newSurfaceMaximumHeightChanged(m_newSurfaceMaximumHeight);
192 }
195void SurfaceManager::setNewSurfaceWidthIncrement(int value)
197 if (m_newSurfaceWidthIncrement != value) {
198 m_newSurfaceWidthIncrement = value;
199 Q_EMIT newSurfaceWidthIncrementChanged(m_newSurfaceWidthIncrement);
200 }
203void SurfaceManager::setNewSurfaceHeightIncrement(int value)
205 if (m_newSurfaceHeightIncrement != value) {
206 m_newSurfaceHeightIncrement = value;
207 Q_EMIT newSurfaceHeightIncrementChanged(m_newSurfaceHeightIncrement);
208 }
211void SurfaceManager::raise(unityapi::MirSurfaceInterface *surface)
213 if (m_underModification)
214 return;
216 DEBUG_MSG("("<<surface<<") started");
217 Q_EMIT modificationsStarted();
218 m_underModification = true;
220 doRaise(surface);
222 m_underModification = false;
223 Q_EMIT modificationsEnded();
224 DEBUG_MSG("("<<surface<<") ended");
227void SurfaceManager::doRaise(unityapi::MirSurfaceInterface *apiSurface)
229 auto surface = static_cast<MirSurface*>(apiSurface);
230 int index = m_surfaces.indexOf(surface);
231 Q_ASSERT(index != -1);
232 m_surfaces.move(index, 0);
234 Q_EMIT surfacesRaised({surface});
237void SurfaceManager::activate(unityapi::MirSurfaceInterface *apiSurface)
239 auto surface = static_cast<MirSurface*>(apiSurface);
241 if (surface == m_focusedSurface) {
242 return;
243 }
245 Q_ASSERT(!m_underModification);
247 DEBUG_MSG("("<<surface<<") started");
248 Q_EMIT modificationsStarted();
249 m_underModification = true;
250 if (m_focusedSurface) {
251 m_focusedSurface->setFocused(false);
252 }
253 if (surface) {
254 if (surface->state() == Mir::HiddenState || surface->state() == Mir::MinimizedState) {
255 if (surface->previousState() != Mir::UnknownState) {
256 surface->setState(surface->previousState());
257 } else {
258 surface->setState(Mir::RestoredState);
259 }
260 }
261 surface->setFocused(true);
262 doRaise(surface);
263 }
264 m_focusedSurface = surface;
265 m_underModification = false;
266 Q_EMIT modificationsEnded();
267 DEBUG_MSG("("<<surface<<") ended");
270void SurfaceManager::onStateRequested(MirSurface *surface, Mir::State state)
272 DEBUG_MSG("("<<surface<<","<<state<<") started");
273 Q_EMIT modificationsStarted();
274 m_underModification = true;
276 surface->setPreviousState(surface->state());
277 surface->setState(state);
279 if ((state == Mir::MinimizedState || state == Mir::HiddenState) && surface->focused()) {
280 Q_ASSERT(m_focusedSurface == surface);
281 surface->setFocused(false);
282 m_focusedSurface = nullptr;
283 focusFirstAvailableSurface();
284 }
286 m_underModification = false;
287 Q_EMIT modificationsEnded();
288 DEBUG_MSG("("<<surface<<","<<state<<") ended");
291void SurfaceManager::onSurfaceDestroyed(MirSurface *surface, const QString& persistentId)
293 m_surfaces.removeAll(surface);
294 if (m_focusedSurface == surface) {
295 m_focusedSurface = nullptr;
297 Q_EMIT modificationsStarted();
298 m_underModification = true;
300 focusFirstAvailableSurface();
302 m_underModification = false;
303 Q_EMIT modificationsEnded();
304 }
305 Q_EMIT surfaceDestroyed(persistentId);
308void SurfaceManager::focusFirstAvailableSurface()
310 MirSurface *chosenSurface = nullptr;
311 for (int i = 0; i < m_surfaces.count() && !chosenSurface; ++i) {
312 auto *surface = m_surfaces[i];
313 if (surface->state() != Mir::HiddenState && surface->state() != Mir::MinimizedState) {
314 chosenSurface = surface;
315 }
316 }
318 if (!chosenSurface) {
319 return;
320 }
322 if (m_focusedSurface) {
323 m_focusedSurface->setFocused(false);
324 }
326 chosenSurface->setFocused(true);
327 doRaise(chosenSurface);
329 m_focusedSurface = chosenSurface;
332void SurfaceManager::createInputMethodSurface()
334 if (!m_virtualKeyboard) {
335 m_virtualKeyboard = new VirtualKeyboard;
336 registerSurface(m_virtualKeyboard);
337 Q_EMIT surfaceCreated(m_virtualKeyboard);
338 }