on cc5a4ec help sign in
unity8/tests/mocks/Unity/Application/SurfaceManager.cpp
388 lines 12 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, surfacesFor(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, surfacesFor(windows));
69 });
72SurfaceManager::~SurfaceManager()
74 DEBUG_MSG("");
76 releaseInputMethodSurface();
78 Q_ASSERT(m_instance == this);
79 m_instance = nullptr;
82MirSurfaceInterface *SurfaceManager::surfaceFor(const miral::Window& window) const
84 auto iter = m_windowToSurface.find({window});
85 if (iter != m_windowToSurface.end()) {
86 return *iter;
87 }
88 return nullptr;
91QVector<MirSurfaceInterface*> SurfaceManager::surfacesFor(const std::vector<miral::Window> &windows) const
93 QVector<unityapi::MirSurfaceInterface*> surfaces;
94 for (size_t i = 0; i < windows.size(); i++) {
95 auto mirSurface = surfaceFor(windows[i]);
96 if (mirSurface) {
97 surfaces.push_back(mirSurface);
98 }
99 }
100 return surfaces;
103miral::Window SurfaceManager::windowFor(MirSurfaceInterface *surface) const
105 auto iter = m_surfaceToWindow.find(surface);
106 if (iter != m_surfaceToWindow.end()) {
107 return iter->window;
108 }
109 return miral::Window();
112MirSurface *SurfaceManager::createSurface(const QString& name,
113 Mir::Type type,
114 Mir::State state,
115 MirSurface *parentSurface,
116 const QUrl &screenshot,
117 const QUrl &qmlFilePath)
119 MirSurface* surface = new MirSurface(name, type, state, parentSurface, screenshot, qmlFilePath);
120 registerSurface(surface);
121 if (parentSurface) {
122 static_cast<MirSurfaceListModel*>(parentSurface->childSurfaceList())->addSurface(surface);
123 }
124 return surface;
127void SurfaceManager::registerSurface(MirSurface *surface)
129 auto fakeSurface = std::make_shared<mir::test::doubles::StubSurface>();
130 WindowWrapper window{miral::Window(nullptr, fakeSurface), fakeSurface};
132 m_surfaces.prepend(surface);
133 m_windowToSurface.insert(window, surface);
134 m_surfaceToWindow.insert(surface, window);
136 if (!surface->parentSurface()) {
137 surface->setMinimumWidth(m_newSurfaceMinimumWidth);
138 surface->setMaximumWidth(m_newSurfaceMaximumWidth);
139 surface->setMinimumHeight(m_newSurfaceMinimumHeight);
140 surface->setMaximumHeight(m_newSurfaceMaximumHeight);
141 surface->setWidthIncrement(m_newSurfaceWidthIncrement);
142 surface->setHeightIncrement(m_newSurfaceHeightIncrement);
143 }
145 connect(surface, &MirSurface::stateRequested, this, [=](Mir::State state) {
146 this->onStateRequested(surface, state);
147 });
149 connect(surface, &QObject::destroyed, this, [=]() {
150 auto iter = m_surfaceToWindow.find(surface);
151 if (iter != m_surfaceToWindow.end()) {
152 WindowWrapper key = m_surfaceToWindow.value(surface);
153 WindowManagementPolicy::instance()->removeWindow(key.window);
154 this->onSurfaceDestroyed(surface);
155 }
156 });
159void SurfaceManager::notifySurfaceCreated(unityapi::MirSurfaceInterface *surface)
161 if (Q_UNLIKELY(!m_surfaceToWindow.contains(surface))) {
162 Q_EMIT surfaceCreated(surface);
163 return;
164 }
166 WindowManagementPolicy::instance()->addWindow(m_surfaceToWindow[surface].window);
169void SurfaceManager::setNewSurfaceMinimumWidth(int value)
171 if (m_newSurfaceMinimumWidth != value) {
172 m_newSurfaceMinimumWidth = value;
173 Q_EMIT newSurfaceMinimumWidthChanged(m_newSurfaceMinimumWidth);
174 }
177void SurfaceManager::setNewSurfaceMaximumWidth(int value)
179 if (m_newSurfaceMaximumWidth != value) {
180 m_newSurfaceMaximumWidth = value;
181 Q_EMIT newSurfaceMaximumWidthChanged(m_newSurfaceMaximumWidth);
182 }
185void SurfaceManager::setNewSurfaceMinimumHeight(int value)
187 if (m_newSurfaceMinimumHeight != value) {
188 m_newSurfaceMinimumHeight = value;
189 Q_EMIT newSurfaceMinimumHeightChanged(m_newSurfaceMinimumHeight);
190 }
193void SurfaceManager::setNewSurfaceMaximumHeight(int value)
195 if (m_newSurfaceMaximumHeight != value) {
196 m_newSurfaceMaximumHeight = value;
197 Q_EMIT newSurfaceMaximumHeightChanged(m_newSurfaceMaximumHeight);
198 }
201void SurfaceManager::setNewSurfaceWidthIncrement(int value)
203 if (m_newSurfaceWidthIncrement != value) {
204 m_newSurfaceWidthIncrement = value;
205 Q_EMIT newSurfaceWidthIncrementChanged(m_newSurfaceWidthIncrement);
206 }
209void SurfaceManager::setNewSurfaceHeightIncrement(int value)
211 if (m_newSurfaceHeightIncrement != value) {
212 m_newSurfaceHeightIncrement = value;
213 Q_EMIT newSurfaceHeightIncrementChanged(m_newSurfaceHeightIncrement);
214 }
217void SurfaceManager::raise(unityapi::MirSurfaceInterface *surface)
219 if (m_underModification)
220 return;
222 DEBUG_MSG("("<<surface<<") started");
223 Q_EMIT modificationsStarted();
224 m_underModification = true;
226 doRaise(surface);
228 m_underModification = false;
229 Q_EMIT modificationsEnded();
230 DEBUG_MSG("("<<surface<<") ended");
233void SurfaceManager::doRaise(unityapi::MirSurfaceInterface *apiSurface)
235 auto surface = static_cast<MirSurface*>(apiSurface);
236 int index = m_surfaces.indexOf(surface);
237 Q_ASSERT(index != -1);
238 m_surfaces.move(index, 0);
240 Q_EMIT surfacesRaised({surface});
243void SurfaceManager::activate(unityapi::MirSurfaceInterface *apiSurface)
245 auto surface = static_cast<MirSurface*>(apiSurface);
247 if (surface == m_focusedSurface) {
248 return;
249 }
251 Q_ASSERT(!m_underModification);
253 DEBUG_MSG("("<<surface<<") started");
254 Q_EMIT modificationsStarted();
255 m_underModification = true;
256 if (m_focusedSurface) {
257 m_focusedSurface->setFocused(false);
258 }
259 if (surface) {
260 if (surface->state() == Mir::HiddenState || surface->state() == Mir::MinimizedState) {
261 if (surface->previousState() != Mir::UnknownState) {
262 surface->setState(surface->previousState());
263 } else {
264 surface->setState(Mir::RestoredState);
265 }
266 }
267 surface->setFocused(true);
268 doRaise(surface);
269 }
270 m_focusedSurface = surface;
271 m_underModification = false;
272 Q_EMIT modificationsEnded();
273 DEBUG_MSG("("<<surface<<") ended");
276void SurfaceManager::forEachSurfaceInWorkspace(const std::shared_ptr<miral::Workspace> &workspace,
277 const std::function<void(unity::shell::application::MirSurfaceInterface*)> &callback)
279 WindowManagementPolicy::instance()->forEachWindowInWorkspace(workspace, [&](const miral::Window &window) {
280 auto surface = surfaceFor(window);
281 if (surface) {
282 callback(surface);
283 }
284 });
287void SurfaceManager::moveSurfaceToWorkspace(unity::shell::application::MirSurfaceInterface* surface,
288 const std::shared_ptr<miral::Workspace> &workspace)
290 auto window = windowFor(surface);
291 if (window) {
292 WindowManagementPolicy::instance()->moveWindowToWorkspace(window, workspace);
293 }
296void SurfaceManager::moveWorkspaceContentToWorkspace(const std::shared_ptr<miral::Workspace> &to,
297 const std::shared_ptr<miral::Workspace> &from)
299 WindowManagementPolicy::instance()->moveWorkspaceContentToWorkspace(to, from);
302void SurfaceManager::onStateRequested(MirSurface *surface, Mir::State state)
304 DEBUG_MSG("("<<surface<<","<<state<<") started");
305 Q_EMIT modificationsStarted();
306 m_underModification = true;
308 surface->setPreviousState(surface->state());
309 surface->setState(state);
311 if ((state == Mir::MinimizedState || state == Mir::HiddenState) && surface->focused()) {
312 Q_ASSERT(m_focusedSurface == surface);
313 surface->setFocused(false);
314 m_focusedSurface = nullptr;
315 focusFirstAvailableSurface();
316 }
318 m_underModification = false;
319 Q_EMIT modificationsEnded();
320 DEBUG_MSG("("<<surface<<","<<state<<") ended");
323void SurfaceManager::onSurfaceDestroyed(MirSurface *surface)
325 m_surfaces.removeAll(surface);
327 auto iter = m_surfaceToWindow.find(surface);
328 if (iter != m_surfaceToWindow.end()) {
329 WindowWrapper key = iter.value();
330 m_windowToSurface.remove(key);
331 m_surfaceToWindow.erase(iter);
332 }
334 if (m_focusedSurface == surface) {
335 m_focusedSurface = nullptr;
337 Q_EMIT modificationsStarted();
338 m_underModification = true;
340 focusFirstAvailableSurface();
342 m_underModification = false;
343 Q_EMIT modificationsEnded();
344 }
345 Q_EMIT surfaceRemoved(surface);
348void SurfaceManager::focusFirstAvailableSurface()
350 MirSurface *chosenSurface = nullptr;
351 for (int i = 0; i < m_surfaces.count() && !chosenSurface; ++i) {
352 auto *surface = m_surfaces[i];
353 if (surface->state() != Mir::HiddenState && surface->state() != Mir::MinimizedState) {
354 chosenSurface = surface;
355 }
356 }
358 if (!chosenSurface) {
359 return;
360 }
362 if (m_focusedSurface) {
363 m_focusedSurface->setFocused(false);
364 }
366 chosenSurface->setFocused(true);
367 doRaise(chosenSurface);
369 m_focusedSurface = chosenSurface;
372void SurfaceManager::createInputMethodSurface()
374 if (!m_virtualKeyboard) {
375 m_virtualKeyboard = new VirtualKeyboard;
376 registerSurface(m_virtualKeyboard);
378 WindowManagementPolicy::instance()->addWindow(m_surfaceToWindow[m_virtualKeyboard].window);
379 }
382void SurfaceManager::releaseInputMethodSurface()
384 if (m_virtualKeyboard) {
385 m_virtualKeyboard->setLive(false);
386 m_virtualKeyboard = nullptr;
387 }