Merge lp:~gerboland/qtmir/multimonitor-spike into lp:qtmir

Proposed by Gerry Boland
Status: Superseded
Proposed branch: lp:~gerboland/qtmir/multimonitor-spike
Merge into: lp:qtmir
Diff against target: 3591 lines (+2090/-463)
51 files modified
debian/changelog (+6/-0)
demos/qml-demo-shell/qml-demo-shell.qml (+71/-1)
src/modules/Unity/CMakeLists.txt (+1/-0)
src/modules/Unity/Screens/CMakeLists.txt (+18/-0)
src/modules/Unity/Screens/plugin.cpp (+41/-0)
src/modules/Unity/Screens/qmldir (+2/-0)
src/modules/Unity/Screens/screens.cpp (+71/-0)
src/modules/Unity/Screens/screens.h (+54/-0)
src/platforms/mirserver/CMakeLists.txt (+4/-2)
src/platforms/mirserver/display.cpp (+0/-46)
src/platforms/mirserver/display.h (+0/-39)
src/platforms/mirserver/logging.h (+1/-0)
src/platforms/mirserver/miropenglcontext.cpp (+24/-9)
src/platforms/mirserver/mirserver.cpp (+32/-4)
src/platforms/mirserver/mirserver.h (+7/-3)
src/platforms/mirserver/mirserverintegration.cpp (+45/-40)
src/platforms/mirserver/mirserverintegration.h (+4/-7)
src/platforms/mirserver/offscreensurface.cpp (+61/-0)
src/platforms/mirserver/offscreensurface.h (+43/-0)
src/platforms/mirserver/qmirserver.cpp (+12/-2)
src/platforms/mirserver/qmirserver.h (+3/-0)
src/platforms/mirserver/qmirserver_p.h (+2/-0)
src/platforms/mirserver/qtcompositor.cpp (+10/-35)
src/platforms/mirserver/qtcompositor.h (+14/-6)
src/platforms/mirserver/qteventfeeder.cpp (+96/-87)
src/platforms/mirserver/qteventfeeder.h (+13/-9)
src/platforms/mirserver/screen.cpp (+97/-8)
src/platforms/mirserver/screen.h (+32/-4)
src/platforms/mirserver/screencontroller.cpp (+261/-0)
src/platforms/mirserver/screencontroller.h (+96/-0)
src/platforms/mirserver/screenwindow.cpp (+32/-83)
src/platforms/mirserver/screenwindow.h (+11/-27)
src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp (+44/-0)
src/platforms/mirserver/tileddisplayconfigurationpolicy.h (+35/-0)
tests/common/fake_displayconfigurationoutput.h (+73/-0)
tests/common/gmock_fixes.h (+124/-0)
tests/common/mock_display.h (+53/-0)
tests/common/mock_display_buffer.h (+43/-0)
tests/common/mock_display_configuration.h (+35/-0)
tests/common/mock_main_loop.h (+53/-0)
tests/mirserver/CMakeLists.txt (+1/-0)
tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h (+17/-10)
tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp (+27/-16)
tests/mirserver/Screen/CMakeLists.txt (+1/-0)
tests/mirserver/Screen/screen_test.cpp (+38/-24)
tests/mirserver/ScreenController/CMakeLists.txt (+28/-0)
tests/mirserver/ScreenController/screencontroller_test.cpp (+193/-0)
tests/mirserver/ScreenController/stub_display.h (+91/-0)
tests/mirserver/ScreenController/stub_screen.h (+31/-0)
tests/mirserver/ScreenController/testable_screencontroller.h (+38/-0)
tests/modules/common/qtmir_test.h (+1/-1)
To merge this branch: bzr merge lp:~gerboland/qtmir/multimonitor-spike
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Daniel d'Andrada (community) Needs Fixing
Review via email: mp+263602@code.launchpad.net

This proposal has been superseded by a proposal from 2015-09-02.

Commit message

Initial multimonitor support - react correctly to Mir DisplayConfiguration changes.

On Mir DisplayConfiguration changes, QtMir now correctly:
1. blocks Mir until it has stopped all renderers and has their GL contexts released
2. reads the new DisplayConfiguration, matches any existing ScreenWindows to new DisplayBuffers should they change (as Mir may destroy and create it on us)
3. restarts all renderers

This also solves shutdown crash issues due to raciness of mir destroying the GL context backing the shell's QWindow before its renderer had stopped

To post a comment you must log in.
Revision history for this message
Gerry Boland (gerboland) wrote :

The QML demo is pretty lame, but I'm holding on until your demo work in the mirSurface is approved.

Also there are FIXMEs related to input, which I would prefer to address later. This MR is big enough.

Revision history for this message
Gerry Boland (gerboland) wrote :

Gah, input on second display not working

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :
Download full text (8.2 KiB)

src/modules/Unity/Screens/screens.h:

"""
public Q_SLOTS:
    void onScreenAdded(QScreen *screen);
    void onScreenRemoved(QScreen *screen);
"""

Shouldn't they be private?

--------------------------------

src/platforms/mirserver/miropenglcontext.h

"""
    EGLDisplay m_eglDisplay;
    EGLContext m_eglContext;
"""

You store them as member variables but they are still only used in the constructor.

----------------------------------

In MirServerIntegration::createPlatformWindow:

"""
    qDebug() << "createPlatformWindow" << window;
"""

A leftover.

"""
    // If Screen was not specified, just grab an unused one, if available
"""

I don't get the first "if". This method doesn't seem to handle the case where a screen *is* specified. It doesn't even seem possible.

"""
    if (!screens) {
        qDebug() << "Screens are not initialized, unable to create a new QWindow/ScreenWindow";
        return nullptr;
    }
    [...]
    if (!screen) {
        qDebug() << "No available Screens to create a new QWindow/ScreenWindow for";
        return nullptr;
    }
"""

I think these should be turned into criticals (and also use the logging category API).

"""
    qDebug() << "New" << window << "with geom" << window->geometry()
             << "is backed by a" << screen << "with geometry" << screen->geometry();
"""

You might want to keep this, but using the logging category API.

--------------------------

In MirServerIntegration::initialize()

"""
        qDebug() << "ScreenController not initialized";
"""

More qDebug. Maybe this should be a qFatal?

-----------------------------

In src/platforms/mirserver/offscreensurface.cpp

"""
#include <QDebug>
"""

You don't need that.

----------------------------

In src/platforms/mirserver/qmirserver.h:

"""
    QWeakPointer<ScreenController> screenController() const;
"""

Why return a weak pointer if all users of it do "screenController().lock()"?. So why not make it return a shared pointer already (making for cleaner code)?

------------------------------

QtEventFeeder::QtEventFeeder

I think it would be cleaner to have two constructors instead:

QtEventFeeder::QtEventFeeder(QSharedPointer<ScreenController> screenController)
    : QtEventFeeder(new QtWindowSystem(screenController))
{
}

QtEventFeeder::QtEventFeeder(QtEventFeeder::QtWindowSystemInterface *windowSystem)
{
- if (windowSystem) {
- mQtWindowSystem = windowSystem;
- } else {
- mQtWindowSystem = new QtWindowSystem;
- }
}

And remove the "= nullptr" from the signature of the second one.

--------------------------

"""
void QtEventFeeder::dispatch(MirEvent const& event)
{
- auto type = mir_event_get_type(&event);
- if (type != mir_event_type_input)
- return;
"""

Why remove it?

----------------------

"""
void QtEventFeeder::sendActiveTouchRelease(ulong timestamp, int id)
{
    [...]
+ mQtWindowSystem->handleTouchEvent(mQtWindowSystem->focusedWindow(), timestamp, mTouchDevice, touchPoints);
}
"""

You have to pass the window chosen in QtEventFeeder::dispatchTouch to validateTouches() as well, so that the function above send the event to the correct window.

----------------------------

Please update...

Read more...

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

As for testing: When I connected my monitor to the micro hdmi port of my yoga 2 laptop, qtmir detected the new display and reacted accordingly. So I saw the unity logo on a green background in the external monitor.

But when I disconnected it, nothing happened on qtmir side. Connected back again and that was when I got the screen disconnected info in qtmir, it seems. Restarted the qml mirserver and now it wouldn't detect the external monitor at all.

Rebooted the laptop.

Run the mirserver again. Connected the external monitor. All fine. Disconnected and reconnected and boom. Laptop shuts itself down.

Despite the somewhat bad results, since this is just the first step in the multi-monitor story I'm still ok with having it merged.

Revision history for this message
Gerry Boland (gerboland) wrote :

I'll be addressing your code comments soon.

On your testing, please watch the console output carefully. ScreenController::update() prints the list of displays each time Mir notifies it something changed. When you unplug, does this list get updated correctly?

Also, can you have the shell animating on both screens before you unplug?

Can you compare with mir_proving_server too?

I'm just trying to figure out if it is a QtMir bug, or a Mir one.
Thanks for the review!

339. By Gerry Boland

Slots can be private, not public

340. By Gerry Boland

Merge trunk

341. By Gerry Boland

MirOpenGLContext does not need to keep copy of the egl display and context

342. By Gerry Boland

Clean up debug outputs in MirServerIntegration, use categories

343. By Gerry Boland

Remove commented out lines and useless debug outputs from ScreenController

344. By Gerry Boland

Update comment in MirServerIntegration to make actual sense

345. By Gerry Boland

Remove unneeded QDebug include from OffscreenSurface

346. By Gerry Boland

Update licence years

347. By Gerry Boland

Remove authors from \*screen.\* licences

348. By Gerry Boland

Remove useless debug prints from ScreenWindow, and use category logging elsewhere

349. By Gerry Boland

s/deconstructor/destructor/

350. By Gerry Boland

ScreenController - remove another useless debug statement

351. By Gerry Boland

TiledDisplayConfig - update licence year

352. By Gerry Boland

Fix FTBFS

353. By Gerry Boland

ScreenController not need mirserver header

354. By Gerry Boland

Fix mouse click on non-primary screen

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
355. By Gerry Boland

Add second QtEventFeeder constructor which creates non-test QtWindowSystemInterface by default

356. By Gerry Boland

Drop ScreenWindow::isExposed

357. By Gerry Boland

Ensure touch validation events are passed to the correct window

358. By Gerry Boland

Move ScreenController explanation comment to the header

359. By Gerry Boland

screencontroller does not depend on mirserver any more, so remove header file include

360. By Gerry Boland

Simplify ScreenWindow further, drop QObject dependence and remove event handler

361. By Gerry Boland

Better variable name in ScreenWindow

362. By Gerry Boland

Use camelCase instead of under_score

363. By Gerry Boland

sc -> screenController

364. By Gerry Boland

screenFactory -> createScreen

365. By Gerry Boland

ScreenController: do not be friends, make public interfaces to be called by MirServer

Revision history for this message
Gerry Boland (gerboland) wrote :

I think I've followed all the recommendations you've made. I've only a couple of replies:

> """
> // If Screen was not specified, just grab an unused one, if available
> """
>
> I don't get the first "if". This method doesn't seem to handle the case where
> a screen *is* specified. It doesn't even seem possible.

You're right, it was terribly phrased. Have updated it to make sense now

> qDebug() << "Screens are not initialized, unable to create a new
> QWindow/ScreenWindow";
<snip>
> qDebug() << "No available Screens to create a new QWindow/ScreenWindow
>
> I think these should be turned into criticals (and also use the logging
> category API).

I did make them critical, but I always want those errors to print so didn't make them part of a category.

> In src/platforms/mirserver/qmirserver.h:
>
> """
> QWeakPointer<ScreenController> screenController() const;
> """
>
> Why return a weak pointer if all users of it do "screenController().lock()"?.
> So why not make it return a shared pointer already (making for cleaner code)?

Because the QMirServer has ownership of the ScreenController, and manages its lifetime. A ScreenController will only exist after the mir server is started, and must be deleted before mir shuts down. I can't have API users keeping it around longer than it should.

This may be exposing an API problem which can be resolved, but I didn't see any obvious solution. So this will have to do.

> src/platforms/mirserver/screencontroller.cpp
> """
> auto displayConfig = display->configuration();
> """
>
> I think you're abusing the use of "auto" here. I would prefer to know the
> class of this object.

You really want to know is it std::unique_ptr<mg::DisplayConfiguration> ? I don't, the variable name is enough for me.

366. By Gerry Boland

Merge trunk

367. By Gerry Boland

Ensure deregister ScreenWindow from Screen on destruction

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 06/08/15 08:49, Gerry Boland wrote:
>> qDebug() << "Screens are not initialized, unable to create a new
>> > QWindow/ScreenWindow";
> <snip>
>> > qDebug() << "No available Screens to create a new QWindow/ScreenWindow
>> >
>> > I think these should be turned into criticals (and also use the logging
>> > category API).
> I did make them critical, but I always want those errors to print so didn't make them part of a category.
>

This doesn't stop you from using logging categories. You can configure
logging categories to print by severity. Eg: only from warnings and
upwards, or only criticals.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

> On 06/08/15 08:49, Gerry Boland wrote:
> > I did make them critical, but I always want those errors to print so didn't
> make them part of a category.
> >
>
> This doesn't stop you from using logging categories. You can configure
> logging categories to print by severity. Eg: only from warnings and
> upwards, or only criticals.

I know that. But IMO this error should always print if that codepath hit, as it's an error path which I see no reason to be filter-able.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

"""
qtmir (0.4.6) vivid; urgency=medium

"""

nitpick: Shouldn't it be UNRELEASED instead of vivid?

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Good clean up! Only a couple of minor issues left:

----------------------

Please update copyright year of src/platforms/mirserver/miropenglcontext.cpp

---------------------

src/platforms/mirserver/screencontroller.cpp

It still has some qDebug() messages and commented-out code.

"""
        if (window && window->window()) { qDebug() << "HIDE" << window;
"""

"""
            //window->setVisible(false);
"""

NB: the stuff above appears in two separate locations in the file

----------------------------------

In tests/mirserver/ScreenController/screencontroller_test.cpp

"""
    ASSERT_EQ(screenController->screens().count(), 1);
"""

Google test format for assertions is as follows: ASSERT_EQ(expected, actual)

But in this file you're doing the other way around, which will make for confusing messages in case of failure.

Same goes for EXPECT_EQ() and friends.

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Ah, and the qml-demo-shell changes, naturally. You probably gonna rebase this branch on top of lp:~dandrader/qtmir/mousePointer or lp:~dandrader/qtmir/mirSurface, right?

368. By Gerry Boland

Update changelog to mark latest as UNRELEASED

369. By Gerry Boland

Update copyright year on MirOpenGLContext

370. By Gerry Boland

debug & commented line removed from ScreenController

371. By Gerry Boland

ScreenControllerTest- flip argument in assert/expect_eq statements

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Unmerged revisions

371. By Gerry Boland

ScreenControllerTest- flip argument in assert/expect_eq statements

370. By Gerry Boland

debug & commented line removed from ScreenController

369. By Gerry Boland

Update copyright year on MirOpenGLContext

368. By Gerry Boland

Update changelog to mark latest as UNRELEASED

367. By Gerry Boland

Ensure deregister ScreenWindow from Screen on destruction

366. By Gerry Boland

Merge trunk

365. By Gerry Boland

ScreenController: do not be friends, make public interfaces to be called by MirServer

364. By Gerry Boland

screenFactory -> createScreen

363. By Gerry Boland

sc -> screenController

362. By Gerry Boland

Use camelCase instead of under_score

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2015-07-28 09:57:00 +0000
+++ debian/changelog 2015-08-07 12:06:18 +0000
@@ -1,3 +1,9 @@
1qtmir (0.4.6) UNRELEASED; urgency=medium
2
3 * Add better MultiMonitor support
4
5 -- Gerry Boland <gerry.boland@canonical.com> Thu, 02 Jul 2015 00:31:23 +0100
6
1qtmir (0.4.5+15.10.20150728-0ubuntu1) wily; urgency=medium7qtmir (0.4.5+15.10.20150728-0ubuntu1) wily; urgency=medium
28
3 [ Gerry Boland ]9 [ Gerry Boland ]
410
=== modified file 'demos/qml-demo-shell/qml-demo-shell.qml'
--- demos/qml-demo-shell/qml-demo-shell.qml 2015-05-01 13:31:30 +0000
+++ demos/qml-demo-shell/qml-demo-shell.qml 2015-08-07 12:06:18 +0000
@@ -1,5 +1,7 @@
1import QtQuick 2.01import QtQuick 2.3
2import QtQuick.Window 2.2
2import Unity.Application 0.13import Unity.Application 0.1
4import Unity.Screens 0.1
35
4Rectangle {6Rectangle {
5 id: root7 id: root
@@ -169,4 +171,72 @@
169 }171 }
170 }172 }
171 }173 }
174
175
176 Component {
177 id: window1
178 Window {
179 color: "lightgreen"
180 visible: true // if not set visible, Window is not created!!
181
182 Image {
183 id: unityLogo1
184 source: "UnityLogo.png"
185 fillMode: Image.PreserveAspectFit
186 anchors.centerIn: parent
187 width: 600
188 height: 600
189
190 RotationAnimation {
191 id: logoAnimation1
192 target: unityLogo1
193 from: 359
194 to: 0
195 duration: 7000
196 easing.type: Easing.Linear
197 loops: Animation.Infinite
198 }
199 Component.onCompleted: print("new window!!")
200 Component.onDestruction: print("window destroyed!!")
201 }
202
203 Rectangle {
204 width: 50; height: 50
205 color: "blue"
206 x: point1.x
207 y: point1.y
208 }
209
210 MultiPointTouchArea {
211 anchors.fill: parent
212 minimumTouchPoints: 1
213 maximumTouchPoints: 1
214 touchPoints: [
215 TouchPoint { id: point1 }
216 ]
217 onPressed: {
218 if (logoAnimation1.paused) {
219 logoAnimation1.resume();
220 } else if (logoAnimation1.running) {
221 logoAnimation1.pause();
222 } else {
223 logoAnimation1.start();
224 }
225 }
226 }
227 }
228 }
229
230 Screens {
231 id: screens
232 property variant secondWindow: null
233 onScreenAdded: {
234 print("Screen added!!")
235 secondWindow = window1.createObject(root)
236 }
237 onScreenRemoved: {
238 print("Screen removed!!!")
239 secondWindow.destroy();
240 }
241 }
172}242}
173243
=== modified file 'src/modules/Unity/CMakeLists.txt'
--- src/modules/Unity/CMakeLists.txt 2014-09-22 18:06:58 +0000
+++ src/modules/Unity/CMakeLists.txt 2015-08-07 12:06:18 +0000
@@ -1,1 +1,2 @@
1add_subdirectory(Application)1add_subdirectory(Application)
2add_subdirectory(Screens)
23
=== added directory 'src/modules/Unity/Screens'
=== added file 'src/modules/Unity/Screens/CMakeLists.txt'
--- src/modules/Unity/Screens/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/CMakeLists.txt 2015-08-07 12:06:18 +0000
@@ -0,0 +1,18 @@
1set(SCREENSPLUGIN_SRC
2 plugin.cpp
3 screens.cpp
4 )
5
6add_library(unityscreensplugin SHARED
7 ${SCREENSPLUGIN_SRC}
8)
9
10target_link_libraries(
11 unityscreensplugin
12
13 Qt5::Gui
14 Qt5::Qml
15)
16
17# install
18add_qml_plugin(Unity.Screens 0.1 Unity/Screens TARGETS unityscreensplugin)
019
=== added file 'src/modules/Unity/Screens/plugin.cpp'
--- src/modules/Unity/Screens/plugin.cpp 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/plugin.cpp 2015-08-07 12:06:18 +0000
@@ -0,0 +1,41 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17// Qt
18#include <QQmlExtensionPlugin>
19#include <QtQml/qqml.h>
20#include <QScreen>
21
22// local
23#include "screens.h"
24
25using namespace qtmir;
26
27class UnityScreensPlugin : public QQmlExtensionPlugin {
28 Q_OBJECT
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
30
31 virtual void registerTypes(const char* uri)
32 {
33 Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Screens"));
34
35 qRegisterMetaType<QScreen*>("QScreen*");
36
37 qmlRegisterType<qtmir::Screens>(uri, 0, 1, "Screens");
38 }
39};
40
41#include "plugin.moc"
042
=== added file 'src/modules/Unity/Screens/qmldir'
--- src/modules/Unity/Screens/qmldir 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/qmldir 2015-08-07 12:06:18 +0000
@@ -0,0 +1,2 @@
1module Unity.Screens
2plugin unityscreensplugin
03
=== added file 'src/modules/Unity/Screens/screens.cpp'
--- src/modules/Unity/Screens/screens.cpp 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/screens.cpp 2015-08-07 12:06:18 +0000
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "screens.h"
18
19#include <QGuiApplication>
20#include <QScreen>
21
22Q_DECLARE_METATYPE(QScreen*)
23
24namespace qtmir {
25
26Screens::Screens(QObject *parent) :
27 QAbstractListModel(parent)
28{
29 auto app = static_cast<QGuiApplication *>(QGuiApplication::instance());
30 if (!app) {
31 return;
32 }
33 connect(app, &QGuiApplication::screenAdded, this, &Screens::onScreenAdded);
34 connect(app, &QGuiApplication::screenRemoved, this, &Screens::onScreenRemoved);
35}
36
37QVariant Screens::data(const QModelIndex &index, int) const
38{
39 QList<QScreen *> qscreenList = QGuiApplication::screens();
40
41 if (!index.isValid() || index.row() >= qscreenList.size()) {
42 return QVariant();
43 }
44
45 return QVariant::fromValue(qscreenList.at(index.row()));
46}
47
48int Screens::rowCount(const QModelIndex &) const
49{
50 return count();
51}
52
53int Screens::count() const
54{
55 return QGuiApplication::screens().size();
56}
57
58void Screens::onScreenAdded(QScreen *screen)
59{
60 Q_EMIT screenAdded(screen);
61 Q_EMIT countChanged();
62}
63
64void Screens::onScreenRemoved(QScreen *screen)
65{
66 Q_EMIT screenRemoved(screen);
67 Q_EMIT countChanged();
68}
69
70
71} // namespace qtmir
072
=== added file 'src/modules/Unity/Screens/screens.h'
--- src/modules/Unity/Screens/screens.h 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/screens.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,54 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef SCREENS_H
18#define SCREENS_H
19
20#include <QAbstractListModel>
21
22class QScreen;
23
24namespace qtmir {
25
26class Screens : public QAbstractListModel
27{
28 Q_OBJECT
29
30 Q_PROPERTY(int count READ count NOTIFY countChanged)
31
32public:
33 explicit Screens(QObject *parent = 0);
34 virtual ~Screens() noexcept = default;
35
36 /* QAbstractItemModel */
37 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
38 int rowCount(const QModelIndex &parent = QModelIndex()) const;
39
40 int count() const;
41
42Q_SIGNALS:
43 void countChanged();
44 void screenAdded(QScreen *screen);
45 void screenRemoved(QScreen *screen);
46
47private Q_SLOTS:
48 void onScreenAdded(QScreen *screen);
49 void onScreenRemoved(QScreen *screen);
50};
51
52} // namespace qtmir
53
54#endif // SCREENS_H
055
=== modified file 'src/platforms/mirserver/CMakeLists.txt'
--- src/platforms/mirserver/CMakeLists.txt 2015-05-19 15:10:48 +0000
+++ src/platforms/mirserver/CMakeLists.txt 2015-08-07 12:06:18 +0000
@@ -51,16 +51,18 @@
51 promptsessionlistener.cpp51 promptsessionlistener.cpp
52 mirserver.cpp52 mirserver.cpp
53 mirserverstatuslistener.cpp53 mirserverstatuslistener.cpp
54 display.cpp
55 screen.cpp54 screen.cpp
56 displaywindow.cpp55 screencontroller.cpp
56 screenwindow.cpp
57 mirserverintegration.cpp57 mirserverintegration.cpp
58 miropenglcontext.cpp58 miropenglcontext.cpp
59 nativeinterface.cpp59 nativeinterface.cpp
60 offscreensurface.cpp
60 qtcompositor.cpp61 qtcompositor.cpp
61 services.cpp62 services.cpp
62 ubuntutheme.cpp63 ubuntutheme.cpp
63 clipboard.cpp64 clipboard.cpp
65 tileddisplayconfigurationpolicy.cpp
64 tracepoints.c66 tracepoints.c
65 )67 )
6668
6769
=== removed file 'src/platforms/mirserver/display.cpp'
--- src/platforms/mirserver/display.cpp 2015-05-27 12:12:45 +0000
+++ src/platforms/mirserver/display.cpp 1970-01-01 00:00:00 +0000
@@ -1,46 +0,0 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Gerry Boland <gerry.boland@canonical.com>
17 */
18
19#include "display.h"
20
21#include "screen.h"
22#include "mirserver.h"
23
24#include <mir/graphics/display.h>
25#include <mir/graphics/display_configuration.h>
26
27namespace mg = mir::graphics;
28
29// TODO: Listen for display changes and update the list accordingly
30
31Display::Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig)
32{
33 displayConfig->for_each_output([this](mg::DisplayConfigurationOutput const& output) {
34 if (output.used) {
35 auto screen = new Screen(output);
36 m_screens.push_back(screen);
37 }
38 });
39}
40
41Display::~Display()
42{
43 for (auto screen : m_screens)
44 delete screen;
45 m_screens.clear();
46}
470
=== removed file 'src/platforms/mirserver/display.h'
--- src/platforms/mirserver/display.h 2015-05-27 12:12:45 +0000
+++ src/platforms/mirserver/display.h 1970-01-01 00:00:00 +0000
@@ -1,39 +0,0 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Gerry Boland <gerry.boland@canonical.com>
17 */
18
19#ifndef DISPLAY_H
20#define DISPLAY_H
21
22#include <qpa/qplatformscreen.h>
23#include <memory>
24
25namespace mir { namespace graphics { class DisplayConfiguration; }}
26
27class Display
28{
29public:
30 Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig);
31 virtual ~Display();
32
33 QList<QPlatformScreen *> screens() const { return m_screens; }
34
35private:
36 QList<QPlatformScreen *> m_screens;
37};
38
39#endif // DISPLAY_H
400
=== modified file 'src/platforms/mirserver/logging.h'
--- src/platforms/mirserver/logging.h 2014-10-01 18:42:26 +0000
+++ src/platforms/mirserver/logging.h 2015-08-07 12:06:18 +0000
@@ -25,5 +25,6 @@
25Q_DECLARE_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES)25Q_DECLARE_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES)
26Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_INPUT)26Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_INPUT)
27Q_DECLARE_LOGGING_CATEGORY(QTMIR_CLIPBOARD)27Q_DECLARE_LOGGING_CATEGORY(QTMIR_CLIPBOARD)
28Q_DECLARE_LOGGING_CATEGORY(QTMIR_SCREENS)
2829
29#endif // UBUNTU_APPLICATION_PLUGIN_LOGGING_H30#endif // UBUNTU_APPLICATION_PLUGIN_LOGGING_H
3031
=== modified file 'src/platforms/mirserver/miropenglcontext.cpp'
--- src/platforms/mirserver/miropenglcontext.cpp 2015-05-01 13:31:30 +0000
+++ src/platforms/mirserver/miropenglcontext.cpp 2015-08-07 12:06:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -18,12 +18,14 @@
1818
19#include "miropenglcontext.h"19#include "miropenglcontext.h"
2020
21#include "displaywindow.h"21#include "offscreensurface.h"
22#include "mirglconfig.h"
22#include "mirserver.h"23#include "mirserver.h"
23#include "mirglconfig.h"24#include "screenwindow.h"
2425
25#include <QDebug>26#include <QDebug>
2627
28#include <QOpenGLFramebufferObject>
27#include <QSurfaceFormat>29#include <QSurfaceFormat>
28#include <QtPlatformSupport/private/qeglconvenience_p.h>30#include <QtPlatformSupport/private/qeglconvenience_p.h>
2931
@@ -110,17 +112,30 @@
110112
111void MirOpenGLContext::swapBuffers(QPlatformSurface *surface)113void MirOpenGLContext::swapBuffers(QPlatformSurface *surface)
112{114{
113 // ultimately calls Mir's DisplayBuffer::post_update()115 if (surface->surface()->surfaceClass() == QSurface::Offscreen) {
114 DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface);116 // NOOP
115 displayBuffer->swapBuffers(); //blocks for vsync117 } else {
118 // ultimately calls Mir's DisplayBuffer::post_update()
119 ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface);
120 screenWindow->swapBuffers(); //blocks for vsync
121 }
116}122}
117123
118bool MirOpenGLContext::makeCurrent(QPlatformSurface *surface)124bool MirOpenGLContext::makeCurrent(QPlatformSurface *surface)
119{125{
126 if (surface->surface()->surfaceClass() == QSurface::Offscreen) {
127 auto offscreen = static_cast<OffscreenSurface *>(surface);
128 if (!offscreen->buffer()) {
129 auto buffer = new QOpenGLFramebufferObject(surface->surface()->size());
130 offscreen->setBuffer(buffer);
131 }
132 return offscreen->buffer()->bind();
133 }
134
120 // ultimately calls Mir's DisplayBuffer::make_current()135 // ultimately calls Mir's DisplayBuffer::make_current()
121 DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface);136 ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface);
122 if (displayBuffer) {137 if (screenWindow) {
123 displayBuffer->makeCurrent();138 screenWindow->makeCurrent();
124139
125#if GL_DEBUG140#if GL_DEBUG
126 if (!m_logger->isLogging() && m_logger->initialize()) {141 if (!m_logger->isLogging() && m_logger->initialize()) {
127142
=== modified file 'src/platforms/mirserver/mirserver.cpp'
--- src/platforms/mirserver/mirserver.cpp 2015-02-09 16:28:40 +0000
+++ src/platforms/mirserver/mirserver.cpp 2015-08-07 12:06:18 +0000
@@ -23,15 +23,22 @@
23#include "mirglconfig.h"23#include "mirglconfig.h"
24#include "mirserverstatuslistener.h"24#include "mirserverstatuslistener.h"
25#include "promptsessionlistener.h"25#include "promptsessionlistener.h"
26#include "screencontroller.h"
26#include "sessionlistener.h"27#include "sessionlistener.h"
27#include "sessionauthorizer.h"28#include "sessionauthorizer.h"
28#include "qtcompositor.h"29#include "qtcompositor.h"
29#include "qteventfeeder.h"30#include "qteventfeeder.h"
31#include "tileddisplayconfigurationpolicy.h"
30#include "logging.h"32#include "logging.h"
3133
34// std
35#include <memory>
36
32// egl37// egl
38#define MESA_EGL_NO_X11_HEADERS
33#include <EGL/egl.h>39#include <EGL/egl.h>
3440
41namespace mg = mir::graphics;
35namespace mo = mir::options;42namespace mo = mir::options;
36namespace msh = mir::shell;43namespace msh = mir::shell;
37namespace ms = mir::scene;44namespace ms = mir::scene;
@@ -45,8 +52,10 @@
4552
46Q_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES, "qtmir.mir")53Q_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES, "qtmir.mir")
4754
48MirServer::MirServer(int argc, char const* argv[], QObject* parent)55MirServer::MirServer(int argc, char const* argv[],
56 const QSharedPointer<ScreenController> &screenController, QObject* parent)
49 : QObject(parent)57 : QObject(parent)
58 , m_screenController(screenController)
50{59{
51 set_command_line_handler(&ignore_unparsed_arguments);60 set_command_line_handler(&ignore_unparsed_arguments);
52 set_command_line(argc, argv);61 set_command_line(argc, argv);
@@ -71,9 +80,9 @@
71 return std::make_shared<QtCompositor>();80 return std::make_shared<QtCompositor>();
72 });81 });
7382
74 override_the_input_dispatcher([]83 override_the_input_dispatcher([&screenController]
75 {84 {
76 return std::make_shared<QtEventFeeder>();85 return std::make_shared<QtEventFeeder>(screenController);
77 });86 });
7887
79 override_the_gl_config([]88 override_the_gl_config([]
@@ -99,17 +108,36 @@
99 return shell;108 return shell;
100 });109 });
101110
102 set_terminator([&](int)111 wrap_display_configuration_policy(
112 [](const std::shared_ptr<mg::DisplayConfigurationPolicy> &wrapped)
113 -> std::shared_ptr<mg::DisplayConfigurationPolicy>
114 {
115 return std::make_shared<TiledDisplayConfigurationPolicy>(wrapped);
116 });
117
118 set_terminator([](int)
103 {119 {
104 qDebug() << "Signal caught by Mir, stopping Mir server..";120 qDebug() << "Signal caught by Mir, stopping Mir server..";
105 QCoreApplication::quit();121 QCoreApplication::quit();
106 });122 });
107123
124 add_init_callback([this, &screenController] {
125 screenController->init(the_display(), the_compositor(), the_main_loop());
126 });
127
108 apply_settings();128 apply_settings();
109129
110 qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created";130 qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created";
111}131}
112132
133// Override default implementation to ensure we terminate the ScreenController first.
134// Code path followed when Qt tries to shutdown the server.
135void MirServer::stop()
136{
137 m_screenController->terminate();
138 mir::Server::stop();
139}
140
113141
114/************************************ Shell side ************************************/142/************************************ Shell side ************************************/
115143
116144
=== modified file 'src/platforms/mirserver/mirserver.h'
--- src/platforms/mirserver/mirserver.h 2015-03-25 14:49:58 +0000
+++ src/platforms/mirserver/mirserver.h 2015-08-07 12:06:18 +0000
@@ -18,6 +18,7 @@
18#define MIRSERVER_H18#define MIRSERVER_H
1919
20#include <QObject>20#include <QObject>
21#include <QSharedPointer>
21#include <mir/server.h>22#include <mir/server.h>
2223
23class QtEventFeeder;24class QtEventFeeder;
@@ -25,6 +26,7 @@
25class SessionAuthorizer;26class SessionAuthorizer;
26class MirShell;27class MirShell;
27class PromptSessionListener;28class PromptSessionListener;
29class ScreenController;
2830
29// We use virtual inheritance of mir::Server to facilitate derived classes (e.g. testing)31// We use virtual inheritance of mir::Server to facilitate derived classes (e.g. testing)
30// calling initialization functions before MirServer is constructed.32// calling initialization functions before MirServer is constructed.
@@ -38,12 +40,12 @@
38 Q_PROPERTY(PromptSessionListener* promptSessionListener READ promptSessionListener CONSTANT)40 Q_PROPERTY(PromptSessionListener* promptSessionListener READ promptSessionListener CONSTANT)
3941
40public:42public:
41 MirServer(int argc, char const* argv[], QObject* parent = 0);43 MirServer(int argc, char const* argv[], const QSharedPointer<ScreenController> &, QObject* parent = 0);
42 ~MirServer() = default;44 ~MirServer() = default;
4345
44 /* mir specific */46 /* mir specific */
45 using mir::Server::run;47 using mir::Server::run;
46 using mir::Server::stop;48 using mir::Server::the_compositor;
47 using mir::Server::the_display;49 using mir::Server::the_display;
48 using mir::Server::the_gl_config;50 using mir::Server::the_gl_config;
49 using mir::Server::the_main_loop;51 using mir::Server::the_main_loop;
@@ -52,6 +54,8 @@
52 using mir::Server::the_session_authorizer;54 using mir::Server::the_session_authorizer;
53 using mir::Server::the_session_listener;55 using mir::Server::the_session_listener;
5456
57 void stop();
58
55 /* qt specific */59 /* qt specific */
56 // getters60 // getters
57 SessionAuthorizer *sessionAuthorizer();61 SessionAuthorizer *sessionAuthorizer();
@@ -60,8 +64,8 @@
60 MirShell *shell();64 MirShell *shell();
6165
62private:66private:
63 std::shared_ptr<QtEventFeeder> m_qtEventFeeder;
64 std::weak_ptr<MirShell> m_shell;67 std::weak_ptr<MirShell> m_shell;
68 const QSharedPointer<ScreenController> m_screenController;
65};69};
6670
67#endif // MIRSERVER_H71#endif // MIRSERVER_H
6872
=== modified file 'src/platforms/mirserver/mirserverintegration.cpp'
--- src/platforms/mirserver/mirserverintegration.cpp 2015-05-27 12:12:45 +0000
+++ src/platforms/mirserver/mirserverintegration.cpp 2015-08-07 12:06:18 +0000
@@ -29,7 +29,8 @@
29#include <qpa/qplatforminputcontextfactory_p.h>29#include <qpa/qplatforminputcontextfactory_p.h>
30#include <qpa/qwindowsysteminterface.h>30#include <qpa/qwindowsysteminterface.h>
3131
32#include <QCoreApplication>32#include <QGuiApplication>
33#include <QStringList>
33#include <QOpenGLContext>34#include <QOpenGLContext>
3435
35#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)36#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
@@ -44,13 +45,16 @@
4445
45// local46// local
46#include "clipboard.h"47#include "clipboard.h"
47#include "display.h"
48#include "displaywindow.h"
49#include "miropenglcontext.h"48#include "miropenglcontext.h"
50#include "nativeinterface.h"49#include "nativeinterface.h"
50#include "offscreensurface.h"
51#include "qmirserver.h"51#include "qmirserver.h"
52#include "screen.h"
53#include "screencontroller.h"
54#include "screenwindow.h"
52#include "services.h"55#include "services.h"
53#include "ubuntutheme.h"56#include "ubuntutheme.h"
57#include "logging.h"
5458
55namespace mg = mir::graphics;59namespace mg = mir::graphics;
56using qtmir::Clipboard;60using qtmir::Clipboard;
@@ -63,7 +67,6 @@
63 , m_eventDispatcher(createUnixEventDispatcher())67 , m_eventDispatcher(createUnixEventDispatcher())
64#endif68#endif
65 , m_mirServer(new QMirServer(QCoreApplication::arguments()))69 , m_mirServer(new QMirServer(QCoreApplication::arguments()))
66 , m_display(nullptr)
67 , m_nativeInterface(nullptr)70 , m_nativeInterface(nullptr)
68 , m_clipboard(new Clipboard)71 , m_clipboard(new Clipboard)
69{72{
@@ -93,7 +96,6 @@
93MirServerIntegration::~MirServerIntegration()96MirServerIntegration::~MirServerIntegration()
94{97{
95 delete m_nativeInterface;98 delete m_nativeInterface;
96 delete m_display;
97}99}
98100
99bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const101bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -104,7 +106,7 @@
104 case ThreadedOpenGL: return true;106 case ThreadedOpenGL: return true;
105 case SharedGraphicsCache: return true;107 case SharedGraphicsCache: return true;
106 case BufferQueueingOpenGL: return true;108 case BufferQueueingOpenGL: return true;
107 case MultipleWindows: return false; // multi-monitor support109 case MultipleWindows: return true; // multi-monitor support
108#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)110#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
109 case WindowManagement: return false; // platform has no WM, as this implements the WM!111 case WindowManagement: return false; // platform has no WM, as this implements the WM!
110 case NonFullScreenWindows: return false;112 case NonFullScreenWindows: return false;
@@ -117,44 +119,35 @@
117{119{
118 QWindowSystemInterface::flushWindowSystemEvents();120 QWindowSystemInterface::flushWindowSystemEvents();
119121
120 DisplayWindow* displayWindow = nullptr;122 // FIXME: QWindow can be created specifying a destination QScreen. For now we
121123 // will ignore it and just associate any unused Screen, if available.
122 auto const mirServer = m_mirServer->mirServer().lock();124 auto screens = m_mirServer->screenController().lock();
123 mg::DisplayBuffer* first_buffer{nullptr};125 if (!screens) {
124 mg::DisplaySyncGroup* first_group{nullptr};126 qCritical("Screens are not initialized, unable to create a new QWindow/ScreenWindow");
125 if (mirServer) {127 return nullptr;
126 mirServer->the_display()->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) {128 }
127 if (!first_group) {129 Screen *screen = screens->getUnusedScreen();
128 first_group = &group;130 if (!screen) {
129 }131 qCritical("No available Screens to create a new QWindow/ScreenWindow for");
130 group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) {132 return nullptr;
131 if (!first_buffer) {133 }
132 first_buffer = &buffer;134 QScreen *qscreen = screen->screen();
133 }135 window->setScreen(qscreen);
134 });136
135 });137 auto platformWindow = new ScreenWindow(window);
136 }138
137139 qCDebug(QTMIR_SCREENS) << "New" << window << "with geom" << window->geometry()
138 // FIXME(gerry) this will go very bad for >1 display buffer140 << "is backed by a" << screen << "with geometry" << screen->geometry();
139 if (first_group && first_buffer)141 return platformWindow;
140 displayWindow = new DisplayWindow(window, first_group, first_buffer);
141
142 if (!displayWindow)
143 return nullptr;
144
145 //displayWindow->requestActivateWindow();
146 return displayWindow;
147}142}
148143
149QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow *window) const144QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow */*window*/) const
150{145{
151 qDebug() << "createPlatformBackingStore" << window;
152 return nullptr;146 return nullptr;
153}147}
154148
155QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const149QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
156{150{
157 qDebug() << "createPlatformOpenGLContext" << context;
158 return new MirOpenGLContext(m_mirServer->mirServer(), context->format());151 return new MirOpenGLContext(m_mirServer->mirServer(), context->format());
159}152}
160153
@@ -172,12 +165,18 @@
172 exit(2);165 exit(2);
173 }166 }
174167
175 m_display = new Display(m_mirServer->mirServer().data()->the_display()->configuration());168 auto screens = m_mirServer->screenController().lock();
169 if (!screens) {
170 qFatal("ScreenController not initialized");
171 }
172 QObject::connect(screens.data(), &ScreenController::screenAdded,
173 [this](Screen *screen) { this->screenAdded(screen); });
174 Q_FOREACH(auto screen, screens->screens()) {
175 screenAdded(screen);
176 }
177
176 m_nativeInterface = new NativeInterface(m_mirServer->mirServer());178 m_nativeInterface = new NativeInterface(m_mirServer->mirServer());
177179
178 for (QPlatformScreen *screen : m_display->screens())
179 screenAdded(screen);
180
181 m_clipboard->setupDBusService();180 m_clipboard->setupDBusService();
182}181}
183182
@@ -216,3 +215,9 @@
216{215{
217 return m_clipboard.data();216 return m_clipboard.data();
218}217}
218
219QPlatformOffscreenSurface *MirServerIntegration::createPlatformOffscreenSurface(
220 QOffscreenSurface *surface) const
221{
222 return new OffscreenSurface(surface);
223}
219224
=== modified file 'src/platforms/mirserver/mirserverintegration.h'
--- src/platforms/mirserver/mirserverintegration.h 2015-05-01 13:36:32 +0000
+++ src/platforms/mirserver/mirserverintegration.h 2015-08-07 12:06:18 +0000
@@ -22,13 +22,9 @@
2222
23// qt23// qt
24#include <qpa/qplatformintegration.h>24#include <qpa/qplatformintegration.h>
2525#include <QScopedPointer>
26// local26
27#include "mirserver.h"
28
29class Display;
30class NativeInterface;27class NativeInterface;
31class MirServer;
32class QMirServer;28class QMirServer;
3329
34namespace qtmir {30namespace qtmir {
@@ -68,6 +64,8 @@
6864
69 QPlatformNativeInterface *nativeInterface() const override;65 QPlatformNativeInterface *nativeInterface() const override;
7066
67 QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
68
71private:69private:
72 QScopedPointer<QPlatformAccessibility> m_accessibility;70 QScopedPointer<QPlatformAccessibility> m_accessibility;
73 QScopedPointer<QPlatformFontDatabase> m_fontDb;71 QScopedPointer<QPlatformFontDatabase> m_fontDb;
@@ -78,7 +76,6 @@
7876
79 QScopedPointer<QMirServer> m_mirServer;77 QScopedPointer<QMirServer> m_mirServer;
8078
81 Display *m_display;
82 NativeInterface *m_nativeInterface;79 NativeInterface *m_nativeInterface;
83 QPlatformInputContext* m_inputContext;80 QPlatformInputContext* m_inputContext;
84 QScopedPointer<qtmir::Clipboard> m_clipboard;81 QScopedPointer<qtmir::Clipboard> m_clipboard;
8582
=== added file 'src/platforms/mirserver/offscreensurface.cpp'
--- src/platforms/mirserver/offscreensurface.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/offscreensurface.cpp 2015-08-07 12:06:18 +0000
@@ -0,0 +1,61 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "offscreensurface.h"
18
19#include "mirserver.h"
20
21// Mir
22#include <mir/graphics/display.h>
23#include <mir/graphics/gl_context.h>
24
25//Qt
26#include <QOffscreenSurface>
27#include <QOpenGLFramebufferObject>
28#include <QSurfaceFormat>
29#include <QtPlatformSupport/private/qeglconvenience_p.h>
30
31namespace mg = mir::graphics;
32
33OffscreenSurface::OffscreenSurface(QOffscreenSurface *offscreenSurface)
34 : QPlatformOffscreenSurface(offscreenSurface)
35 , m_buffer(nullptr)
36 , m_format(offscreenSurface->requestedFormat())
37{
38}
39
40QSurfaceFormat OffscreenSurface::format() const
41{
42 return m_format;
43}
44
45bool OffscreenSurface::isValid() const
46{
47 if (m_buffer) {
48 return m_buffer->isValid();
49 }
50 return false;
51}
52
53QOpenGLFramebufferObject* OffscreenSurface::buffer() const
54{
55 return m_buffer;
56}
57
58void OffscreenSurface::setBuffer(QOpenGLFramebufferObject *buffer)
59{
60 m_buffer = buffer;
61}
062
=== added file 'src/platforms/mirserver/offscreensurface.h'
--- src/platforms/mirserver/offscreensurface.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/offscreensurface.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef OFFSCREENSURFACE_H
18#define OFFSCREENSURFACE_H
19
20#include <qpa/qplatformoffscreensurface.h>
21#include <QSurfaceFormat>
22#include <QSharedPointer>
23
24class MirServer;
25class QOpenGLFramebufferObject;
26
27class OffscreenSurface : public QPlatformOffscreenSurface
28{
29public:
30 OffscreenSurface(QOffscreenSurface *offscreenSurface);
31
32 QSurfaceFormat format() const override;
33 bool isValid() const override;
34
35 QOpenGLFramebufferObject* buffer() const;
36 void setBuffer(QOpenGLFramebufferObject *buffer);
37
38private:
39 QOpenGLFramebufferObject *m_buffer;
40 QSurfaceFormat m_format;
41};
42
43#endif // OFFSCREENSURFACE_H
044
=== modified file 'src/platforms/mirserver/qmirserver.cpp'
--- src/platforms/mirserver/qmirserver.cpp 2015-05-19 15:36:17 +0000
+++ src/platforms/mirserver/qmirserver.cpp 2015-08-07 12:06:18 +0000
@@ -23,7 +23,8 @@
23#include "mirserver.h"23#include "mirserver.h"
24#include "qmirserver.h"24#include "qmirserver.h"
25#include "qmirserver_p.h"25#include "qmirserver_p.h"
2626#include "screencontroller.h"
27#include "screen.h"
2728
28QMirServer::QMirServer(const QStringList &arguments, QObject *parent)29QMirServer::QMirServer(const QStringList &arguments, QObject *parent)
29 : QObject(parent)30 : QObject(parent)
@@ -40,7 +41,9 @@
40 }41 }
41 argv[argc] = '\0';42 argv[argc] = '\0';
4243
43 d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv)));44 d->screenController = QSharedPointer<ScreenController>(new ScreenController());
45
46 d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv), d->screenController));
4447
45 d->serverThread = new MirServerThread(d->server);48 d->serverThread = new MirServerThread(d->server);
4649
@@ -63,6 +66,7 @@
63 qCritical() << "ERROR: QMirServer - Mir failed to start";66 qCritical() << "ERROR: QMirServer - Mir failed to start";
64 return false;67 return false;
65 }68 }
69 d->screenController->update();
6670
67 Q_EMIT started();71 Q_EMIT started();
68 return true;72 return true;
@@ -93,3 +97,9 @@
93 Q_D(const QMirServer);97 Q_D(const QMirServer);
94 return d->server.toWeakRef();98 return d->server.toWeakRef();
95}99}
100
101QWeakPointer<ScreenController> QMirServer::screenController() const
102{
103 Q_D(const QMirServer);
104 return d->screenController;
105}
96106
=== modified file 'src/platforms/mirserver/qmirserver.h'
--- src/platforms/mirserver/qmirserver.h 2015-05-18 20:39:09 +0000
+++ src/platforms/mirserver/qmirserver.h 2015-08-07 12:06:18 +0000
@@ -23,6 +23,7 @@
2323
24class QMirServerPrivate;24class QMirServerPrivate;
25class MirServer;25class MirServer;
26class ScreenController;
2627
27class QMirServer: public QObject28class QMirServer: public QObject
28{29{
@@ -38,6 +39,8 @@
3839
39 QWeakPointer<MirServer> mirServer() const;40 QWeakPointer<MirServer> mirServer() const;
4041
42 QWeakPointer<ScreenController> screenController() const;
43
41Q_SIGNALS:44Q_SIGNALS:
42 void started();45 void started();
43 void stopped();46 void stopped();
4447
=== modified file 'src/platforms/mirserver/qmirserver_p.h'
--- src/platforms/mirserver/qmirserver_p.h 2015-05-18 18:30:33 +0000
+++ src/platforms/mirserver/qmirserver_p.h 2015-08-07 12:06:18 +0000
@@ -27,6 +27,7 @@
2727
28// local28// local
29#include "mirserver.h"29#include "mirserver.h"
30#include "screencontroller.h"
3031
31class QMirServer;32class QMirServer;
32class MirServerThread;33class MirServerThread;
@@ -34,6 +35,7 @@
34struct QMirServerPrivate35struct QMirServerPrivate
35{36{
36 QSharedPointer<MirServer> server;37 QSharedPointer<MirServer> server;
38 QSharedPointer<ScreenController> screenController;
37 MirServerThread *serverThread;39 MirServerThread *serverThread;
38};40};
3941
4042
=== modified file 'src/platforms/mirserver/qtcompositor.cpp'
--- src/platforms/mirserver/qtcompositor.cpp 2014-07-16 22:10:40 +0000
+++ src/platforms/mirserver/qtcompositor.cpp 2015-08-07 12:06:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013,2014 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -18,44 +18,19 @@
18 */18 */
1919
20#include "qtcompositor.h"20#include "qtcompositor.h"
21#include "displaywindow.h"21#include "logging.h"
2222
23#include <QGuiApplication>23// Lives in a Mir thread
24#include <QWindow>
25
26#include <QDebug>
27
28QtCompositor::QtCompositor()
29{
30
31}
32
33void QtCompositor::start()24void QtCompositor::start()
34{25{
35 // (Re)Start Qt's render thread by setting all its windows to exposed26 qCDebug(QTMIR_SCREENS) << "QtCompositor::start";
36 setAllWindowsExposed(true);27
28 Q_EMIT starting(); // blocks
37}29}
3830
39void QtCompositor::stop()31void QtCompositor::stop()
40{32{
41 // Stop Qt's render threads by setting all its windows it obscured33 qCDebug(QTMIR_SCREENS) << "QtCompositor::stop";
42 setAllWindowsExposed(false);34
43}35 Q_EMIT stopping(); // blocks
44
45void QtCompositor::setAllWindowsExposed(const bool exposed)
46{
47 qDebug() << "QtCompositor::setAllWindowsExposed" << exposed;
48 QList<QWindow *> windowList = QGuiApplication::allWindows();
49
50 // manipulate Qt object's indirectly via posted events as we're not in Qt's GUI thread
51 auto iterator = windowList.constBegin();
52 while (iterator != windowList.constEnd()) {
53 QWindow *window = *iterator;
54 DisplayWindow *displayWindow = static_cast<DisplayWindow*>(window->handle());
55 if (displayWindow) {
56 QCoreApplication::postEvent(displayWindow,
57 new QEvent( (exposed) ? QEvent::Show : QEvent::Hide));
58 }
59 iterator++;
60 }
61}36}
6237
=== modified file 'src/platforms/mirserver/qtcompositor.h'
--- src/platforms/mirserver/qtcompositor.h 2014-07-16 22:10:40 +0000
+++ src/platforms/mirserver/qtcompositor.h 2015-08-07 12:06:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -19,18 +19,26 @@
19#ifndef QTCOMPOSITOR_H19#ifndef QTCOMPOSITOR_H
20#define QTCOMPOSITOR_H20#define QTCOMPOSITOR_H
2121
22#include "mir/compositor/compositor.h"22#include <mir/compositor/compositor.h>
2323
24class QtCompositor : public mir::compositor::Compositor24// Qt
25#include <QObject>
26
27class QtCompositor : public QObject, public mir::compositor::Compositor
25{28{
29 Q_OBJECT
26public:30public:
27 QtCompositor();31 QtCompositor() = default;
32 virtual ~QtCompositor() noexcept = default;
2833
29 void start();34 void start();
30 void stop();35 void stop();
3136
37Q_SIGNALS:
38 void starting();
39 void stopping();
40
32private:41private:
33 void setAllWindowsExposed(const bool exposed);
34};42};
3543
36#endif // QTCOMPOSITOR_H44#endif // QTCOMPOSITOR_H
3745
=== modified file 'src/platforms/mirserver/qteventfeeder.cpp'
--- src/platforms/mirserver/qteventfeeder.cpp 2015-06-24 23:08:44 +0000
+++ src/platforms/mirserver/qteventfeeder.cpp 2015-08-07 12:06:18 +0000
@@ -19,6 +19,7 @@
1919
20#include "qteventfeeder.h"20#include "qteventfeeder.h"
21#include "logging.h"21#include "logging.h"
22#include "screencontroller.h"
2223
23#include <qpa/qplatforminputcontext.h>24#include <qpa/qplatforminputcontext.h>
24#include <qpa/qplatformintegration.h>25#include <qpa/qplatformintegration.h>
@@ -140,20 +141,21 @@
140141
141namespace {142namespace {
142143
143class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {144class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface
144145{
145 bool hasTargetWindow() override146 void setScreenController(const QSharedPointer<ScreenController> &sc) override
146 {147 {
147 if (mTopLevelWindow.isNull() && !QGuiApplication::topLevelWindows().isEmpty()) {148 m_screenController = sc;
148 mTopLevelWindow = QGuiApplication::topLevelWindows().first();149 }
149 }150
150 return !mTopLevelWindow.isNull();151 virtual QWindow* focusedWindow() override
151 }152 {
152153 return QGuiApplication::focusWindow();
153 QRect targetWindowGeometry() override154 }
154 {155
155 Q_ASSERT(!mTopLevelWindow.isNull());156 QWindow* getWindowForTouchPoint(const QPoint &point) override //FIXME: not efficient, not updating focused window
156 return mTopLevelWindow->geometry();157 {
158 return m_screenController->getWindowForPoint(point);
157 }159 }
158160
159 void registerTouchDevice(QTouchDevice *device) override161 void registerTouchDevice(QTouchDevice *device) override
@@ -161,47 +163,44 @@
161 QWindowSystemInterface::registerTouchDevice(device);163 QWindowSystemInterface::registerTouchDevice(device);
162 }164 }
163165
164 void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key,166 void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key,
165 Qt::KeyboardModifiers modifiers,167 Qt::KeyboardModifiers modifiers,
166 quint32 nativeScanCode, quint32 nativeVirtualKey,168 quint32 nativeScanCode, quint32 nativeVirtualKey,
167 quint32 nativeModifiers,169 quint32 nativeModifiers,
168 const QString& text, bool autorep, ushort count) override170 const QString& text, bool autorep, ushort count) override
169 {171 {
170 Q_ASSERT(!mTopLevelWindow.isNull());172 QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, type, key, modifiers,
171 QWindowSystemInterface::handleExtendedKeyEvent(mTopLevelWindow.data(), timestamp, type, key, modifiers,
172 nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);173 nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
173 }174 }
174175
175 void handleTouchEvent(ulong timestamp, QTouchDevice *device,176 void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device,
176 const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override177 const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override
177 {178 {
178 Q_ASSERT(!mTopLevelWindow.isNull());179 QWindowSystemInterface::handleTouchEvent(window, timestamp, device, points, mods);
179 QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods);180 }
180 }
181181
182 void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) override182 void handleMouseEvent(QWindow *window, ulong timestamp, QPointF point, Qt::MouseButton buttons,
183 Qt::KeyboardModifiers modifiers) override
183 {184 {
184 Q_ASSERT(!mTopLevelWindow.isNull());185 QWindowSystemInterface::handleMouseEvent(window, timestamp, point, point, // local and global point are the same
185 QWindowSystemInterface::handleMouseEvent(mTopLevelWindow.data(), timestamp, point, point, // local and global point are the same
186 buttons, modifiers);186 buttons, modifiers);
187 }187 }
188188
189
190private:189private:
191 QPointer<QWindow> mTopLevelWindow;190 QSharedPointer<ScreenController> m_screenController;
192};191};
193192
194} // anonymous namespace193} // anonymous namespace
195194
196195QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController)
197QtEventFeeder::QtEventFeeder(QtEventFeeder::QtWindowSystemInterface *windowSystem)196 : QtEventFeeder(screenController, new QtWindowSystem)
198{197{
199 if (windowSystem) {198}
200 mQtWindowSystem = windowSystem;199
201 } else {200QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController,
202 mQtWindowSystem = new QtWindowSystem;201 QtEventFeeder::QtWindowSystemInterface *windowSystem)
203 }202 : mQtWindowSystem(windowSystem)
204203{
205 // Initialize touch device. Hardcoded just like in qtubuntu204 // Initialize touch device. Hardcoded just like in qtubuntu
206 // TODO: Create them from info gathered from Mir and store things like device id and source205 // TODO: Create them from info gathered from Mir and store things like device id and source
207 // in a QTouchDevice-derived class created by us. So that we can properly assemble back206 // in a QTouchDevice-derived class created by us. So that we can properly assemble back
@@ -211,6 +210,7 @@
211 mTouchDevice->setCapabilities(210 mTouchDevice->setCapabilities(
212 QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure |211 QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure |
213 QTouchDevice::NormalizedPosition);212 QTouchDevice::NormalizedPosition);
213 mQtWindowSystem->setScreenController(screenController);
214 mQtWindowSystem->registerTouchDevice(mTouchDevice);214 mQtWindowSystem->registerTouchDevice(mTouchDevice);
215}215}
216216
@@ -224,6 +224,7 @@
224 auto type = mir_event_get_type(&event);224 auto type = mir_event_get_type(&event);
225 if (type != mir_event_type_input)225 if (type != mir_event_type_input)
226 return false;226 return false;
227
227 auto iev = mir_event_get_input_event(&event);228 auto iev = mir_event_get_input_event(&event);
228229
229 switch (mir_input_event_get_type(iev)) {230 switch (mir_input_event_get_type(iev)) {
@@ -281,27 +282,24 @@
281282
282void QtEventFeeder::dispatchPointer(MirInputEvent const* ev)283void QtEventFeeder::dispatchPointer(MirInputEvent const* ev)
283{284{
284 if (!mQtWindowSystem->hasTargetWindow())
285 return;
286
287 auto timestamp = mir_input_event_get_event_time(ev) / 1000000;285 auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
288286
289 auto pev = mir_input_event_get_pointer_event(ev);287 auto pev = mir_input_event_get_pointer_event(ev);
290 auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev));288 auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev));
291 auto buttons = getQtMouseButtonsfromMirPointerEvent(pev);289 auto buttons = getQtMouseButtonsfromMirPointerEvent(pev);
292290
293 auto local_point = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),291 auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
294 mir_pointer_event_axis_value(pev, mir_pointer_axis_y));292 mir_pointer_event_axis_value(pev, mir_pointer_axis_y));
295293
296 mQtWindowSystem->handleMouseEvent(timestamp, local_point,294 auto window = mQtWindowSystem->getWindowForTouchPoint(localPoint.toPoint());
295 localPoint -= window->geometry().topLeft(); // make position relative to window
296
297 mQtWindowSystem->handleMouseEvent(window, timestamp, localPoint,
297 buttons, modifiers);298 buttons, modifiers);
298}299}
299300
300void QtEventFeeder::dispatchKey(MirInputEvent const* event)301void QtEventFeeder::dispatchKey(MirInputEvent const* event)
301{302{
302 if (!mQtWindowSystem->hasTargetWindow())
303 return;
304
305 ulong timestamp = mir_input_event_get_event_time(event) / 1000000;303 ulong timestamp = mir_input_event_get_event_time(event) / 1000000;
306304
307 auto kev = mir_input_event_get_keyboard_event(event);305 auto kev = mir_input_event_get_keyboard_event(event);
@@ -348,7 +346,8 @@
348 }346 }
349 }347 }
350348
351 mQtWindowSystem->handleExtendedKeyEvent(timestamp, keyType, keyCode, modifiers,349 mQtWindowSystem->handleExtendedKeyEvent(mQtWindowSystem->focusedWindow(),
350 timestamp, keyType, keyCode, modifiers,
352 mir_keyboard_event_scan_code(kev),351 mir_keyboard_event_scan_code(kev),
353 mir_keyboard_event_key_code(kev),352 mir_keyboard_event_key_code(kev),
354 mir_keyboard_event_modifiers(kev), text, is_auto_rep);353 mir_keyboard_event_modifiers(kev), text, is_auto_rep);
@@ -356,59 +355,69 @@
356355
357void QtEventFeeder::dispatchTouch(MirInputEvent const* event)356void QtEventFeeder::dispatchTouch(MirInputEvent const* event)
358{357{
359 if (!mQtWindowSystem->hasTargetWindow())
360 return;
361
362 auto tev = mir_input_event_get_touch_event(event);358 auto tev = mir_input_event_get_touch_event(event);
363 qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev));359 qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev));
364360
365 // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That361 // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That
366 // needs to be fixed as soon as the compat input lib adds query support.362 // needs to be fixed as soon as the compat input lib adds query support.
367 const float kMaxPressure = 1.28;363 const float kMaxPressure = 1.28;
368 const QRect kWindowGeometry = mQtWindowSystem->targetWindowGeometry();364 const int kPointerCount = mir_touch_event_point_count(tev);
369 QList<QWindowSystemInterface::TouchPoint> touchPoints;365 QList<QWindowSystemInterface::TouchPoint> touchPoints;
370366 QWindow *window = nullptr;
371 // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left367
372 // as Qt::TouchPointMoved368 if (kPointerCount > 0) {
373 const int kPointerCount = mir_touch_event_point_count(tev);369 window = mQtWindowSystem->getWindowForTouchPoint(
374 for (int i = 0; i < kPointerCount; ++i) {370 QPoint(mir_touch_event_axis_value(tev, 0, mir_touch_axis_x),
375 QWindowSystemInterface::TouchPoint touchPoint;371 mir_touch_event_axis_value(tev, 0, mir_touch_axis_y)));
376372
377 const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x);373 if (!window) {
378 const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y);374 qCDebug(QTMIR_MIR_INPUT) << "REJECTING INPUT EVENT, no matching window";
379 const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major);375 return;
380 const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor);376 }
381 const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);377
382 touchPoint.id = mir_touch_event_id(tev, i);378 const QRect kWindowGeometry = window->geometry();
383379
384 touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());380 // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left
385 touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH);381 // as Qt::TouchPointMoved
386 touchPoint.pressure = kP / kMaxPressure;382 for (int i = 0; i < kPointerCount; ++i) {
387 switch (mir_touch_event_action(tev, i))383 QWindowSystemInterface::TouchPoint touchPoint;
388 {384
389 case mir_touch_action_up:385 const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x);
390 touchPoint.state = Qt::TouchPointReleased;386 const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y);
391 break;387 const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major);
392 case mir_touch_action_down:388 const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor);
393 touchPoint.state = Qt::TouchPointPressed;389 const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);
394 break;390 touchPoint.id = mir_touch_event_id(tev, i);
395 case mir_touch_action_change:391
396 touchPoint.state = Qt::TouchPointMoved;392 touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());
397 break;393 touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH);
398 default:394 touchPoint.pressure = kP / kMaxPressure;
399 break;395 switch (mir_touch_event_action(tev, i))
400 }396 {
401397 case mir_touch_action_up:
402 touchPoints.append(touchPoint);398 touchPoint.state = Qt::TouchPointReleased;
399 break;
400 case mir_touch_action_down:
401 touchPoint.state = Qt::TouchPointPressed;
402 break;
403 case mir_touch_action_change:
404 touchPoint.state = Qt::TouchPointMoved;
405 break;
406 default:
407 break;
408 }
409
410 touchPoints.append(touchPoint);
411 }
403 }412 }
404413
405 // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding414 // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding
406 // any insanity.415 // any insanity.
407 validateTouches(mir_input_event_get_event_time(event) / 1000000, touchPoints);416 validateTouches(window, mir_input_event_get_event_time(event) / 1000000, touchPoints);
408417
409 // Touch event propagation.418 // Touch event propagation.
410 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));419 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));
411 mQtWindowSystem->handleTouchEvent(420 mQtWindowSystem->handleTouchEvent(window,
412 //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable421 //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable
413 mir_input_event_get_event_time(event) / 1000000,422 mir_input_event_get_event_time(event) / 1000000,
414 mTouchDevice,423 mTouchDevice,
@@ -425,7 +434,7 @@
425 // not used434 // not used
426}435}
427436
428void QtEventFeeder::validateTouches(ulong timestamp,437void QtEventFeeder::validateTouches(QWindow *window, ulong timestamp,
429 QList<QWindowSystemInterface::TouchPoint> &touchPoints)438 QList<QWindowSystemInterface::TouchPoint> &touchPoints)
430{439{
431 QSet<int> updatedTouches;440 QSet<int> updatedTouches;
@@ -449,7 +458,7 @@
449 if (!updatedTouches.contains(it.key())) {458 if (!updatedTouches.contains(it.key())) {
450 qCWarning(QTMIR_MIR_INPUT)459 qCWarning(QTMIR_MIR_INPUT)
451 << "There's a touch (id =" << it.key() << ") missing. Releasing it.";460 << "There's a touch (id =" << it.key() << ") missing. Releasing it.";
452 sendActiveTouchRelease(timestamp, it.key());461 sendActiveTouchRelease(window, timestamp, it.key());
453 it = mActiveTouches.erase(it);462 it = mActiveTouches.erase(it);
454 } else {463 } else {
455 ++it;464 ++it;
@@ -467,7 +476,7 @@
467 }476 }
468}477}
469478
470void QtEventFeeder::sendActiveTouchRelease(ulong timestamp, int id)479void QtEventFeeder::sendActiveTouchRelease(QWindow *window, ulong timestamp, int id)
471{480{
472 QList<QWindowSystemInterface::TouchPoint> touchPoints = mActiveTouches.values();481 QList<QWindowSystemInterface::TouchPoint> touchPoints = mActiveTouches.values();
473482
@@ -481,7 +490,7 @@
481 }490 }
482491
483 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));492 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));
484 mQtWindowSystem->handleTouchEvent(timestamp, mTouchDevice, touchPoints);493 mQtWindowSystem->handleTouchEvent(window, timestamp, mTouchDevice, touchPoints);
485}494}
486495
487bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint)496bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint)
488497
=== modified file 'src/platforms/mirserver/qteventfeeder.h'
--- src/platforms/mirserver/qteventfeeder.h 2015-06-24 23:08:44 +0000
+++ src/platforms/mirserver/qteventfeeder.h 2015-08-07 12:06:18 +0000
@@ -25,6 +25,7 @@
25#include <qpa/qwindowsysteminterface.h>25#include <qpa/qwindowsysteminterface.h>
2626
27class QTouchDevice;27class QTouchDevice;
28class ScreenController;
2829
29/*30/*
30 Fills Qt's event loop with input events from Mir31 Fills Qt's event loop with input events from Mir
@@ -35,26 +36,29 @@
35 // Interface between QtEventFeeder and the actual QWindowSystemInterface functions36 // Interface between QtEventFeeder and the actual QWindowSystemInterface functions
36 // and other related Qt methods and objects to enable replacing them with mocks in37 // and other related Qt methods and objects to enable replacing them with mocks in
37 // pure unit tests.38 // pure unit tests.
38 // TODO - Make it work with multimonitor scenarios
39 class QtWindowSystemInterface {39 class QtWindowSystemInterface {
40 public:40 public:
41 virtual ~QtWindowSystemInterface() {}41 virtual ~QtWindowSystemInterface() {}
42 virtual bool hasTargetWindow() = 0;42 virtual void setScreenController(const QSharedPointer<ScreenController> &sc) = 0;
43 virtual QRect targetWindowGeometry() = 0;43 virtual QWindow* getWindowForTouchPoint(const QPoint &point) = 0;
44 virtual QWindow* focusedWindow() = 0;
44 virtual void registerTouchDevice(QTouchDevice *device) = 0;45 virtual void registerTouchDevice(QTouchDevice *device) = 0;
45 virtual void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key,46 virtual void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key,
46 Qt::KeyboardModifiers modifiers,47 Qt::KeyboardModifiers modifiers,
47 quint32 nativeScanCode, quint32 nativeVirtualKey,48 quint32 nativeScanCode, quint32 nativeVirtualKey,
48 quint32 nativeModifiers,49 quint32 nativeModifiers,
49 const QString& text = QString(), bool autorep = false,50 const QString& text = QString(), bool autorep = false,
50 ushort count = 1) = 0;51 ushort count = 1) = 0;
51 virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device,52 virtual void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device,
52 const QList<struct QWindowSystemInterface::TouchPoint> &points,53 const QList<struct QWindowSystemInterface::TouchPoint> &points,
53 Qt::KeyboardModifiers mods = Qt::NoModifier) = 0;54 Qt::KeyboardModifiers mods = Qt::NoModifier) = 0;
54 virtual void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0;55 virtual void handleMouseEvent(QWindow *window, ulong timestamp, QPointF point,
56 Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0;
55 };57 };
5658
57 QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr);59 QtEventFeeder(const QSharedPointer<ScreenController> &screenController);
60 QtEventFeeder(const QSharedPointer<ScreenController> &screenController,
61 QtWindowSystemInterface *windowSystem);
58 virtual ~QtEventFeeder();62 virtual ~QtEventFeeder();
5963
60 static const int MirEventActionMask;64 static const int MirEventActionMask;
@@ -69,9 +73,9 @@
69 void dispatchKey(MirInputEvent const* event);73 void dispatchKey(MirInputEvent const* event);
70 void dispatchTouch(MirInputEvent const* event);74 void dispatchTouch(MirInputEvent const* event);
71 void dispatchPointer(MirInputEvent const* event);75 void dispatchPointer(MirInputEvent const* event);
72 void validateTouches(ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints);76 void validateTouches(QWindow *window, ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints);
73 bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint);77 bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint);
74 void sendActiveTouchRelease(ulong timestamp, int id);78 void sendActiveTouchRelease(QWindow *window, ulong timestamp, int id);
7579
76 QString touchesToString(const QList<struct QWindowSystemInterface::TouchPoint> &points);80 QString touchesToString(const QList<struct QWindowSystemInterface::TouchPoint> &points);
7781
7882
=== modified file 'src/platforms/mirserver/screen.cpp'
--- src/platforms/mirserver/screen.cpp 2014-10-22 15:47:49 +0000
+++ src/platforms/mirserver/screen.cpp 2015-08-07 12:06:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013,2014 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -24,12 +24,13 @@
2424
25// Mir25// Mir
26#include "mir/geometry/size.h"26#include "mir/geometry/size.h"
27#include "mir/graphics/buffer.h"
28#include "mir/graphics/display_buffer.h"
29#include "mir/graphics/display.h"
2730
28// Qt31// Qt
29#include <QCoreApplication>32#include <QCoreApplication>
30#include <qpa/qwindowsysteminterface.h>33#include <qpa/qwindowsysteminterface.h>
31#include <QtSensors/QOrientationSensor>
32#include <QtSensors/QOrientationReading>
33#include <QThread>34#include <QThread>
3435
35// Qt sensors36// Qt sensors
@@ -106,12 +107,15 @@
106107
107bool Screen::skipDBusRegistration = false;108bool Screen::skipDBusRegistration = false;
108109
109Screen::Screen(mir::graphics::DisplayConfigurationOutput const &screen)110Screen::Screen(const mir::graphics::DisplayConfigurationOutput &screen)
110 : QObject(nullptr)111 : QObject(nullptr)
112 , m_displayBuffer(nullptr)
113 , m_displayGroup(nullptr)
111 , m_orientationSensor(new QOrientationSensor(this))114 , m_orientationSensor(new QOrientationSensor(this))
115 , m_screenWindow(nullptr)
112 , m_unityScreen(nullptr)116 , m_unityScreen(nullptr)
113{117{
114 readMirDisplayConfiguration(screen);118 setMirDisplayConfiguration(screen);
115119
116 // Set the default orientation based on the initial screen dimmensions.120 // Set the default orientation based on the initial screen dimmensions.
117 m_nativeOrientation = (m_geometry.width() >= m_geometry.height())121 m_nativeOrientation = (m_geometry.width() >= m_geometry.height())
@@ -143,6 +147,14 @@
143 }147 }
144}148}
145149
150Screen::~Screen()
151{
152 //if a ScreenWindow associated with this screen, kill it
153 if (m_screenWindow) {
154 m_screenWindow->window()->destroy(); // ends up destroying m_ScreenWindow
155 }
156}
157
146bool Screen::orientationSensorEnabled()158bool Screen::orientationSensorEnabled()
147{159{
148 return m_orientationSensor->isActive();160 return m_orientationSensor->isActive();
@@ -154,8 +166,15 @@
154 toggleSensors(status);166 toggleSensors(status);
155}167}
156168
157void Screen::readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const &screen)169void Screen::setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &screen)
158{170{
171 // Note: DisplayConfigurationOutput will be destroyed after this function returns
172
173 // Output data - each output has a unique id and corresponding type. Can be multiple cards.
174 m_outputId = screen.id;
175 m_cardId = screen.card_id;
176 m_type = screen.type;
177
159 // Physical screen size178 // Physical screen size
160 m_physicalSize.setWidth(screen.physical_size_mm.width.as_float());179 m_physicalSize.setWidth(screen.physical_size_mm.width.as_float());
161 m_physicalSize.setHeight(screen.physical_size_mm.height.as_float());180 m_physicalSize.setHeight(screen.physical_size_mm.height.as_float());
@@ -166,12 +185,34 @@
166 // Pixel depth185 // Pixel depth
167 m_depth = 8 * MIR_BYTES_PER_PIXEL(screen.current_format);186 m_depth = 8 * MIR_BYTES_PER_PIXEL(screen.current_format);
168187
169 // Mode = Resolution & refresh rate188 // Power mode
189 m_powerMode = screen.power_mode;
190
191 QRect oldGeometry = m_geometry;
192 // Position of screen in virtual desktop coordinate space
193 m_geometry.setTop(screen.top_left.y.as_int());
194 m_geometry.setLeft(screen.top_left.x.as_int());
195
196 // Mode = current resolution & refresh rate
170 mir::graphics::DisplayConfigurationMode mode = screen.modes.at(screen.current_mode_index);197 mir::graphics::DisplayConfigurationMode mode = screen.modes.at(screen.current_mode_index);
171 m_geometry.setWidth(mode.size.width.as_int());198 m_geometry.setWidth(mode.size.width.as_int());
172 m_geometry.setHeight(mode.size.height.as_int());199 m_geometry.setHeight(mode.size.height.as_int());
173200
174 m_refreshRate = mode.vrefresh_hz;201 // DPI - unnecessary to calculate, default implementation in QPlatformScreen is sufficient
202
203 // Check for Screen geometry change
204 if (m_geometry != oldGeometry) {
205 QWindowSystemInterface::handleScreenGeometryChange(this->screen(), m_geometry, m_geometry);
206 if (m_screenWindow) { // resize corresponding window immediately
207 m_screenWindow->setGeometry(m_geometry);
208 }
209 }
210
211 // Refresh rate
212 if (m_refreshRate != mode.vrefresh_hz) {
213 m_refreshRate = mode.vrefresh_hz;
214 QWindowSystemInterface::handleScreenRefreshRateChange(this->screen(), mode.vrefresh_hz);
215 }
175}216}
176217
177void Screen::toggleSensors(const bool enable) const218void Screen::toggleSensors(const bool enable) const
@@ -230,3 +271,51 @@
230 OrientationReadingEvent::m_type,271 OrientationReadingEvent::m_type,
231 m_orientationSensor->reading()->orientation()));272 m_orientationSensor->reading()->orientation()));
232}273}
274
275ScreenWindow* Screen::window() const
276{
277 return m_screenWindow;
278}
279
280void Screen::setWindow(ScreenWindow *window)
281{
282 if (m_screenWindow) {
283 qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen::setWindow - overwriting existing ScreenWindow";
284 }
285 m_screenWindow = window;
286}
287
288void Screen::setMirDisplayBuffer(mir::graphics::DisplayBuffer *buffer, mir::graphics::DisplaySyncGroup *group)
289{
290 // This operation should only be performed while rendering is stopped
291 m_displayBuffer = buffer;
292 m_displayGroup = group;
293}
294
295void Screen::swapBuffers()
296{
297 m_displayBuffer->gl_swap_buffers();
298
299 /* FIXME this exposes a QtMir architecture problem, as Screen is supposed to wrap a mg::DisplayBuffer.
300 * We use Qt's multithreaded renderer, where each Screen is rendered to relatively independently, and
301 * post() called also individually.
302 *
303 * But if this is a native server on Android, in the multimonitor case a DisplaySyncGroup can contain
304 * 2+ DisplayBuffers, one post() call will submit all mg::DisplayBuffers in the group for flipping.
305 * This will cause just one Screen to be updated, blocking the swap call for the other Screens, which
306 * will slow rendering dramatically.
307 *
308 * Integrating the Qt Scenegraph renderer as a Mir renderer should solve this issue.
309 */
310 m_displayGroup->post();
311}
312
313void Screen::makeCurrent()
314{
315 m_displayBuffer->make_current();
316}
317
318void Screen::doneCurrent()
319{
320 m_displayBuffer->release_current();
321}
233322
=== modified file 'src/platforms/mirserver/screen.h'
--- src/platforms/mirserver/screen.h 2014-10-22 15:47:49 +0000
+++ src/platforms/mirserver/screen.h 2015-08-07 12:06:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013,2014 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -20,20 +20,27 @@
20#ifndef SCREEN_H20#ifndef SCREEN_H
21#define SCREEN_H21#define SCREEN_H
2222
23// Qt
23#include <QObject>24#include <QObject>
24#include <QTimer>25#include <QTimer>
25#include <QtDBus/QDBusInterface>26#include <QtDBus/QDBusInterface>
26#include <qpa/qplatformscreen.h>27#include <qpa/qplatformscreen.h>
2728
29// Mir
28#include "mir/graphics/display_configuration.h"30#include "mir/graphics/display_configuration.h"
2931
32// local
33#include "screenwindow.h"
34
30class QOrientationSensor;35class QOrientationSensor;
36namespace mir { namespace graphics { class DisplayBuffer; class DisplaySyncGroup; }}
3137
32class Screen : public QObject, public QPlatformScreen38class Screen : public QObject, public QPlatformScreen
33{39{
34 Q_OBJECT40 Q_OBJECT
35public:41public:
36 Screen(mir::graphics::DisplayConfigurationOutput const&);42 Screen(const mir::graphics::DisplayConfigurationOutput &);
43 ~Screen();
3744
38 // QPlatformScreen methods.45 // QPlatformScreen methods.
39 QRect geometry() const override { return m_geometry; }46 QRect geometry() const override { return m_geometry; }
@@ -45,6 +52,9 @@
45 Qt::ScreenOrientation orientation() const override { return m_currentOrientation; }52 Qt::ScreenOrientation orientation() const override { return m_currentOrientation; }
4653
47 void toggleSensors(const bool enable) const;54 void toggleSensors(const bool enable) const;
55 mir::graphics::DisplayConfigurationOutputType outputType() const { return m_type; }
56
57 ScreenWindow* window() const;
4858
49 // QObject methods.59 // QObject methods.
50 void customEvent(QEvent* event) override;60 void customEvent(QEvent* event) override;
@@ -57,20 +67,38 @@
57 void onDisplayPowerStateChanged(int, int);67 void onDisplayPowerStateChanged(int, int);
58 void onOrientationReadingChanged();68 void onOrientationReadingChanged();
5969
70protected:
71 void setWindow(ScreenWindow *window);
72
73 void setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &);
74 void setMirDisplayBuffer(mir::graphics::DisplayBuffer *, mir::graphics::DisplaySyncGroup *);
75 void swapBuffers();
76 void makeCurrent();
77 void doneCurrent();
78
60private:79private:
61 void readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const&);
62
63 QRect m_geometry;80 QRect m_geometry;
64 int m_depth;81 int m_depth;
65 QImage::Format m_format;82 QImage::Format m_format;
66 QSizeF m_physicalSize;83 QSizeF m_physicalSize;
67 qreal m_refreshRate;84 qreal m_refreshRate;
6885
86 mir::graphics::DisplayBuffer *m_displayBuffer;
87 mir::graphics::DisplaySyncGroup *m_displayGroup;
88 mir::graphics::DisplayConfigurationOutputId m_outputId;
89 mir::graphics::DisplayConfigurationCardId m_cardId;
90 mir::graphics::DisplayConfigurationOutputType m_type;
91 MirPowerMode m_powerMode;
92
69 Qt::ScreenOrientation m_nativeOrientation;93 Qt::ScreenOrientation m_nativeOrientation;
70 Qt::ScreenOrientation m_currentOrientation;94 Qt::ScreenOrientation m_currentOrientation;
71 QOrientationSensor *m_orientationSensor;95 QOrientationSensor *m_orientationSensor;
7296
97 ScreenWindow *m_screenWindow;
73 QDBusInterface *m_unityScreen;98 QDBusInterface *m_unityScreen;
99
100 friend class ScreenController;
101 friend class ScreenWindow;
74};102};
75103
76#endif // SCREEN_H104#endif // SCREEN_H
77105
=== added file 'src/platforms/mirserver/screencontroller.cpp'
--- src/platforms/mirserver/screencontroller.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/screencontroller.cpp 2015-08-07 12:06:18 +0000
@@ -0,0 +1,261 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "screencontroller.h"
18
19#include "screenwindow.h"
20#include "qtcompositor.h"
21#include "logging.h"
22#include "mirserverintegration.h"
23#include "screen.h"
24
25// Mir
26#include <mir/graphics/display.h>
27#include <mir/graphics/display_buffer.h>
28#include <mir/main_loop.h>
29
30// Qt
31#include <QScreen>
32#include <QQuickWindow>
33#include <qpa/qwindowsysteminterface.h>
34
35// std
36#include <memory>
37
38Q_LOGGING_CATEGORY(QTMIR_SCREENS, "qtmir.screens")
39
40namespace mg = mir::graphics;
41
42
43ScreenController::ScreenController(QObject *parent)
44 : QObject(parent)
45{
46 qCDebug(QTMIR_SCREENS) << "ScreenController::ScreenController";
47}
48
49// init only after MirServer has initialized - runs on MirServerThread!!!
50void ScreenController::init(const std::shared_ptr<mir::graphics::Display> &display,
51 const std::shared_ptr<mir::compositor::Compositor> &compositor,
52 const std::shared_ptr<mir::MainLoop> &mainLoop)
53{
54 m_display = display;
55 m_compositor = compositor;
56
57 // Use a Blocking Queued Connection to enforce synchronization of Qt GUI thread with Mir thread(s)
58 // on compositor shutdown. Compositor startup can be lazy.
59 // Queued connections work because the thread affinity of this class is with the Qt GUI thread.
60 auto qtCompositor = static_cast<QtCompositor *>(compositor.get());
61 connect(qtCompositor, &QtCompositor::starting,
62 this, &ScreenController::onCompositorStarting);
63 connect(qtCompositor, &QtCompositor::stopping,
64 this, &ScreenController::onCompositorStopping, Qt::BlockingQueuedConnection);
65
66
67 display->register_configuration_change_handler(*mainLoop, [this]() {
68 // display hardware configuration changed, update! - not called when we set new configuration
69 QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
70 });
71}
72
73// terminate before shutting down the Mir server, or else liable to deadlock with the blocking connection above
74// Runs on MirServerThread!!!
75void ScreenController::terminate()
76{
77 auto qtCompositor = static_cast<QtCompositor *>(m_compositor.get());
78 qtCompositor->disconnect();
79}
80
81void ScreenController::onCompositorStarting()
82{
83 qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStarting";
84
85 update();
86
87 // (Re)Start Qt's render thread by setting all windows with a corresponding screen to exposed.
88 for (auto screen : m_screenList) {
89 auto window = static_cast<ScreenWindow *>(screen->window());
90 if (window && window->window()) {
91 window->window()->show();
92 }
93 }
94}
95
96void ScreenController::onCompositorStopping()
97{
98 qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStopping";
99
100 // Stop Qt's render threads by setting all its windows it obscured. Must
101 // block until all windows have their GL contexts released.
102 for (auto screen : m_screenList) {
103 auto window = static_cast<ScreenWindow *>(screen->window());
104 if (window && window->window()) {
105 window->window()->hide();
106 }
107 }
108
109 update();
110}
111
112void ScreenController::update()
113{
114 qCDebug(QTMIR_SCREENS) << "ScreenController::update";
115 auto display = m_display.lock();
116 if (!display)
117 return;
118 auto displayConfig = display->configuration();
119
120 // Mir only tells us something changed, it is up to us to figure out what.
121 QList<Screen*> newScreenList;
122 QList<Screen*> oldScreenList = m_screenList;
123 m_screenList.clear();
124
125 displayConfig->for_each_output(
126 [this, &oldScreenList, &newScreenList](const mg::DisplayConfigurationOutput &output) {
127 if (output.used && output.connected) {
128 Screen *screen = findScreenWithId(oldScreenList, output.id);
129 if (screen) { // we've already set up this display before, refresh its internals
130 screen->setMirDisplayConfiguration(output);
131 oldScreenList.removeAll(screen);
132 } else {
133 // new display, so create Screen for it
134 screen = this->createScreen(output);
135 newScreenList.append(screen);
136 qCDebug(QTMIR_SCREENS) << "Added Screen with id" << output.id.as_value()
137 << "and geometry" << screen->geometry();
138 }
139 m_screenList.append(screen);
140 }
141 }
142 );
143
144 // Delete any old & unused Screens
145 for (auto screen: oldScreenList) {
146 qCDebug(QTMIR_SCREENS) << "Removed Screen with id" << screen->m_outputId.as_value()
147 << "and geometry" << screen->geometry();
148 // The screen is automatically removed from Qt's internal list by the QPlatformScreen destructor.
149 auto window = static_cast<ScreenWindow *>(screen->window());
150 if (window && window->window() && window->isExposed()) {
151 window->window()->hide();
152 }
153 delete screen;
154 }
155
156 // Match up the new Mir DisplayBuffers with each Screen
157 display->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) {
158 group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) {
159 // only way to match Screen to a DisplayBuffer is by matching the geometry
160 QRect dbGeom(buffer.view_area().top_left.x.as_int(),
161 buffer.view_area().top_left.y.as_int(),
162 buffer.view_area().size.width.as_int(),
163 buffer.view_area().size.height.as_int());
164
165 for (auto screen : m_screenList) {
166 if (dbGeom == screen->geometry()) {
167 screen->setMirDisplayBuffer(&buffer, &group);
168 }
169 }
170 });
171 });
172
173 qCDebug(QTMIR_SCREENS) << "=======================================";
174 for (auto screen: m_screenList) {
175 qCDebug(QTMIR_SCREENS) << "Screen - id:" << screen->m_outputId.as_value()
176 << "geometry:" << screen->geometry()
177 << "window:" << screen->window()
178 << "type" << static_cast<int>(screen->outputType());
179 }
180 qCDebug(QTMIR_SCREENS) << "=======================================";
181
182 for (auto screen : newScreenList) {
183 Q_EMIT screenAdded(screen);
184 }
185}
186
187Screen* ScreenController::createScreen(const mir::graphics::DisplayConfigurationOutput &output) const
188{
189 return new Screen(output);
190}
191
192Screen* ScreenController::getUnusedScreen()
193{
194 if (m_screenList.empty()) {
195 return nullptr;
196 } else if (m_screenList.size() == 1) {
197 return m_screenList.at(0);
198 }
199
200 // FIXME: Until we have better way of identifying screens, prioritize outputs based on their output type.
201 // Note the priorities defined here are nothing more than guesses. It tries to select internal displays first,
202 // then digital outputs, and finally analogue.
203 QMap <int, Screen*> priorityList;
204 auto prioritize = [](const mg::DisplayConfigurationOutputType &type) {
205 using out = mg::DisplayConfigurationOutputType;
206 switch(type) {
207 case out::lvds:
208 case out::edp:
209 return 0;
210 case out::displayport:
211 case out::hdmia:
212 case out::hdmib:
213 return 1;
214 case out::dvii:
215 case out::dvid:
216 case out::dvia:
217 return 2;
218 case out::vga:
219 return 3;
220 case out::ninepindin:
221 return 4;
222 case out::component:
223 case out::composite:
224 case out::svideo:
225 return 5;
226 case out::tv:
227 return 6;
228 case out::unknown:
229 default:
230 return 9;
231 }
232 };
233
234 for (auto screen : m_screenList) {
235 if (!screen->window()) {
236 priorityList.insert(prioritize(screen->outputType()), screen);
237 }
238 }
239
240 return priorityList.first(); // Map sorted by key, so first is the key with highest priority.
241}
242
243Screen* ScreenController::findScreenWithId(const QList<Screen *> &list, const mg::DisplayConfigurationOutputId id)
244{
245 for (Screen *screen : list) {
246 if (screen->m_outputId == id) {
247 return screen;
248 }
249 }
250 return nullptr;
251}
252
253QWindow* ScreenController::getWindowForPoint(const QPoint &point) //FIXME - not thread safe & not efficient
254{
255 for (Screen *screen : m_screenList) {
256 if (screen->window() && screen->geometry().contains(point)) {
257 return screen->window()->window();
258 }
259 }
260 return nullptr;
261}
0262
=== added file 'src/platforms/mirserver/screencontroller.h'
--- src/platforms/mirserver/screencontroller.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/screencontroller.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,96 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef SCREENCONTROLLER_H
18#define SCREENCONTROLLER_H
19
20#include <QObject>
21#include <QPoint>
22
23// Mir
24#include <mir/graphics/display_configuration.h>
25
26// std
27#include <memory>
28
29namespace mir {
30 class MainLoop;
31 namespace graphics { class Display; }
32 namespace compositor { class Compositor; }
33}
34class Screen;
35class QWindow;
36
37/*
38 * ScreenController monitors the Mir display configuration and compositor status, and updates
39 * the relevant QScreen and QWindow states accordingly.
40 *
41 * Primary purposes are:
42 * 1. to update QScreen state on Mir display configuration changes
43 * 2. to stop the Qt renderer by hiding its QWindow when Mir wants to stop all compositing,
44 * and resume Qt's renderer by showing its QWindow when Mir wants to resume compositing.
45 *
46 *
47 * Threading Note:
48 * This object must have affinity to the main Qt GUI thread, as it creates & destroys Platform
49 * objects which Qt uses internally. However beware as the init() & terminate() methods need to
50 * be called on the MirServerThread thread, as we need to monitor the screen state *after*
51 * Mir has initialized but before Qt's event loop has started, and tear down before Mir terminates.
52 * Also note the MirServerThread does not have an QEventLoop.
53 *
54 * All other methods must be called on the Qt GUI thread.
55 */
56
57class ScreenController : public QObject
58{
59 Q_OBJECT
60public:
61 explicit ScreenController(QObject *parent = 0);
62
63 Screen* getUnusedScreen();
64 QList<Screen*> screens() const { return m_screenList; }
65
66 QWindow* getWindowForPoint(const QPoint &point);
67
68Q_SIGNALS:
69 void screenAdded(Screen *screen);
70
71public Q_SLOTS:
72 void update();
73
74public:
75 // called by MirServer
76 void init(const std::shared_ptr<mir::graphics::Display> &display,
77 const std::shared_ptr<mir::compositor::Compositor> &compositor,
78 const std::shared_ptr<mir::MainLoop> &mainLoop);
79 void terminate();
80
81 // override for testing purposes
82 virtual Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const;
83
84protected Q_SLOTS:
85 void onCompositorStarting();
86 void onCompositorStopping();
87
88private:
89 Screen* findScreenWithId(const QList<Screen*> &list, const mir::graphics::DisplayConfigurationOutputId id);
90
91 std::weak_ptr<mir::graphics::Display> m_display;
92 std::shared_ptr<mir::compositor::Compositor> m_compositor;
93 QList<Screen*> m_screenList;
94};
95
96#endif // SCREENCONTROLLER_H
097
=== renamed file 'src/platforms/mirserver/displaywindow.cpp' => 'src/platforms/mirserver/screenwindow.cpp'
--- src/platforms/mirserver/displaywindow.cpp 2015-03-25 14:58:57 +0000
+++ src/platforms/mirserver/screenwindow.cpp 2015-08-07 12:06:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013,2014 Canonical, Ltd.2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -12,19 +12,18 @@
12 *12 *
13 * You should have received a copy of the GNU Lesser General Public License13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Gerry Boland <gerry.boland@canonical.com>
17 * Daniel d'Andrada <daniel.dandrada@canonical.com>
18 */15 */
1916
20#include "displaywindow.h"17#include "screenwindow.h"
18#include "screen.h"
2119
22#include "mir/geometry/size.h"20#include <mir/geometry/size.h>
21#include <mir/graphics/display_buffer.h>
2322
24#include <qpa/qwindowsysteminterface.h>23#include <qpa/qwindowsysteminterface.h>
25#include <qpa/qplatformscreen.h>24#include <qpa/qplatformscreen.h>
2625
27#include <QDebug>26#include "logging.h"
2827
29static WId newWId()28static WId newWId()
30{29{
@@ -36,18 +35,16 @@
36 return ++id;35 return ++id;
37}36}
3837
39DisplayWindow::DisplayWindow(38ScreenWindow::ScreenWindow(QWindow *window)
40 QWindow *window,39 : QPlatformWindow(window)
41 mir::graphics::DisplaySyncGroup *displayGroup,
42 mir::graphics::DisplayBuffer *displayBuffer)
43 : QObject(nullptr), QPlatformWindow(window)
44 , m_isExposed(true)
45 , m_winId(newWId())40 , m_winId(newWId())
46 , m_displayGroup(displayGroup)
47 , m_displayBuffer(displayBuffer)
48{41{
49 qDebug() << "DisplayWindow::DisplayWindow";42 qCDebug(QTMIR_SCREENS) << "Window" << this << "with window ID" << uint(m_winId);
50 qWarning("Window %p: %p 0x%x\n", this, window, uint(m_winId));43
44 // Register with the Screen it is associated with
45 auto myScreen = static_cast<Screen *>(screen());
46 Q_ASSERT(myScreen);
47 myScreen->setWindow(this);
5148
52 QRect screenGeometry(screen()->availableGeometry());49 QRect screenGeometry(screen()->availableGeometry());
53 if (window->geometry() != screenGeometry) {50 if (window->geometry() != screenGeometry) {
@@ -60,70 +57,22 @@
60 requestActivateWindow();57 requestActivateWindow();
61}58}
6259
63QRect DisplayWindow::geometry() const60ScreenWindow::~ScreenWindow()
64{61{
65 // For yet-to-become-fullscreen windows report the geometry covering the entire62 static_cast<Screen *>(screen())->setWindow(nullptr);
66 // screen. This is particularly important for Quick where the root object may get63}
67 // sized to some geometry queried before calling create().64
68 return screen()->availableGeometry();65void ScreenWindow::swapBuffers()
69}66{
7067 static_cast<Screen *>(screen())->swapBuffers();
71void DisplayWindow::setGeometry(const QRect &)68}
72{69
73 // We only support full-screen windows70void ScreenWindow::makeCurrent()
74 QRect rect(screen()->availableGeometry());71{
75 QWindowSystemInterface::handleGeometryChange(window(), rect);72 static_cast<Screen *>(screen())->makeCurrent();
76 QPlatformWindow::setGeometry(rect);73}
77}74
7875void ScreenWindow::doneCurrent()
79bool DisplayWindow::isExposed() const76{
80{77 static_cast<Screen *>(screen())->doneCurrent();
81 return m_isExposed;
82}
83
84bool DisplayWindow::event(QEvent *event)
85{
86 // Intercept Hide event and convert to Expose event, as Hide causes Qt to release GL
87 // resources, which we don't want. Must intercept Show to un-do hide.
88 if (event->type() == QEvent::Hide) {
89 qDebug() << "DisplayWindow::event got QEvent::Hide";
90 m_isExposed = false;
91 QWindowSystemInterface::handleExposeEvent(window(), QRect());
92 QWindowSystemInterface::flushWindowSystemEvents();
93 return true;
94 } else if (event->type() == QEvent::Show) {
95 qDebug() << "DisplayWindow::event got QEvent::Show";
96 m_isExposed = true;
97 QRect rect(QPoint(), geometry().size());
98 QWindowSystemInterface::handleExposeEvent(window(), rect);
99 QWindowSystemInterface::flushWindowSystemEvents();
100 return true;
101 }
102 return QObject::event(event);
103}
104
105void DisplayWindow::swapBuffers()
106{
107 m_displayBuffer->gl_swap_buffers();
108
109 // FIXME this exposes a QtMir architecture problem now, as DisplayWindow
110 // is supposed to wrap a mg::DisplayBuffer. We use Qt's multithreaded
111 // renderer, where each DisplayWindow is rendered to relatively
112 // independently, and post() called also individually.
113 //
114 // But in multimonitor case where a DisplaySyncGroup contains 2
115 // DisplayBuffers, one post() call will submit both
116 // mg::DisplayBuffers for flipping, which can happen before the other
117 // DisplayWindow has been rendered to, causing visual artifacts
118 m_displayGroup->post();
119}
120
121void DisplayWindow::makeCurrent()
122{
123 m_displayBuffer->make_current();
124}
125
126void DisplayWindow::doneCurrent()
127{
128 m_displayBuffer->release_current();
129}78}
13079
=== renamed file 'src/platforms/mirserver/displaywindow.h' => 'src/platforms/mirserver/screenwindow.h'
--- src/platforms/mirserver/displaywindow.h 2015-03-11 14:53:34 +0000
+++ src/platforms/mirserver/screenwindow.h 2015-08-07 12:06:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2013 Canonical, Ltd.2 * Copyright (C) 2015 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -12,47 +12,31 @@
12 *12 *
13 * You should have received a copy of the GNU Lesser General Public License13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Gerry Boland <gerry.boland@canonical.com>
17 */15 */
1816
19#ifndef DISPLAYWINDOW_H17#ifndef SCREENWINDOW_H
20#define DISPLAYWINDOW_H18#define SCREENWINDOW_H
2119
22#include <qpa/qplatformwindow.h>20#include <qpa/qplatformwindow.h>
2321
24#include <mir/graphics/display.h>22// ScreenWindow implements the basics of a QPlatformWindow.
25#include <mir/graphics/display_buffer.h>23// QtMir enforces one Window per Screen, so Window and Screen are tightly coupled.
2624// All Mir specifics live in the associated Screen object.
27#include <QObject>25
2826class ScreenWindow : public QPlatformWindow
29// DisplayWindow wraps the whatever implementation Mir creates of a DisplayBuffer,
30// which is the buffer output for an individual display.
31
32class DisplayWindow : public QObject, public QPlatformWindow
33{27{
34 Q_OBJECT
35public:28public:
36 explicit DisplayWindow(QWindow *window, mir::graphics::DisplaySyncGroup*, mir::graphics::DisplayBuffer*);29 explicit ScreenWindow(QWindow *window);
3730 virtual ~ScreenWindow();
38 QRect geometry() const override;
39 void setGeometry(const QRect &rect) override;
4031
41 WId winId() const override { return m_winId; }32 WId winId() const override { return m_winId; }
4233
43 bool isExposed() const override;
44
45 bool event(QEvent *event) override;
46
47 void swapBuffers();34 void swapBuffers();
48 void makeCurrent();35 void makeCurrent();
49 void doneCurrent();36 void doneCurrent();
5037
51private:38private:
52 bool m_isExposed;
53 WId m_winId;39 WId m_winId;
54 mir::graphics::DisplaySyncGroup *m_displayGroup;
55 mir::graphics::DisplayBuffer *m_displayBuffer;
56};40};
5741
58#endif // DISPLAYWINDOW_H42#endif // SCREENWINDOW_H
5943
=== added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp'
--- src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 2015-08-07 12:06:18 +0000
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "tileddisplayconfigurationpolicy.h"
18
19#include <mir/graphics/display_configuration.h>
20#include <mir/geometry/point.h>
21
22namespace mg = mir::graphics;
23
24TiledDisplayConfigurationPolicy::TiledDisplayConfigurationPolicy(
25 const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped)
26 : m_wrapped(wrapped)
27{
28}
29
30void TiledDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf)
31{
32 int nextTopLeftPosition = 0;
33
34 m_wrapped->apply_to(conf);
35
36 conf.for_each_output(
37 [&](mg::UserDisplayConfigurationOutput& output)
38 {
39 if (output.connected && output.used) {
40 output.top_left = mir::geometry::Point{nextTopLeftPosition, 0};
41 nextTopLeftPosition += output.modes[output.preferred_mode_index].size.width.as_int();
42 }
43 });
44}
045
=== added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.h'
--- src/platforms/mirserver/tileddisplayconfigurationpolicy.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/tileddisplayconfigurationpolicy.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef TILEDDISPLAYCONFIGURATIONPOLICY_H
18#define TILEDDISPLAYCONFIGURATIONPOLICY_H
19
20#include <mir/graphics/display_configuration_policy.h>
21
22#include <memory>
23
24class TiledDisplayConfigurationPolicy : public mir::graphics::DisplayConfigurationPolicy
25{
26public:
27 TiledDisplayConfigurationPolicy(const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped);
28
29 void apply_to(mir::graphics::DisplayConfiguration& conf) override;
30
31private:
32 const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> m_wrapped;
33};
34
35#endif // TILEDDISPLAYCONFIGURATIONPOLICY_H
036
=== added directory 'tests/common'
=== added file 'tests/common/fake_displayconfigurationoutput.h'
--- tests/common/fake_displayconfigurationoutput.h 1970-01-01 00:00:00 +0000
+++ tests/common/fake_displayconfigurationoutput.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,73 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef FAKE_DISPLAYCONFIGURATIONOUTPUT_H
18#define FAKE_DISPLAYCONFIGURATIONOUTPUT_H
19
20#include <mir/graphics/display_configuration.h>
21
22namespace mg = mir::graphics;
23namespace geom = mir::geometry;
24
25const mg::DisplayConfigurationOutput fakeOutput1
26{
27 mg::DisplayConfigurationOutputId{3},
28 mg::DisplayConfigurationCardId{2},
29 mg::DisplayConfigurationOutputType::dvid,
30 {
31 mir_pixel_format_abgr_8888
32 },
33 {
34 {geom::Size{100, 200}, 60.0},
35 {geom::Size{100, 200}, 59.0},
36 {geom::Size{150, 200}, 59.0}
37 },
38 0,
39 geom::Size{1111, 2222},
40 true,
41 true,
42 geom::Point(),
43 2,
44 mir_pixel_format_abgr_8888,
45 mir_power_mode_on,
46 mir_orientation_normal
47};
48
49const mg::DisplayConfigurationOutput fakeOutput2
50{
51 mg::DisplayConfigurationOutputId{2},
52 mg::DisplayConfigurationCardId{4},
53 mg::DisplayConfigurationOutputType::lvds,
54 {
55 mir_pixel_format_xbgr_8888
56 },
57 {
58 {geom::Size{800, 1200}, 90.0},
59 {geom::Size{1600, 2400}, 60.0},
60 {geom::Size{1500, 2000}, 75.0}
61 },
62 0,
63 geom::Size{1000, 2000},
64 true,
65 true,
66 geom::Point(500, 600),
67 2,
68 mir_pixel_format_xbgr_8888,
69 mir_power_mode_on,
70 mir_orientation_left
71};
72
73#endif // FAKE_DISPLAYCONFIGURATIONOUTPUT_H
074
=== added file 'tests/common/gmock_fixes.h'
--- tests/common/gmock_fixes.h 1970-01-01 00:00:00 +0000
+++ tests/common/gmock_fixes.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,124 @@
1//
2// Copyright © 2012 Canonical Ltd. Copyright 2007, Google Inc.
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31//
32// Author: wan@google.com (Zhanyong Wan)
33// Authored by: Alan Griffiths <alan@octopull.co.uk>
34
35#ifndef MIR_TEST_GMOCK_FIXES_H_
36#define MIR_TEST_GMOCK_FIXES_H_
37
38#include <memory>
39#include <gmock/gmock.h>
40
41namespace testing
42{
43namespace internal
44{
45
46template<typename T>
47class ActionResultHolder<std::unique_ptr<T>>
48: public UntypedActionResultHolderBase {
49 public:
50 explicit ActionResultHolder(std::unique_ptr<T>&& a_value) :
51 value_(std::move(a_value)) {}
52
53 // The compiler-generated copy constructor and assignment operator
54 // are exactly what we need, so we don't need to define them.
55
56 // Returns the held value and deletes this object.
57 std::unique_ptr<T> GetValueAndDelete() const {
58 std::unique_ptr<T> retval(std::move(value_));
59 delete this;
60 return retval;
61 }
62
63 // Prints the held value as an action's result to os.
64 virtual void PrintAsActionResult(::std::ostream* os) const {
65 *os << "\n Returns: ";
66 // T may be a reference type, so we don't use UniversalPrint().
67 UniversalPrinter<std::unique_ptr<T>>::Print(value_, os);
68 }
69
70 // Performs the given mock function's default action and returns the
71 // result in a new-ed ActionResultHolder.
72 template <typename F>
73 static ActionResultHolder* PerformDefaultAction(
74 const FunctionMockerBase<F>* func_mocker,
75 const typename Function<F>::ArgumentTuple& args,
76 const string& call_description) {
77 return new ActionResultHolder(
78 func_mocker->PerformDefaultAction(args, call_description));
79 }
80
81 // Performs the given action and returns the result in a new-ed
82 // ActionResultHolder.
83 template <typename F>
84 static ActionResultHolder*
85 PerformAction(const Action<F>& action,
86 const typename Function<F>::ArgumentTuple& args) {
87 return new ActionResultHolder(action.Perform(args));
88 }
89
90 private:
91 std::unique_ptr<T> mutable value_;
92
93 // T could be a reference type, so = isn't supported.
94 GTEST_DISALLOW_ASSIGN_(ActionResultHolder);
95};
96
97}
98
99template<typename T>
100class DefaultValue<std::unique_ptr<T>> {
101 public:
102 // Unsets the default value for type T.
103 static void Clear() {}
104
105 // Returns true iff the user has set the default value for type T.
106 static bool IsSet() { return false; }
107
108 // Returns true if T has a default return value set by the user or there
109 // exists a built-in default value.
110 static bool Exists() {
111 return true;
112 }
113
114 // Returns the default value for type T if the user has set one;
115 // otherwise returns the built-in default value if there is one;
116 // otherwise aborts the process.
117 static std::unique_ptr<T> Get() {
118 return std::unique_ptr<T>();
119 }
120};
121
122}
123
124#endif /* MIR_TEST_GMOCK_FIXES_H_ */
0125
=== added file 'tests/common/mock_display.h'
--- tests/common/mock_display.h 1970-01-01 00:00:00 +0000
+++ tests/common/mock_display.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MOCKDISPLAY_H
18#define MOCKDISPLAY_H
19
20#include <mir/graphics/display.h>
21#include <mir/graphics/gl_context.h>
22
23#include <gmock/gmock.h>
24#include "gmock_fixes.h"
25
26class MockDisplaySyncGroup : public mir::graphics::DisplaySyncGroup
27{
28public:
29 MOCK_METHOD1(for_each_display_buffer, void(std::function<void(mir::graphics::DisplayBuffer&)> const& f));
30 MOCK_METHOD0(post, void());
31};
32
33struct MockDisplay : public mir::graphics::Display
34{
35public:
36 MOCK_METHOD1(for_each_display_sync_group, void(std::function<void(mir::graphics::DisplaySyncGroup&)> const&));
37 MOCK_CONST_METHOD0(configuration, std::unique_ptr<mir::graphics::DisplayConfiguration>());
38 MOCK_METHOD1(configure, void(mir::graphics::DisplayConfiguration const&));
39 MOCK_METHOD2(register_configuration_change_handler,
40 void(mir::graphics::EventHandlerRegister&, mir::graphics::DisplayConfigurationChangeHandler const&));
41
42 MOCK_METHOD3(register_pause_resume_handlers, void(mir::graphics::EventHandlerRegister&,
43 mir::graphics::DisplayPauseHandler const&,
44 mir::graphics::DisplayResumeHandler const&));
45 MOCK_METHOD0(pause, void());
46 MOCK_METHOD0(resume, void());
47 MOCK_METHOD1(create_hardware_cursor, std::shared_ptr<mir::graphics::Cursor>(std::shared_ptr<mir::graphics::CursorImage> const&));
48 MOCK_METHOD0(create_gl_context, std::unique_ptr<mir::graphics::GLContext>());
49};
50
51
52
53#endif // MOCKDISPLAY_H
054
=== added file 'tests/common/mock_display_buffer.h'
--- tests/common/mock_display_buffer.h 1970-01-01 00:00:00 +0000
+++ tests/common/mock_display_buffer.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MOCK_DISPLAY_BUFFER_H
18#define MOCK_DISPLAY_BUFFER_H
19
20#include <mir/graphics/display_buffer.h>
21
22#include <gmock/gmock.h>
23
24class MockDisplayBuffer : public mir::graphics::DisplayBuffer
25{
26public:
27 MockDisplayBuffer()
28 {
29 using namespace testing;
30 ON_CALL(*this, view_area())
31 .WillByDefault(Return(mir::geometry::Rectangle{{0,0},{0,0}}));
32 }
33 MOCK_CONST_METHOD0(view_area, mir::geometry::Rectangle());
34 MOCK_METHOD0(make_current, void());
35 MOCK_METHOD0(release_current, void());
36 MOCK_METHOD0(gl_swap_buffers, void());
37 MOCK_METHOD1(post_renderables_if_optimizable, bool(mir::graphics::RenderableList const&));
38 MOCK_CONST_METHOD0(orientation, MirOrientation());
39 MOCK_CONST_METHOD0(uses_alpha, bool());
40};
41
42
43#endif // MOCK_DISPLAY_BUFFER_H
044
=== added file 'tests/common/mock_display_configuration.h'
--- tests/common/mock_display_configuration.h 1970-01-01 00:00:00 +0000
+++ tests/common/mock_display_configuration.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MOCK_DISPLAY_CONFIGURATION_H
18#define MOCK_DISPLAY_CONFIGURATION_H
19
20#include <mir/graphics/display_configuration.h>
21
22#include <gmock/gmock.h>
23#include "gmock_fixes.h"
24
25class MockDisplayConfiguration : public mir::graphics::DisplayConfiguration
26{
27public:
28 MOCK_CONST_METHOD1(for_each_card, void(std::function<void(mir::graphics::DisplayConfigurationCard const&)>));
29
30 MOCK_CONST_METHOD1(for_each_output, void(std::function<void(mir::graphics::DisplayConfigurationOutput const&)>));
31 MOCK_METHOD1(for_each_output, void(std::function<void(mir::graphics::UserDisplayConfigurationOutput&)>));
32
33 MOCK_CONST_METHOD0(valid, bool());
34};
35#endif // MOCK_DISPLAY_CONFIGURATION_H
036
=== added file 'tests/common/mock_main_loop.h'
--- tests/common/mock_main_loop.h 1970-01-01 00:00:00 +0000
+++ tests/common/mock_main_loop.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MOCKMAINLOOP_H
18#define MOCKMAINLOOP_H
19
20#include <gmock/gmock.h>
21
22#include <mir/main_loop.h>
23
24#include <memory>
25
26class MockMainLoop : public mir::MainLoop
27{
28public:
29 ~MockMainLoop() noexcept {}
30
31 void run() override {}
32 void stop() override {}
33
34 MOCK_METHOD2(register_signal_handler,
35 void(std::initializer_list<int>,
36 std::function<void(int)> const&));
37
38 MOCK_METHOD3(register_fd_handler,
39 void(std::initializer_list<int>, void const*,
40 std::function<void(int)> const&));
41
42 MOCK_METHOD1(unregister_fd_handler, void(void const*));
43
44 MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&));
45 MOCK_METHOD1(pause_processing_for,void (void const*));
46 MOCK_METHOD1(resume_processing_for,void (void const*));
47
48 MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::function<void()> const& callback));
49 MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::shared_ptr<mir::LockableCallback> const& callback));
50};
51
52
53#endif // MOCKMAINLOOP_H
054
=== modified file 'tests/mirserver/CMakeLists.txt'
--- tests/mirserver/CMakeLists.txt 2014-11-13 15:47:30 +0000
+++ tests/mirserver/CMakeLists.txt 2015-08-07 12:06:18 +0000
@@ -1,3 +1,4 @@
1add_subdirectory(QtEventFeeder)1add_subdirectory(QtEventFeeder)
2add_subdirectory(Clipboard)2add_subdirectory(Clipboard)
3add_subdirectory(Screen)3add_subdirectory(Screen)
4add_subdirectory(ScreenController)
45
=== modified file 'tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h'
--- tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-04-01 15:02:36 +0000
+++ tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-08-07 12:06:18 +0000
@@ -19,22 +19,29 @@
19#define MOCK_QTWINDOWSYSTEM_H19#define MOCK_QTWINDOWSYSTEM_H
2020
21#include <qteventfeeder.h>21#include <qteventfeeder.h>
22#include <QWindow>
2223
23class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {24class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {
24public:25public:
25 MOCK_METHOD0(hasTargetWindow, bool());26 MOCK_CONST_METHOD0(ready, bool());
26 MOCK_METHOD0(targetWindowGeometry, QRect());27 MOCK_METHOD1(setScreenController, void(const QSharedPointer<ScreenController> &));
28 MOCK_METHOD1(getWindowForTouchPoint, QWindow*(const QPoint &point));
29 MOCK_METHOD0(lastWindow, QWindow*());
30 MOCK_METHOD0(focusedWindow, QWindow*());
27 MOCK_METHOD1(registerTouchDevice, void(QTouchDevice* device));31 MOCK_METHOD1(registerTouchDevice, void(QTouchDevice* device));
28 MOCK_METHOD10(handleExtendedKeyEvent, void(ulong timestamp, QEvent::Type type, int key,32
29 Qt::KeyboardModifiers modifiers,33 // Wanted to use GMock, but MOCK_METHOD11 not implemented
30 quint32 nativeScanCode, quint32 nativeVirtualKey,34 void handleExtendedKeyEvent(QWindow */*window*/, ulong /*timestamp*/, QEvent::Type /*type*/, int /*key*/,
31 quint32 nativeModifiers,35 Qt::KeyboardModifiers /*modifiers*/,
32 const QString& text, bool autorep,36 quint32 /*nativeScanCode*/, quint32 /*nativeVirtualKey*/,
33 ushort count));37 quint32 /*nativeModifiers*/,
34 MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device,38 const QString& /*text*/ = QString(), bool /*autorep*/ = false,
39 ushort /*count*/ = 1) {}
40
41 MOCK_METHOD5(handleTouchEvent, void(QWindow *window, ulong timestamp, QTouchDevice *device,
35 const QList<struct QWindowSystemInterface::TouchPoint> &points,42 const QList<struct QWindowSystemInterface::TouchPoint> &points,
36 Qt::KeyboardModifiers mods));43 Qt::KeyboardModifiers mods));
37 MOCK_METHOD4(handleMouseEvent, void(ulong, QPointF, Qt::MouseButton, Qt::KeyboardModifiers));44 MOCK_METHOD5(handleMouseEvent, void(QWindow *window, ulong, QPointF, Qt::MouseButton, Qt::KeyboardModifiers));
38};45};
3946
40namespace testing47namespace testing
4148
=== modified file 'tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp'
--- tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-06-24 23:08:44 +0000
+++ tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-08-07 12:06:18 +0000
@@ -70,33 +70,44 @@
7070
71 MockQtWindowSystem *mockWindowSystem;71 MockQtWindowSystem *mockWindowSystem;
72 QtEventFeeder *qtEventFeeder;72 QtEventFeeder *qtEventFeeder;
73 QWindow *window;
74 QGuiApplication *app;
73};75};
7476
75void QtEventFeederTest::SetUp()77void QtEventFeederTest::SetUp()
76{78{
77 mockWindowSystem = new MockQtWindowSystem;79 mockWindowSystem = new MockQtWindowSystem;
80 auto screens = QSharedPointer<ScreenController>();
7881
79 EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_));82 EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_));
8083
81 qtEventFeeder = new QtEventFeeder(mockWindowSystem);84 qtEventFeeder = new QtEventFeeder(screens, mockWindowSystem);
8285
83 ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));86 ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
87
88 int argc = 0;
89 char **argv = nullptr;
90 setenv("QT_QPA_PLATFORM", "minimal", 1);
91 app = new QGuiApplication(argc, argv);
92 window = new QWindow;
84}93}
8594
86void QtEventFeederTest::TearDown()95void QtEventFeederTest::TearDown()
87{96{
88 // mockWindowSystem will be deleted by QtEventFeeder97 // mockWindowSystem will be deleted by QtEventFeeder
89 delete qtEventFeeder;98 delete qtEventFeeder;
99 delete window;
100 delete app;
90}101}
91102
92void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()103void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()
93{104{
94 EXPECT_CALL(*mockWindowSystem, hasTargetWindow())105 EXPECT_CALL(*mockWindowSystem, getWindowForTouchPoint(_))
95 .Times(AnyNumber())106 .Times(AnyNumber())
96 .WillRepeatedly(Return(true));107 .WillRepeatedly(Return(window));
97 EXPECT_CALL(*mockWindowSystem, targetWindowGeometry())108 EXPECT_CALL(*mockWindowSystem, focusedWindow())
98 .Times(AnyNumber())109 .Times(AnyNumber())
99 .WillRepeatedly(Return(QRect(0,0,100,100)));110 .WillRepeatedly(Return(window));
100}111}
101112
102113
@@ -114,7 +125,7 @@
114125
115 setIrrelevantMockWindowSystemExpectations();126 setIrrelevantMockWindowSystemExpectations();
116127
117 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),128 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1),
118 Contains(AllOf(HasId(0),129 Contains(AllOf(HasId(0),
119 IsPressed()))),_)).Times(1);130 IsPressed()))),_)).Times(1);
120131
@@ -133,12 +144,12 @@
133 InSequence sequence;144 InSequence sequence;
134145
135 EXPECT_CALL(*mockWindowSystem,146 EXPECT_CALL(*mockWindowSystem,
136 handleTouchEvent(_,_,AllOf(SizeIs(1),147 handleTouchEvent(_,_,_,AllOf(SizeIs(1),
137 Contains(AllOf(HasId(0),IsReleased()))148 Contains(AllOf(HasId(0),IsReleased()))
138 ),_)).Times(1);149 ),_)).Times(1);
139150
140 EXPECT_CALL(*mockWindowSystem,151 EXPECT_CALL(*mockWindowSystem,
141 handleTouchEvent(_,_,AllOf(SizeIs(1),152 handleTouchEvent(_,_,_,AllOf(SizeIs(1),
142 Contains(AllOf(HasId(1),IsPressed()))153 Contains(AllOf(HasId(1),IsPressed()))
143 ),_)).Times(1);154 ),_)).Times(1);
144 }155 }
@@ -162,7 +173,7 @@
162 10, 10, 10 /* x, y, pressure*/,173 10, 10, 10 /* x, y, pressure*/,
163 1, 1, 10 /* touch major, minor, size */);174 1, 1, 10 /* touch major, minor, size */);
164175
165 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),176 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1),
166 Contains(AllOf(HasId(0),177 Contains(AllOf(HasId(0),
167 IsPressed()))),_)).Times(1);178 IsPressed()))),_)).Times(1);
168 qtEventFeeder->dispatch(*ev1);179 qtEventFeeder->dispatch(*ev1);
@@ -182,7 +193,7 @@
182 1, 1, 10 /* touch major, minor, size */);193 1, 1, 10 /* touch major, minor, size */);
183194
184 EXPECT_CALL(*mockWindowSystem,195 EXPECT_CALL(*mockWindowSystem,
185 handleTouchEvent(_,_,AllOf(SizeIs(2),196 handleTouchEvent(_,_,_,AllOf(SizeIs(2),
186 Contains(AllOf(HasId(0), StateIsMoved())),197 Contains(AllOf(HasId(0), StateIsMoved())),
187 Contains(AllOf(HasId(1), IsPressed()))198 Contains(AllOf(HasId(1), IsPressed()))
188 ),_)).Times(1);199 ),_)).Times(1);
@@ -209,14 +220,14 @@
209220
210 // first release touch 0221 // first release touch 0
211 EXPECT_CALL(*mockWindowSystem,222 EXPECT_CALL(*mockWindowSystem,
212 handleTouchEvent(_,_,AllOf(SizeIs(2),223 handleTouchEvent(_,_,_,AllOf(SizeIs(2),
213 Contains(AllOf(HasId(0), IsReleased())),224 Contains(AllOf(HasId(0), IsReleased())),
214 Contains(AllOf(HasId(1), IsStationary()))225 Contains(AllOf(HasId(1), IsStationary()))
215 ),_)).Times(1);226 ),_)).Times(1);
216227
217 // then press touch 2228 // then press touch 2
218 EXPECT_CALL(*mockWindowSystem,229 EXPECT_CALL(*mockWindowSystem,
219 handleTouchEvent(_,_,AllOf(SizeIs(2),230 handleTouchEvent(_,_,_,AllOf(SizeIs(2),
220 Contains(AllOf(HasId(1), StateIsMoved())),231 Contains(AllOf(HasId(1), StateIsMoved())),
221 Contains(AllOf(HasId(2), IsPressed()))232 Contains(AllOf(HasId(2), IsPressed()))
222 ),_)).Times(1);233 ),_)).Times(1);
@@ -231,7 +242,7 @@
231{242{
232 setIrrelevantMockWindowSystemExpectations();243 setIrrelevantMockWindowSystemExpectations();
233244
234 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),245 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1),
235 Contains(AllOf(HasId(0),246 Contains(AllOf(HasId(0),
236 IsPressed()))),_)).Times(1);247 IsPressed()))),_)).Times(1);
237248
@@ -244,7 +255,7 @@
244255
245 setIrrelevantMockWindowSystemExpectations();256 setIrrelevantMockWindowSystemExpectations();
246257
247 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),258 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1),
248 Contains(AllOf(HasId(0), StateIsMoved()))259 Contains(AllOf(HasId(0), StateIsMoved()))
249 ),_)).Times(1);260 ),_)).Times(1);
250261
251262
=== modified file 'tests/mirserver/Screen/CMakeLists.txt'
--- tests/mirserver/Screen/CMakeLists.txt 2014-12-03 08:56:35 +0000
+++ tests/mirserver/Screen/CMakeLists.txt 2015-08-07 12:06:18 +0000
@@ -5,6 +5,7 @@
5)5)
66
7include_directories(7include_directories(
8 ${CMAKE_SOURCE_DIR}/tests/common
8 ${CMAKE_SOURCE_DIR}/src/platforms/mirserver9 ${CMAKE_SOURCE_DIR}/src/platforms/mirserver
9 ${CMAKE_SOURCE_DIR}/src/common10 ${CMAKE_SOURCE_DIR}/src/common
10 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}11 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
1112
=== modified file 'tests/mirserver/Screen/screen_test.cpp'
--- tests/mirserver/Screen/screen_test.cpp 2015-03-05 16:23:47 +0000
+++ tests/mirserver/Screen/screen_test.cpp 2015-08-07 12:06:18 +0000
@@ -19,37 +19,21 @@
19#include <gtest/gtest.h>19#include <gtest/gtest.h>
2020
21#include "mir/graphics/display_configuration.h"21#include "mir/graphics/display_configuration.h"
22#include "fake_displayconfigurationoutput.h"
2223
23#include <screen.h>24#include <screen.h>
2425
26using namespace ::testing;
27
25namespace mg = mir::graphics;28namespace mg = mir::graphics;
26namespace geom = mir::geometry;29namespace geom = mir::geometry;
2730
28mg::DisplayConfigurationOutput const fake_output31class ScreenTest : public ::testing::Test {
29{32protected:
30 mg::DisplayConfigurationOutputId{3},33 void SetUp() override;
31 mg::DisplayConfigurationCardId{2},
32 mg::DisplayConfigurationOutputType::dvid,
33 {
34 mir_pixel_format_abgr_8888
35 },
36 {
37 {geom::Size{10, 20}, 60.0},
38 {geom::Size{10, 20}, 59.0},
39 {geom::Size{15, 20}, 59.0}
40 },
41 0,
42 geom::Size{10, 20},
43 true,
44 true,
45 geom::Point(),
46 2,
47 mir_pixel_format_abgr_8888,
48 mir_power_mode_on,
49 mir_orientation_normal
50};34};
5135
52TEST(ScreenTest, OrientationSensor)36void ScreenTest::SetUp()
53{37{
54 if (!qEnvironmentVariableIsSet("QT_ACCEL_FILEPATH")) {38 if (!qEnvironmentVariableIsSet("QT_ACCEL_FILEPATH")) {
55 // Trick Qt >= 5.4.1 to load the generic sensors39 // Trick Qt >= 5.4.1 to load the generic sensors
@@ -57,7 +41,11 @@
57 }41 }
5842
59 Screen::skipDBusRegistration = true;43 Screen::skipDBusRegistration = true;
60 Screen *screen = new Screen(fake_output);44}
45
46TEST_F(ScreenTest, OrientationSensor)
47{
48 Screen *screen = new Screen(fakeOutput1);
6149
62 // Default state should be active50 // Default state should be active
63 ASSERT_TRUE(screen->orientationSensorEnabled());51 ASSERT_TRUE(screen->orientationSensorEnabled());
@@ -68,3 +56,29 @@
68 screen->onDisplayPowerStateChanged(1,0);56 screen->onDisplayPowerStateChanged(1,0);
69 ASSERT_TRUE(screen->orientationSensorEnabled());57 ASSERT_TRUE(screen->orientationSensorEnabled());
70}58}
59
60TEST_F(ScreenTest, ReadConfigurationFromDisplayConfig)
61{
62 Screen *screen = new Screen(fakeOutput1);
63
64 EXPECT_EQ(screen->geometry(), QRect(0, 0, 150, 200));
65 EXPECT_EQ(screen->availableGeometry(), QRect(0, 0, 150, 200));
66 EXPECT_EQ(screen->depth(), 32);
67 EXPECT_EQ(screen->format(), QImage::Format_RGBA8888);
68 EXPECT_EQ(screen->refreshRate(), 59);
69 EXPECT_EQ(screen->physicalSize(), QSize(1111, 2222));
70 EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::dvid);
71}
72
73TEST_F(ScreenTest, ReadDifferentConfigurationFromDisplayConfig)
74{
75 Screen *screen = new Screen(fakeOutput2);
76
77 EXPECT_EQ(screen->geometry(), QRect(500, 600, 1500, 2000));
78 EXPECT_EQ(screen->availableGeometry(), QRect(500, 600, 1500, 2000));
79 EXPECT_EQ(screen->depth(), 32);
80 EXPECT_EQ(screen->format(), QImage::Format_RGBX8888);
81 EXPECT_EQ(screen->refreshRate(), 75);
82 EXPECT_EQ(screen->physicalSize(), QSize(1000, 2000));
83 EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::lvds);
84}
7185
=== added directory 'tests/mirserver/ScreenController'
=== added file 'tests/mirserver/ScreenController/CMakeLists.txt'
--- tests/mirserver/ScreenController/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/CMakeLists.txt 2015-08-07 12:06:18 +0000
@@ -0,0 +1,28 @@
1set(
2 SCREENCONTROLLER_TEST_SOURCES
3 screencontroller_test.cpp
4 ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp
5 # to be moc-ed
6 stub_screen.h
7 testable_screencontroller.h
8)
9
10include_directories(
11 ${CMAKE_SOURCE_DIR}/tests/common
12 ${CMAKE_SOURCE_DIR}/src/platforms/mirserver
13 ${CMAKE_SOURCE_DIR}/src/common
14 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
15 ${MIRSERVER_INCLUDE_DIRS}
16)
17
18add_executable(ScreenControllerTest ${SCREENCONTROLLER_TEST_SOURCES})
19
20target_link_libraries(
21 ScreenControllerTest
22 qpa-mirserver
23
24 ${GTEST_BOTH_LIBRARIES}
25 ${GMOCK_LIBRARIES}
26)
27
28add_test(ScreenController, ScreenControllerTest)
029
=== added file 'tests/mirserver/ScreenController/screencontroller_test.cpp'
--- tests/mirserver/ScreenController/screencontroller_test.cpp 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/screencontroller_test.cpp 2015-08-07 12:06:18 +0000
@@ -0,0 +1,193 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <gtest/gtest.h>
18#include "gmock_fixes.h"
19
20#include "stub_display.h"
21#include "mock_main_loop.h"
22#include "qtcompositor.h"
23#include "fake_displayconfigurationoutput.h"
24
25#include "testable_screencontroller.h"
26#include "screen.h"
27#include "screenwindow.h"
28
29#include <QGuiApplication>
30
31using namespace ::testing;
32
33namespace mg = mir::graphics;
34namespace geom = mir::geometry;
35
36class ScreenControllerTest : public ::testing::Test {
37protected:
38 void SetUp() override;
39 void TearDown() override;
40
41 ScreenController *screenController;
42 std::shared_ptr<StubDisplay> display;
43 std::shared_ptr<QtCompositor> compositor;
44 QGuiApplication *app;
45};
46
47void ScreenControllerTest::SetUp()
48{
49 setenv("QT_QPA_PLATFORM", "minimal", 1);
50 Screen::skipDBusRegistration = true;
51
52 screenController = new TestableScreenController;
53 display = std::make_shared<StubDisplay>();
54 compositor = std::make_shared<QtCompositor>();
55 auto mainLoop = std::make_shared<MockMainLoop>();
56
57 EXPECT_CALL(*display, register_configuration_change_handler(_,_))
58 .Times(1);
59
60 static_cast<TestableScreenController*>(screenController)->do_init(display, compositor, mainLoop);
61
62 int argc = 0;
63 char **argv = nullptr;
64 setenv("QT_QPA_PLATFORM", "minimal", 1);
65 app = new QGuiApplication(argc, argv);
66}
67
68void ScreenControllerTest::TearDown()
69{
70 delete screenController;
71}
72
73TEST_F(ScreenControllerTest, SingleScreenFound)
74{
75 // Set up display state
76 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1};
77 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
78 display->setFakeConfiguration(config, bufferConfig);
79
80 screenController->update();
81
82 ASSERT_EQ(1, screenController->screens().count());
83 Screen* screen = screenController->screens().first();
84 EXPECT_EQ(QRect(0, 0, 150, 200), screen->geometry());
85}
86
87TEST_F(ScreenControllerTest, MultipleScreenFound)
88{
89 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2};
90 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
91 display->setFakeConfiguration(config, bufferConfig);
92
93 screenController->update();
94
95 ASSERT_EQ(2, screenController->screens().count());
96 EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry());
97 EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry());
98}
99
100TEST_F(ScreenControllerTest, ScreenAdded)
101{
102 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1};
103 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
104 display->setFakeConfiguration(config, bufferConfig);
105
106 screenController->update();
107
108 config.push_back(fakeOutput2);
109 display->setFakeConfiguration(config, bufferConfig);
110
111 ASSERT_EQ(1, screenController->screens().count());
112 EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry());
113
114 screenController->update();
115
116 ASSERT_EQ(2, screenController->screens().count());
117 EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry());
118 EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry());
119}
120
121TEST_F(ScreenControllerTest, ScreenRemoved)
122{
123 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput2, fakeOutput1};
124 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
125 display->setFakeConfiguration(config, bufferConfig);
126
127 screenController->update();
128
129 config.pop_back();
130 display->setFakeConfiguration(config, bufferConfig);
131
132 ASSERT_EQ(2, screenController->screens().count());
133 EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry());
134 EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(1)->geometry());
135
136 screenController->update();
137
138 ASSERT_EQ(1, screenController->screens().count());
139 EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry());
140}
141
142TEST_F(ScreenControllerTest, CheckPrioritizedGetUnusedScreen)
143{
144 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput2, fakeOutput1};
145 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
146 display->setFakeConfiguration(config, bufferConfig);
147
148 screenController->update();
149
150 auto screen = screenController->getUnusedScreen();
151 EXPECT_EQ(mg::DisplayConfigurationOutputType::lvds, screen->outputType());
152}
153
154TEST_F(ScreenControllerTest, MatchBufferWithDisplay)
155{
156 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1};
157 MockDisplayBuffer buffer1;
158 std::vector<MockDisplayBuffer*> buffers {&buffer1};
159
160 geom::Rectangle buffer1Geom{{0, 0}, {150, 200}};
161 EXPECT_CALL(buffer1, view_area())
162 .WillRepeatedly(Return(buffer1Geom));
163
164 display->setFakeConfiguration(config, buffers);
165 screenController->update();
166
167 ASSERT_EQ(1, screenController->screens().count());
168 EXPECT_CALL(buffer1, make_current());
169 static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent();
170}
171
172TEST_F(ScreenControllerTest, MultipleMatchBuffersWithDisplays)
173{
174 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2};
175 MockDisplayBuffer buffer1, buffer2;
176 std::vector<MockDisplayBuffer*> buffers {&buffer1, &buffer2};
177
178 geom::Rectangle buffer1Geom{{500, 600}, {1500, 2000}};
179 geom::Rectangle buffer2Geom{{0, 0}, {150, 200}};
180 EXPECT_CALL(buffer1, view_area())
181 .WillRepeatedly(Return(buffer1Geom));
182 EXPECT_CALL(buffer2, view_area())
183 .WillRepeatedly(Return(buffer2Geom));
184
185 display->setFakeConfiguration(config, buffers);
186 screenController->update();
187
188 ASSERT_EQ(2, screenController->screens().count());
189 EXPECT_CALL(buffer1, make_current());
190 EXPECT_CALL(buffer2, make_current());
191 static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent();
192 static_cast<StubScreen*>(screenController->screens().at(1))->makeCurrent();
193}
0194
=== added file 'tests/mirserver/ScreenController/stub_display.h'
--- tests/mirserver/ScreenController/stub_display.h 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/stub_display.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,91 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef STUB_DISPLAY_H
18#define STUB_DISPLAY_H
19
20#include "mock_display.h"
21#include "mock_display_buffer.h"
22#include "mock_display_configuration.h"
23
24namespace mg = mir::graphics;
25namespace geom = mir::geometry;
26
27class StubDisplayConfiguration : public MockDisplayConfiguration
28{
29public:
30 StubDisplayConfiguration(const std::vector<mg::DisplayConfigurationOutput> &config)
31 : m_config(config)
32 {}
33
34 void for_each_output(std::function<void(mg::DisplayConfigurationOutput const&)> f) const override
35 {
36 for (auto config : m_config) {
37 f(config);
38 }
39 }
40
41private:
42 const std::vector<mg::DisplayConfigurationOutput> m_config;
43};
44
45
46class StubDisplaySyncGroup : public MockDisplaySyncGroup
47{
48public:
49 StubDisplaySyncGroup(MockDisplayBuffer *buffer) : buffer(buffer) {}
50
51 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override
52 {
53 f(*buffer);
54 }
55private:
56 MockDisplayBuffer *buffer;
57};
58
59
60class StubDisplay : public MockDisplay
61{
62public:
63 // Note, GMock cannot mock functions which return non-copyable objects, so stubbing needed
64 std::unique_ptr<mg::DisplayConfiguration> configuration() const override
65 {
66 return std::unique_ptr<mg::DisplayConfiguration>(
67 new StubDisplayConfiguration(m_config)
68 );
69 }
70
71 void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override
72 {
73 for (auto displayBuffer : m_displayBuffers) {
74 StubDisplaySyncGroup b(displayBuffer);
75 f(b);
76 }
77 }
78
79 void setFakeConfiguration(std::vector<mg::DisplayConfigurationOutput> &config,
80 std::vector<MockDisplayBuffer*> &displayBuffers)
81 {
82 m_config = config;
83 m_displayBuffers = displayBuffers;
84 }
85
86private:
87 std::vector<mg::DisplayConfigurationOutput> m_config;
88 std::vector<MockDisplayBuffer*> m_displayBuffers;
89};
90
91#endif // STUB_DISPLAY_H
092
=== added file 'tests/mirserver/ScreenController/stub_screen.h'
--- tests/mirserver/ScreenController/stub_screen.h 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/stub_screen.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef STUBSCREEN_H
18#define STUBSCREEN_H
19
20#include "screen.h"
21
22class StubScreen : public Screen
23{
24 Q_OBJECT
25public:
26 StubScreen(const mir::graphics::DisplayConfigurationOutput &output) : Screen(output) {}
27
28 void makeCurrent() { Screen::makeCurrent(); }
29};
30
31#endif // STUBSCREEN_H
032
=== added file 'tests/mirserver/ScreenController/testable_screencontroller.h'
--- tests/mirserver/ScreenController/testable_screencontroller.h 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/testable_screencontroller.h 2015-08-07 12:06:18 +0000
@@ -0,0 +1,38 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "screencontroller.h"
18#include "stub_screen.h"
19
20struct TestableScreenController : public ScreenController
21{
22 Q_OBJECT
23
24public:
25 Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const override
26 {
27 return new StubScreen(output);
28 }
29
30 void do_init(const std::shared_ptr<mir::graphics::Display> &display,
31 const std::shared_ptr<mir::compositor::Compositor> &compositor,
32 const std::shared_ptr<mir::MainLoop> &mainLoop)
33 {
34 init(display, compositor, mainLoop);
35 }
36
37 void do_terminate() { terminate(); }
38};
039
=== modified file 'tests/modules/common/qtmir_test.h'
--- tests/modules/common/qtmir_test.h 2015-03-24 23:38:33 +0000
+++ tests/modules/common/qtmir_test.h 2015-08-07 12:06:18 +0000
@@ -68,7 +68,7 @@
68{68{
69public:69public:
70 FakeMirServer()70 FakeMirServer()
71 : MirServer(0, nullptr)71 : MirServer(0, nullptr, QSharedPointer<ScreenController>())
72 {72 {
73 }73 }
7474

Subscribers

People subscribed via source and target branches