Merge lp:~ci-train-bot/qtmir/qtmir-ubuntu-xenial-landing-064 into lp:qtmir

Proposed by Michał Sawicz
Status: Merged
Merged at revision: 462
Proposed branch: lp:~ci-train-bot/qtmir/qtmir-ubuntu-xenial-landing-064
Merge into: lp:qtmir
Diff against target: 4345 lines (+3483/-201)
42 files modified
debian/changelog (+30/-0)
debian/tests/control (+0/-5)
debian/tests/run-tests (+0/-10)
src/modules/Unity/Application/mirsurface.cpp (+5/-0)
src/modules/Unity/Application/mirsurfacemanager.cpp (+15/-0)
src/modules/Unity/Application/mirsurfacemanager.h (+5/-1)
src/platforms/mirserver/CMakeLists.txt (+2/-0)
src/platforms/mirserver/argvHelper.h (+52/-0)
src/platforms/mirserver/miropenglcontext.cpp (+7/-2)
src/platforms/mirserver/miropenglcontext.h (+2/-0)
src/platforms/mirserver/mirserver.cpp (+24/-11)
src/platforms/mirserver/mirserver.h (+1/-1)
src/platforms/mirserver/mirserverintegration.cpp (+2/-2)
src/platforms/mirserver/mirserverintegration.h (+1/-1)
src/platforms/mirserver/plugin.cpp (+4/-8)
src/platforms/mirserver/plugin.h (+1/-2)
src/platforms/mirserver/qmirserver.cpp (+2/-11)
src/platforms/mirserver/qmirserver.h (+1/-1)
src/platforms/mirserver/screen.cpp (+24/-4)
src/platforms/mirserver/screen.h (+3/-1)
src/platforms/mirserver/screenwindow.cpp (+1/-1)
src/platforms/mirserver/wm-wip/CMakeLists.txt (+22/-0)
src/platforms/mirserver/wm-wip/README (+5/-0)
src/platforms/mirserver/wm-wip/server_example_basic_window_manager.cpp (+312/-0)
src/platforms/mirserver/wm-wip/server_example_basic_window_manager.h (+252/-0)
src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.cpp (+946/-0)
src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.h (+132/-0)
src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.cpp (+640/-0)
src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.h (+124/-0)
src/platforms/mirserver/wm-wip/server_example_window_management.cpp (+155/-0)
src/platforms/mirserver/wm-wip/server_example_window_management.h (+33/-0)
src/platforms/mirserver/wm-wip/server_example_window_management_info.cpp (+406/-0)
src/platforms/mirserver/wm-wip/server_example_window_management_info.h (+103/-0)
tests/framework/mock_proc_info.cpp (+2/-0)
tests/framework/mock_session.cpp (+1/-0)
tests/framework/mock_task_controller.cpp (+4/-4)
tests/framework/qtmir_test.cpp (+2/-2)
tests/mirserver/ArgvHelper/CMakeLists.txt (+18/-0)
tests/mirserver/ArgvHelper/argvHelper_test.cpp (+72/-0)
tests/mirserver/CMakeLists.txt (+1/-0)
tests/mirserver/Screen/screen_test.cpp (+17/-3)
tests/modules/ApplicationManager/application_manager_test.cpp (+54/-131)
To merge this branch: bzr merge lp:~ci-train-bot/qtmir/qtmir-ubuntu-xenial-landing-064
Reviewer Review Type Date Requested Status
Mir development team Pending
Review via email: mp+288756@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2016-02-19 10:41:19 +0000
3+++ debian/changelog 2016-03-11 11:36:44 +0000
4@@ -1,3 +1,33 @@
5+qtmir (0.4.7+16.04.20160310.1-0ubuntu1) xenial; urgency=medium
6+
7+ [ Alan Griffiths ]
8+ * Copy the Window Management work-in-progress from Mir examples.
9+
10+ [ Alberto Aguirre ]
11+ * Hook MirOpenGLContext::doneCurrent to Screen::doneCurrent
12+
13+ [ Daniel d'Andrada ]
14+ * Ensure QmlEngine doesn't delete our MirSurfaces
15+
16+ [ Gerry Boland ]
17+ * Allow Mir remove command line arguments it understands, before
18+ letting Qt process them.
19+ * Ensure ScreenWindow geometry correctly set and used after moving
20+ Screen (LP: #1545286)
21+ * Screen: only enable orientation sensor for internal display. (LP:
22+ #1545286)
23+
24+ [ Michael Terry ]
25+ * Fix some mocks to use more realistic code paths.
26+
27+ [ Michael Zanetti ]
28+ * Add a dedicated property for the inputMethodSurface (LP: #1545286)
29+
30+ [ Michał Sawicz ]
31+ * Drop dummy autopkgtest
32+
33+ -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 10 Mar 2016 09:29:49 +0000
34+
35 qtmir (0.4.7+16.04.20160219-0ubuntu1) xenial; urgency=medium
36
37 * Mir 0.20 Release
38
39=== removed directory 'debian/tests'
40=== removed file 'debian/tests/control'
41--- debian/tests/control 2015-10-27 15:53:28 +0000
42+++ debian/tests/control 1970-01-01 00:00:00 +0000
43@@ -1,5 +0,0 @@
44-Tests: run-tests
45-Restrictions: build-needed
46-Depends: qtdeclarative5-qtmir-plugin,
47- qtmir-desktop,
48- qtmir-tests,
49
50=== removed file 'debian/tests/run-tests'
51--- debian/tests/run-tests 2015-06-15 15:57:04 +0000
52+++ debian/tests/run-tests 1970-01-01 00:00:00 +0000
53@@ -1,10 +0,0 @@
54-#!/bin/sh
55-
56-set -ex
57-
58-# Do nothing here. We don't need to run the tests multiple times, and they
59-# are already being run during the build phase of the autopkgtest, as we
60-# require a built tree to run them, and the tests are run as part of the
61-# normal package build process. We do want to test that things install, though
62-# and at least one test is actually required, for autopkgtest to work.
63-
64
65=== modified file 'src/modules/Unity/Application/mirsurface.cpp'
66--- src/modules/Unity/Application/mirsurface.cpp 2016-02-11 11:58:16 +0000
67+++ src/modules/Unity/Application/mirsurface.cpp 2016-03-11 11:36:44 +0000
68@@ -32,6 +32,9 @@
69 // mirserver
70 #include <logging.h>
71
72+// Qt
73+#include <QQmlEngine>
74+
75 using namespace qtmir;
76
77 #define DEBUG_MSG qCDebug(QTMIR_SURFACES).nospace() << "MirSurface[" << (void*)this << "," << appId() <<"]::" << __func__
78@@ -223,6 +226,8 @@
79 // in practice rarely happen.
80 m_frameDropperTimer.setInterval(200);
81 m_frameDropperTimer.setSingleShot(false);
82+
83+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
84 }
85
86 MirSurface::~MirSurface()
87
88=== modified file 'src/modules/Unity/Application/mirsurfacemanager.cpp'
89--- src/modules/Unity/Application/mirsurfacemanager.cpp 2016-02-11 11:58:16 +0000
90+++ src/modules/Unity/Application/mirsurfacemanager.cpp 2016-03-11 11:36:44 +0000
91@@ -114,6 +114,11 @@
92 if (session)
93 session->registerSurface(qmlSurface);
94
95+ if (qmlSurface->type() == Mir::InputMethodType) {
96+ m_inputMethodSurface = qmlSurface;
97+ Q_EMIT inputMethodSurfaceChanged();
98+ }
99+
100 // Only notify QML of surface creation once it has drawn its first frame.
101 connect(qmlSurface, &MirSurfaceInterface::firstFrameDrawn, this, [=]() {
102 tracepoint(qtmir, firstFrameDrawn);
103@@ -155,8 +160,18 @@
104 }
105 }
106
107+ if (qmlSurface->type() == Mir::InputMethodType) {
108+ m_inputMethodSurface = nullptr;
109+ Q_EMIT inputMethodSurfaceChanged();
110+ }
111+
112 qmlSurface->setLive(false);
113 Q_EMIT surfaceDestroyed(qmlSurface);
114 }
115
116+MirSurfaceInterface* MirSurfaceManager::inputMethodSurface() const
117+{
118+ return m_inputMethodSurface;
119+}
120+
121 } // namespace qtmir
122
123=== modified file 'src/modules/Unity/Application/mirsurfacemanager.h'
124--- src/modules/Unity/Application/mirsurfacemanager.h 2016-02-11 11:58:16 +0000
125+++ src/modules/Unity/Application/mirsurfacemanager.h 2016-03-11 11:36:44 +0000
126@@ -54,7 +54,7 @@
127 class MirSurfaceManager : public QObject
128 {
129 Q_OBJECT
130-
131+ Q_PROPERTY(MirSurfaceInterface* inputMethodSurface READ inputMethodSurface NOTIFY inputMethodSurfaceChanged)
132 public:
133 explicit MirSurfaceManager(
134 const QSharedPointer<MirServer>& mirServer,
135@@ -66,7 +66,10 @@
136
137 static MirSurfaceManager* singleton();
138
139+ MirSurfaceInterface* inputMethodSurface() const;
140+
141 Q_SIGNALS:
142+ void inputMethodSurfaceChanged();
143 void surfaceCreated(MirSurfaceInterface* surface);
144 void surfaceDestroyed(MirSurfaceInterface* surface);
145
146@@ -86,6 +89,7 @@
147 mir::shell::Shell *const m_shell;
148 SessionManager* m_sessionManager;
149 static MirSurfaceManager *instance;
150+ MirSurfaceInterface* m_inputMethodSurface = nullptr;
151 };
152
153 } // namespace qtmir
154
155=== modified file 'src/platforms/mirserver/CMakeLists.txt'
156--- src/platforms/mirserver/CMakeLists.txt 2016-02-11 11:58:16 +0000
157+++ src/platforms/mirserver/CMakeLists.txt 2016-03-11 11:36:44 +0000
158@@ -36,6 +36,8 @@
159 ${APPLICATION_API_INCLUDE_DIRS}
160 )
161
162+add_subdirectory(wm-wip)
163+
164 # We have to remove -pedantic for tracepoints.c
165 string (REPLACE " -pedantic " " " CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
166 # Needed to compile tracepoints in C99 mode.
167
168=== added file 'src/platforms/mirserver/argvHelper.h'
169--- src/platforms/mirserver/argvHelper.h 1970-01-01 00:00:00 +0000
170+++ src/platforms/mirserver/argvHelper.h 2016-03-11 11:36:44 +0000
171@@ -0,0 +1,52 @@
172+/*
173+ * Copyright (C) 2015 Canonical, Ltd.
174+ *
175+ * This program is free software: you can redistribute it and/or modify it under
176+ * the terms of the GNU Lesser General Public License version 3, as published by
177+ * the Free Software Foundation.
178+ *
179+ * This program is distributed in the hope that it will be useful, but WITHOUT
180+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
181+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
182+ * Lesser General Public License for more details.
183+ *
184+ * You should have received a copy of the GNU Lesser General Public License
185+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
186+ */
187+
188+#ifndef ARGVHELPER_P_H
189+#define ARGVHELPER_P_H
190+
191+#include <cassert>
192+
193+namespace qtmir {
194+
195+// Function to edit argv to strip out unmatched entries of targetArray, so both arrays have identical contents
196+// Note: Mir parses out arguments that it understands, but it also removes argv[0] (bug pad.lv/1511509)
197+// so need to ensure argv[0] is the binary name as usual.
198+void editArgvToMatch(int &argcToEdit, char** argvToEdit, int targetCount, const char* const targetArray[])
199+{
200+ // Make copy of the argv array of pointers, as we will be editing the original
201+ const size_t arraySize = (argcToEdit + 1) * sizeof(char*);
202+ char** argvCopy = static_cast<char**>(malloc(arraySize));
203+ memcpy(argvCopy, argvToEdit, arraySize);
204+
205+ int k=1; // index of argv we want to edit - note we'll leave argv[0] alone
206+ for (int i=0; i<targetCount; i++) { // taking each argument Mir did not parse out
207+ for (int j=1; j<argcToEdit; j++) { // find pointer to same argument in argvCopy (leave arg[0] out)
208+ if (strcmp(targetArray[i], argvCopy[j]) == 0) {
209+ argvToEdit[k] = const_cast<char*>(argvCopy[j]); // edit argv to position that argument to match argv2.
210+ k++;
211+ break;
212+ }
213+ }
214+ }
215+ assert(k == targetCount+1);
216+ argvToEdit[k] = nullptr;
217+ free(argvCopy);
218+ argcToEdit = targetCount+1; // now argv and targetArray should have list the same strings.
219+}
220+
221+} // namespace qtmir
222+
223+#endif // ARGVHELPER_P_H
224
225=== modified file 'src/platforms/mirserver/miropenglcontext.cpp'
226--- src/platforms/mirserver/miropenglcontext.cpp 2015-09-14 22:38:20 +0000
227+++ src/platforms/mirserver/miropenglcontext.cpp 2016-03-11 11:36:44 +0000
228@@ -36,8 +36,9 @@
229 // (i.e. individual display output buffers) to use as a common base context.
230
231 MirOpenGLContext::MirOpenGLContext(const QSharedPointer<MirServer> &server, const QSurfaceFormat &format)
232+ : m_currentWindow(nullptr)
233 #ifndef QT_NO_DEBUG
234- : m_logger(new QOpenGLDebugLogger(this))
235+ , m_logger(new QOpenGLDebugLogger(this))
236 #endif
237 {
238 auto display = server->the_display();
239@@ -131,6 +132,7 @@
240 // ultimately calls Mir's DisplayBuffer::make_current()
241 ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface);
242 if (screenWindow) {
243+ m_currentWindow = screenWindow;
244 screenWindow->makeCurrent();
245
246 #ifndef QT_NO_DEBUG
247@@ -148,7 +150,10 @@
248
249 void MirOpenGLContext::doneCurrent()
250 {
251- // FIXME: create a temporary GL context just to release? Would be better to get existing one.
252+ if (m_currentWindow) {
253+ m_currentWindow->doneCurrent();
254+ m_currentWindow = nullptr;
255+ }
256 }
257
258 QFunctionPointer MirOpenGLContext::getProcAddress(const QByteArray &procName)
259
260=== modified file 'src/platforms/mirserver/miropenglcontext.h'
261--- src/platforms/mirserver/miropenglcontext.h 2015-09-14 22:38:20 +0000
262+++ src/platforms/mirserver/miropenglcontext.h 2016-03-11 11:36:44 +0000
263@@ -25,6 +25,7 @@
264
265
266 class MirServer;
267+class ScreenWindow;
268
269 class MirOpenGLContext : public QObject, public QPlatformOpenGLContext
270 {
271@@ -49,6 +50,7 @@
272
273 private:
274 QSurfaceFormat m_format;
275+ ScreenWindow *m_currentWindow;
276 #ifndef QT_NO_DEBUG
277 QOpenGLDebugLogger *m_logger;
278 #endif
279
280=== modified file 'src/platforms/mirserver/mirserver.cpp'
281--- src/platforms/mirserver/mirserver.cpp 2016-02-11 11:58:16 +0000
282+++ src/platforms/mirserver/mirserver.cpp 2016-03-11 11:36:44 +0000
283@@ -19,6 +19,7 @@
284 #include "mirserver.h"
285
286 // local
287+#include "argvHelper.h"
288 #include "mircursorimages.h"
289 #include "mirwindowmanager.h"
290 #include "mirglconfig.h"
291@@ -47,22 +48,24 @@
292 namespace msh = mir::shell;
293 namespace ms = mir::scene;
294
295-namespace
296-{
297-void ignore_unparsed_arguments(int /*argc*/, char const* const/*argv*/[])
298-{
299-}
300-}
301-
302 Q_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES, "qtmir.mir")
303
304-MirServer::MirServer(int argc, char const* argv[],
305+
306+MirServer::MirServer(int &argc, char **argv,
307 const QSharedPointer<ScreenController> &screenController, QObject* parent)
308 : QObject(parent)
309 , m_screenController(screenController)
310 {
311- set_command_line_handler(&ignore_unparsed_arguments);
312- set_command_line(argc, argv);
313+ bool unknownArgsFound = false;
314+ set_command_line_handler([&argc, &argv, &unknownArgsFound](int filteredCount, const char* const filteredArgv[]) {
315+ unknownArgsFound = true;
316+ // Want to edit argv to match that which Mir returns, as those are for to Qt alone to process. Edit existing
317+ // argc as filteredArgv only defined in this scope.
318+ qtmir::editArgvToMatch(argc, argv, filteredCount, filteredArgv);
319+ });
320+
321+ // Casting char** to be a const char** safe as Mir won't change it, nor will we
322+ set_command_line(argc, const_cast<const char **>(argv));
323
324 override_the_session_listener([]
325 {
326@@ -130,7 +133,16 @@
327 screenController->init(the_display(), the_compositor());
328 });
329
330- apply_settings();
331+ try {
332+ apply_settings();
333+ } catch (const std::exception &ex) {
334+ qCritical() << ex.what();
335+ exit(1);
336+ }
337+
338+ if (!unknownArgsFound) { // mir parsed all the arguments, so edit argv to pretend to have just argv[0]
339+ argc = 1;
340+ }
341
342 // We will draw our own cursor.
343 // FIXME: Call override_the_cusor() instead once this method becomes available in a
344@@ -142,6 +154,7 @@
345 });
346
347 qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created";
348+ qCDebug(QTMIR_MIR_MESSAGES) << "Command line arguments passed to Qt:" << QCoreApplication::arguments();
349 }
350
351 // Override default implementation to ensure we terminate the ScreenController first.
352
353=== modified file 'src/platforms/mirserver/mirserver.h'
354--- src/platforms/mirserver/mirserver.h 2016-02-11 11:54:59 +0000
355+++ src/platforms/mirserver/mirserver.h 2016-03-11 11:36:44 +0000
356@@ -41,7 +41,7 @@
357 Q_PROPERTY(PromptSessionListener* promptSessionListener READ promptSessionListener CONSTANT)
358
359 public:
360- MirServer(int argc, char const* argv[], const QSharedPointer<ScreenController> &, QObject* parent = 0);
361+ MirServer(int &argc, char **argv, const QSharedPointer<ScreenController> &, QObject* parent = 0);
362 ~MirServer() = default;
363
364 /* mir specific */
365
366=== modified file 'src/platforms/mirserver/mirserverintegration.cpp'
367--- src/platforms/mirserver/mirserverintegration.cpp 2015-10-21 11:46:33 +0000
368+++ src/platforms/mirserver/mirserverintegration.cpp 2016-03-11 11:36:44 +0000
369@@ -51,11 +51,11 @@
370 namespace mg = mir::graphics;
371 using qtmir::Clipboard;
372
373-MirServerIntegration::MirServerIntegration()
374+MirServerIntegration::MirServerIntegration(int &argc, char **argv)
375 : m_accessibility(new QPlatformAccessibility())
376 , m_fontDb(new QGenericUnixFontDatabase())
377 , m_services(new Services)
378- , m_mirServer(new QMirServer(QCoreApplication::arguments()))
379+ , m_mirServer(new QMirServer(argc, argv))
380 , m_nativeInterface(nullptr)
381 , m_clipboard(new Clipboard)
382 {
383
384=== modified file 'src/platforms/mirserver/mirserverintegration.h'
385--- src/platforms/mirserver/mirserverintegration.h 2015-08-20 10:16:54 +0000
386+++ src/platforms/mirserver/mirserverintegration.h 2016-03-11 11:36:44 +0000
387@@ -31,7 +31,7 @@
388 class MirServerIntegration : public QPlatformIntegration
389 {
390 public:
391- MirServerIntegration();
392+ MirServerIntegration(int &argc, char **argv);
393 ~MirServerIntegration();
394
395 bool hasCapability(QPlatformIntegration::Capability cap) const override;
396
397=== modified file 'src/platforms/mirserver/plugin.cpp'
398--- src/platforms/mirserver/plugin.cpp 2015-08-11 12:08:32 +0000
399+++ src/platforms/mirserver/plugin.cpp 2016-03-11 11:36:44 +0000
400@@ -17,14 +17,10 @@
401 #include "plugin.h"
402 #include "mirserverintegration.h"
403
404-QStringList MirServerIntegrationPlugin::keys() const {
405- QStringList list;
406- list << "mirserver";
407- return list;
408-}
409-
410-QPlatformIntegration* MirServerIntegrationPlugin::create(const QString &system, const QStringList &) {
411+QPlatformIntegration *MirServerIntegrationPlugin::create(const QString &system, const QStringList &/*paramList*/,
412+ int &argc, char **argv)
413+{
414 if (system.toLower() == "mirserver")
415- return new MirServerIntegration;
416+ return new MirServerIntegration(argc, argv);
417 return 0;
418 }
419
420=== modified file 'src/platforms/mirserver/plugin.h'
421--- src/platforms/mirserver/plugin.h 2015-08-11 12:08:32 +0000
422+++ src/platforms/mirserver/plugin.h 2016-03-11 11:36:44 +0000
423@@ -25,8 +25,7 @@
424 Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "mirserver.json")
425
426 public:
427- QStringList keys() const;
428- QPlatformIntegration* create(const QString&, const QStringList&);
429+ QPlatformIntegration *create(const QString &system, const QStringList &paramList, int &argc, char **argv) override;
430 };
431
432 #endif // PLUGIN_H
433
434=== modified file 'src/platforms/mirserver/qmirserver.cpp'
435--- src/platforms/mirserver/qmirserver.cpp 2015-11-19 12:55:57 +0000
436+++ src/platforms/mirserver/qmirserver.cpp 2016-03-11 11:36:44 +0000
437@@ -26,24 +26,15 @@
438 #include "screencontroller.h"
439 #include "screen.h"
440
441-QMirServer::QMirServer(const QStringList &arguments, QObject *parent)
442+QMirServer::QMirServer(int &argc, char **argv, QObject *parent)
443 : QObject(parent)
444 , d_ptr(new QMirServerPrivate())
445 {
446 Q_D(QMirServer);
447
448- // convert arguments back into argc-argv form that Mir wants
449- int argc = arguments.size();
450- char **argv = new char*[argc + 1];
451- for (int i = 0; i < argc; i++) {
452- argv[i] = new char[strlen(arguments.at(i).toStdString().c_str())+1];
453- memcpy(argv[i], arguments.at(i).toStdString().c_str(), strlen(arguments.at(i).toStdString().c_str())+1);
454- }
455- argv[argc] = nullptr;
456-
457 d->screenController = QSharedPointer<ScreenController>(new ScreenController());
458
459- d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv), d->screenController));
460+ d->server = QSharedPointer<MirServer>(new MirServer(argc, argv, d->screenController));
461
462 d->serverThread = new MirServerThread(d->server);
463
464
465=== modified file 'src/platforms/mirserver/qmirserver.h'
466--- src/platforms/mirserver/qmirserver.h 2015-08-20 10:16:54 +0000
467+++ src/platforms/mirserver/qmirserver.h 2016-03-11 11:36:44 +0000
468@@ -30,7 +30,7 @@
469 Q_OBJECT
470
471 public:
472- QMirServer(const QStringList &arguments, QObject* parent=0);
473+ QMirServer(int &argc, char **argv, QObject* parent=0);
474 virtual ~QMirServer();
475
476 bool start();
477
478=== modified file 'src/platforms/mirserver/screen.cpp'
479--- src/platforms/mirserver/screen.cpp 2015-10-14 22:59:04 +0000
480+++ src/platforms/mirserver/screen.cpp 2016-03-11 11:36:44 +0000
481@@ -135,9 +135,11 @@
482 ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
483 qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen - initial currentOrientation is:" << m_currentOrientation;
484
485- QObject::connect(m_orientationSensor, &QOrientationSensor::readingChanged,
486- this, &Screen::onOrientationReadingChanged);
487- m_orientationSensor->start();
488+ if (internalDisplay()) { // only enable orientation sensor for device-internal display
489+ QObject::connect(m_orientationSensor, &QOrientationSensor::readingChanged,
490+ this, &Screen::onOrientationReadingChanged);
491+ m_orientationSensor->start();
492+ }
493
494 if (!skipDBusRegistration) {
495 // FIXME This is a unity8 specific dbus call and shouldn't be in qtmir
496@@ -171,7 +173,9 @@
497 void Screen::onDisplayPowerStateChanged(int status, int reason)
498 {
499 Q_UNUSED(reason);
500- toggleSensors(status);
501+ if (internalDisplay()) {
502+ toggleSensors(status);
503+ }
504 }
505
506 void Screen::setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &screen)
507@@ -297,6 +301,13 @@
508 qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen::setWindow - overwriting existing ScreenWindow";
509 }
510 m_screenWindow = window;
511+
512+ if (m_screenWindow) {
513+ if (m_screenWindow->geometry() != geometry()) {
514+ qCDebug(QTMIR_SCREENS) << "Screen::setWindow - new geometry for shell surface" << window->window() << geometry();
515+ m_screenWindow->setGeometry(geometry());
516+ }
517+ }
518 }
519
520 void Screen::setMirDisplayBuffer(mir::graphics::DisplayBuffer *buffer, mir::graphics::DisplaySyncGroup *group)
521@@ -334,3 +345,12 @@
522 {
523 m_renderTarget->release_current();
524 }
525+
526+bool Screen::internalDisplay() const
527+{
528+ using namespace mir::graphics;
529+ if (m_type == DisplayConfigurationOutputType::lvds || m_type == DisplayConfigurationOutputType::edp) {
530+ return true;
531+ }
532+ return false;
533+}
534
535=== modified file 'src/platforms/mirserver/screen.h'
536--- src/platforms/mirserver/screen.h 2015-10-14 22:59:04 +0000
537+++ src/platforms/mirserver/screen.h 2016-03-11 11:36:44 +0000
538@@ -53,7 +53,6 @@
539 Qt::ScreenOrientation orientation() const override { return m_currentOrientation; }
540 QPlatformCursor *cursor() const override;
541
542- void toggleSensors(const bool enable) const;
543 mir::graphics::DisplayConfigurationOutputType outputType() const { return m_type; }
544
545 ScreenWindow* window() const;
546@@ -79,6 +78,9 @@
547 void doneCurrent();
548
549 private:
550+ void toggleSensors(const bool enable) const;
551+ bool internalDisplay() const;
552+
553 QRect m_geometry;
554 int m_depth;
555 QImage::Format m_format;
556
557=== modified file 'src/platforms/mirserver/screenwindow.cpp'
558--- src/platforms/mirserver/screenwindow.cpp 2015-10-15 07:05:16 +0000
559+++ src/platforms/mirserver/screenwindow.cpp 2016-03-11 11:36:44 +0000
560@@ -89,7 +89,7 @@
561 auto renderer = QSGRenderLoop::instance();
562 if (exposed) {
563 renderer->show(quickWindow);
564- QWindowSystemInterface::handleExposeEvent(window(), QRegion()); // else it won't redraw
565+ QWindowSystemInterface::handleExposeEvent(window(), geometry()); // else it won't redraw
566 } else {
567 quickWindow->setPersistentOpenGLContext(false);
568 quickWindow->setPersistentSceneGraph(false);
569
570=== added directory 'src/platforms/mirserver/wm-wip'
571=== added file 'src/platforms/mirserver/wm-wip/CMakeLists.txt'
572--- src/platforms/mirserver/wm-wip/CMakeLists.txt 1970-01-01 00:00:00 +0000
573+++ src/platforms/mirserver/wm-wip/CMakeLists.txt 2016-03-11 11:36:44 +0000
574@@ -0,0 +1,22 @@
575+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fPIC")
576+
577+add_library(experimentalwindowmanager STATIC
578+ server_example_basic_window_manager.cpp
579+ server_example_basic_window_manager.h
580+ server_example_window_management_info.cpp
581+ server_example_window_management_info.h
582+)
583+
584+
585+if (EXAMPLE_MIR_WINDOW_MANAGERS)
586+
587+add_library(examplewindowmanager STATIC
588+ server_example_canonical_window_manager.h
589+ server_example_tiling_window_manager.h
590+ server_example_window_management.h
591+ server_example_canonical_window_manager.cpp
592+ server_example_tiling_window_manager.cpp
593+ server_example_window_management.cpp
594+)
595+
596+endif()
597
598=== added file 'src/platforms/mirserver/wm-wip/README'
599--- src/platforms/mirserver/wm-wip/README 1970-01-01 00:00:00 +0000
600+++ src/platforms/mirserver/wm-wip/README 2016-03-11 11:36:44 +0000
601@@ -0,0 +1,5 @@
602+examples for mir clients. you should have package 'libmirclient-dev' installed
603+
604+you can compile with a command like:
605+ g++ -std=c++0x -o mir_demo_client_scroll `pkg-config --libs --cflags mirclient` demo_client_scroll.cpp graphics_utils.cpp
606+ gcc -o mir_demo_client_flicker `pkg-config --libs --cflags mirclient` demo_client_flicker.c
607
608=== added file 'src/platforms/mirserver/wm-wip/server_example_basic_window_manager.cpp'
609--- src/platforms/mirserver/wm-wip/server_example_basic_window_manager.cpp 1970-01-01 00:00:00 +0000
610+++ src/platforms/mirserver/wm-wip/server_example_basic_window_manager.cpp 2016-03-11 11:36:44 +0000
611@@ -0,0 +1,312 @@
612+/*
613+ * Copyright © 2015 Canonical Ltd.
614+ *
615+ * This program is free software: you can redistribute it and/or modify it
616+ * under the terms of the GNU General Public License version 3,
617+ * as published by the Free Software Foundation.
618+ *
619+ * This program is distributed in the hope that it will be useful,
620+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
621+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
622+ * GNU General Public License for more details.
623+ *
624+ * You should have received a copy of the GNU General Public License
625+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
626+ *
627+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
628+ */
629+
630+#include "server_example_basic_window_manager.h"
631+
632+#include "mir/scene/session.h"
633+#include "mir/scene/surface.h"
634+#include "mir/scene/surface_creation_parameters.h"
635+
636+namespace me = mir::examples;
637+
638+me::BasicWindowManager::BasicWindowManager(
639+ shell::FocusController* focus_controller,
640+ std::unique_ptr<WindowManagementPolicy> policy) :
641+ focus_controller(focus_controller),
642+ policy(std::move(policy))
643+{
644+}
645+
646+void me::BasicWindowManager::add_session(std::shared_ptr<scene::Session> const& session)
647+{
648+ std::lock_guard<decltype(mutex)> lock(mutex);
649+ session_info[session] = SessionInfo();
650+ policy->handle_session_info_updated(session_info, displays);
651+}
652+
653+void me::BasicWindowManager::remove_session(std::shared_ptr<scene::Session> const& session)
654+{
655+ std::lock_guard<decltype(mutex)> lock(mutex);
656+ session_info.erase(session);
657+ policy->handle_session_info_updated(session_info, displays);
658+}
659+
660+auto me::BasicWindowManager::add_surface(
661+ std::shared_ptr<scene::Session> const& session,
662+ scene::SurfaceCreationParameters const& params,
663+ std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build)
664+-> frontend::SurfaceId
665+{
666+ std::lock_guard<decltype(mutex)> lock(mutex);
667+ scene::SurfaceCreationParameters const placed_params = policy->handle_place_new_surface(session, params);
668+ auto const result = build(session, placed_params);
669+ auto const surface = session->surface(result);
670+ surface_info.emplace(surface, SurfaceInfo{session, surface, placed_params});
671+ policy->handle_new_surface(session, surface);
672+ policy->generate_decorations_for(session, surface, surface_info, build);
673+ return result;
674+}
675+
676+void me::BasicWindowManager::modify_surface(
677+ std::shared_ptr<scene::Session> const& session,
678+ std::shared_ptr<scene::Surface> const& surface,
679+ shell::SurfaceSpecification const& modifications)
680+{
681+ std::lock_guard<decltype(mutex)> lock(mutex);
682+ policy->handle_modify_surface(session, surface, modifications);
683+}
684+
685+void me::BasicWindowManager::remove_surface(
686+ std::shared_ptr<scene::Session> const& session,
687+ std::weak_ptr<scene::Surface> const& surface)
688+{
689+ std::lock_guard<decltype(mutex)> lock(mutex);
690+ policy->handle_delete_surface(session, surface);
691+
692+ surface_info.erase(surface);
693+}
694+
695+void me::BasicWindowManager::forget(std::weak_ptr<scene::Surface> const& surface)
696+{
697+ surface_info.erase(surface);
698+}
699+
700+void me::BasicWindowManager::add_display(geometry::Rectangle const& area)
701+{
702+ std::lock_guard<decltype(mutex)> lock(mutex);
703+ displays.add(area);
704+ policy->handle_displays_updated(session_info, displays);
705+}
706+
707+void me::BasicWindowManager::remove_display(geometry::Rectangle const& area)
708+{
709+ std::lock_guard<decltype(mutex)> lock(mutex);
710+ displays.remove(area);
711+ policy->handle_displays_updated(session_info, displays);
712+}
713+
714+bool me::BasicWindowManager::handle_keyboard_event(MirKeyboardEvent const* event)
715+{
716+ std::lock_guard<decltype(mutex)> lock(mutex);
717+ update_event_timestamp(event);
718+ return policy->handle_keyboard_event(event);
719+}
720+
721+bool me::BasicWindowManager::handle_touch_event(MirTouchEvent const* event)
722+{
723+ std::lock_guard<decltype(mutex)> lock(mutex);
724+ update_event_timestamp(event);
725+ return policy->handle_touch_event(event);
726+}
727+
728+bool me::BasicWindowManager::handle_pointer_event(MirPointerEvent const* event)
729+{
730+ std::lock_guard<decltype(mutex)> lock(mutex);
731+ update_event_timestamp(event);
732+
733+ cursor = {
734+ mir_pointer_event_axis_value(event, mir_pointer_axis_x),
735+ mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
736+
737+ return policy->handle_pointer_event(event);
738+}
739+
740+void me::BasicWindowManager::handle_raise_surface(
741+ std::shared_ptr<scene::Session> const& session,
742+ std::shared_ptr<scene::Surface> const& surface,
743+ uint64_t timestamp)
744+{
745+ std::lock_guard<decltype(mutex)> lock(mutex);
746+ if (timestamp >= last_input_event_timestamp)
747+ policy->handle_raise_surface(session, surface);
748+}
749+
750+int me::BasicWindowManager::set_surface_attribute(
751+ std::shared_ptr<scene::Session> const& /*session*/,
752+ std::shared_ptr<scene::Surface> const& surface,
753+ MirSurfaceAttrib attrib,
754+ int value)
755+{
756+ std::lock_guard<decltype(mutex)> lock(mutex);
757+ switch (attrib)
758+ {
759+ case mir_surface_attrib_state:
760+ {
761+ auto const state = policy->handle_set_state(surface, MirSurfaceState(value));
762+ return surface->configure(attrib, state);
763+ }
764+ default:
765+ return surface->configure(attrib, value);
766+ }
767+}
768+
769+auto me::BasicWindowManager::find_session(std::function<bool(SessionInfo const& info)> const& predicate)
770+-> std::shared_ptr<scene::Session>
771+ {
772+ for(auto& info : session_info)
773+ {
774+ if (predicate(info.second))
775+ {
776+ return info.first.lock();
777+ }
778+ }
779+
780+ return std::shared_ptr<scene::Session>{};
781+ }
782+
783+auto me::BasicWindowManager::info_for(std::weak_ptr<scene::Session> const& session) const
784+-> SessionInfo&
785+{
786+ return const_cast<SessionInfo&>(session_info.at(session));
787+}
788+
789+auto me::BasicWindowManager::info_for(std::weak_ptr<scene::Surface> const& surface) const
790+-> SurfaceInfo&
791+{
792+ return const_cast<SurfaceInfo&>(surface_info.at(surface));
793+}
794+
795+auto me::BasicWindowManager::focused_session() const
796+-> std::shared_ptr<scene::Session>
797+{
798+ return focus_controller->focused_session();
799+}
800+
801+auto me::BasicWindowManager::focused_surface() const
802+->std::shared_ptr<scene::Surface>
803+{
804+ return focus_controller->focused_surface();
805+}
806+
807+void me::BasicWindowManager::focus_next_session()
808+{
809+ focus_controller->focus_next_session();
810+}
811+
812+void me::BasicWindowManager::set_focus_to(
813+ std::shared_ptr<scene::Session> const& focus,
814+ std::shared_ptr<scene::Surface> const& surface)
815+{
816+ focus_controller->set_focus_to(focus, surface);
817+}
818+
819+auto me::BasicWindowManager::surface_at(geometry::Point cursor) const
820+-> std::shared_ptr<scene::Surface>
821+{
822+ return focus_controller->surface_at(cursor);
823+}
824+
825+auto me::BasicWindowManager::active_display()
826+-> geometry::Rectangle const
827+{
828+ geometry::Rectangle result;
829+
830+ // 1. If a window has input focus, whichever display contains the largest
831+ // proportion of the area of that window.
832+ if (auto const surface = focused_surface())
833+ {
834+ auto const surface_rect = surface->input_bounds();
835+ int max_overlap_area = -1;
836+
837+ for (auto const& display : displays)
838+ {
839+ auto const intersection = surface_rect.intersection_with(display).size;
840+ if (intersection.width.as_int()*intersection.height.as_int() > max_overlap_area)
841+ {
842+ max_overlap_area = intersection.width.as_int()*intersection.height.as_int();
843+ result = display;
844+ }
845+ }
846+ return result;
847+ }
848+
849+ // 2. Otherwise, if any window previously had input focus, for the window that had
850+ // it most recently, the display that contained the largest proportion of the
851+ // area of that window at the moment it closed, as long as that display is still
852+ // available.
853+
854+ // 3. Otherwise, the display that contains the pointer, if there is one.
855+ for (auto const& display : displays)
856+ {
857+ if (display.contains(cursor))
858+ {
859+ // Ignore the (unspecified) possiblity of overlapping displays
860+ return display;
861+ }
862+ }
863+
864+ // 4. Otherwise, the primary display, if there is one (for example, the laptop display).
865+
866+ // 5. Otherwise, the first display.
867+ if (displays.size())
868+ result = *displays.begin();
869+
870+ return result;
871+}
872+
873+void me::BasicWindowManager::raise_tree(std::shared_ptr<scene::Surface> const& root)
874+{
875+ SurfaceSet surfaces;
876+ std::function<void(std::weak_ptr<scene::Surface> const& surface)> const add_children =
877+ [&,this](std::weak_ptr<scene::Surface> const& surface)
878+ {
879+ auto const& info = info_for(surface);
880+ surfaces.insert(begin(info.children), end(info.children));
881+ for (auto const& child : info.children)
882+ add_children(child);
883+ };
884+
885+ surfaces.insert(root);
886+ add_children(root);
887+
888+ focus_controller->raise(surfaces);
889+}
890+
891+void me::BasicWindowManager::update_event_timestamp(MirKeyboardEvent const* kev)
892+{
893+ auto iev = mir_keyboard_event_input_event(kev);
894+ last_input_event_timestamp = mir_input_event_get_event_time(iev);
895+}
896+
897+void me::BasicWindowManager::update_event_timestamp(MirPointerEvent const* pev)
898+{
899+ auto iev = mir_pointer_event_input_event(pev);
900+ auto pointer_action = mir_pointer_event_action(pev);
901+
902+ if (pointer_action == mir_pointer_action_button_up ||
903+ pointer_action == mir_pointer_action_button_down)
904+ {
905+ last_input_event_timestamp = mir_input_event_get_event_time(iev);
906+ }
907+}
908+
909+void me::BasicWindowManager::update_event_timestamp(MirTouchEvent const* tev)
910+{
911+ auto iev = mir_touch_event_input_event(tev);
912+ auto touch_count = mir_touch_event_point_count(tev);
913+ for (unsigned i = 0; i < touch_count; i++)
914+ {
915+ auto touch_action = mir_touch_event_action(tev, i);
916+ if (touch_action == mir_touch_action_up ||
917+ touch_action == mir_touch_action_down)
918+ {
919+ last_input_event_timestamp = mir_input_event_get_event_time(iev);
920+ break;
921+ }
922+ }
923+}
924
925=== added file 'src/platforms/mirserver/wm-wip/server_example_basic_window_manager.h'
926--- src/platforms/mirserver/wm-wip/server_example_basic_window_manager.h 1970-01-01 00:00:00 +0000
927+++ src/platforms/mirserver/wm-wip/server_example_basic_window_manager.h 2016-03-11 11:36:44 +0000
928@@ -0,0 +1,252 @@
929+/*
930+ * Copyright © 2015 Canonical Ltd.
931+ *
932+ * This program is free software: you can redistribute it and/or modify it
933+ * under the terms of the GNU General Public License version 3,
934+ * as published by the Free Software Foundation.
935+ *
936+ * This program is distributed in the hope that it will be useful,
937+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
938+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
939+ * GNU General Public License for more details.
940+ *
941+ * You should have received a copy of the GNU General Public License
942+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
943+ *
944+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
945+ */
946+
947+#ifndef MIR_EXAMPLE_BASIC_WINDOW_MANAGER_H_
948+#define MIR_EXAMPLE_BASIC_WINDOW_MANAGER_H_
949+
950+#include "server_example_window_management_info.h"
951+
952+#include "mir/geometry/rectangles.h"
953+#include "mir/shell/abstract_shell.h"
954+#include "mir/shell/window_manager.h"
955+
956+#include <map>
957+#include <mutex>
958+
959+///\example server_example_basic_window_manager.h
960+/// A generic policy-based window manager implementation
961+
962+namespace mir
963+{
964+namespace examples
965+{
966+using shell::SurfaceSet;
967+
968+/// The interface through which the policy instructs the controller.
969+/// These functions assume that the BasicWindowManager data structures can be accessed freely.
970+/// I.e. should only be invoked by the policy handle_... methods (where any necessary locks are held).
971+class WindowManagerTools
972+{
973+public:
974+ using SurfaceInfoMap = std::map<std::weak_ptr<scene::Surface>, SurfaceInfo, std::owner_less<std::weak_ptr<scene::Surface>>>;
975+ using SessionInfoMap = std::map<std::weak_ptr<scene::Session>, SessionInfo, std::owner_less<std::weak_ptr<scene::Session>>>;
976+
977+ virtual auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
978+ -> std::shared_ptr<scene::Session> = 0;
979+
980+ virtual auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& = 0;
981+
982+ virtual auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& = 0;
983+
984+ virtual std::shared_ptr<scene::Session> focused_session() const = 0;
985+
986+ virtual std::shared_ptr<scene::Surface> focused_surface() const = 0;
987+
988+ virtual void focus_next_session() = 0;
989+
990+ virtual void set_focus_to(
991+ std::shared_ptr<scene::Session> const& focus,
992+ std::shared_ptr<scene::Surface> const& surface) = 0;
993+
994+ virtual auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> = 0;
995+
996+ virtual auto active_display() -> geometry::Rectangle const = 0;
997+
998+ virtual void forget(std::weak_ptr<scene::Surface> const& surface) = 0;
999+
1000+ virtual void raise_tree(std::shared_ptr<scene::Surface> const& root) = 0;
1001+
1002+ virtual ~WindowManagerTools() = default;
1003+ WindowManagerTools() = default;
1004+ WindowManagerTools(WindowManagerTools const&) = delete;
1005+ WindowManagerTools& operator=(WindowManagerTools const&) = delete;
1006+};
1007+
1008+class WindowManagementPolicy
1009+{
1010+public:
1011+ using SessionInfoMap = typename WindowManagerTools::SessionInfoMap;
1012+ using SurfaceInfoMap = typename WindowManagerTools::SurfaceInfoMap;
1013+
1014+ virtual void handle_session_info_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays) = 0;
1015+
1016+ virtual void handle_displays_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays) = 0;
1017+
1018+ virtual auto handle_place_new_surface(
1019+ std::shared_ptr<scene::Session> const& session,
1020+ scene::SurfaceCreationParameters const& request_parameters)
1021+ -> scene::SurfaceCreationParameters = 0;
1022+
1023+ virtual void handle_new_surface(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface) = 0;
1024+
1025+ virtual void handle_modify_surface(
1026+ std::shared_ptr<scene::Session> const& session,
1027+ std::shared_ptr<scene::Surface> const& surface,
1028+ shell::SurfaceSpecification const& modifications) = 0;
1029+
1030+ virtual void handle_delete_surface(std::shared_ptr<scene::Session> const& session, std::weak_ptr<scene::Surface> const& surface) = 0;
1031+
1032+ virtual int handle_set_state(std::shared_ptr<scene::Surface> const& surface, MirSurfaceState value) = 0;
1033+
1034+ virtual void generate_decorations_for(
1035+ std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface,
1036+ SurfaceInfoMap& surface_info,
1037+ std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const&, scene::SurfaceCreationParameters const&)> const& build) = 0;
1038+
1039+ virtual bool handle_keyboard_event(MirKeyboardEvent const* event) = 0;
1040+
1041+ virtual bool handle_touch_event(MirTouchEvent const* event) = 0;
1042+
1043+ virtual bool handle_pointer_event(MirPointerEvent const* event) = 0;
1044+
1045+ virtual void handle_raise_surface(
1046+ std::shared_ptr<scene::Session> const& session,
1047+ std::shared_ptr<scene::Surface> const& surface) = 0;
1048+
1049+ virtual ~WindowManagementPolicy() = default;
1050+ WindowManagementPolicy() = default;
1051+ WindowManagementPolicy(WindowManagementPolicy const&) = delete;
1052+ WindowManagementPolicy& operator=(WindowManagementPolicy const&) = delete;
1053+};
1054+
1055+/// A policy based window manager.
1056+/// This takes care of the management of any meta implementation held for the sessions and surfaces.
1057+class BasicWindowManager : public virtual shell::WindowManager,
1058+ protected WindowManagerTools
1059+{
1060+protected:
1061+ BasicWindowManager(
1062+ shell::FocusController* focus_controller,
1063+ std::unique_ptr<WindowManagementPolicy> policy);
1064+
1065+public:
1066+ using typename WindowManagerTools::SurfaceInfoMap;
1067+ using typename WindowManagerTools::SessionInfoMap;
1068+
1069+ void add_session(std::shared_ptr<scene::Session> const& session) override;
1070+
1071+ void remove_session(std::shared_ptr<scene::Session> const& session) override;
1072+
1073+ auto add_surface(
1074+ std::shared_ptr<scene::Session> const& session,
1075+ scene::SurfaceCreationParameters const& params,
1076+ std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build)
1077+ -> frontend::SurfaceId override;
1078+
1079+ void modify_surface(
1080+ std::shared_ptr<scene::Session> const& session,
1081+ std::shared_ptr<scene::Surface> const& surface,
1082+ shell::SurfaceSpecification const& modifications) override;
1083+
1084+ void remove_surface(
1085+ std::shared_ptr<scene::Session> const& session,
1086+ std::weak_ptr<scene::Surface> const& surface) override;
1087+
1088+ void forget(std::weak_ptr<scene::Surface> const& surface) override;
1089+
1090+ void add_display(geometry::Rectangle const& area) override;
1091+
1092+ void remove_display(geometry::Rectangle const& area) override;
1093+
1094+ bool handle_keyboard_event(MirKeyboardEvent const* event) override;
1095+
1096+ bool handle_touch_event(MirTouchEvent const* event) override;
1097+
1098+ bool handle_pointer_event(MirPointerEvent const* event) override;
1099+
1100+ void handle_raise_surface(
1101+ std::shared_ptr<scene::Session> const& session,
1102+ std::shared_ptr<scene::Surface> const& surface,
1103+ uint64_t timestamp) override;
1104+
1105+ int set_surface_attribute(
1106+ std::shared_ptr<scene::Session> const& /*session*/,
1107+ std::shared_ptr<scene::Surface> const& surface,
1108+ MirSurfaceAttrib attrib,
1109+ int value) override;
1110+
1111+ auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
1112+ -> std::shared_ptr<scene::Session> override;
1113+
1114+ auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& override;
1115+
1116+ auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& override;
1117+
1118+ std::shared_ptr<scene::Session> focused_session() const override;
1119+
1120+ std::shared_ptr<scene::Surface> focused_surface() const override;
1121+
1122+ void focus_next_session() override;
1123+
1124+ void set_focus_to(
1125+ std::shared_ptr<scene::Session> const& focus,
1126+ std::shared_ptr<scene::Surface> const& surface) override;
1127+
1128+ auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> override;
1129+
1130+ auto active_display() -> geometry::Rectangle const override;
1131+
1132+ void raise_tree(std::shared_ptr<scene::Surface> const& root) override;
1133+
1134+private:
1135+ shell::FocusController* const focus_controller;
1136+ std::unique_ptr<WindowManagementPolicy> const policy;
1137+
1138+ std::mutex mutex;
1139+ SessionInfoMap session_info;
1140+ SurfaceInfoMap surface_info;
1141+ geometry::Rectangles displays;
1142+ geometry::Point cursor;
1143+ uint64_t last_input_event_timestamp{0};
1144+
1145+ void update_event_timestamp(MirKeyboardEvent const* kev);
1146+ void update_event_timestamp(MirPointerEvent const* pev);
1147+ void update_event_timestamp(MirTouchEvent const* tev);
1148+};
1149+
1150+/// A policy based window manager. This exists to initialize BasicWindowManager and
1151+/// the WMPolicy (in an awkward manner).
1152+/// TODO revisit this initialization sequence.
1153+template<typename WMPolicy>
1154+class WindowManagerBuilder : public BasicWindowManager
1155+{
1156+public:
1157+
1158+ template <typename... PolicyArgs>
1159+ WindowManagerBuilder(
1160+ shell::FocusController* focus_controller,
1161+ PolicyArgs&&... policy_args) :
1162+ BasicWindowManager(
1163+ focus_controller,
1164+ build_policy(std::forward<PolicyArgs>(policy_args)...))
1165+ {
1166+ }
1167+
1168+private:
1169+ template <typename... PolicyArgs>
1170+ auto build_policy(PolicyArgs&&... policy_args)
1171+ -> std::unique_ptr<WMPolicy>
1172+ {
1173+ return std::unique_ptr<WMPolicy>(
1174+ new WMPolicy(this, std::forward<PolicyArgs>(policy_args)...));
1175+ }
1176+};
1177+}
1178+}
1179+
1180+#endif /* MIR_EXAMPLE_BASIC_WINDOW_MANAGER_H_ */
1181
1182=== added file 'src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.cpp'
1183--- src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.cpp 1970-01-01 00:00:00 +0000
1184+++ src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.cpp 2016-03-11 11:36:44 +0000
1185@@ -0,0 +1,946 @@
1186+/*
1187+ * Copyright © 2015 Canonical Ltd.
1188+ *
1189+ * This program is free software: you can redistribute it and/or modify it
1190+ * under the terms of the GNU General Public License version 3,
1191+ * as published by the Free Software Foundation.
1192+ *
1193+ * This program is distributed in the hope that it will be useful,
1194+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1195+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1196+ * GNU General Public License for more details.
1197+ *
1198+ * You should have received a copy of the GNU General Public License
1199+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1200+ *
1201+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
1202+ */
1203+
1204+#include "server_example_canonical_window_manager.h"
1205+
1206+#include "mir/scene/session.h"
1207+#include "mir/scene/surface.h"
1208+#include "mir/scene/surface_creation_parameters.h"
1209+#include "mir/shell/surface_ready_observer.h"
1210+#include "mir/shell/display_layout.h"
1211+
1212+#include <linux/input.h>
1213+#include <csignal>
1214+#include <algorithm>
1215+
1216+namespace me = mir::examples;
1217+namespace ms = mir::scene;
1218+using namespace mir::geometry;
1219+
1220+///\example server_example_canonical_window_manager.cpp
1221+// Based on "Mir and Unity: Surfaces, input, and displays (v0.3)"
1222+
1223+namespace
1224+{
1225+int const title_bar_height = 10;
1226+Size titlebar_size_for_window(Size window_size)
1227+{
1228+ return {window_size.width, Height{title_bar_height}};
1229+}
1230+
1231+Point titlebar_position_for_window(Point window_position)
1232+{
1233+ return {
1234+ window_position.x,
1235+ window_position.y - DeltaY(title_bar_height)
1236+ };
1237+}
1238+}
1239+
1240+me::CanonicalWindowManagerPolicyCopy::CanonicalWindowManagerPolicyCopy(
1241+ WindowManagerTools* const tools,
1242+ std::shared_ptr<shell::DisplayLayout> const& display_layout) :
1243+ tools{tools},
1244+ display_layout{display_layout}
1245+{
1246+}
1247+
1248+void me::CanonicalWindowManagerPolicyCopy::click(Point cursor)
1249+{
1250+ if (auto const surface = tools->surface_at(cursor))
1251+ select_active_surface(surface);
1252+}
1253+
1254+void me::CanonicalWindowManagerPolicyCopy::handle_session_info_updated(SessionInfoMap& /*session_info*/, Rectangles const& /*displays*/)
1255+{
1256+}
1257+
1258+void me::CanonicalWindowManagerPolicyCopy::handle_displays_updated(SessionInfoMap& /*session_info*/, Rectangles const& displays)
1259+{
1260+ display_area = displays.bounding_rectangle();
1261+
1262+ for (auto const weak_surface : fullscreen_surfaces)
1263+ {
1264+ if (auto const surface = weak_surface.lock())
1265+ {
1266+ auto const& info = tools->info_for(weak_surface);
1267+ Rectangle rect{surface->top_left(), surface->size()};
1268+
1269+ display_layout->place_in_output(info.output_id.value(), rect);
1270+ surface->move_to(rect.top_left);
1271+ surface->resize(rect.size);
1272+ }
1273+ }
1274+}
1275+
1276+void me::CanonicalWindowManagerPolicyCopy::resize(Point cursor)
1277+{
1278+ select_active_surface(tools->surface_at(old_cursor));
1279+ resize(active_surface(), cursor, old_cursor, display_area);
1280+}
1281+
1282+auto me::CanonicalWindowManagerPolicyCopy::handle_place_new_surface(
1283+ std::shared_ptr<ms::Session> const& session,
1284+ ms::SurfaceCreationParameters const& request_parameters)
1285+-> ms::SurfaceCreationParameters
1286+{
1287+ auto parameters = request_parameters;
1288+ auto surf_type = parameters.type.is_set() ? parameters.type.value() : mir_surface_type_normal;
1289+ bool const needs_titlebar = SurfaceInfo::needs_titlebar(surf_type);
1290+
1291+ if (needs_titlebar)
1292+ parameters.size.height = parameters.size.height + DeltaY{title_bar_height};
1293+
1294+ if (!parameters.state.is_set())
1295+ parameters.state = mir_surface_state_restored;
1296+
1297+ auto const active_display = tools->active_display();
1298+
1299+ auto const width = parameters.size.width.as_int();
1300+ auto const height = parameters.size.height.as_int();
1301+
1302+ bool positioned = false;
1303+
1304+ auto const parent = parameters.parent.lock();
1305+
1306+ if (parameters.output_id != mir::graphics::DisplayConfigurationOutputId{0})
1307+ {
1308+ Rectangle rect{parameters.top_left, parameters.size};
1309+ display_layout->place_in_output(parameters.output_id, rect);
1310+ parameters.top_left = rect.top_left;
1311+ parameters.size = rect.size;
1312+ parameters.state = mir_surface_state_fullscreen;
1313+ positioned = true;
1314+ }
1315+ else if (!parent) // No parent => client can't suggest positioning
1316+ {
1317+ if (auto const default_surface = session->default_surface())
1318+ {
1319+ static Displacement const offset{title_bar_height, title_bar_height};
1320+
1321+ parameters.top_left = default_surface->top_left() + offset;
1322+
1323+ geometry::Rectangle display_for_app{default_surface->top_left(), default_surface->size()};
1324+
1325+ display_layout->size_to_output(display_for_app);
1326+
1327+ positioned = display_for_app.overlaps(Rectangle{parameters.top_left, parameters.size});
1328+ }
1329+ }
1330+
1331+ if (parent && parameters.aux_rect.is_set() && parameters.edge_attachment.is_set())
1332+ {
1333+ auto const edge_attachment = parameters.edge_attachment.value();
1334+ auto const aux_rect = parameters.aux_rect.value();
1335+ auto const parent_top_left = parent->top_left();
1336+ auto const top_left = aux_rect.top_left -Point{} + parent_top_left;
1337+ auto const top_right= aux_rect.top_right() -Point{} + parent_top_left;
1338+ auto const bot_left = aux_rect.bottom_left()-Point{} + parent_top_left;
1339+
1340+ if (edge_attachment & mir_edge_attachment_vertical)
1341+ {
1342+ if (active_display.contains(top_right + Displacement{width, height}))
1343+ {
1344+ parameters.top_left = top_right;
1345+ positioned = true;
1346+ }
1347+ else if (active_display.contains(top_left + Displacement{-width, height}))
1348+ {
1349+ parameters.top_left = top_left + Displacement{-width, 0};
1350+ positioned = true;
1351+ }
1352+ }
1353+
1354+ if (edge_attachment & mir_edge_attachment_horizontal)
1355+ {
1356+ if (active_display.contains(bot_left + Displacement{width, height}))
1357+ {
1358+ parameters.top_left = bot_left;
1359+ positioned = true;
1360+ }
1361+ else if (active_display.contains(top_left + Displacement{width, -height}))
1362+ {
1363+ parameters.top_left = top_left + Displacement{0, -height};
1364+ positioned = true;
1365+ }
1366+ }
1367+ }
1368+ else if (parent)
1369+ {
1370+ // o Otherwise, if the dialog is not the same as any previous dialog for the
1371+ // same parent window, and/or it does not have user-customized position:
1372+ // o It should be optically centered relative to its parent, unless this
1373+ // would overlap or cover the title bar of the parent.
1374+ // o Otherwise, it should be cascaded vertically (but not horizontally)
1375+ // relative to its parent, unless, this would cause at least part of
1376+ // it to extend into shell space.
1377+ auto const parent_top_left = parent->top_left();
1378+ auto const centred = parent_top_left
1379+ + 0.5*(as_displacement(parent->size()) - as_displacement(parameters.size))
1380+ - DeltaY{(parent->size().height.as_int()-height)/6};
1381+
1382+ parameters.top_left = centred;
1383+ positioned = true;
1384+ }
1385+
1386+ if (!positioned)
1387+ {
1388+ auto const centred = active_display.top_left
1389+ + 0.5*(as_displacement(active_display.size) - as_displacement(parameters.size))
1390+ - DeltaY{(active_display.size.height.as_int()-height)/6};
1391+
1392+ switch (parameters.state.value())
1393+ {
1394+ case mir_surface_state_fullscreen:
1395+ case mir_surface_state_maximized:
1396+ parameters.top_left = active_display.top_left;
1397+ parameters.size = active_display.size;
1398+ break;
1399+
1400+ case mir_surface_state_vertmaximized:
1401+ parameters.top_left = centred;
1402+ parameters.top_left.y = active_display.top_left.y;
1403+ parameters.size.height = active_display.size.height;
1404+ break;
1405+
1406+ case mir_surface_state_horizmaximized:
1407+ parameters.top_left = centred;
1408+ parameters.top_left.x = active_display.top_left.x;
1409+ parameters.size.width = active_display.size.width;
1410+ break;
1411+
1412+ default:
1413+ parameters.top_left = centred;
1414+ }
1415+
1416+ if (parameters.top_left.y < display_area.top_left.y)
1417+ parameters.top_left.y = display_area.top_left.y;
1418+ }
1419+
1420+ if (parameters.state != mir_surface_state_fullscreen && needs_titlebar)
1421+ {
1422+ parameters.top_left.y = parameters.top_left.y + DeltaY{title_bar_height};
1423+ parameters.size.height = parameters.size.height - DeltaY{title_bar_height};
1424+ }
1425+
1426+ return parameters;
1427+}
1428+
1429+void me::CanonicalWindowManagerPolicyCopy::generate_decorations_for(
1430+ std::shared_ptr<scene::Session> const& session,
1431+ std::shared_ptr<scene::Surface> const& surface,
1432+ SurfaceInfoMap& surface_map,
1433+ std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build)
1434+{
1435+ if (!SurfaceInfo::needs_titlebar(surface->type()))
1436+ return;
1437+
1438+ auto format = mir_pixel_format_xrgb_8888;
1439+ ms::SurfaceCreationParameters params;
1440+ params.of_size(titlebar_size_for_window(surface->size()))
1441+ .of_name("decoration")
1442+ .of_pixel_format(format)
1443+ .of_buffer_usage(mir::graphics::BufferUsage::software)
1444+ .of_position(titlebar_position_for_window(surface->top_left()))
1445+ .of_type(mir_surface_type_gloss);
1446+ auto id = build(session, params);
1447+ auto titlebar = session->surface(id);
1448+ titlebar->set_alpha(0.9);
1449+
1450+ auto& surface_info = tools->info_for(surface);
1451+ surface_info.titlebar = titlebar;
1452+ surface_info.titlebar_id = id;
1453+ surface_info.children.push_back(titlebar);
1454+
1455+ SurfaceInfo& titlebar_info =
1456+ surface_map.emplace(titlebar, SurfaceInfo{session, titlebar, {}}).first->second;
1457+ titlebar_info.is_titlebar = true;
1458+ titlebar_info.parent = surface;
1459+ titlebar_info.init_titlebar(titlebar);
1460+}
1461+
1462+void me::CanonicalWindowManagerPolicyCopy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)
1463+{
1464+ auto& surface_info = tools->info_for(surface);
1465+ if (auto const parent = surface_info.parent.lock())
1466+ {
1467+ tools->info_for(parent).children.push_back(surface);
1468+ }
1469+
1470+ tools->info_for(session).surfaces.push_back(surface);
1471+
1472+ if (surface_info.can_be_active())
1473+ {
1474+ surface->add_observer(std::make_shared<shell::SurfaceReadyObserver>(
1475+ [this](std::shared_ptr<scene::Session> const& /*session*/,
1476+ std::shared_ptr<scene::Surface> const& surface)
1477+ {
1478+ select_active_surface(surface);
1479+ },
1480+ session,
1481+ surface));
1482+ }
1483+
1484+ if (surface_info.state == mir_surface_state_fullscreen)
1485+ fullscreen_surfaces.insert(surface);
1486+}
1487+
1488+void me::CanonicalWindowManagerPolicyCopy::handle_modify_surface(
1489+ std::shared_ptr<scene::Session> const& session,
1490+ std::shared_ptr<scene::Surface> const& surface,
1491+ shell::SurfaceSpecification const& modifications)
1492+{
1493+ auto& surface_info_old = tools->info_for(surface);
1494+
1495+ auto surface_info = surface_info_old;
1496+
1497+ if (modifications.parent.is_set())
1498+ surface_info.parent = modifications.parent.value();
1499+
1500+ if (modifications.type.is_set() &&
1501+ surface_info.type != modifications.type.value())
1502+ {
1503+ auto const new_type = modifications.type.value();
1504+
1505+ if (!surface_info.can_morph_to(new_type))
1506+ {
1507+ throw std::runtime_error("Unsupported surface type change");
1508+ }
1509+
1510+ surface_info.type = new_type;
1511+
1512+ if (surface_info.must_not_have_parent())
1513+ {
1514+ if (modifications.parent.is_set())
1515+ throw std::runtime_error("Target surface type does not support parent");
1516+
1517+ surface_info.parent.reset();
1518+ }
1519+ else if (surface_info.must_have_parent())
1520+ {
1521+ if (!surface_info.parent.lock())
1522+ throw std::runtime_error("Target surface type requires parent");
1523+ }
1524+
1525+ surface->configure(mir_surface_attrib_type, new_type);
1526+ }
1527+
1528+ #define COPY_IF_SET(field)\
1529+ if (modifications.field.is_set())\
1530+ surface_info.field = modifications.field.value()
1531+
1532+ COPY_IF_SET(min_width);
1533+ COPY_IF_SET(min_height);
1534+ COPY_IF_SET(max_width);
1535+ COPY_IF_SET(max_height);
1536+ COPY_IF_SET(min_width);
1537+ COPY_IF_SET(width_inc);
1538+ COPY_IF_SET(height_inc);
1539+ COPY_IF_SET(min_aspect);
1540+ COPY_IF_SET(max_aspect);
1541+ COPY_IF_SET(output_id);
1542+
1543+ #undef COPY_IF_SET
1544+
1545+ std::swap(surface_info, surface_info_old);
1546+
1547+ if (modifications.name.is_set())
1548+ surface->rename(modifications.name.value());
1549+
1550+ if (modifications.streams.is_set())
1551+ {
1552+ auto v = modifications.streams.value();
1553+ std::vector<shell::StreamSpecification> l (v.begin(), v.end());
1554+ session->configure_streams(*surface, l);
1555+ }
1556+
1557+ if (modifications.input_shape.is_set())
1558+ {
1559+ surface->set_input_region(modifications.input_shape.value());
1560+ }
1561+
1562+ if (modifications.width.is_set() || modifications.height.is_set())
1563+ {
1564+ auto new_size = surface->size();
1565+
1566+ if (modifications.width.is_set())
1567+ new_size.width = modifications.width.value();
1568+
1569+ if (modifications.height.is_set())
1570+ new_size.height = modifications.height.value();
1571+
1572+ auto top_left = surface->top_left();
1573+
1574+ surface_info.constrain_resize(
1575+ surface,
1576+ top_left,
1577+ new_size,
1578+ false,
1579+ false,
1580+ display_area);
1581+
1582+ apply_resize(surface, surface_info.titlebar, top_left, new_size);
1583+ }
1584+
1585+ if (modifications.state.is_set())
1586+ {
1587+ auto const state = handle_set_state(surface, modifications.state.value());
1588+ surface->configure(mir_surface_attrib_state, state);
1589+ }
1590+}
1591+
1592+void me::CanonicalWindowManagerPolicyCopy::handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface)
1593+{
1594+ fullscreen_surfaces.erase(surface);
1595+
1596+ auto& info = tools->info_for(surface);
1597+
1598+ if (auto const parent = info.parent.lock())
1599+ {
1600+ auto& siblings = tools->info_for(parent).children;
1601+
1602+ for (auto i = begin(siblings); i != end(siblings); ++i)
1603+ {
1604+ if (surface.lock() == i->lock())
1605+ {
1606+ siblings.erase(i);
1607+ break;
1608+ }
1609+ }
1610+ }
1611+
1612+ session->destroy_surface(surface);
1613+ if (info.titlebar)
1614+ {
1615+ session->destroy_surface(info.titlebar_id);
1616+ tools->forget(info.titlebar);
1617+ }
1618+
1619+ auto& surfaces = tools->info_for(session).surfaces;
1620+
1621+ for (auto i = begin(surfaces); i != end(surfaces); ++i)
1622+ {
1623+ if (surface.lock() == i->lock())
1624+ {
1625+ surfaces.erase(i);
1626+ break;
1627+ }
1628+ }
1629+
1630+ if (surfaces.empty() && session == tools->focused_session())
1631+ {
1632+ active_surface_.reset();
1633+ tools->focus_next_session();
1634+ select_active_surface(tools->focused_surface());
1635+ }
1636+}
1637+
1638+int me::CanonicalWindowManagerPolicyCopy::handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value)
1639+{
1640+ auto& info = tools->info_for(surface);
1641+
1642+ switch (value)
1643+ {
1644+ case mir_surface_state_restored:
1645+ case mir_surface_state_maximized:
1646+ case mir_surface_state_vertmaximized:
1647+ case mir_surface_state_horizmaximized:
1648+ case mir_surface_state_fullscreen:
1649+ case mir_surface_state_hidden:
1650+ case mir_surface_state_minimized:
1651+ break;
1652+
1653+ default:
1654+ return info.state;
1655+ }
1656+
1657+ if (info.state == mir_surface_state_restored)
1658+ {
1659+ info.restore_rect = {surface->top_left(), surface->size()};
1660+ }
1661+
1662+ if (info.state != mir_surface_state_fullscreen)
1663+ {
1664+ info.output_id = decltype(info.output_id){};
1665+ fullscreen_surfaces.erase(surface);
1666+ }
1667+ else
1668+ {
1669+ fullscreen_surfaces.insert(surface);
1670+ }
1671+
1672+ if (info.state == value)
1673+ {
1674+ return info.state;
1675+ }
1676+
1677+ auto const old_pos = surface->top_left();
1678+ Displacement movement;
1679+
1680+ switch (value)
1681+ {
1682+ case mir_surface_state_restored:
1683+ movement = info.restore_rect.top_left - old_pos;
1684+ surface->resize(info.restore_rect.size);
1685+ if (info.titlebar)
1686+ {
1687+ info.titlebar->resize(titlebar_size_for_window(info.restore_rect.size));
1688+ info.titlebar->show();
1689+ }
1690+ break;
1691+
1692+ case mir_surface_state_maximized:
1693+ movement = display_area.top_left - old_pos;
1694+ surface->resize(display_area.size);
1695+ if (info.titlebar)
1696+ info.titlebar->hide();
1697+ break;
1698+
1699+ case mir_surface_state_horizmaximized:
1700+ movement = Point{display_area.top_left.x, info.restore_rect.top_left.y} - old_pos;
1701+ surface->resize({display_area.size.width, info.restore_rect.size.height});
1702+ if (info.titlebar)
1703+ {
1704+ info.titlebar->resize(titlebar_size_for_window({display_area.size.width, info.restore_rect.size.height}));
1705+ info.titlebar->show();
1706+ }
1707+ break;
1708+
1709+ case mir_surface_state_vertmaximized:
1710+ movement = Point{info.restore_rect.top_left.x, display_area.top_left.y} - old_pos;
1711+ surface->resize({info.restore_rect.size.width, display_area.size.height});
1712+ if (info.titlebar)
1713+ info.titlebar->hide();
1714+ break;
1715+
1716+ case mir_surface_state_fullscreen:
1717+ {
1718+ Rectangle rect{old_pos, surface->size()};
1719+
1720+ if (info.output_id.is_set())
1721+ {
1722+ display_layout->place_in_output(info.output_id.value(), rect);
1723+ }
1724+ else
1725+ {
1726+ display_layout->size_to_output(rect);
1727+ }
1728+
1729+ movement = rect.top_left - old_pos;
1730+ surface->resize(rect.size);
1731+ break;
1732+ }
1733+
1734+ case mir_surface_state_hidden:
1735+ case mir_surface_state_minimized:
1736+ if (info.titlebar)
1737+ info.titlebar->hide();
1738+ surface->hide();
1739+ return info.state = value;
1740+
1741+ default:
1742+ break;
1743+ }
1744+
1745+ // TODO It is rather simplistic to move a tree WRT the top_left of the root
1746+ // TODO when resizing. But for more sophistication we would need to encode
1747+ // TODO some sensible layout rules.
1748+ move_tree(surface, movement);
1749+
1750+ info.state = value;
1751+
1752+ if (info.is_visible())
1753+ surface->show();
1754+
1755+ return info.state;
1756+}
1757+
1758+void me::CanonicalWindowManagerPolicyCopy::drag(Point cursor)
1759+{
1760+ select_active_surface(tools->surface_at(old_cursor));
1761+ drag(active_surface(), cursor, old_cursor, display_area);
1762+}
1763+
1764+void me::CanonicalWindowManagerPolicyCopy::handle_raise_surface(
1765+ std::shared_ptr<ms::Session> const& /*session*/,
1766+ std::shared_ptr<ms::Surface> const& surface)
1767+{
1768+ select_active_surface(surface);
1769+}
1770+
1771+bool me::CanonicalWindowManagerPolicyCopy::handle_keyboard_event(MirKeyboardEvent const* event)
1772+{
1773+ auto const action = mir_keyboard_event_action(event);
1774+ auto const scan_code = mir_keyboard_event_scan_code(event);
1775+ auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask;
1776+
1777+ if (action == mir_keyboard_action_down && scan_code == KEY_F11)
1778+ {
1779+ switch (modifiers)
1780+ {
1781+ case mir_input_event_modifier_alt:
1782+ toggle(mir_surface_state_maximized);
1783+ return true;
1784+
1785+ case mir_input_event_modifier_shift:
1786+ toggle(mir_surface_state_vertmaximized);
1787+ return true;
1788+
1789+ case mir_input_event_modifier_ctrl:
1790+ toggle(mir_surface_state_horizmaximized);
1791+ return true;
1792+
1793+ default:
1794+ break;
1795+ }
1796+ }
1797+ else if (action == mir_keyboard_action_down && scan_code == KEY_F4)
1798+ {
1799+ if (auto const session = tools->focused_session())
1800+ {
1801+ switch (modifiers)
1802+ {
1803+ case mir_input_event_modifier_alt:
1804+ kill(session->process_id(), SIGTERM);
1805+ return true;
1806+
1807+ case mir_input_event_modifier_ctrl:
1808+ if (auto const surf = session->default_surface())
1809+ {
1810+ surf->request_client_surface_close();
1811+ return true;
1812+ }
1813+
1814+ default:
1815+ break;
1816+ }
1817+ }
1818+ }
1819+ else if (action == mir_keyboard_action_down &&
1820+ modifiers == mir_input_event_modifier_alt &&
1821+ scan_code == KEY_TAB)
1822+ {
1823+ tools->focus_next_session();
1824+ if (auto const surface = tools->focused_surface())
1825+ select_active_surface(surface);
1826+
1827+ return true;
1828+ }
1829+ else if (action == mir_keyboard_action_down &&
1830+ modifiers == mir_input_event_modifier_alt &&
1831+ scan_code == KEY_GRAVE)
1832+ {
1833+ if (auto const prev = tools->focused_surface())
1834+ {
1835+ if (auto const app = tools->focused_session())
1836+ select_active_surface(app->surface_after(prev));
1837+ }
1838+
1839+ return true;
1840+ }
1841+
1842+ return false;
1843+}
1844+
1845+bool me::CanonicalWindowManagerPolicyCopy::handle_touch_event(MirTouchEvent const* event)
1846+{
1847+ auto const count = mir_touch_event_point_count(event);
1848+
1849+ long total_x = 0;
1850+ long total_y = 0;
1851+
1852+ for (auto i = 0U; i != count; ++i)
1853+ {
1854+ total_x += mir_touch_event_axis_value(event, i, mir_touch_axis_x);
1855+ total_y += mir_touch_event_axis_value(event, i, mir_touch_axis_y);
1856+ }
1857+
1858+ Point const cursor{total_x/count, total_y/count};
1859+
1860+ bool is_drag = true;
1861+ for (auto i = 0U; i != count; ++i)
1862+ {
1863+ switch (mir_touch_event_action(event, i))
1864+ {
1865+ case mir_touch_action_up:
1866+ return false;
1867+
1868+ case mir_touch_action_down:
1869+ is_drag = false;
1870+
1871+ case mir_touch_action_change:
1872+ continue;
1873+ }
1874+ }
1875+
1876+ bool consumes_event = false;
1877+ if (is_drag)
1878+ {
1879+ switch (count)
1880+ {
1881+ case 2:
1882+ resize(cursor);
1883+ consumes_event = true;
1884+ break;
1885+
1886+ case 3:
1887+ drag(cursor);
1888+ consumes_event = true;
1889+ break;
1890+ }
1891+ }
1892+
1893+ old_cursor = cursor;
1894+ return consumes_event;
1895+}
1896+
1897+bool me::CanonicalWindowManagerPolicyCopy::handle_pointer_event(MirPointerEvent const* event)
1898+{
1899+ auto const action = mir_pointer_event_action(event);
1900+ auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask;
1901+ Point const cursor{
1902+ mir_pointer_event_axis_value(event, mir_pointer_axis_x),
1903+ mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
1904+
1905+ bool consumes_event = false;
1906+
1907+ if (action == mir_pointer_action_button_down)
1908+ {
1909+ click(cursor);
1910+ }
1911+ else if (action == mir_pointer_action_motion &&
1912+ modifiers == mir_input_event_modifier_alt)
1913+ {
1914+ if (mir_pointer_event_button_state(event, mir_pointer_button_primary))
1915+ {
1916+ drag(cursor);
1917+ consumes_event = true;
1918+ }
1919+
1920+ if (mir_pointer_event_button_state(event, mir_pointer_button_tertiary))
1921+ {
1922+ resize(cursor);
1923+ consumes_event = true;
1924+ }
1925+ }
1926+ else if (action == mir_pointer_action_motion && !modifiers)
1927+ {
1928+ if (mir_pointer_event_button_state(event, mir_pointer_button_primary))
1929+ {
1930+ if (auto const possible_titlebar = tools->surface_at(old_cursor))
1931+ {
1932+ if (tools->info_for(possible_titlebar).is_titlebar)
1933+ {
1934+ drag(cursor);
1935+ consumes_event = true;
1936+ }
1937+ }
1938+ }
1939+ }
1940+
1941+ old_cursor = cursor;
1942+ return consumes_event;
1943+}
1944+
1945+void me::CanonicalWindowManagerPolicyCopy::toggle(MirSurfaceState state)
1946+{
1947+ if (auto const surface = active_surface())
1948+ {
1949+ auto& info = tools->info_for(surface);
1950+
1951+ if (info.state == state)
1952+ state = mir_surface_state_restored;
1953+
1954+ auto const value = handle_set_state(surface, MirSurfaceState(state));
1955+ surface->configure(mir_surface_attrib_state, value);
1956+ }
1957+}
1958+
1959+void me::CanonicalWindowManagerPolicyCopy::select_active_surface(std::shared_ptr<ms::Surface> const& surface)
1960+{
1961+ if (surface == active_surface_.lock())
1962+ return;
1963+
1964+ if (!surface)
1965+ {
1966+ if (auto const active_surface = active_surface_.lock())
1967+ {
1968+ if (auto const titlebar = tools->info_for(active_surface).titlebar)
1969+ {
1970+ tools->info_for(titlebar).paint_titlebar(0x3F);
1971+ }
1972+ }
1973+
1974+ if (active_surface_.lock())
1975+ tools->set_focus_to({}, {});
1976+
1977+ active_surface_.reset();
1978+ return;
1979+ }
1980+
1981+ auto const& info_for = tools->info_for(surface);
1982+
1983+ if (info_for.can_be_active())
1984+ {
1985+ if (auto const active_surface = active_surface_.lock())
1986+ {
1987+ if (auto const titlebar = tools->info_for(active_surface).titlebar)
1988+ {
1989+ tools->info_for(titlebar).paint_titlebar(0x3F);
1990+ }
1991+ }
1992+ if (auto const titlebar = tools->info_for(surface).titlebar)
1993+ {
1994+ tools->info_for(titlebar).paint_titlebar(0xFF);
1995+ }
1996+ tools->set_focus_to(info_for.session.lock(), surface);
1997+ tools->raise_tree(surface);
1998+ active_surface_ = surface;
1999+ }
2000+ else
2001+ {
2002+ // Cannot have input focus - try the parent
2003+ if (auto const parent = info_for.parent.lock())
2004+ select_active_surface(parent);
2005+ }
2006+}
2007+
2008+auto me::CanonicalWindowManagerPolicyCopy::active_surface() const
2009+-> std::shared_ptr<ms::Surface>
2010+{
2011+ if (auto const surface = active_surface_.lock())
2012+ return surface;
2013+
2014+ if (auto const session = tools->focused_session())
2015+ {
2016+ if (auto const surface = session->default_surface())
2017+ return surface;
2018+ }
2019+
2020+ return std::shared_ptr<ms::Surface>{};
2021+}
2022+
2023+bool me::CanonicalWindowManagerPolicyCopy::resize(std::shared_ptr<ms::Surface> const& surface, Point cursor, Point old_cursor, Rectangle bounds)
2024+{
2025+ if (!surface || !surface->input_area_contains(old_cursor))
2026+ return false;
2027+
2028+ auto const top_left = surface->top_left();
2029+ Rectangle const old_pos{top_left, surface->size()};
2030+
2031+ auto anchor = top_left;
2032+
2033+ for (auto const& corner : {
2034+ old_pos.top_right(),
2035+ old_pos.bottom_left(),
2036+ old_pos.bottom_right()})
2037+ {
2038+ if ((old_cursor - anchor).length_squared() <
2039+ (old_cursor - corner).length_squared())
2040+ {
2041+ anchor = corner;
2042+ }
2043+ }
2044+
2045+ bool const left_resize = anchor.x != top_left.x;
2046+ bool const top_resize = anchor.y != top_left.y;
2047+ int const x_sign = left_resize? -1 : 1;
2048+ int const y_sign = top_resize? -1 : 1;
2049+
2050+ auto const delta = cursor-old_cursor;
2051+
2052+ Size new_size{old_pos.size.width + x_sign*delta.dx, old_pos.size.height + y_sign*delta.dy};
2053+
2054+ Point new_pos = top_left + left_resize*delta.dx + top_resize*delta.dy;
2055+
2056+
2057+ auto const& surface_info = tools->info_for(surface);
2058+
2059+ surface_info.constrain_resize(surface, new_pos, new_size, left_resize, top_resize, bounds);
2060+
2061+ apply_resize(surface, surface_info.titlebar, new_pos, new_size);
2062+
2063+ return true;
2064+}
2065+
2066+void me::CanonicalWindowManagerPolicyCopy::apply_resize(
2067+ std::shared_ptr<ms::Surface> const& surface,
2068+ std::shared_ptr<ms::Surface> const& titlebar,
2069+ Point const& new_pos,
2070+ Size const& new_size) const
2071+{
2072+ if (titlebar)
2073+ titlebar->resize({new_size.width, Height{title_bar_height}});
2074+
2075+ surface->resize(new_size);
2076+
2077+ move_tree(surface, new_pos-surface->top_left());
2078+}
2079+
2080+bool me::CanonicalWindowManagerPolicyCopy::drag(std::shared_ptr<ms::Surface> surface, Point to, Point from, Rectangle /*bounds*/)
2081+{
2082+ if (!surface)
2083+ return false;
2084+
2085+ if (!surface->input_area_contains(from) && !tools->info_for(surface).titlebar)
2086+ return false;
2087+
2088+ auto movement = to - from;
2089+
2090+ // placeholder - constrain onscreen
2091+
2092+ switch (tools->info_for(surface).state)
2093+ {
2094+ case mir_surface_state_restored:
2095+ break;
2096+
2097+ // "A vertically maximised surface is anchored to the top and bottom of
2098+ // the available workspace and can have any width."
2099+ case mir_surface_state_vertmaximized:
2100+ movement.dy = DeltaY(0);
2101+ break;
2102+
2103+ // "A horizontally maximised surface is anchored to the left and right of
2104+ // the available workspace and can have any height"
2105+ case mir_surface_state_horizmaximized:
2106+ movement.dx = DeltaX(0);
2107+ break;
2108+
2109+ // "A maximised surface is anchored to the top, bottom, left and right of the
2110+ // available workspace. For example, if the launcher is always-visible then
2111+ // the left-edge of the surface is anchored to the right-edge of the launcher."
2112+ case mir_surface_state_maximized:
2113+ case mir_surface_state_fullscreen:
2114+ default:
2115+ return true;
2116+ }
2117+
2118+ move_tree(surface, movement);
2119+
2120+ return true;
2121+}
2122+
2123+void me::CanonicalWindowManagerPolicyCopy::move_tree(std::shared_ptr<ms::Surface> const& root, Displacement movement) const
2124+{
2125+ root->move_to(root->top_left() + movement);
2126+
2127+ for (auto const& child: tools->info_for(root).children)
2128+ {
2129+ move_tree(child.lock(), movement);
2130+ }
2131+}
2132
2133=== added file 'src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.h'
2134--- src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.h 1970-01-01 00:00:00 +0000
2135+++ src/platforms/mirserver/wm-wip/server_example_canonical_window_manager.h 2016-03-11 11:36:44 +0000
2136@@ -0,0 +1,132 @@
2137+/*
2138+ * Copyright © 2015 Canonical Ltd.
2139+ *
2140+ * This program is free software: you can redistribute it and/or modify it
2141+ * under the terms of the GNU General Public License version 3,
2142+ * as published by the Free Software Foundation.
2143+ *
2144+ * This program is distributed in the hope that it will be useful,
2145+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2146+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2147+ * GNU General Public License for more details.
2148+ *
2149+ * You should have received a copy of the GNU General Public License
2150+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2151+ *
2152+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
2153+ */
2154+
2155+#ifndef MIR_EXAMPLE_CANONICAL_WINDOW_MANAGER_H_
2156+#define MIR_EXAMPLE_CANONICAL_WINDOW_MANAGER_H_
2157+
2158+#include "server_example_basic_window_manager.h"
2159+
2160+#include "mir/geometry/displacement.h"
2161+
2162+#include <atomic>
2163+#include <set>
2164+
2165+///\example server_example_canonical_window_manager.h
2166+// Based on "Mir and Unity: Surfaces, input, and displays (v0.3)"
2167+
2168+namespace mir
2169+{
2170+namespace shell { class DisplayLayout; }
2171+namespace examples
2172+{
2173+// standard window management algorithm:
2174+// o Switch apps: tap or click on the corresponding tile
2175+// o Move window: Alt-leftmousebutton drag (three finger drag)
2176+// o Resize window: Alt-middle_button drag (two finger drag)
2177+// o Maximize/restore current window (to display size): Alt-F11
2178+// o Maximize/restore current window (to display height): Shift-F11
2179+// o Maximize/restore current window (to display width): Ctrl-F11
2180+// o client requests to maximize, vertically maximize & restore
2181+class CanonicalWindowManagerPolicyCopy : public WindowManagementPolicy
2182+{
2183+public:
2184+
2185+ explicit CanonicalWindowManagerPolicyCopy(
2186+ WindowManagerTools* const tools,
2187+ std::shared_ptr<shell::DisplayLayout> const& display_layout);
2188+
2189+ void click(geometry::Point cursor);
2190+
2191+ void handle_session_info_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays);
2192+
2193+ void handle_displays_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays);
2194+
2195+ void resize(geometry::Point cursor);
2196+
2197+ auto handle_place_new_surface(
2198+ std::shared_ptr<scene::Session> const& session,
2199+ scene::SurfaceCreationParameters const& request_parameters)
2200+ -> scene::SurfaceCreationParameters;
2201+
2202+ void handle_new_surface(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface);
2203+
2204+ void handle_modify_surface(
2205+ std::shared_ptr<scene::Session> const& session,
2206+ std::shared_ptr<scene::Surface> const& surface,
2207+ shell::SurfaceSpecification const& modifications);
2208+
2209+ void handle_delete_surface(std::shared_ptr<scene::Session> const& session, std::weak_ptr<scene::Surface> const& surface);
2210+
2211+ int handle_set_state(std::shared_ptr<scene::Surface> const& surface, MirSurfaceState value);
2212+
2213+ void drag(geometry::Point cursor);
2214+
2215+ bool handle_keyboard_event(MirKeyboardEvent const* event);
2216+
2217+ bool handle_touch_event(MirTouchEvent const* event);
2218+
2219+ bool handle_pointer_event(MirPointerEvent const* event);
2220+
2221+ void handle_raise_surface(
2222+ std::shared_ptr<scene::Session> const& session,
2223+ std::shared_ptr<scene::Surface> const& surface);
2224+
2225+ void generate_decorations_for(
2226+ std::shared_ptr<scene::Session> const& session,
2227+ std::shared_ptr<scene::Surface> const& surface,
2228+ SurfaceInfoMap& surface_map,
2229+ std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build);
2230+
2231+private:
2232+ static const int modifier_mask =
2233+ mir_input_event_modifier_alt |
2234+ mir_input_event_modifier_shift |
2235+ mir_input_event_modifier_sym |
2236+ mir_input_event_modifier_ctrl |
2237+ mir_input_event_modifier_meta;
2238+
2239+ void toggle(MirSurfaceState state);
2240+
2241+ // "Mir and Unity: Surfaces, input, and displays (v0.3)" talks about active
2242+ // *window*,but Mir really only understands surfaces
2243+ void select_active_surface(std::shared_ptr<scene::Surface> const& surface);
2244+ auto active_surface() const -> std::shared_ptr<scene::Surface>;
2245+
2246+ bool resize(std::shared_ptr<scene::Surface> const& surface, geometry::Point cursor, geometry::Point old_cursor, geometry::Rectangle bounds);
2247+ bool drag(std::shared_ptr<scene::Surface> surface, geometry::Point to, geometry::Point from, geometry::Rectangle bounds);
2248+ void move_tree(std::shared_ptr<scene::Surface> const& root, geometry::Displacement movement) const;
2249+ void apply_resize(
2250+ std::shared_ptr<mir::scene::Surface> const& surface,
2251+ std::shared_ptr<mir::scene::Surface> const& titlebar,
2252+ geometry::Point const& new_pos,
2253+ geometry::Size const& new_size) const;
2254+
2255+ WindowManagerTools* const tools;
2256+ std::shared_ptr<shell::DisplayLayout> const display_layout;
2257+
2258+ geometry::Rectangle display_area;
2259+ geometry::Point old_cursor{};
2260+ std::weak_ptr<scene::Surface> active_surface_;
2261+ using FullscreenSurfaces = std::set<std::weak_ptr<scene::Surface>, std::owner_less<std::weak_ptr<scene::Surface>>>;
2262+
2263+ FullscreenSurfaces fullscreen_surfaces;
2264+};
2265+}
2266+}
2267+
2268+#endif /* MIR_EXAMPLE_CANONICAL_WINDOW_MANAGER_H_ */
2269
2270=== added file 'src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.cpp'
2271--- src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.cpp 1970-01-01 00:00:00 +0000
2272+++ src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.cpp 2016-03-11 11:36:44 +0000
2273@@ -0,0 +1,640 @@
2274+/*
2275+ * Copyright © 2015 Canonical Ltd.
2276+ *
2277+ * This program is free software: you can redistribute it and/or modify it
2278+ * under the terms of the GNU General Public License version 3,
2279+ * as published by the Free Software Foundation.
2280+ *
2281+ * This program is distributed in the hope that it will be useful,
2282+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2283+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2284+ * GNU General Public License for more details.
2285+ *
2286+ * You should have received a copy of the GNU General Public License
2287+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2288+ *
2289+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
2290+ */
2291+
2292+#include "server_example_tiling_window_manager.h"
2293+
2294+#include "mir/scene/session.h"
2295+#include "mir/scene/surface.h"
2296+#include "mir/scene/surface_creation_parameters.h"
2297+#include "mir/shell/surface_specification.h"
2298+#include "mir/shell/surface_stack.h"
2299+#include "mir/shell/surface_ready_observer.h"
2300+#include "mir/geometry/displacement.h"
2301+
2302+#include <linux/input.h>
2303+#include <csignal>
2304+
2305+namespace me = mir::examples;
2306+namespace ms = mir::scene;
2307+namespace mf = mir::frontend;
2308+using namespace mir::geometry;
2309+
2310+///\example server_example_tiling_window_manager.cpp
2311+/// Demonstrate implementing a simple tiling algorithm
2312+
2313+me::TilingWindowManagerPolicy::TilingWindowManagerPolicy(WindowManagerTools* const tools) :
2314+ tools{tools}
2315+{
2316+}
2317+
2318+void me::TilingWindowManagerPolicy::click(Point cursor)
2319+{
2320+ auto const session = session_under(cursor);
2321+ auto const surface = tools->surface_at(cursor);
2322+ select_active_surface(session, surface);
2323+}
2324+
2325+void me::TilingWindowManagerPolicy::handle_session_info_updated(SessionInfoMap& session_info, Rectangles const& displays)
2326+{
2327+ update_tiles(session_info, displays);
2328+}
2329+
2330+void me::TilingWindowManagerPolicy::handle_displays_updated(SessionInfoMap& session_info, Rectangles const& displays)
2331+{
2332+ update_tiles(session_info, displays);
2333+}
2334+
2335+void me::TilingWindowManagerPolicy::resize(Point cursor)
2336+{
2337+ if (auto const session = session_under(cursor))
2338+ {
2339+ if (session == session_under(old_cursor))
2340+ {
2341+ if (auto const surface = select_active_surface(session, tools->surface_at(old_cursor)))
2342+ {
2343+ resize(surface, cursor, old_cursor, tools->info_for(session).tile);
2344+ }
2345+ }
2346+ }
2347+}
2348+
2349+auto me::TilingWindowManagerPolicy::handle_place_new_surface(
2350+ std::shared_ptr<ms::Session> const& session,
2351+ ms::SurfaceCreationParameters const& request_parameters)
2352+-> ms::SurfaceCreationParameters
2353+{
2354+ auto parameters = request_parameters;
2355+
2356+ Rectangle const& tile = tools->info_for(session).tile;
2357+ parameters.top_left = parameters.top_left + (tile.top_left - Point{0, 0});
2358+
2359+ if (auto const parent = parameters.parent.lock())
2360+ {
2361+ auto const width = parameters.size.width.as_int();
2362+ auto const height = parameters.size.height.as_int();
2363+
2364+ if (parameters.aux_rect.is_set() && parameters.edge_attachment.is_set())
2365+ {
2366+ auto const edge_attachment = parameters.edge_attachment.value();
2367+ auto const aux_rect = parameters.aux_rect.value();
2368+ auto const parent_top_left = parent->top_left();
2369+ auto const top_left = aux_rect.top_left -Point{} + parent_top_left;
2370+ auto const top_right= aux_rect.top_right() -Point{} + parent_top_left;
2371+ auto const bot_left = aux_rect.bottom_left()-Point{} + parent_top_left;
2372+
2373+ if (edge_attachment & mir_edge_attachment_vertical)
2374+ {
2375+ if (tile.contains(top_right + Displacement{width, height}))
2376+ {
2377+ parameters.top_left = top_right;
2378+ }
2379+ else if (tile.contains(top_left + Displacement{-width, height}))
2380+ {
2381+ parameters.top_left = top_left + Displacement{-width, 0};
2382+ }
2383+ }
2384+
2385+ if (edge_attachment & mir_edge_attachment_horizontal)
2386+ {
2387+ if (tile.contains(bot_left + Displacement{width, height}))
2388+ {
2389+ parameters.top_left = bot_left;
2390+ }
2391+ else if (tile.contains(top_left + Displacement{width, -height}))
2392+ {
2393+ parameters.top_left = top_left + Displacement{0, -height};
2394+ }
2395+ }
2396+ }
2397+ else
2398+ {
2399+ auto const parent_top_left = parent->top_left();
2400+ auto const centred = parent_top_left
2401+ + 0.5*(as_displacement(parent->size()) - as_displacement(parameters.size))
2402+ - DeltaY{(parent->size().height.as_int()-height)/6};
2403+
2404+ parameters.top_left = centred;
2405+ }
2406+ }
2407+
2408+ clip_to_tile(parameters, tile);
2409+ return parameters;
2410+}
2411+
2412+void me::TilingWindowManagerPolicy::generate_decorations_for(
2413+ std::shared_ptr<ms::Session> const&,
2414+ std::shared_ptr<ms::Surface> const&,
2415+ SurfaceInfoMap&,
2416+ std::function<mf::SurfaceId(std::shared_ptr<ms::Session> const&, ms::SurfaceCreationParameters const&)> const&)
2417+{
2418+}
2419+
2420+void me::TilingWindowManagerPolicy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)
2421+{
2422+ tools->info_for(session).surfaces.push_back(surface);
2423+
2424+ auto& surface_info = tools->info_for(surface);
2425+ if (auto const parent = surface_info.parent.lock())
2426+ {
2427+ tools->info_for(parent).children.push_back(surface);
2428+ }
2429+
2430+ if (surface_info.can_be_active())
2431+ {
2432+ surface->add_observer(std::make_shared<shell::SurfaceReadyObserver>(
2433+ [this](std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface)
2434+ { select_active_surface(session, surface); },
2435+ session,
2436+ surface));
2437+ }
2438+}
2439+
2440+void me::TilingWindowManagerPolicy::handle_modify_surface(
2441+ std::shared_ptr<scene::Session> const& /*session*/,
2442+ std::shared_ptr<scene::Surface> const& surface,
2443+ shell::SurfaceSpecification const& modifications)
2444+{
2445+ if (modifications.name.is_set())
2446+ surface->rename(modifications.name.value());
2447+}
2448+
2449+void me::TilingWindowManagerPolicy::handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface)
2450+{
2451+ auto& info = tools->info_for(surface);
2452+
2453+ if (auto const parent = info.parent.lock())
2454+ {
2455+ auto& siblings = tools->info_for(parent).children;
2456+
2457+ for (auto i = begin(siblings); i != end(siblings); ++i)
2458+ {
2459+ if (surface.lock() == i->lock())
2460+ {
2461+ siblings.erase(i);
2462+ break;
2463+ }
2464+ }
2465+ }
2466+
2467+ auto& surfaces = tools->info_for(session).surfaces;
2468+
2469+ for (auto i = begin(surfaces); i != end(surfaces); ++i)
2470+ {
2471+ if (surface.lock() == i->lock())
2472+ {
2473+ surfaces.erase(i);
2474+ break;
2475+ }
2476+ }
2477+
2478+ session->destroy_surface(surface);
2479+
2480+ if (surfaces.empty() && session == tools->focused_session())
2481+ {
2482+ tools->focus_next_session();
2483+ select_active_surface(tools->focused_session(), tools->focused_surface());
2484+ }
2485+}
2486+
2487+int me::TilingWindowManagerPolicy::handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value)
2488+{
2489+ auto& info = tools->info_for(surface);
2490+
2491+ switch (value)
2492+ {
2493+ case mir_surface_state_restored:
2494+ case mir_surface_state_maximized:
2495+ case mir_surface_state_vertmaximized:
2496+ case mir_surface_state_horizmaximized:
2497+ break;
2498+
2499+ default:
2500+ return info.state;
2501+ }
2502+
2503+ if (info.state == mir_surface_state_restored)
2504+ {
2505+ info.restore_rect = {surface->top_left(), surface->size()};
2506+ }
2507+
2508+ if (info.state == value)
2509+ {
2510+ return info.state;
2511+ }
2512+
2513+ auto const& tile = tools->info_for(info.session).tile;
2514+
2515+ switch (value)
2516+ {
2517+ case mir_surface_state_restored:
2518+ surface->resize(info.restore_rect.size);
2519+ drag(surface, info.restore_rect.top_left, surface->top_left(), tile);
2520+ break;
2521+
2522+ case mir_surface_state_maximized:
2523+ surface->resize(tile.size);
2524+ drag(surface, tile.top_left, surface->top_left(), tile);
2525+ break;
2526+
2527+ case mir_surface_state_horizmaximized:
2528+ surface->resize({tile.size.width, info.restore_rect.size.height});
2529+ drag(surface, {tile.top_left.x, info.restore_rect.top_left.y}, surface->top_left(), tile);
2530+ break;
2531+
2532+ case mir_surface_state_vertmaximized:
2533+ surface->resize({info.restore_rect.size.width, tile.size.height});
2534+ drag(surface, {info.restore_rect.top_left.x, tile.top_left.y}, surface->top_left(), tile);
2535+ break;
2536+
2537+ default:
2538+ break;
2539+ }
2540+
2541+ return info.state = value;
2542+}
2543+
2544+void me::TilingWindowManagerPolicy::drag(Point cursor)
2545+{
2546+ if (auto const session = session_under(cursor))
2547+ {
2548+ if (session == session_under(old_cursor))
2549+ {
2550+ if (auto const surface = select_active_surface(session, tools->surface_at(old_cursor)))
2551+ {
2552+ drag(surface, cursor, old_cursor, tools->info_for(session).tile);
2553+ }
2554+ }
2555+ }
2556+}
2557+
2558+void me::TilingWindowManagerPolicy::handle_raise_surface(
2559+ std::shared_ptr<ms::Session> const& session,
2560+ std::shared_ptr<ms::Surface> const& surface)
2561+{
2562+ select_active_surface(session, surface);
2563+}
2564+
2565+bool me::TilingWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* event)
2566+{
2567+ auto const action = mir_keyboard_event_action(event);
2568+ auto const scan_code = mir_keyboard_event_scan_code(event);
2569+ auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask;
2570+
2571+ if (action == mir_keyboard_action_down && scan_code == KEY_F11)
2572+ {
2573+ switch (modifiers & modifier_mask)
2574+ {
2575+ case mir_input_event_modifier_alt:
2576+ toggle(mir_surface_state_maximized);
2577+ return true;
2578+
2579+ case mir_input_event_modifier_shift:
2580+ toggle(mir_surface_state_vertmaximized);
2581+ return true;
2582+
2583+ case mir_input_event_modifier_ctrl:
2584+ toggle(mir_surface_state_horizmaximized);
2585+ return true;
2586+
2587+ default:
2588+ break;
2589+ }
2590+ }
2591+ else if (action == mir_keyboard_action_down && scan_code == KEY_F4)
2592+ {
2593+ if (auto const session = tools->focused_session())
2594+ {
2595+ switch (modifiers & modifier_mask)
2596+ {
2597+ case mir_input_event_modifier_alt:
2598+ kill(session->process_id(), SIGTERM);
2599+ return true;
2600+
2601+ case mir_input_event_modifier_ctrl:
2602+ if (auto const surf = session->default_surface())
2603+ {
2604+ surf->request_client_surface_close();
2605+ return true;
2606+ }
2607+
2608+ default:
2609+ break;
2610+ }
2611+ }
2612+ }
2613+ else if (action == mir_keyboard_action_down &&
2614+ modifiers == mir_input_event_modifier_alt &&
2615+ scan_code == KEY_TAB)
2616+ {
2617+ tools->focus_next_session();
2618+ select_active_surface(tools->focused_session(), tools->focused_surface());
2619+
2620+ return true;
2621+ }
2622+ else if (action == mir_keyboard_action_down &&
2623+ modifiers == mir_input_event_modifier_alt &&
2624+ scan_code == KEY_GRAVE)
2625+ {
2626+ if (auto const prev = tools->focused_surface())
2627+ {
2628+ if (auto const app = tools->focused_session())
2629+ if (auto const surface = app->surface_after(prev))
2630+ {
2631+ select_active_surface(app, surface);
2632+ }
2633+ }
2634+
2635+ return true;
2636+ }
2637+
2638+ return false;
2639+}
2640+
2641+bool me::TilingWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event)
2642+{
2643+ auto const count = mir_touch_event_point_count(event);
2644+
2645+ long total_x = 0;
2646+ long total_y = 0;
2647+
2648+ for (auto i = 0U; i != count; ++i)
2649+ {
2650+ total_x += mir_touch_event_axis_value(event, i, mir_touch_axis_x);
2651+ total_y += mir_touch_event_axis_value(event, i, mir_touch_axis_y);
2652+ }
2653+
2654+ Point const cursor{total_x/count, total_y/count};
2655+
2656+ bool is_drag = true;
2657+ for (auto i = 0U; i != count; ++i)
2658+ {
2659+ switch (mir_touch_event_action(event, i))
2660+ {
2661+ case mir_touch_action_up:
2662+ return false;
2663+
2664+ case mir_touch_action_down:
2665+ is_drag = false;
2666+
2667+ case mir_touch_action_change:
2668+ continue;
2669+ }
2670+ }
2671+
2672+ bool consumes_event = false;
2673+ if (is_drag)
2674+ {
2675+ switch (count)
2676+ {
2677+ case 2:
2678+ resize(cursor);
2679+ consumes_event = true;
2680+ break;
2681+
2682+ case 3:
2683+ drag(cursor);
2684+ consumes_event = true;
2685+ break;
2686+ }
2687+ }
2688+
2689+ old_cursor = cursor;
2690+ return consumes_event;
2691+}
2692+
2693+bool me::TilingWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* event)
2694+{
2695+ auto const action = mir_pointer_event_action(event);
2696+ auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask;
2697+ Point const cursor{
2698+ mir_pointer_event_axis_value(event, mir_pointer_axis_x),
2699+ mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
2700+
2701+ bool consumes_event = false;
2702+
2703+ if (action == mir_pointer_action_button_down)
2704+ {
2705+ click(cursor);
2706+ }
2707+ else if (action == mir_pointer_action_motion &&
2708+ modifiers == mir_input_event_modifier_alt)
2709+ {
2710+ if (mir_pointer_event_button_state(event, mir_pointer_button_primary))
2711+ {
2712+ drag(cursor);
2713+ consumes_event = true;
2714+ }
2715+ else if (mir_pointer_event_button_state(event, mir_pointer_button_tertiary))
2716+ {
2717+ resize(cursor);
2718+ consumes_event = true;
2719+ }
2720+ }
2721+
2722+ old_cursor = cursor;
2723+ return consumes_event;
2724+}
2725+
2726+void me::TilingWindowManagerPolicy::toggle(MirSurfaceState state)
2727+{
2728+ if (auto const session = tools->focused_session())
2729+ {
2730+ if (auto const surface = session->default_surface())
2731+ {
2732+ if (surface->state() == state)
2733+ state = mir_surface_state_restored;
2734+
2735+ auto const value = handle_set_state(surface, MirSurfaceState(state));
2736+ surface->configure(mir_surface_attrib_state, value);
2737+ }
2738+ }
2739+}
2740+
2741+std::shared_ptr<ms::Session> me::TilingWindowManagerPolicy::session_under(Point position)
2742+{
2743+ return tools->find_session([&](SessionInfo const& info) { return info.tile.contains(position);});
2744+}
2745+
2746+void me::TilingWindowManagerPolicy::update_tiles(
2747+ SessionInfoMap& session_info,
2748+ Rectangles const& displays)
2749+{
2750+ if (session_info.size() < 1 || displays.size() < 1) return;
2751+
2752+ auto const sessions = session_info.size();
2753+
2754+ auto const bounding_rect = displays.bounding_rectangle();
2755+
2756+ auto const total_width = bounding_rect.size.width.as_int();
2757+ auto const total_height = bounding_rect.size.height.as_int();
2758+
2759+ auto index = 0;
2760+
2761+ for (auto& info : session_info)
2762+ {
2763+ auto const x = (total_width*index)/sessions;
2764+ ++index;
2765+ auto const dx = (total_width*index)/sessions - x;
2766+
2767+ auto const old_tile = info.second.tile;
2768+ Rectangle const new_tile{{x, 0}, {dx, total_height}};
2769+
2770+ update_surfaces(info.first, old_tile, new_tile);
2771+
2772+ info.second.tile = new_tile;
2773+ }
2774+}
2775+
2776+void me::TilingWindowManagerPolicy::update_surfaces(std::weak_ptr<ms::Session> const& session, Rectangle const& old_tile, Rectangle const& new_tile)
2777+{
2778+ auto displacement = new_tile.top_left - old_tile.top_left;
2779+ auto& info = tools->info_for(session);
2780+
2781+ for (auto const& ps : info.surfaces)
2782+ {
2783+ if (auto const surface = ps.lock())
2784+ {
2785+ auto const old_pos = surface->top_left();
2786+ surface->move_to(old_pos + displacement);
2787+
2788+ fit_to_new_tile(*surface, old_tile, new_tile);
2789+ }
2790+ }
2791+}
2792+
2793+void me::TilingWindowManagerPolicy::clip_to_tile(ms::SurfaceCreationParameters& parameters, Rectangle const& tile)
2794+{
2795+ auto const displacement = parameters.top_left - tile.top_left;
2796+
2797+ auto width = std::min(tile.size.width.as_int()-displacement.dx.as_int(), parameters.size.width.as_int());
2798+ auto height = std::min(tile.size.height.as_int()-displacement.dy.as_int(), parameters.size.height.as_int());
2799+
2800+ parameters.size = Size{width, height};
2801+}
2802+
2803+void me::TilingWindowManagerPolicy::fit_to_new_tile(ms::Surface& surface, Rectangle const& old_tile, Rectangle const& new_tile)
2804+{
2805+ auto const displacement = surface.top_left() - new_tile.top_left;
2806+
2807+ // For now just scale if was filling width/height of tile
2808+ auto const old_size = surface.size();
2809+ auto const scaled_width = old_size.width == old_tile.size.width ? new_tile.size.width : old_size.width;
2810+ auto const scaled_height = old_size.height == old_tile.size.height ? new_tile.size.height : old_size.height;
2811+
2812+ auto width = std::min(new_tile.size.width.as_int()-displacement.dx.as_int(), scaled_width.as_int());
2813+ auto height = std::min(new_tile.size.height.as_int()-displacement.dy.as_int(), scaled_height.as_int());
2814+
2815+ surface.resize({width, height});
2816+}
2817+
2818+void me::TilingWindowManagerPolicy::drag(std::shared_ptr<ms::Surface> surface, Point to, Point from, Rectangle bounds)
2819+{
2820+ if (surface && surface->input_area_contains(from))
2821+ {
2822+ auto movement = to - from;
2823+
2824+ constrained_move(surface, movement, bounds);
2825+
2826+ for (auto const& child: tools->info_for(surface).children)
2827+ {
2828+ auto move = movement;
2829+ constrained_move(child.lock(), move, bounds);
2830+ }
2831+ }
2832+}
2833+
2834+void me::TilingWindowManagerPolicy::constrained_move(
2835+ std::shared_ptr<scene::Surface> const& surface,
2836+ Displacement& movement,
2837+ Rectangle const& bounds)
2838+{
2839+ auto const top_left = surface->top_left();
2840+ auto const surface_size = surface->size();
2841+ auto const bottom_right = top_left + as_displacement(surface_size);
2842+
2843+ if (movement.dx < DeltaX{0})
2844+ movement.dx = std::max(movement.dx, (bounds.top_left - top_left).dx);
2845+
2846+ if (movement.dy < DeltaY{0})
2847+ movement.dy = std::max(movement.dy, (bounds.top_left - top_left).dy);
2848+
2849+ if (movement.dx > DeltaX{0})
2850+ movement.dx = std::min(movement.dx, (bounds.bottom_right() - bottom_right).dx);
2851+
2852+ if (movement.dy > DeltaY{0})
2853+ movement.dy = std::min(movement.dy, (bounds.bottom_right() - bottom_right).dy);
2854+
2855+ auto new_pos = surface->top_left() + movement;
2856+
2857+ surface->move_to(new_pos);
2858+}
2859+
2860+void me::TilingWindowManagerPolicy::resize(std::shared_ptr<ms::Surface> surface, Point cursor, Point old_cursor, Rectangle bounds)
2861+{
2862+ if (surface && surface->input_area_contains(old_cursor))
2863+ {
2864+ auto const top_left = surface->top_left();
2865+
2866+ auto const old_displacement = old_cursor - top_left;
2867+ auto const new_displacement = cursor - top_left;
2868+
2869+ auto const scale_x = new_displacement.dx.as_float()/std::max(1.0f, old_displacement.dx.as_float());
2870+ auto const scale_y = new_displacement.dy.as_float()/std::max(1.0f, old_displacement.dy.as_float());
2871+
2872+ if (scale_x <= 0.0f || scale_y <= 0.0f) return;
2873+
2874+ auto const old_size = surface->size();
2875+ Size new_size{scale_x*old_size.width, scale_y*old_size.height};
2876+
2877+ auto const size_limits = as_size(bounds.bottom_right() - top_left);
2878+
2879+ if (new_size.width > size_limits.width)
2880+ new_size.width = size_limits.width;
2881+
2882+ if (new_size.height > size_limits.height)
2883+ new_size.height = size_limits.height;
2884+
2885+ surface->resize(new_size);
2886+ }
2887+}
2888+
2889+std::shared_ptr<ms::Surface> me::TilingWindowManagerPolicy::select_active_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<scene::Surface> const& surface)
2890+{
2891+ if (!surface)
2892+ {
2893+ tools->set_focus_to({}, {});
2894+ return surface;
2895+ }
2896+
2897+ auto const& info_for = tools->info_for(surface);
2898+
2899+ if (info_for.can_be_active())
2900+ {
2901+ tools->set_focus_to(session, surface);
2902+ tools->raise_tree(surface);
2903+ return surface;
2904+ }
2905+ else
2906+ {
2907+ // Cannot have input focus - try the parent
2908+ if (auto const parent = info_for.parent.lock())
2909+ return select_active_surface(session, parent);
2910+
2911+ return {};
2912+ }
2913+}
2914
2915=== added file 'src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.h'
2916--- src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.h 1970-01-01 00:00:00 +0000
2917+++ src/platforms/mirserver/wm-wip/server_example_tiling_window_manager.h 2016-03-11 11:36:44 +0000
2918@@ -0,0 +1,124 @@
2919+/*
2920+ * Copyright © 2015 Canonical Ltd.
2921+ *
2922+ * This program is free software: you can redistribute it and/or modify it
2923+ * under the terms of the GNU General Public License version 3,
2924+ * as published by the Free Software Foundation.
2925+ *
2926+ * This program is distributed in the hope that it will be useful,
2927+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2928+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2929+ * GNU General Public License for more details.
2930+ *
2931+ * You should have received a copy of the GNU General Public License
2932+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2933+ *
2934+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
2935+ */
2936+
2937+#ifndef MIR_EXAMPLE_TILING_WINDOW_MANAGER_H_
2938+#define MIR_EXAMPLE_TILING_WINDOW_MANAGER_H_
2939+
2940+#include "server_example_basic_window_manager.h"
2941+
2942+///\example server_example_tiling_window_manager.h
2943+/// Demonstrate implementing a simple tiling algorithm
2944+
2945+namespace mir
2946+{
2947+namespace examples
2948+{
2949+// simple tiling algorithm:
2950+// o Switch apps: tap or click on the corresponding tile
2951+// o Move window: Alt-leftmousebutton drag (three finger drag)
2952+// o Resize window: Alt-middle_button drag (two finger drag)
2953+// o Maximize/restore current window (to tile size): Alt-F11
2954+// o Maximize/restore current window (to tile height): Shift-F11
2955+// o Maximize/restore current window (to tile width): Ctrl-F11
2956+// o client requests to maximize, vertically maximize & restore
2957+class TilingWindowManagerPolicy : public WindowManagementPolicy
2958+{
2959+public:
2960+ explicit TilingWindowManagerPolicy(WindowManagerTools* const tools);
2961+
2962+ void click(geometry::Point cursor);
2963+
2964+ void handle_session_info_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays);
2965+
2966+ void handle_displays_updated(SessionInfoMap& session_info, geometry::Rectangles const& displays);
2967+
2968+ void resize(geometry::Point cursor);
2969+
2970+ auto handle_place_new_surface(
2971+ std::shared_ptr<scene::Session> const& session,
2972+ scene::SurfaceCreationParameters const& request_parameters)
2973+ -> scene::SurfaceCreationParameters;
2974+
2975+ void handle_new_surface(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface);
2976+
2977+ void handle_modify_surface(
2978+ std::shared_ptr<scene::Session> const& session,
2979+ std::shared_ptr<scene::Surface> const& surface,
2980+ shell::SurfaceSpecification const& modifications);
2981+
2982+ void handle_delete_surface(std::shared_ptr<scene::Session> const& session, std::weak_ptr<scene::Surface> const& surface);
2983+
2984+ int handle_set_state(std::shared_ptr<scene::Surface> const& surface, MirSurfaceState value);
2985+
2986+ void drag(geometry::Point cursor);
2987+
2988+ bool handle_keyboard_event(MirKeyboardEvent const* event);
2989+
2990+ bool handle_touch_event(MirTouchEvent const* event);
2991+
2992+ bool handle_pointer_event(MirPointerEvent const* event);
2993+
2994+ void handle_raise_surface(
2995+ std::shared_ptr<scene::Session> const& session,
2996+ std::shared_ptr<scene::Surface> const& surface);
2997+
2998+ void generate_decorations_for(
2999+ std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface,
3000+ SurfaceInfoMap& surface_info,
3001+ std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const&, scene::SurfaceCreationParameters const&)> const& build);
3002+
3003+private:
3004+ static const int modifier_mask =
3005+ mir_input_event_modifier_alt |
3006+ mir_input_event_modifier_shift |
3007+ mir_input_event_modifier_sym |
3008+ mir_input_event_modifier_ctrl |
3009+ mir_input_event_modifier_meta;
3010+
3011+ void toggle(MirSurfaceState state);
3012+
3013+ std::shared_ptr<scene::Session> session_under(geometry::Point position);
3014+
3015+ void update_tiles(
3016+ SessionInfoMap& session_info,
3017+ geometry::Rectangles const& displays);
3018+
3019+ void update_surfaces(std::weak_ptr<scene::Session> const& session, geometry::Rectangle const& old_tile, geometry::Rectangle const& new_tile);
3020+
3021+ static void clip_to_tile(scene::SurfaceCreationParameters& parameters, geometry::Rectangle const& tile);
3022+
3023+ static void fit_to_new_tile(scene::Surface& surface, geometry::Rectangle const& old_tile, geometry::Rectangle const& new_tile);
3024+
3025+ void drag(std::shared_ptr<scene::Surface> surface, geometry::Point to, geometry::Point from, geometry::Rectangle bounds);
3026+
3027+ static void resize(std::shared_ptr<scene::Surface> surface, geometry::Point cursor, geometry::Point old_cursor, geometry::Rectangle bounds);
3028+
3029+ static void constrained_move(std::shared_ptr<scene::Surface> const& surface, geometry::Displacement& movement, geometry::Rectangle const& bounds);
3030+
3031+ std::shared_ptr<scene::Surface> select_active_surface(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface);
3032+
3033+ WindowManagerTools* const tools;
3034+
3035+ geometry::Point old_cursor{};
3036+};
3037+
3038+using TilingWindowManager = WindowManagerBuilder<TilingWindowManagerPolicy>;
3039+}
3040+}
3041+
3042+#endif /* MIR_EXAMPLE_TILING_WINDOW_MANAGER_H_ */
3043
3044=== added file 'src/platforms/mirserver/wm-wip/server_example_window_management.cpp'
3045--- src/platforms/mirserver/wm-wip/server_example_window_management.cpp 1970-01-01 00:00:00 +0000
3046+++ src/platforms/mirserver/wm-wip/server_example_window_management.cpp 2016-03-11 11:36:44 +0000
3047@@ -0,0 +1,155 @@
3048+/*
3049+ * Copyright © 2014 Canonical Ltd.
3050+ *
3051+ * This program is free software: you can redistribute it and/or modify it
3052+ * under the terms of the GNU General Public License version 3,
3053+ * as published by the Free Software Foundation.
3054+ *
3055+ * This program is distributed in the hope that it will be useful,
3056+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3057+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3058+ * GNU General Public License for more details.
3059+ *
3060+ * You should have received a copy of the GNU General Public License
3061+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3062+ *
3063+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
3064+ */
3065+
3066+#include "server_example_window_management.h"
3067+
3068+#include "server_example_tiling_window_manager.h"
3069+#include "server_example_canonical_window_manager.h"
3070+
3071+#include "mir/abnormal_exit.h"
3072+#include "mir/server.h"
3073+#include "mir/input/composite_event_filter.h"
3074+#include "mir/options/option.h"
3075+#include "mir/scene/session.h"
3076+#include "mir/scene/surface_creation_parameters.h"
3077+#include "mir/shell/display_layout.h"
3078+#include "mir/shell/system_compositor_window_manager.h"
3079+
3080+namespace me = mir::examples;
3081+namespace mf = mir::frontend;
3082+namespace mg = mir::graphics;
3083+namespace mi = mir::input;
3084+namespace ms = mir::scene;
3085+namespace msh = mir::shell;
3086+using namespace mir::geometry;
3087+
3088+///\example server_example_window_management.cpp
3089+/// Demonstrate introducing a window management strategy
3090+
3091+namespace
3092+{
3093+char const* const wm_option = "window-manager";
3094+char const* const wm_description = "window management strategy [{tiling|fullscreen|canonical|system-compositor}]";
3095+
3096+char const* const wm_tiling = "tiling";
3097+char const* const wm_fullscreen = "fullscreen";
3098+char const* const wm_canonical = "canonical";
3099+char const* const wm_system_compositor = "system-compositor";
3100+
3101+// Very simple - make every surface fullscreen
3102+class FullscreenWindowManagerPolicy : public me::WindowManagementPolicy
3103+{
3104+public:
3105+ FullscreenWindowManagerPolicy(me::WindowManagerTools* const /*tools*/, std::shared_ptr<msh::DisplayLayout> const& display_layout) :
3106+ display_layout{display_layout} {}
3107+
3108+ void handle_session_info_updated(SessionInfoMap& /*session_info*/, Rectangles const& /*displays*/) {}
3109+
3110+ void handle_displays_updated(SessionInfoMap& /*session_info*/, Rectangles const& /*displays*/) {}
3111+
3112+ auto handle_place_new_surface(
3113+ std::shared_ptr<ms::Session> const& /*session*/,
3114+ ms::SurfaceCreationParameters const& request_parameters)
3115+ -> ms::SurfaceCreationParameters
3116+ {
3117+ auto placed_parameters = request_parameters;
3118+
3119+ Rectangle rect{request_parameters.top_left, request_parameters.size};
3120+ display_layout->size_to_output(rect);
3121+ placed_parameters.size = rect.size;
3122+
3123+ return placed_parameters;
3124+ }
3125+ void handle_modify_surface(
3126+ std::shared_ptr<ms::Session> const& /*session*/,
3127+ std::shared_ptr<ms::Surface> const& /*surface*/,
3128+ msh::SurfaceSpecification const& /*modifications*/)
3129+ {
3130+ }
3131+
3132+ void handle_new_surface(std::shared_ptr<ms::Session> const& /*session*/, std::shared_ptr<ms::Surface> const& /*surface*/)
3133+ {
3134+ }
3135+
3136+ void handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface)
3137+ { session->destroy_surface(surface); }
3138+
3139+ int handle_set_state(std::shared_ptr<ms::Surface> const& /*surface*/, MirSurfaceState value)
3140+ { return value; }
3141+
3142+ bool handle_keyboard_event(MirKeyboardEvent const* /*event*/) { return false; }
3143+
3144+ bool handle_touch_event(MirTouchEvent const* /*event*/) { return false; }
3145+
3146+ bool handle_pointer_event(MirPointerEvent const* /*event*/) { return false; }
3147+
3148+ void handle_raise_surface(
3149+ std::shared_ptr<ms::Session> const& /*session*/,
3150+ std::shared_ptr<ms::Surface> const& /*surface*/)
3151+ {
3152+ }
3153+
3154+ void generate_decorations_for(
3155+ std::shared_ptr<ms::Session> const&,
3156+ std::shared_ptr<ms::Surface> const&,
3157+ SurfaceInfoMap&,
3158+ std::function<mf::SurfaceId(std::shared_ptr<ms::Session> const&, ms::SurfaceCreationParameters const&)> const&)
3159+ {
3160+ }
3161+private:
3162+ std::shared_ptr<msh::DisplayLayout> const display_layout;
3163+};
3164+
3165+}
3166+
3167+using FullscreenWindowManager = me::WindowManagerBuilder<FullscreenWindowManagerPolicy>;
3168+using CanonicalWindowManager = me::WindowManagerBuilder<me::CanonicalWindowManagerPolicyCopy>;
3169+
3170+void me::add_window_manager_option_to(Server& server)
3171+{
3172+ server.add_configuration_option(wm_option, wm_description, wm_canonical);
3173+
3174+ server.override_the_window_manager_builder([&server](msh::FocusController* focus_controller)
3175+ -> std::shared_ptr<msh::WindowManager>
3176+ {
3177+ auto const options = server.get_options();
3178+ auto const selection = options->get<std::string>(wm_option);
3179+
3180+ if (selection == wm_tiling)
3181+ {
3182+ return std::make_shared<TilingWindowManager>(focus_controller);
3183+ }
3184+ else if (selection == wm_fullscreen)
3185+ {
3186+ return std::make_shared<FullscreenWindowManager>(focus_controller, server.the_shell_display_layout());
3187+ }
3188+ else if (selection == wm_canonical)
3189+ {
3190+ return std::make_shared<CanonicalWindowManager>(focus_controller, server.the_shell_display_layout());
3191+ }
3192+ else if (selection == wm_system_compositor)
3193+ {
3194+ return std::make_shared<msh::SystemCompositorWindowManager>(
3195+ focus_controller,
3196+ server.the_shell_display_layout(),
3197+ server.the_session_coordinator());
3198+ }
3199+
3200+ throw mir::AbnormalExit("Unknown window manager: " + selection);
3201+ });
3202+}
3203
3204=== added file 'src/platforms/mirserver/wm-wip/server_example_window_management.h'
3205--- src/platforms/mirserver/wm-wip/server_example_window_management.h 1970-01-01 00:00:00 +0000
3206+++ src/platforms/mirserver/wm-wip/server_example_window_management.h 2016-03-11 11:36:44 +0000
3207@@ -0,0 +1,33 @@
3208+/*
3209+ * Copyright © 2014 Canonical Ltd.
3210+ *
3211+ * This program is free software: you can redistribute it and/or modify it
3212+ * under the terms of the GNU General Public License version 3,
3213+ * as published by the Free Software Foundation.
3214+ *
3215+ * This program is distributed in the hope that it will be useful,
3216+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3217+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3218+ * GNU General Public License for more details.
3219+ *
3220+ * You should have received a copy of the GNU General Public License
3221+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3222+ *
3223+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
3224+ */
3225+
3226+#ifndef MIR_EXAMPLES_WINDOW_MANAGEMENT_H_
3227+#define MIR_EXAMPLES_WINDOW_MANAGEMENT_H_
3228+
3229+namespace mir
3230+{
3231+class Server;
3232+
3233+namespace examples
3234+{
3235+void add_window_manager_option_to(Server& server);
3236+}
3237+} // namespace mir
3238+
3239+
3240+#endif // MIR_EXAMPLES_WINDOW_MANAGEMENT_H_
3241
3242=== added file 'src/platforms/mirserver/wm-wip/server_example_window_management_info.cpp'
3243--- src/platforms/mirserver/wm-wip/server_example_window_management_info.cpp 1970-01-01 00:00:00 +0000
3244+++ src/platforms/mirserver/wm-wip/server_example_window_management_info.cpp 2016-03-11 11:36:44 +0000
3245@@ -0,0 +1,406 @@
3246+/*
3247+ * Copyright © 2015 Canonical Ltd.
3248+ *
3249+ * This program is free software: you can redistribute it and/or modify it
3250+ * under the terms of the GNU General Public License version 3,
3251+ * as published by the Free Software Foundation.
3252+ *
3253+ * This program is distributed in the hope that it will be useful,
3254+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3255+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3256+ * GNU General Public License for more details.
3257+ *
3258+ * You should have received a copy of the GNU General Public License
3259+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3260+ *
3261+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
3262+ */
3263+
3264+#include "server_example_window_management_info.h"
3265+
3266+#include "mir/scene/surface.h"
3267+#include "mir/scene/surface_creation_parameters.h"
3268+
3269+#include "mir/graphics/buffer.h"
3270+
3271+#include <atomic>
3272+
3273+namespace me = mir::examples;
3274+namespace ms = mir::scene;
3275+namespace mg = mir::graphics;
3276+using namespace mir::geometry;
3277+
3278+me::SurfaceInfo::SurfaceInfo(
3279+ std::shared_ptr<scene::Session> const& session,
3280+ std::shared_ptr<scene::Surface> const& surface,
3281+ scene::SurfaceCreationParameters const& params) :
3282+ type{surface->type()},
3283+ state{surface->state()},
3284+ restore_rect{surface->top_left(), surface->size()},
3285+ session{session},
3286+ parent{params.parent},
3287+ min_width{params.min_width.is_set() ? params.min_width.value() : Width{}},
3288+ min_height{params.min_height.is_set() ? params.min_height.value() : Height{}},
3289+ max_width{params.max_width.is_set() ? params.max_width.value() : Width{std::numeric_limits<int>::max()}},
3290+ max_height{params.max_height.is_set() ? params.max_height.value() : Height{std::numeric_limits<int>::max()}},
3291+ width_inc{params.width_inc},
3292+ height_inc{params.height_inc},
3293+ min_aspect{params.min_aspect},
3294+ max_aspect{params.max_aspect}
3295+{
3296+ if (params.output_id != mir::graphics::DisplayConfigurationOutputId{0})
3297+ output_id = params.output_id;
3298+}
3299+
3300+bool me::SurfaceInfo::can_be_active() const
3301+{
3302+ switch (type)
3303+ {
3304+ case mir_surface_type_normal: /**< AKA "regular" */
3305+ case mir_surface_type_utility: /**< AKA "floating" */
3306+ case mir_surface_type_dialog:
3307+ case mir_surface_type_satellite: /**< AKA "toolbox"/"toolbar" */
3308+ case mir_surface_type_freestyle:
3309+ case mir_surface_type_menu:
3310+ case mir_surface_type_inputmethod: /**< AKA "OSK" or handwriting etc. */
3311+ return true;
3312+
3313+ case mir_surface_type_gloss:
3314+ case mir_surface_type_tip: /**< AKA "tooltip" */
3315+ default:
3316+ // Cannot have input focus
3317+ return false;
3318+ }
3319+}
3320+
3321+bool me::SurfaceInfo::must_have_parent() const
3322+{
3323+ switch (type)
3324+ {
3325+ case mir_surface_type_overlay:;
3326+ case mir_surface_type_inputmethod:
3327+ case mir_surface_type_satellite:
3328+ case mir_surface_type_tip:
3329+ return true;
3330+
3331+ default:
3332+ return false;
3333+ }
3334+}
3335+
3336+bool me::SurfaceInfo::can_morph_to(MirSurfaceType new_type) const
3337+{
3338+ switch (new_type)
3339+ {
3340+ case mir_surface_type_normal:
3341+ case mir_surface_type_utility:
3342+ case mir_surface_type_satellite:
3343+ switch (type)
3344+ {
3345+ case mir_surface_type_normal:
3346+ case mir_surface_type_utility:
3347+ case mir_surface_type_dialog:
3348+ case mir_surface_type_satellite:
3349+ return true;
3350+
3351+ default:
3352+ break;
3353+ }
3354+ break;
3355+
3356+ case mir_surface_type_dialog:
3357+ switch (type)
3358+ {
3359+ case mir_surface_type_normal:
3360+ case mir_surface_type_utility:
3361+ case mir_surface_type_dialog:
3362+ case mir_surface_type_popover:
3363+ case mir_surface_type_satellite:
3364+ return true;
3365+
3366+ default:
3367+ break;
3368+ }
3369+ break;
3370+
3371+ default:
3372+ break;
3373+ }
3374+
3375+ return false;
3376+}
3377+
3378+bool me::SurfaceInfo::must_not_have_parent() const
3379+{
3380+ switch (type)
3381+ {
3382+ case mir_surface_type_normal:
3383+ case mir_surface_type_utility:
3384+ return true;
3385+
3386+ default:
3387+ return false;
3388+ }
3389+}
3390+
3391+bool me::SurfaceInfo::is_visible() const
3392+{
3393+ switch (state)
3394+ {
3395+ case mir_surface_state_hidden:
3396+ case mir_surface_state_minimized:
3397+ return false;
3398+ default:
3399+ break;
3400+ }
3401+ return true;
3402+}
3403+
3404+struct mir::examples::SurfaceInfo::StreamPainter
3405+{
3406+ virtual void paint(int) = 0;
3407+ virtual ~StreamPainter() = default;
3408+ StreamPainter() = default;
3409+ StreamPainter(StreamPainter const&) = delete;
3410+ StreamPainter& operator=(StreamPainter const&) = delete;
3411+};
3412+
3413+struct mir::examples::SurfaceInfo::SwappingPainter
3414+ : mir::examples::SurfaceInfo::StreamPainter
3415+{
3416+ SwappingPainter(std::shared_ptr<frontend::BufferStream> const& buffer_stream) :
3417+ buffer_stream{buffer_stream}, buffer{nullptr}
3418+ {
3419+ swap_buffers();
3420+ }
3421+
3422+ void swap_buffers()
3423+ {
3424+ auto const callback = [this](mir::graphics::Buffer* new_buffer)
3425+ {
3426+ buffer.store(new_buffer);
3427+ };
3428+
3429+ buffer_stream->swap_buffers(buffer, callback);
3430+ }
3431+
3432+ void paint(int intensity) override
3433+ {
3434+ if (auto const buf = buffer.load())
3435+ {
3436+ auto const format = buffer_stream->pixel_format();
3437+ auto const sz = buf->size().height.as_int() *
3438+ buf->size().width.as_int() * MIR_BYTES_PER_PIXEL(format);
3439+ std::vector<unsigned char> pixels(sz, intensity);
3440+ buf->write(pixels.data(), sz);
3441+ swap_buffers();
3442+ }
3443+ }
3444+
3445+ std::shared_ptr<frontend::BufferStream> const buffer_stream;
3446+ std::atomic<graphics::Buffer*> buffer;
3447+};
3448+
3449+struct mir::examples::SurfaceInfo::AllocatingPainter
3450+ : mir::examples::SurfaceInfo::StreamPainter
3451+{
3452+ AllocatingPainter(std::shared_ptr<frontend::BufferStream> const& buffer_stream, Size size) :
3453+ buffer_stream(buffer_stream),
3454+ properties({
3455+ size,
3456+ buffer_stream->pixel_format(),
3457+ mg::BufferUsage::software
3458+ }),
3459+ front_buffer(buffer_stream->allocate_buffer(properties)),
3460+ back_buffer(buffer_stream->allocate_buffer(properties))
3461+ {
3462+ }
3463+
3464+ void paint(int intensity) override
3465+ {
3466+ buffer_stream->with_buffer(back_buffer,
3467+ [this, intensity](graphics::Buffer& buffer)
3468+ {
3469+ auto const format = buffer.pixel_format();
3470+ auto const sz = buffer.size().height.as_int() *
3471+ buffer.size().width.as_int() * MIR_BYTES_PER_PIXEL(format);
3472+ std::vector<unsigned char> pixels(sz, intensity);
3473+ buffer.write(pixels.data(), sz);
3474+ buffer_stream->swap_buffers(&buffer, [](mg::Buffer*){});
3475+ });
3476+ std::swap(front_buffer, back_buffer);
3477+ }
3478+
3479+ ~AllocatingPainter()
3480+ {
3481+ buffer_stream->remove_buffer(front_buffer);
3482+ buffer_stream->remove_buffer(back_buffer);
3483+ }
3484+
3485+ std::shared_ptr<frontend::BufferStream> const buffer_stream;
3486+ mg::BufferProperties properties;
3487+ mg::BufferID front_buffer;
3488+ mg::BufferID back_buffer;
3489+};
3490+
3491+void mir::examples::SurfaceInfo::init_titlebar(std::shared_ptr<scene::Surface> const& surface)
3492+{
3493+ auto stream = surface->primary_buffer_stream();
3494+ try
3495+ {
3496+ stream_painter = std::make_shared<AllocatingPainter>(stream, surface->size());
3497+ }
3498+ catch (...)
3499+ {
3500+ stream_painter = std::make_shared<SwappingPainter>(stream);
3501+ }
3502+}
3503+
3504+void mir::examples::SurfaceInfo::paint_titlebar(int intensity)
3505+{
3506+ stream_painter->paint(intensity);
3507+}
3508+
3509+void me::SurfaceInfo::constrain_resize(
3510+ std::shared_ptr<ms::Surface> const& surface,
3511+ Point& requested_pos,
3512+ Size& requested_size,
3513+ bool const left_resize,
3514+ bool const top_resize,
3515+ Rectangle const& /*bounds*/) const
3516+{
3517+ Point new_pos = requested_pos;
3518+ Size new_size = requested_size;
3519+
3520+ if (min_aspect.is_set())
3521+ {
3522+ auto const ar = min_aspect.value();
3523+
3524+ auto const error = new_size.height.as_int()*long(ar.width) - new_size.width.as_int()*long(ar.height);
3525+
3526+ if (error > 0)
3527+ {
3528+ // Add (denominator-1) to numerator to ensure rounding up
3529+ auto const width_correction = (error+(ar.height-1))/ar.height;
3530+ auto const height_correction = (error+(ar.width-1))/ar.width;
3531+
3532+ if (width_correction < height_correction)
3533+ {
3534+ new_size.width = new_size.width + DeltaX(width_correction);
3535+ }
3536+ else
3537+ {
3538+ new_size.height = new_size.height - DeltaY(height_correction);
3539+ }
3540+ }
3541+ }
3542+
3543+ if (max_aspect.is_set())
3544+ {
3545+ auto const ar = max_aspect.value();
3546+
3547+ auto const error = new_size.width.as_int()*long(ar.height) - new_size.height.as_int()*long(ar.width);
3548+
3549+ if (error > 0)
3550+ {
3551+ // Add (denominator-1) to numerator to ensure rounding up
3552+ auto const height_correction = (error+(ar.width-1))/ar.width;
3553+ auto const width_correction = (error+(ar.height-1))/ar.height;
3554+
3555+ if (width_correction < height_correction)
3556+ {
3557+ new_size.width = new_size.width - DeltaX(width_correction);
3558+ }
3559+ else
3560+ {
3561+ new_size.height = new_size.height + DeltaY(height_correction);
3562+ }
3563+ }
3564+ }
3565+
3566+ if (min_width > new_size.width)
3567+ new_size.width = min_width;
3568+
3569+ if (min_height > new_size.height)
3570+ new_size.height = min_height;
3571+
3572+ if (max_width < new_size.width)
3573+ new_size.width = max_width;
3574+
3575+ if (max_height < new_size.height)
3576+ new_size.height = max_height;
3577+
3578+ if (width_inc.is_set())
3579+ {
3580+ auto const width = new_size.width.as_int() - min_width.as_int();
3581+ auto inc = width_inc.value().as_int();
3582+ if (width % inc)
3583+ new_size.width = min_width + DeltaX{inc*(((2L*width + inc)/2)/inc)};
3584+ }
3585+
3586+ if (height_inc.is_set())
3587+ {
3588+ auto const height = new_size.height.as_int() - min_height.as_int();
3589+ auto inc = height_inc.value().as_int();
3590+ if (height % inc)
3591+ new_size.height = min_height + DeltaY{inc*(((2L*height + inc)/2)/inc)};
3592+ }
3593+
3594+ if (left_resize)
3595+ new_pos.x += new_size.width - requested_size.width;
3596+
3597+ if (top_resize)
3598+ new_pos.y += new_size.height - requested_size.height;
3599+
3600+ // placeholder - constrain onscreen
3601+
3602+ switch (state)
3603+ {
3604+ case mir_surface_state_restored:
3605+ break;
3606+
3607+ // "A vertically maximised surface is anchored to the top and bottom of
3608+ // the available workspace and can have any width."
3609+ case mir_surface_state_vertmaximized:
3610+ new_pos.y = surface->top_left().y;
3611+ new_size.height = surface->size().height;
3612+ break;
3613+
3614+ // "A horizontally maximised surface is anchored to the left and right of
3615+ // the available workspace and can have any height"
3616+ case mir_surface_state_horizmaximized:
3617+ new_pos.x = surface->top_left().x;
3618+ new_size.width = surface->size().width;
3619+ break;
3620+
3621+ // "A maximised surface is anchored to the top, bottom, left and right of the
3622+ // available workspace. For example, if the launcher is always-visible then
3623+ // the left-edge of the surface is anchored to the right-edge of the launcher."
3624+ case mir_surface_state_maximized:
3625+ default:
3626+ new_pos.x = surface->top_left().x;
3627+ new_pos.y = surface->top_left().y;
3628+ new_size.width = surface->size().width;
3629+ new_size.height = surface->size().height;
3630+ break;
3631+ }
3632+
3633+ requested_pos = new_pos;
3634+ requested_size = new_size;
3635+}
3636+
3637+bool me::SurfaceInfo::needs_titlebar(MirSurfaceType type)
3638+{
3639+ switch (type)
3640+ {
3641+ case mir_surface_type_freestyle:
3642+ case mir_surface_type_menu:
3643+ case mir_surface_type_inputmethod:
3644+ case mir_surface_type_gloss:
3645+ case mir_surface_type_tip:
3646+ // No decorations for these surface types
3647+ return false;
3648+ default:
3649+ return true;
3650+ }
3651+}
3652
3653=== added file 'src/platforms/mirserver/wm-wip/server_example_window_management_info.h'
3654--- src/platforms/mirserver/wm-wip/server_example_window_management_info.h 1970-01-01 00:00:00 +0000
3655+++ src/platforms/mirserver/wm-wip/server_example_window_management_info.h 2016-03-11 11:36:44 +0000
3656@@ -0,0 +1,103 @@
3657+/*
3658+ * Copyright © 2015 Canonical Ltd.
3659+ *
3660+ * This program is free software: you can redistribute it and/or modify it
3661+ * under the terms of the GNU General Public License version 3,
3662+ * as published by the Free Software Foundation.
3663+ *
3664+ * This program is distributed in the hope that it will be useful,
3665+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3666+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3667+ * GNU General Public License for more details.
3668+ *
3669+ * You should have received a copy of the GNU General Public License
3670+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3671+ *
3672+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
3673+ */
3674+
3675+#ifndef MIR_SERVER_EXAMPLE_WINDOW_MANAGEMENT_INFO_H
3676+#define MIR_SERVER_EXAMPLE_WINDOW_MANAGEMENT_INFO_H
3677+
3678+#include "mir/geometry/rectangles.h"
3679+#include "mir/optional_value.h"
3680+#include "mir/shell/surface_specification.h"
3681+
3682+#include <vector>
3683+
3684+namespace mir
3685+{
3686+namespace scene { class Session; class Surface; class SurfaceCreationParameters; }
3687+namespace examples
3688+{
3689+struct SurfaceInfo
3690+{
3691+ SurfaceInfo(
3692+ std::shared_ptr <scene::Session> const& session,
3693+ std::shared_ptr <scene::Surface> const& surface,
3694+ scene::SurfaceCreationParameters const& params);
3695+
3696+ bool can_be_active() const;
3697+
3698+ bool can_morph_to(MirSurfaceType new_type) const;
3699+
3700+ bool must_have_parent() const;
3701+
3702+ bool must_not_have_parent() const;
3703+
3704+ bool is_visible() const;
3705+
3706+ static bool needs_titlebar(MirSurfaceType type);
3707+
3708+ void constrain_resize(
3709+ std::shared_ptr <scene::Surface> const& surface,
3710+ geometry::Point& requested_pos,
3711+ geometry::Size& requested_size,
3712+ const bool left_resize,
3713+ const bool top_resize,
3714+ geometry::Rectangle const& bounds) const;
3715+
3716+ MirSurfaceType type;
3717+ MirSurfaceState state;
3718+ geometry::Rectangle restore_rect;
3719+ std::weak_ptr <scene::Session> session;
3720+ std::weak_ptr <scene::Surface> parent;
3721+ std::vector <std::weak_ptr<scene::Surface>> children;
3722+ std::shared_ptr <scene::Surface> titlebar;
3723+ frontend::SurfaceId titlebar_id;
3724+ bool is_titlebar = false;
3725+ geometry::Width min_width;
3726+ geometry::Height min_height;
3727+ geometry::Width max_width;
3728+ geometry::Height max_height;
3729+ mir::optional_value<geometry::DeltaX> width_inc;
3730+ mir::optional_value<geometry::DeltaY> height_inc;
3731+ mir::optional_value<shell::SurfaceAspectRatio> min_aspect;
3732+ mir::optional_value<shell::SurfaceAspectRatio> max_aspect;
3733+ mir::optional_value<graphics::DisplayConfigurationOutputId> output_id;
3734+
3735+ void init_titlebar(std::shared_ptr <scene::Surface> const& surface);
3736+
3737+ void paint_titlebar(int intensity);
3738+
3739+private:
3740+
3741+ struct StreamPainter;
3742+ struct AllocatingPainter;
3743+ struct SwappingPainter;
3744+
3745+ std::shared_ptr <StreamPainter> stream_painter;
3746+};
3747+
3748+struct SessionInfo
3749+{
3750+ std::vector<std::weak_ptr<scene::Surface>> surfaces;
3751+
3752+ // This is only used by the TilingWindowManagerPolicy,
3753+ // perhaps we need a more extensible mechanism. (std::experimental::any?)
3754+ geometry::Rectangle tile;
3755+};
3756+}
3757+}
3758+
3759+#endif //MIR_SERVER_EXAMPLE_WINDOW_MANAGEMENT_INFO_H
3760
3761=== modified file 'tests/framework/mock_proc_info.cpp'
3762--- tests/framework/mock_proc_info.cpp 2015-11-20 16:47:09 +0000
3763+++ tests/framework/mock_proc_info.cpp 2016-03-11 11:36:44 +0000
3764@@ -21,6 +21,8 @@
3765
3766 MockProcInfo::MockProcInfo()
3767 {
3768+ using namespace ::testing;
3769+ ON_CALL(*this, command_line(_)).WillByDefault(Return(QByteArray()));
3770 }
3771
3772 MockProcInfo::~MockProcInfo()
3773
3774=== modified file 'tests/framework/mock_session.cpp'
3775--- tests/framework/mock_session.cpp 2015-10-19 10:45:42 +0000
3776+++ tests/framework/mock_session.cpp 2016-03-11 11:36:44 +0000
3777@@ -23,6 +23,7 @@
3778 : SessionInterface(0)
3779 {
3780 m_state = Starting;
3781+ ON_CALL(*this, name()).WillByDefault(::testing::Return(QString()));
3782 ON_CALL(*this, suspend()).WillByDefault(::testing::Invoke(this, &MockSession::doSuspend));
3783 ON_CALL(*this, resume()).WillByDefault(::testing::Invoke(this, &MockSession::doResume));
3784 ON_CALL(*this, stop()).WillByDefault(::testing::Invoke(this, &MockSession::doStop));
3785
3786=== modified file 'tests/framework/mock_task_controller.cpp'
3787--- tests/framework/mock_task_controller.cpp 2016-02-11 11:52:06 +0000
3788+++ tests/framework/mock_task_controller.cpp 2016-03-11 11:36:44 +0000
3789@@ -68,11 +68,11 @@
3790
3791 bool MockTaskController::doAppIdHasProcessId(const QString &appId, pid_t pid)
3792 {
3793- auto it = children.find(appId);
3794- if (it == children.end())
3795- return -1;
3796+ auto primaryPid = primaryPidForAppId(appId);
3797+ if (primaryPid == -1)
3798+ return false;
3799
3800- return it->pid() == pid;
3801+ return primaryPid == pid;
3802 }
3803
3804
3805
3806=== modified file 'tests/framework/qtmir_test.cpp'
3807--- tests/framework/qtmir_test.cpp 2016-02-11 11:52:06 +0000
3808+++ tests/framework/qtmir_test.cpp 2016-03-11 11:36:44 +0000
3809@@ -99,13 +99,13 @@
3810 };
3811
3812
3813-namespace { char const* argv[] = { nullptr }; }
3814+namespace { int argc = 0; char* argv[] = { nullptr }; }
3815
3816 class FakeMirServer: private TestMirServerInit, public MirServer
3817 {
3818 public:
3819 FakeMirServer(std::shared_ptr<StubPromptSessionManager> const& promptSessionManager)
3820- : TestMirServerInit(promptSessionManager), MirServer(0, argv, QSharedPointer<ScreenController>())
3821+ : TestMirServerInit(promptSessionManager), MirServer(argc, argv, QSharedPointer<ScreenController>())
3822 {
3823 }
3824
3825
3826=== added directory 'tests/mirserver/ArgvHelper'
3827=== added file 'tests/mirserver/ArgvHelper/CMakeLists.txt'
3828--- tests/mirserver/ArgvHelper/CMakeLists.txt 1970-01-01 00:00:00 +0000
3829+++ tests/mirserver/ArgvHelper/CMakeLists.txt 2016-03-11 11:36:44 +0000
3830@@ -0,0 +1,18 @@
3831+set(
3832+ ARGVHELPER_TEST_SOURCES
3833+ argvHelper_test.cpp
3834+)
3835+
3836+add_executable(ArgvHelperTest ${ARGVHELPER_TEST_SOURCES})
3837+
3838+include_directories(
3839+ ${CMAKE_SOURCE_DIR}/src/platforms/mirserver
3840+)
3841+
3842+target_link_libraries(
3843+ ArgvHelperTest
3844+
3845+ ${GTEST_BOTH_LIBRARIES}
3846+)
3847+
3848+add_test(ArgvHelper, ArgvHelperTest)
3849
3850=== added file 'tests/mirserver/ArgvHelper/argvHelper_test.cpp'
3851--- tests/mirserver/ArgvHelper/argvHelper_test.cpp 1970-01-01 00:00:00 +0000
3852+++ tests/mirserver/ArgvHelper/argvHelper_test.cpp 2016-03-11 11:36:44 +0000
3853@@ -0,0 +1,72 @@
3854+/*
3855+ * Copyright (C) 2015 Canonical, Ltd.
3856+ *
3857+ * This program is free software: you can redistribute it and/or modify it under
3858+ * the terms of the GNU Lesser General Public License version 3, as published by
3859+ * the Free Software Foundation.
3860+ *
3861+ * This program is distributed in the hope that it will be useful, but WITHOUT
3862+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
3863+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3864+ * Lesser General Public License for more details.
3865+ *
3866+ * You should have received a copy of the GNU Lesser General Public License
3867+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3868+ */
3869+
3870+#include <gtest/gtest.h>
3871+
3872+#include <argvHelper.h>
3873+
3874+using namespace qtmir;
3875+
3876+TEST(ArgvHelperTest, StripsCorrectly)
3877+{
3878+ int argc = 5;
3879+ const char *argv[6] = { "/usr/bin/unity8", "-fullscreen", "--debug",
3880+ "--platform-input-lib=/path/to/lib.so", "-testability", nullptr };
3881+
3882+ const int filteredArgc = 2;
3883+ const char *filteredArgv[3] = { "-fullscreen", "-testability", nullptr };
3884+
3885+ editArgvToMatch(argc, const_cast<char**>(argv), filteredArgc, filteredArgv);
3886+
3887+ EXPECT_EQ(argc, 3);
3888+ EXPECT_EQ(argv[0], "/usr/bin/unity8");
3889+ EXPECT_EQ(argv[1], "-fullscreen");
3890+ EXPECT_EQ(argv[2], "-testability");
3891+ EXPECT_EQ(argv[3], nullptr);
3892+}
3893+
3894+TEST(ArgvHelperTest, NothingToStrip)
3895+{
3896+ int argc = 4;
3897+ const char *argv[5] = { "/usr/bin/unity8", "-fullscreen", "--multisample", "-testability", nullptr };
3898+
3899+ const int filteredArgc = 3;
3900+ const char *filteredArgv[4] = { "-fullscreen", "-testability", "--multisample", nullptr };
3901+
3902+ editArgvToMatch(argc, const_cast<char**>(argv), filteredArgc, filteredArgv);
3903+
3904+ EXPECT_EQ(argc, 4);
3905+ EXPECT_EQ(argv[0], "/usr/bin/unity8");
3906+ EXPECT_EQ(argv[1], "-fullscreen");
3907+ EXPECT_EQ(argv[2], "-testability");
3908+ EXPECT_EQ(argv[3], "--multisample");
3909+ EXPECT_EQ(argv[4], nullptr);
3910+}
3911+
3912+TEST(ArgvHelperTest, NothingToDo)
3913+{
3914+ int argc = 1;
3915+ const char *argv[2] = { "/usr/bin/unity8", nullptr };
3916+
3917+ const int filteredArgc = 0;
3918+ const char *filteredArgv[1] = { nullptr };
3919+
3920+ editArgvToMatch(argc, const_cast<char**>(argv), filteredArgc, filteredArgv);
3921+
3922+ EXPECT_EQ(argc, 1);
3923+ EXPECT_EQ(argv[0], "/usr/bin/unity8");
3924+ EXPECT_EQ(argv[1], nullptr);
3925+}
3926
3927=== modified file 'tests/mirserver/CMakeLists.txt'
3928--- tests/mirserver/CMakeLists.txt 2015-10-27 10:17:45 +0000
3929+++ tests/mirserver/CMakeLists.txt 2016-03-11 11:36:44 +0000
3930@@ -1,3 +1,4 @@
3931+add_subdirectory(ArgvHelper)
3932 add_subdirectory(QtEventFeeder)
3933 add_subdirectory(Clipboard)
3934 add_subdirectory(Screen)
3935
3936=== modified file 'tests/mirserver/Screen/screen_test.cpp'
3937--- tests/mirserver/Screen/screen_test.cpp 2015-10-14 22:59:04 +0000
3938+++ tests/mirserver/Screen/screen_test.cpp 2016-03-11 11:36:44 +0000
3939@@ -42,9 +42,23 @@
3940 Screen::skipDBusRegistration = true;
3941 }
3942
3943-TEST_F(ScreenTest, OrientationSensor)
3944-{
3945- Screen *screen = new Screen(fakeOutput1);
3946+TEST_F(ScreenTest, OrientationSensorForExternalDisplay)
3947+{
3948+ Screen *screen = new Screen(fakeOutput1); // is external display (dvi)
3949+
3950+ // Default state should be disabled
3951+ ASSERT_FALSE(screen->orientationSensorEnabled());
3952+
3953+ screen->onDisplayPowerStateChanged(0,0);
3954+ ASSERT_FALSE(screen->orientationSensorEnabled());
3955+
3956+ screen->onDisplayPowerStateChanged(1,0);
3957+ ASSERT_FALSE(screen->orientationSensorEnabled());
3958+}
3959+
3960+TEST_F(ScreenTest, OrientationSensorForInternalDisplay)
3961+{
3962+ Screen *screen = new Screen(fakeOutput2); // is internal display
3963
3964 // Default state should be active
3965 ASSERT_TRUE(screen->orientationSensorEnabled());
3966
3967=== modified file 'tests/modules/ApplicationManager/application_manager_test.cpp'
3968--- tests/modules/ApplicationManager/application_manager_test.cpp 2016-02-12 00:07:09 +0000
3969+++ tests/modules/ApplicationManager/application_manager_test.cpp 2016-03-11 11:36:44 +0000
3970@@ -71,6 +71,13 @@
3971 ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
3972 }
3973
3974+ static inline qtmir::DesktopFileReader* createMockDesktopFileReader(const QString &appId, const QFileInfo &fi) {
3975+ using namespace ::testing;
3976+ auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, fi);
3977+ ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
3978+ return mockDesktopFileReader;
3979+ }
3980+
3981 protected:
3982 virtual void SetUp() override {
3983 if (m_tempDir.isValid()) qputenv("XDG_CACHE_HOME", m_tempDir.path().toUtf8());
3984@@ -751,11 +758,7 @@
3985 const QString appId("testAppId");
3986
3987 // Set up Mocks & signal watcher
3988- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
3989- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
3990- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
3991-
3992- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
3993+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
3994
3995 EXPECT_CALL(*taskController, start(appId, _))
3996 .Times(1)
3997@@ -789,11 +792,8 @@
3998 const pid_t procId = 5551;
3999
4000 // Set up Mocks & signal watcher
4001- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4002- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4003- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4004-
4005- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4006+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4007+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4008
4009 EXPECT_CALL(*taskController, start(appId, _))
4010 .Times(1)
4011@@ -833,11 +833,8 @@
4012 const pid_t procId = 5551;
4013
4014 // Set up Mocks & signal watcher
4015- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4016- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4017- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4018-
4019- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4020+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4021+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4022
4023 EXPECT_CALL(*taskController, start(appId, _))
4024 .Times(1)
4025@@ -869,16 +866,11 @@
4026 {
4027 using namespace ::testing;
4028 const QString appId("testAppId");
4029- const QString desktopFilePath("testAppId.desktop");
4030 const pid_t procId = 5551;
4031
4032 // Set up Mocks & signal watcher
4033- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4034- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4035- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4036- ON_CALL(*mockDesktopFileReader, file()).WillByDefault(Return(desktopFilePath));
4037-
4038- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4039+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4040+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4041
4042 EXPECT_CALL(*taskController, start(appId, _))
4043 .Times(1)
4044@@ -917,11 +909,8 @@
4045 const pid_t procId = 5551;
4046
4047 // Set up Mocks & signal watcher
4048- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4049- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4050- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4051-
4052- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4053+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4054+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4055
4056 EXPECT_CALL(*taskController, start(appId, _))
4057 .Times(1)
4058@@ -960,11 +949,8 @@
4059 const pid_t procId = 5551;
4060
4061 // Set up Mocks & signal watcher
4062- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4063- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4064- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4065-
4066- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4067+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4068+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4069
4070 EXPECT_CALL(*taskController, start(appId, _))
4071 .Times(1)
4072@@ -1006,11 +992,8 @@
4073 const pid_t procId = 5551;
4074
4075 // Set up Mocks & signal watcher
4076- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4077- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4078- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4079-
4080- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4081+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4082+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4083
4084 EXPECT_CALL(*taskController, start(appId, _))
4085 .Times(1)
4086@@ -1051,11 +1034,8 @@
4087 const pid_t procId = 5551;
4088
4089 // Set up Mocks & signal watcher
4090- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4091- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4092- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4093-
4094- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4095+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4096+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4097
4098 EXPECT_CALL(*taskController, start(appId, _))
4099 .Times(1)
4100@@ -1102,11 +1082,8 @@
4101 const pid_t procId = 5551;
4102
4103 // Set up Mocks & signal watcher
4104- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4105- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4106- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4107-
4108- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4109+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4110+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4111
4112 EXPECT_CALL(*taskController, start(appId, _))
4113 .Times(1)
4114@@ -1160,11 +1137,8 @@
4115 const pid_t procId = 5551;
4116
4117 // Set up Mocks & signal watcher
4118- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4119- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4120- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4121-
4122- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4123+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4124+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4125
4126 EXPECT_CALL(*taskController, start(appId, _))
4127 .Times(1)
4128@@ -1213,11 +1187,8 @@
4129 const pid_t procId = 5551;
4130
4131 // Set up Mocks & signal watcher
4132- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4133- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4134- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4135-
4136- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4137+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4138+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4139
4140 EXPECT_CALL(*taskController, start(appId, _))
4141 .Times(1)
4142@@ -1252,11 +1223,8 @@
4143 const pid_t procId = 5551;
4144
4145 // Set up Mocks & signal watcher
4146- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4147- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4148- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4149-
4150- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4151+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4152+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4153
4154 EXPECT_CALL(*taskController, start(appId, _))
4155 .Times(1)
4156@@ -1348,11 +1316,8 @@
4157 const pid_t procId = 5551;
4158
4159 // Set up Mocks & signal watcher
4160- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4161- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4162- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4163-
4164- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4165+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4166+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4167
4168 EXPECT_CALL(*taskController, start(appId, _))
4169 .Times(1)
4170@@ -1407,12 +1372,8 @@
4171 const pid_t procId = 5551;
4172
4173 // Set up Mocks & signal watcher
4174- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4175- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4176- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4177- ON_CALL(*mockDesktopFileReader, file()).WillByDefault(Return(appId + ".desktop"));
4178-
4179- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4180+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4181+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4182
4183 EXPECT_CALL(*taskController, start(appId, _))
4184 .Times(1)
4185@@ -1465,11 +1426,7 @@
4186 ON_CALL(*taskController,appIdHasProcessId(_, procId2)).WillByDefault(Return(false));
4187
4188 // Set up Mocks & signal watcher
4189- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4190- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4191- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4192-
4193- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4194+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4195
4196 EXPECT_CALL(*taskController, start(appId, _))
4197 .Times(1)
4198@@ -1525,11 +1482,7 @@
4199 ON_CALL(*taskController,appIdHasProcessId(_, procId2)).WillByDefault(Return(false));
4200
4201 // Set up Mocks & signal watcher
4202- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4203- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4204- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4205-
4206- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4207+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4208
4209 EXPECT_CALL(*taskController, start(appId, _))
4210 .Times(1)
4211@@ -1583,11 +1536,8 @@
4212 const pid_t procId = 5551;
4213
4214 // Set up Mocks & signal watcher
4215- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4216- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4217- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4218-
4219- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4220+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4221+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4222
4223 EXPECT_CALL(*taskController, start(appId, _))
4224 .Times(1)
4225@@ -1629,19 +1579,14 @@
4226 {
4227 using namespace testing;
4228 const QString appId("webapp");
4229- const QString desktopFilePath("webapp.desktop");
4230 const pid_t procId = 5551;
4231
4232 std::mutex mutex;
4233 std::condition_variable cv;
4234 bool done = false;
4235
4236- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4237- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4238- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4239- ON_CALL(*mockDesktopFileReader, file()).WillByDefault(Return(desktopFilePath));
4240-
4241- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4242+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4243+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4244
4245 EXPECT_CALL(*taskController, start(appId, _))
4246 .Times(1)
4247@@ -1753,11 +1698,8 @@
4248 const quint64 procId = 12345;
4249
4250 // Set up Mocks & signal watcher
4251- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4252- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4253- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4254-
4255- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4256+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4257+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4258
4259 EXPECT_CALL(*taskController, start(appId, _))
4260 .Times(1)
4261@@ -1821,11 +1763,8 @@
4262 const quint64 procId = 12345;
4263
4264 // Set up Mocks & signal watcher
4265- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4266- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4267- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4268-
4269- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4270+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4271+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4272
4273 EXPECT_CALL(*taskController, start(appId, _))
4274 .Times(1)
4275@@ -1863,12 +1802,8 @@
4276 const pid_t procId = 5551;
4277
4278 // Set up Mocks & signal watcher
4279- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4280- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4281- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4282- ON_CALL(*mockDesktopFileReader, file()).WillByDefault(Return(appId + ".desktop"));
4283-
4284- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4285+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4286+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4287
4288 EXPECT_CALL(*taskController, start(appId, _))
4289 .Times(1)
4290@@ -1908,11 +1843,8 @@
4291 const pid_t procId = 5551;
4292
4293 // Set up Mocks & signal watcher
4294- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4295- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4296- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4297-
4298- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4299+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4300+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4301
4302 EXPECT_CALL(*taskController, start(appId, _))
4303 .Times(1)
4304@@ -1957,11 +1889,8 @@
4305 const pid_t procId = 5551;
4306
4307 // Set up Mocks & signal watcher
4308- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4309- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4310- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4311-
4312- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4313+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4314+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4315
4316 EXPECT_CALL(*taskController, start(appId, _))
4317 .Times(1)
4318@@ -2032,12 +1961,8 @@
4319 const QString appId("testAppId");
4320 quint64 procId = 5551;
4321
4322- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
4323- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
4324- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
4325- ON_CALL(*mockDesktopFileReader, file()).WillByDefault(Return(appId + ".desktop"));
4326-
4327- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
4328+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4329+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4330
4331 EXPECT_CALL(*taskController, start(appId, _))
4332 .Times(1)
4333@@ -2085,10 +2010,8 @@
4334 const QString appId("testAppId");
4335 quint64 procId = 5551;
4336
4337- ON_CALL(desktopFileReaderFactory, createInstance(appId, _))
4338- .WillByDefault(Invoke(
4339- [](const QString &appId, const QFileInfo&) { return new FakeDesktopFileReader(appId); }
4340- ));
4341+ ON_CALL(*taskController, primaryPidForAppId(appId)).WillByDefault(Return(procId));
4342+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Invoke(createMockDesktopFileReader));
4343
4344 EXPECT_CALL(*taskController, start(appId, _))
4345 .Times(1)

Subscribers

People subscribed via source and target branches