Merge lp:~gerboland/qtmir/multimonitor-spike into lp:qtmir
- multimonitor-spike
- Merge into trunk
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 |
Related bugs: |
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 DisplayConfigur
On Mir DisplayConfigur
1. blocks Mir until it has stopped all renderers and has their GL contexts released
2. reads the new DisplayConfigur
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
Description of the change
Gerry Boland (gerboland) wrote : | # |
Gerry Boland (gerboland) wrote : | # |
Gah, input on second display not working
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:338
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
src/modules/
"""
public Q_SLOTS:
void onScreenAdded(
void onScreenRemoved
"""
Shouldn't they be private?
-------
src/platforms/
"""
EGLDisplay m_eglDisplay;
EGLContext m_eglContext;
"""
You store them as member variables but they are still only used in the constructor.
-------
In MirServerIntegr
"""
qDebug() << "createPlatform
"""
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/
return nullptr;
}
[...]
if (!screen) {
qDebug() << "No available Screens to create a new QWindow/
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 MirServerIntegr
"""
qDebug() << "ScreenController not initialized";
"""
More qDebug. Maybe this should be a qFatal?
-------
In src/platforms/
"""
#include <QDebug>
"""
You don't need that.
-------
In src/platforms/
"""
QWeakPointe
"""
Why return a weak pointer if all users of it do "screenControll
-------
QtEventFeeder:
I think it would be cleaner to have two constructors instead:
QtEventFeeder:
: QtEventFeeder(new QtWindowSystem(
{
}
QtEventFeeder:
{
- if (windowSystem) {
- mQtWindowSystem = windowSystem;
- } else {
- mQtWindowSystem = new QtWindowSystem;
- }
}
And remove the "= nullptr" from the signature of the second one.
-------
"""
void QtEventFeeder:
{
- auto type = mir_event_
- if (type != mir_event_
- return;
"""
Why remove it?
-------
"""
void QtEventFeeder:
{
[...]
+ mQtWindowSystem
}
"""
You have to pass the window chosen in QtEventFeeder:
-------
Please update...
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.
Gerry Boland (gerboland) wrote : | # |
I'll be addressing your code comments soon.
On your testing, please watch the console output carefully. ScreenControlle
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 MirServerIntegr
ation, use categories - 343. By Gerry Boland
-
Remove commented out lines and useless debug outputs from ScreenController
- 344. By Gerry Boland
-
Update comment in MirServerIntegr
ation 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
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:354
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 355. By Gerry Boland
-
Add second QtEventFeeder constructor which creates non-test QtWindowSystemI
nterface 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
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/
<snip>
> qDebug() << "No available Screens to create a new QWindow/
>
> 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/
>
> """
> QWeakPointer<
> """
>
> Why return a weak pointer if all users of it do "screenControll
> 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/
> """
> auto displayConfig = display-
> """
>
> 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_
- 366. By Gerry Boland
-
Merge trunk
- 367. By Gerry Boland
-
Ensure deregister ScreenWindow from Screen on destruction
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:366
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
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/
> <snip>
>> > qDebug() << "No available Screens to create a new QWindow/
>> >
>> > 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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:367
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
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.
Daniel d'Andrada (dandrader) wrote : | # |
"""
qtmir (0.4.6) vivid; urgency=medium
"""
nitpick: Shouldn't it be UNRELEASED instead of vivid?
Daniel d'Andrada (dandrader) wrote : | # |
Good clean up! Only a couple of minor issues left:
-------
Please update copyright year of src/platforms/
-------
src/platforms/
It still has some qDebug() messages and commented-out code.
"""
if (window && window->window()) { qDebug() << "HIDE" << window;
"""
"""
"""
NB: the stuff above appears in two separate locations in the file
-------
In tests/mirserver
"""
ASSERT_
"""
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.
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
-
ScreenControlle
rTest- flip argument in assert/expect_eq statements
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:371
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Unmerged revisions
- 371. By Gerry Boland
-
ScreenControlle
rTest- 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
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2015-07-28 09:57:00 +0000 |
3 | +++ debian/changelog 2015-08-07 12:06:18 +0000 |
4 | @@ -1,3 +1,9 @@ |
5 | +qtmir (0.4.6) UNRELEASED; urgency=medium |
6 | + |
7 | + * Add better MultiMonitor support |
8 | + |
9 | + -- Gerry Boland <gerry.boland@canonical.com> Thu, 02 Jul 2015 00:31:23 +0100 |
10 | + |
11 | qtmir (0.4.5+15.10.20150728-0ubuntu1) wily; urgency=medium |
12 | |
13 | [ Gerry Boland ] |
14 | |
15 | === modified file 'demos/qml-demo-shell/qml-demo-shell.qml' |
16 | --- demos/qml-demo-shell/qml-demo-shell.qml 2015-05-01 13:31:30 +0000 |
17 | +++ demos/qml-demo-shell/qml-demo-shell.qml 2015-08-07 12:06:18 +0000 |
18 | @@ -1,5 +1,7 @@ |
19 | -import QtQuick 2.0 |
20 | +import QtQuick 2.3 |
21 | +import QtQuick.Window 2.2 |
22 | import Unity.Application 0.1 |
23 | +import Unity.Screens 0.1 |
24 | |
25 | Rectangle { |
26 | id: root |
27 | @@ -169,4 +171,72 @@ |
28 | } |
29 | } |
30 | } |
31 | + |
32 | + |
33 | + Component { |
34 | + id: window1 |
35 | + Window { |
36 | + color: "lightgreen" |
37 | + visible: true // if not set visible, Window is not created!! |
38 | + |
39 | + Image { |
40 | + id: unityLogo1 |
41 | + source: "UnityLogo.png" |
42 | + fillMode: Image.PreserveAspectFit |
43 | + anchors.centerIn: parent |
44 | + width: 600 |
45 | + height: 600 |
46 | + |
47 | + RotationAnimation { |
48 | + id: logoAnimation1 |
49 | + target: unityLogo1 |
50 | + from: 359 |
51 | + to: 0 |
52 | + duration: 7000 |
53 | + easing.type: Easing.Linear |
54 | + loops: Animation.Infinite |
55 | + } |
56 | + Component.onCompleted: print("new window!!") |
57 | + Component.onDestruction: print("window destroyed!!") |
58 | + } |
59 | + |
60 | + Rectangle { |
61 | + width: 50; height: 50 |
62 | + color: "blue" |
63 | + x: point1.x |
64 | + y: point1.y |
65 | + } |
66 | + |
67 | + MultiPointTouchArea { |
68 | + anchors.fill: parent |
69 | + minimumTouchPoints: 1 |
70 | + maximumTouchPoints: 1 |
71 | + touchPoints: [ |
72 | + TouchPoint { id: point1 } |
73 | + ] |
74 | + onPressed: { |
75 | + if (logoAnimation1.paused) { |
76 | + logoAnimation1.resume(); |
77 | + } else if (logoAnimation1.running) { |
78 | + logoAnimation1.pause(); |
79 | + } else { |
80 | + logoAnimation1.start(); |
81 | + } |
82 | + } |
83 | + } |
84 | + } |
85 | + } |
86 | + |
87 | + Screens { |
88 | + id: screens |
89 | + property variant secondWindow: null |
90 | + onScreenAdded: { |
91 | + print("Screen added!!") |
92 | + secondWindow = window1.createObject(root) |
93 | + } |
94 | + onScreenRemoved: { |
95 | + print("Screen removed!!!") |
96 | + secondWindow.destroy(); |
97 | + } |
98 | + } |
99 | } |
100 | |
101 | === modified file 'src/modules/Unity/CMakeLists.txt' |
102 | --- src/modules/Unity/CMakeLists.txt 2014-09-22 18:06:58 +0000 |
103 | +++ src/modules/Unity/CMakeLists.txt 2015-08-07 12:06:18 +0000 |
104 | @@ -1,1 +1,2 @@ |
105 | add_subdirectory(Application) |
106 | +add_subdirectory(Screens) |
107 | |
108 | === added directory 'src/modules/Unity/Screens' |
109 | === added file 'src/modules/Unity/Screens/CMakeLists.txt' |
110 | --- src/modules/Unity/Screens/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
111 | +++ src/modules/Unity/Screens/CMakeLists.txt 2015-08-07 12:06:18 +0000 |
112 | @@ -0,0 +1,18 @@ |
113 | +set(SCREENSPLUGIN_SRC |
114 | + plugin.cpp |
115 | + screens.cpp |
116 | + ) |
117 | + |
118 | +add_library(unityscreensplugin SHARED |
119 | + ${SCREENSPLUGIN_SRC} |
120 | +) |
121 | + |
122 | +target_link_libraries( |
123 | + unityscreensplugin |
124 | + |
125 | + Qt5::Gui |
126 | + Qt5::Qml |
127 | +) |
128 | + |
129 | +# install |
130 | +add_qml_plugin(Unity.Screens 0.1 Unity/Screens TARGETS unityscreensplugin) |
131 | |
132 | === added file 'src/modules/Unity/Screens/plugin.cpp' |
133 | --- src/modules/Unity/Screens/plugin.cpp 1970-01-01 00:00:00 +0000 |
134 | +++ src/modules/Unity/Screens/plugin.cpp 2015-08-07 12:06:18 +0000 |
135 | @@ -0,0 +1,41 @@ |
136 | +/* |
137 | + * Copyright (C) 2015 Canonical, Ltd. |
138 | + * |
139 | + * This program is free software: you can redistribute it and/or modify it under |
140 | + * the terms of the GNU Lesser General Public License version 3, as published by |
141 | + * the Free Software Foundation. |
142 | + * |
143 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
144 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
145 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
146 | + * Lesser General Public License for more details. |
147 | + * |
148 | + * You should have received a copy of the GNU Lesser General Public License |
149 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
150 | + */ |
151 | + |
152 | +// Qt |
153 | +#include <QQmlExtensionPlugin> |
154 | +#include <QtQml/qqml.h> |
155 | +#include <QScreen> |
156 | + |
157 | +// local |
158 | +#include "screens.h" |
159 | + |
160 | +using namespace qtmir; |
161 | + |
162 | +class UnityScreensPlugin : public QQmlExtensionPlugin { |
163 | + Q_OBJECT |
164 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") |
165 | + |
166 | + virtual void registerTypes(const char* uri) |
167 | + { |
168 | + Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Screens")); |
169 | + |
170 | + qRegisterMetaType<QScreen*>("QScreen*"); |
171 | + |
172 | + qmlRegisterType<qtmir::Screens>(uri, 0, 1, "Screens"); |
173 | + } |
174 | +}; |
175 | + |
176 | +#include "plugin.moc" |
177 | |
178 | === added file 'src/modules/Unity/Screens/qmldir' |
179 | --- src/modules/Unity/Screens/qmldir 1970-01-01 00:00:00 +0000 |
180 | +++ src/modules/Unity/Screens/qmldir 2015-08-07 12:06:18 +0000 |
181 | @@ -0,0 +1,2 @@ |
182 | +module Unity.Screens |
183 | +plugin unityscreensplugin |
184 | |
185 | === added file 'src/modules/Unity/Screens/screens.cpp' |
186 | --- src/modules/Unity/Screens/screens.cpp 1970-01-01 00:00:00 +0000 |
187 | +++ src/modules/Unity/Screens/screens.cpp 2015-08-07 12:06:18 +0000 |
188 | @@ -0,0 +1,71 @@ |
189 | +/* |
190 | + * Copyright (C) 2015 Canonical, Ltd. |
191 | + * |
192 | + * This program is free software: you can redistribute it and/or modify it under |
193 | + * the terms of the GNU Lesser General Public License version 3, as published by |
194 | + * the Free Software Foundation. |
195 | + * |
196 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
197 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
198 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
199 | + * Lesser General Public License for more details. |
200 | + * |
201 | + * You should have received a copy of the GNU Lesser General Public License |
202 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
203 | + */ |
204 | + |
205 | +#include "screens.h" |
206 | + |
207 | +#include <QGuiApplication> |
208 | +#include <QScreen> |
209 | + |
210 | +Q_DECLARE_METATYPE(QScreen*) |
211 | + |
212 | +namespace qtmir { |
213 | + |
214 | +Screens::Screens(QObject *parent) : |
215 | + QAbstractListModel(parent) |
216 | +{ |
217 | + auto app = static_cast<QGuiApplication *>(QGuiApplication::instance()); |
218 | + if (!app) { |
219 | + return; |
220 | + } |
221 | + connect(app, &QGuiApplication::screenAdded, this, &Screens::onScreenAdded); |
222 | + connect(app, &QGuiApplication::screenRemoved, this, &Screens::onScreenRemoved); |
223 | +} |
224 | + |
225 | +QVariant Screens::data(const QModelIndex &index, int) const |
226 | +{ |
227 | + QList<QScreen *> qscreenList = QGuiApplication::screens(); |
228 | + |
229 | + if (!index.isValid() || index.row() >= qscreenList.size()) { |
230 | + return QVariant(); |
231 | + } |
232 | + |
233 | + return QVariant::fromValue(qscreenList.at(index.row())); |
234 | +} |
235 | + |
236 | +int Screens::rowCount(const QModelIndex &) const |
237 | +{ |
238 | + return count(); |
239 | +} |
240 | + |
241 | +int Screens::count() const |
242 | +{ |
243 | + return QGuiApplication::screens().size(); |
244 | +} |
245 | + |
246 | +void Screens::onScreenAdded(QScreen *screen) |
247 | +{ |
248 | + Q_EMIT screenAdded(screen); |
249 | + Q_EMIT countChanged(); |
250 | +} |
251 | + |
252 | +void Screens::onScreenRemoved(QScreen *screen) |
253 | +{ |
254 | + Q_EMIT screenRemoved(screen); |
255 | + Q_EMIT countChanged(); |
256 | +} |
257 | + |
258 | + |
259 | +} // namespace qtmir |
260 | |
261 | === added file 'src/modules/Unity/Screens/screens.h' |
262 | --- src/modules/Unity/Screens/screens.h 1970-01-01 00:00:00 +0000 |
263 | +++ src/modules/Unity/Screens/screens.h 2015-08-07 12:06:18 +0000 |
264 | @@ -0,0 +1,54 @@ |
265 | +/* |
266 | + * Copyright (C) 2015 Canonical, Ltd. |
267 | + * |
268 | + * This program is free software: you can redistribute it and/or modify it under |
269 | + * the terms of the GNU Lesser General Public License version 3, as published by |
270 | + * the Free Software Foundation. |
271 | + * |
272 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
273 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
274 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
275 | + * Lesser General Public License for more details. |
276 | + * |
277 | + * You should have received a copy of the GNU Lesser General Public License |
278 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
279 | + */ |
280 | + |
281 | +#ifndef SCREENS_H |
282 | +#define SCREENS_H |
283 | + |
284 | +#include <QAbstractListModel> |
285 | + |
286 | +class QScreen; |
287 | + |
288 | +namespace qtmir { |
289 | + |
290 | +class Screens : public QAbstractListModel |
291 | +{ |
292 | + Q_OBJECT |
293 | + |
294 | + Q_PROPERTY(int count READ count NOTIFY countChanged) |
295 | + |
296 | +public: |
297 | + explicit Screens(QObject *parent = 0); |
298 | + virtual ~Screens() noexcept = default; |
299 | + |
300 | + /* QAbstractItemModel */ |
301 | + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; |
302 | + int rowCount(const QModelIndex &parent = QModelIndex()) const; |
303 | + |
304 | + int count() const; |
305 | + |
306 | +Q_SIGNALS: |
307 | + void countChanged(); |
308 | + void screenAdded(QScreen *screen); |
309 | + void screenRemoved(QScreen *screen); |
310 | + |
311 | +private Q_SLOTS: |
312 | + void onScreenAdded(QScreen *screen); |
313 | + void onScreenRemoved(QScreen *screen); |
314 | +}; |
315 | + |
316 | +} // namespace qtmir |
317 | + |
318 | +#endif // SCREENS_H |
319 | |
320 | === modified file 'src/platforms/mirserver/CMakeLists.txt' |
321 | --- src/platforms/mirserver/CMakeLists.txt 2015-05-19 15:10:48 +0000 |
322 | +++ src/platforms/mirserver/CMakeLists.txt 2015-08-07 12:06:18 +0000 |
323 | @@ -51,16 +51,18 @@ |
324 | promptsessionlistener.cpp |
325 | mirserver.cpp |
326 | mirserverstatuslistener.cpp |
327 | - display.cpp |
328 | screen.cpp |
329 | - displaywindow.cpp |
330 | + screencontroller.cpp |
331 | + screenwindow.cpp |
332 | mirserverintegration.cpp |
333 | miropenglcontext.cpp |
334 | nativeinterface.cpp |
335 | + offscreensurface.cpp |
336 | qtcompositor.cpp |
337 | services.cpp |
338 | ubuntutheme.cpp |
339 | clipboard.cpp |
340 | + tileddisplayconfigurationpolicy.cpp |
341 | tracepoints.c |
342 | ) |
343 | |
344 | |
345 | === removed file 'src/platforms/mirserver/display.cpp' |
346 | --- src/platforms/mirserver/display.cpp 2015-05-27 12:12:45 +0000 |
347 | +++ src/platforms/mirserver/display.cpp 1970-01-01 00:00:00 +0000 |
348 | @@ -1,46 +0,0 @@ |
349 | -/* |
350 | - * Copyright (C) 2013 Canonical, Ltd. |
351 | - * |
352 | - * This program is free software: you can redistribute it and/or modify it under |
353 | - * the terms of the GNU Lesser General Public License version 3, as published by |
354 | - * the Free Software Foundation. |
355 | - * |
356 | - * This program is distributed in the hope that it will be useful, but WITHOUT |
357 | - * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
358 | - * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
359 | - * Lesser General Public License for more details. |
360 | - * |
361 | - * You should have received a copy of the GNU Lesser General Public License |
362 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
363 | - * |
364 | - * Author: Gerry Boland <gerry.boland@canonical.com> |
365 | - */ |
366 | - |
367 | -#include "display.h" |
368 | - |
369 | -#include "screen.h" |
370 | -#include "mirserver.h" |
371 | - |
372 | -#include <mir/graphics/display.h> |
373 | -#include <mir/graphics/display_configuration.h> |
374 | - |
375 | -namespace mg = mir::graphics; |
376 | - |
377 | -// TODO: Listen for display changes and update the list accordingly |
378 | - |
379 | -Display::Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig) |
380 | -{ |
381 | - displayConfig->for_each_output([this](mg::DisplayConfigurationOutput const& output) { |
382 | - if (output.used) { |
383 | - auto screen = new Screen(output); |
384 | - m_screens.push_back(screen); |
385 | - } |
386 | - }); |
387 | -} |
388 | - |
389 | -Display::~Display() |
390 | -{ |
391 | - for (auto screen : m_screens) |
392 | - delete screen; |
393 | - m_screens.clear(); |
394 | -} |
395 | |
396 | === removed file 'src/platforms/mirserver/display.h' |
397 | --- src/platforms/mirserver/display.h 2015-05-27 12:12:45 +0000 |
398 | +++ src/platforms/mirserver/display.h 1970-01-01 00:00:00 +0000 |
399 | @@ -1,39 +0,0 @@ |
400 | -/* |
401 | - * Copyright (C) 2013 Canonical, Ltd. |
402 | - * |
403 | - * This program is free software: you can redistribute it and/or modify it under |
404 | - * the terms of the GNU Lesser General Public License version 3, as published by |
405 | - * the Free Software Foundation. |
406 | - * |
407 | - * This program is distributed in the hope that it will be useful, but WITHOUT |
408 | - * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
409 | - * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
410 | - * Lesser General Public License for more details. |
411 | - * |
412 | - * You should have received a copy of the GNU Lesser General Public License |
413 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
414 | - * |
415 | - * Author: Gerry Boland <gerry.boland@canonical.com> |
416 | - */ |
417 | - |
418 | -#ifndef DISPLAY_H |
419 | -#define DISPLAY_H |
420 | - |
421 | -#include <qpa/qplatformscreen.h> |
422 | -#include <memory> |
423 | - |
424 | -namespace mir { namespace graphics { class DisplayConfiguration; }} |
425 | - |
426 | -class Display |
427 | -{ |
428 | -public: |
429 | - Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig); |
430 | - virtual ~Display(); |
431 | - |
432 | - QList<QPlatformScreen *> screens() const { return m_screens; } |
433 | - |
434 | -private: |
435 | - QList<QPlatformScreen *> m_screens; |
436 | -}; |
437 | - |
438 | -#endif // DISPLAY_H |
439 | |
440 | === modified file 'src/platforms/mirserver/logging.h' |
441 | --- src/platforms/mirserver/logging.h 2014-10-01 18:42:26 +0000 |
442 | +++ src/platforms/mirserver/logging.h 2015-08-07 12:06:18 +0000 |
443 | @@ -25,5 +25,6 @@ |
444 | Q_DECLARE_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES) |
445 | Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_INPUT) |
446 | Q_DECLARE_LOGGING_CATEGORY(QTMIR_CLIPBOARD) |
447 | +Q_DECLARE_LOGGING_CATEGORY(QTMIR_SCREENS) |
448 | |
449 | #endif // UBUNTU_APPLICATION_PLUGIN_LOGGING_H |
450 | |
451 | === modified file 'src/platforms/mirserver/miropenglcontext.cpp' |
452 | --- src/platforms/mirserver/miropenglcontext.cpp 2015-05-01 13:31:30 +0000 |
453 | +++ src/platforms/mirserver/miropenglcontext.cpp 2015-08-07 12:06:18 +0000 |
454 | @@ -1,5 +1,5 @@ |
455 | /* |
456 | - * Copyright (C) 2013 Canonical, Ltd. |
457 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
458 | * |
459 | * This program is free software: you can redistribute it and/or modify it under |
460 | * the terms of the GNU Lesser General Public License version 3, as published by |
461 | @@ -18,12 +18,14 @@ |
462 | |
463 | #include "miropenglcontext.h" |
464 | |
465 | -#include "displaywindow.h" |
466 | +#include "offscreensurface.h" |
467 | +#include "mirglconfig.h" |
468 | #include "mirserver.h" |
469 | -#include "mirglconfig.h" |
470 | +#include "screenwindow.h" |
471 | |
472 | #include <QDebug> |
473 | |
474 | +#include <QOpenGLFramebufferObject> |
475 | #include <QSurfaceFormat> |
476 | #include <QtPlatformSupport/private/qeglconvenience_p.h> |
477 | |
478 | @@ -110,17 +112,30 @@ |
479 | |
480 | void MirOpenGLContext::swapBuffers(QPlatformSurface *surface) |
481 | { |
482 | - // ultimately calls Mir's DisplayBuffer::post_update() |
483 | - DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface); |
484 | - displayBuffer->swapBuffers(); //blocks for vsync |
485 | + if (surface->surface()->surfaceClass() == QSurface::Offscreen) { |
486 | + // NOOP |
487 | + } else { |
488 | + // ultimately calls Mir's DisplayBuffer::post_update() |
489 | + ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface); |
490 | + screenWindow->swapBuffers(); //blocks for vsync |
491 | + } |
492 | } |
493 | |
494 | bool MirOpenGLContext::makeCurrent(QPlatformSurface *surface) |
495 | { |
496 | + if (surface->surface()->surfaceClass() == QSurface::Offscreen) { |
497 | + auto offscreen = static_cast<OffscreenSurface *>(surface); |
498 | + if (!offscreen->buffer()) { |
499 | + auto buffer = new QOpenGLFramebufferObject(surface->surface()->size()); |
500 | + offscreen->setBuffer(buffer); |
501 | + } |
502 | + return offscreen->buffer()->bind(); |
503 | + } |
504 | + |
505 | // ultimately calls Mir's DisplayBuffer::make_current() |
506 | - DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface); |
507 | - if (displayBuffer) { |
508 | - displayBuffer->makeCurrent(); |
509 | + ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface); |
510 | + if (screenWindow) { |
511 | + screenWindow->makeCurrent(); |
512 | |
513 | #if GL_DEBUG |
514 | if (!m_logger->isLogging() && m_logger->initialize()) { |
515 | |
516 | === modified file 'src/platforms/mirserver/mirserver.cpp' |
517 | --- src/platforms/mirserver/mirserver.cpp 2015-02-09 16:28:40 +0000 |
518 | +++ src/platforms/mirserver/mirserver.cpp 2015-08-07 12:06:18 +0000 |
519 | @@ -23,15 +23,22 @@ |
520 | #include "mirglconfig.h" |
521 | #include "mirserverstatuslistener.h" |
522 | #include "promptsessionlistener.h" |
523 | +#include "screencontroller.h" |
524 | #include "sessionlistener.h" |
525 | #include "sessionauthorizer.h" |
526 | #include "qtcompositor.h" |
527 | #include "qteventfeeder.h" |
528 | +#include "tileddisplayconfigurationpolicy.h" |
529 | #include "logging.h" |
530 | |
531 | +// std |
532 | +#include <memory> |
533 | + |
534 | // egl |
535 | +#define MESA_EGL_NO_X11_HEADERS |
536 | #include <EGL/egl.h> |
537 | |
538 | +namespace mg = mir::graphics; |
539 | namespace mo = mir::options; |
540 | namespace msh = mir::shell; |
541 | namespace ms = mir::scene; |
542 | @@ -45,8 +52,10 @@ |
543 | |
544 | Q_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES, "qtmir.mir") |
545 | |
546 | -MirServer::MirServer(int argc, char const* argv[], QObject* parent) |
547 | +MirServer::MirServer(int argc, char const* argv[], |
548 | + const QSharedPointer<ScreenController> &screenController, QObject* parent) |
549 | : QObject(parent) |
550 | + , m_screenController(screenController) |
551 | { |
552 | set_command_line_handler(&ignore_unparsed_arguments); |
553 | set_command_line(argc, argv); |
554 | @@ -71,9 +80,9 @@ |
555 | return std::make_shared<QtCompositor>(); |
556 | }); |
557 | |
558 | - override_the_input_dispatcher([] |
559 | + override_the_input_dispatcher([&screenController] |
560 | { |
561 | - return std::make_shared<QtEventFeeder>(); |
562 | + return std::make_shared<QtEventFeeder>(screenController); |
563 | }); |
564 | |
565 | override_the_gl_config([] |
566 | @@ -99,17 +108,36 @@ |
567 | return shell; |
568 | }); |
569 | |
570 | - set_terminator([&](int) |
571 | + wrap_display_configuration_policy( |
572 | + [](const std::shared_ptr<mg::DisplayConfigurationPolicy> &wrapped) |
573 | + -> std::shared_ptr<mg::DisplayConfigurationPolicy> |
574 | + { |
575 | + return std::make_shared<TiledDisplayConfigurationPolicy>(wrapped); |
576 | + }); |
577 | + |
578 | + set_terminator([](int) |
579 | { |
580 | qDebug() << "Signal caught by Mir, stopping Mir server.."; |
581 | QCoreApplication::quit(); |
582 | }); |
583 | |
584 | + add_init_callback([this, &screenController] { |
585 | + screenController->init(the_display(), the_compositor(), the_main_loop()); |
586 | + }); |
587 | + |
588 | apply_settings(); |
589 | |
590 | qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created"; |
591 | } |
592 | |
593 | +// Override default implementation to ensure we terminate the ScreenController first. |
594 | +// Code path followed when Qt tries to shutdown the server. |
595 | +void MirServer::stop() |
596 | +{ |
597 | + m_screenController->terminate(); |
598 | + mir::Server::stop(); |
599 | +} |
600 | + |
601 | |
602 | /************************************ Shell side ************************************/ |
603 | |
604 | |
605 | === modified file 'src/platforms/mirserver/mirserver.h' |
606 | --- src/platforms/mirserver/mirserver.h 2015-03-25 14:49:58 +0000 |
607 | +++ src/platforms/mirserver/mirserver.h 2015-08-07 12:06:18 +0000 |
608 | @@ -18,6 +18,7 @@ |
609 | #define MIRSERVER_H |
610 | |
611 | #include <QObject> |
612 | +#include <QSharedPointer> |
613 | #include <mir/server.h> |
614 | |
615 | class QtEventFeeder; |
616 | @@ -25,6 +26,7 @@ |
617 | class SessionAuthorizer; |
618 | class MirShell; |
619 | class PromptSessionListener; |
620 | +class ScreenController; |
621 | |
622 | // We use virtual inheritance of mir::Server to facilitate derived classes (e.g. testing) |
623 | // calling initialization functions before MirServer is constructed. |
624 | @@ -38,12 +40,12 @@ |
625 | Q_PROPERTY(PromptSessionListener* promptSessionListener READ promptSessionListener CONSTANT) |
626 | |
627 | public: |
628 | - MirServer(int argc, char const* argv[], QObject* parent = 0); |
629 | + MirServer(int argc, char const* argv[], const QSharedPointer<ScreenController> &, QObject* parent = 0); |
630 | ~MirServer() = default; |
631 | |
632 | /* mir specific */ |
633 | using mir::Server::run; |
634 | - using mir::Server::stop; |
635 | + using mir::Server::the_compositor; |
636 | using mir::Server::the_display; |
637 | using mir::Server::the_gl_config; |
638 | using mir::Server::the_main_loop; |
639 | @@ -52,6 +54,8 @@ |
640 | using mir::Server::the_session_authorizer; |
641 | using mir::Server::the_session_listener; |
642 | |
643 | + void stop(); |
644 | + |
645 | /* qt specific */ |
646 | // getters |
647 | SessionAuthorizer *sessionAuthorizer(); |
648 | @@ -60,8 +64,8 @@ |
649 | MirShell *shell(); |
650 | |
651 | private: |
652 | - std::shared_ptr<QtEventFeeder> m_qtEventFeeder; |
653 | std::weak_ptr<MirShell> m_shell; |
654 | + const QSharedPointer<ScreenController> m_screenController; |
655 | }; |
656 | |
657 | #endif // MIRSERVER_H |
658 | |
659 | === modified file 'src/platforms/mirserver/mirserverintegration.cpp' |
660 | --- src/platforms/mirserver/mirserverintegration.cpp 2015-05-27 12:12:45 +0000 |
661 | +++ src/platforms/mirserver/mirserverintegration.cpp 2015-08-07 12:06:18 +0000 |
662 | @@ -29,7 +29,8 @@ |
663 | #include <qpa/qplatforminputcontextfactory_p.h> |
664 | #include <qpa/qwindowsysteminterface.h> |
665 | |
666 | -#include <QCoreApplication> |
667 | +#include <QGuiApplication> |
668 | +#include <QStringList> |
669 | #include <QOpenGLContext> |
670 | |
671 | #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) |
672 | @@ -44,13 +45,16 @@ |
673 | |
674 | // local |
675 | #include "clipboard.h" |
676 | -#include "display.h" |
677 | -#include "displaywindow.h" |
678 | #include "miropenglcontext.h" |
679 | #include "nativeinterface.h" |
680 | +#include "offscreensurface.h" |
681 | #include "qmirserver.h" |
682 | +#include "screen.h" |
683 | +#include "screencontroller.h" |
684 | +#include "screenwindow.h" |
685 | #include "services.h" |
686 | #include "ubuntutheme.h" |
687 | +#include "logging.h" |
688 | |
689 | namespace mg = mir::graphics; |
690 | using qtmir::Clipboard; |
691 | @@ -63,7 +67,6 @@ |
692 | , m_eventDispatcher(createUnixEventDispatcher()) |
693 | #endif |
694 | , m_mirServer(new QMirServer(QCoreApplication::arguments())) |
695 | - , m_display(nullptr) |
696 | , m_nativeInterface(nullptr) |
697 | , m_clipboard(new Clipboard) |
698 | { |
699 | @@ -93,7 +96,6 @@ |
700 | MirServerIntegration::~MirServerIntegration() |
701 | { |
702 | delete m_nativeInterface; |
703 | - delete m_display; |
704 | } |
705 | |
706 | bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const |
707 | @@ -104,7 +106,7 @@ |
708 | case ThreadedOpenGL: return true; |
709 | case SharedGraphicsCache: return true; |
710 | case BufferQueueingOpenGL: return true; |
711 | - case MultipleWindows: return false; // multi-monitor support |
712 | + case MultipleWindows: return true; // multi-monitor support |
713 | #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) |
714 | case WindowManagement: return false; // platform has no WM, as this implements the WM! |
715 | case NonFullScreenWindows: return false; |
716 | @@ -117,44 +119,35 @@ |
717 | { |
718 | QWindowSystemInterface::flushWindowSystemEvents(); |
719 | |
720 | - DisplayWindow* displayWindow = nullptr; |
721 | - |
722 | - auto const mirServer = m_mirServer->mirServer().lock(); |
723 | - mg::DisplayBuffer* first_buffer{nullptr}; |
724 | - mg::DisplaySyncGroup* first_group{nullptr}; |
725 | - if (mirServer) { |
726 | - mirServer->the_display()->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) { |
727 | - if (!first_group) { |
728 | - first_group = &group; |
729 | - } |
730 | - group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) { |
731 | - if (!first_buffer) { |
732 | - first_buffer = &buffer; |
733 | - } |
734 | - }); |
735 | - }); |
736 | - } |
737 | - |
738 | - // FIXME(gerry) this will go very bad for >1 display buffer |
739 | - if (first_group && first_buffer) |
740 | - displayWindow = new DisplayWindow(window, first_group, first_buffer); |
741 | - |
742 | - if (!displayWindow) |
743 | - return nullptr; |
744 | - |
745 | - //displayWindow->requestActivateWindow(); |
746 | - return displayWindow; |
747 | + // FIXME: QWindow can be created specifying a destination QScreen. For now we |
748 | + // will ignore it and just associate any unused Screen, if available. |
749 | + auto screens = m_mirServer->screenController().lock(); |
750 | + if (!screens) { |
751 | + qCritical("Screens are not initialized, unable to create a new QWindow/ScreenWindow"); |
752 | + return nullptr; |
753 | + } |
754 | + Screen *screen = screens->getUnusedScreen(); |
755 | + if (!screen) { |
756 | + qCritical("No available Screens to create a new QWindow/ScreenWindow for"); |
757 | + return nullptr; |
758 | + } |
759 | + QScreen *qscreen = screen->screen(); |
760 | + window->setScreen(qscreen); |
761 | + |
762 | + auto platformWindow = new ScreenWindow(window); |
763 | + |
764 | + qCDebug(QTMIR_SCREENS) << "New" << window << "with geom" << window->geometry() |
765 | + << "is backed by a" << screen << "with geometry" << screen->geometry(); |
766 | + return platformWindow; |
767 | } |
768 | |
769 | -QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow *window) const |
770 | +QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow */*window*/) const |
771 | { |
772 | - qDebug() << "createPlatformBackingStore" << window; |
773 | return nullptr; |
774 | } |
775 | |
776 | QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const |
777 | { |
778 | - qDebug() << "createPlatformOpenGLContext" << context; |
779 | return new MirOpenGLContext(m_mirServer->mirServer(), context->format()); |
780 | } |
781 | |
782 | @@ -172,12 +165,18 @@ |
783 | exit(2); |
784 | } |
785 | |
786 | - m_display = new Display(m_mirServer->mirServer().data()->the_display()->configuration()); |
787 | + auto screens = m_mirServer->screenController().lock(); |
788 | + if (!screens) { |
789 | + qFatal("ScreenController not initialized"); |
790 | + } |
791 | + QObject::connect(screens.data(), &ScreenController::screenAdded, |
792 | + [this](Screen *screen) { this->screenAdded(screen); }); |
793 | + Q_FOREACH(auto screen, screens->screens()) { |
794 | + screenAdded(screen); |
795 | + } |
796 | + |
797 | m_nativeInterface = new NativeInterface(m_mirServer->mirServer()); |
798 | |
799 | - for (QPlatformScreen *screen : m_display->screens()) |
800 | - screenAdded(screen); |
801 | - |
802 | m_clipboard->setupDBusService(); |
803 | } |
804 | |
805 | @@ -216,3 +215,9 @@ |
806 | { |
807 | return m_clipboard.data(); |
808 | } |
809 | + |
810 | +QPlatformOffscreenSurface *MirServerIntegration::createPlatformOffscreenSurface( |
811 | + QOffscreenSurface *surface) const |
812 | +{ |
813 | + return new OffscreenSurface(surface); |
814 | +} |
815 | |
816 | === modified file 'src/platforms/mirserver/mirserverintegration.h' |
817 | --- src/platforms/mirserver/mirserverintegration.h 2015-05-01 13:36:32 +0000 |
818 | +++ src/platforms/mirserver/mirserverintegration.h 2015-08-07 12:06:18 +0000 |
819 | @@ -22,13 +22,9 @@ |
820 | |
821 | // qt |
822 | #include <qpa/qplatformintegration.h> |
823 | - |
824 | -// local |
825 | -#include "mirserver.h" |
826 | - |
827 | -class Display; |
828 | +#include <QScopedPointer> |
829 | + |
830 | class NativeInterface; |
831 | -class MirServer; |
832 | class QMirServer; |
833 | |
834 | namespace qtmir { |
835 | @@ -68,6 +64,8 @@ |
836 | |
837 | QPlatformNativeInterface *nativeInterface() const override; |
838 | |
839 | + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; |
840 | + |
841 | private: |
842 | QScopedPointer<QPlatformAccessibility> m_accessibility; |
843 | QScopedPointer<QPlatformFontDatabase> m_fontDb; |
844 | @@ -78,7 +76,6 @@ |
845 | |
846 | QScopedPointer<QMirServer> m_mirServer; |
847 | |
848 | - Display *m_display; |
849 | NativeInterface *m_nativeInterface; |
850 | QPlatformInputContext* m_inputContext; |
851 | QScopedPointer<qtmir::Clipboard> m_clipboard; |
852 | |
853 | === added file 'src/platforms/mirserver/offscreensurface.cpp' |
854 | --- src/platforms/mirserver/offscreensurface.cpp 1970-01-01 00:00:00 +0000 |
855 | +++ src/platforms/mirserver/offscreensurface.cpp 2015-08-07 12:06:18 +0000 |
856 | @@ -0,0 +1,61 @@ |
857 | +/* |
858 | + * Copyright (C) 2015 Canonical, Ltd. |
859 | + * |
860 | + * This program is free software: you can redistribute it and/or modify it under |
861 | + * the terms of the GNU Lesser General Public License version 3, as published by |
862 | + * the Free Software Foundation. |
863 | + * |
864 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
865 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
866 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
867 | + * Lesser General Public License for more details. |
868 | + * |
869 | + * You should have received a copy of the GNU Lesser General Public License |
870 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
871 | + */ |
872 | + |
873 | +#include "offscreensurface.h" |
874 | + |
875 | +#include "mirserver.h" |
876 | + |
877 | +// Mir |
878 | +#include <mir/graphics/display.h> |
879 | +#include <mir/graphics/gl_context.h> |
880 | + |
881 | +//Qt |
882 | +#include <QOffscreenSurface> |
883 | +#include <QOpenGLFramebufferObject> |
884 | +#include <QSurfaceFormat> |
885 | +#include <QtPlatformSupport/private/qeglconvenience_p.h> |
886 | + |
887 | +namespace mg = mir::graphics; |
888 | + |
889 | +OffscreenSurface::OffscreenSurface(QOffscreenSurface *offscreenSurface) |
890 | + : QPlatformOffscreenSurface(offscreenSurface) |
891 | + , m_buffer(nullptr) |
892 | + , m_format(offscreenSurface->requestedFormat()) |
893 | +{ |
894 | +} |
895 | + |
896 | +QSurfaceFormat OffscreenSurface::format() const |
897 | +{ |
898 | + return m_format; |
899 | +} |
900 | + |
901 | +bool OffscreenSurface::isValid() const |
902 | +{ |
903 | + if (m_buffer) { |
904 | + return m_buffer->isValid(); |
905 | + } |
906 | + return false; |
907 | +} |
908 | + |
909 | +QOpenGLFramebufferObject* OffscreenSurface::buffer() const |
910 | +{ |
911 | + return m_buffer; |
912 | +} |
913 | + |
914 | +void OffscreenSurface::setBuffer(QOpenGLFramebufferObject *buffer) |
915 | +{ |
916 | + m_buffer = buffer; |
917 | +} |
918 | |
919 | === added file 'src/platforms/mirserver/offscreensurface.h' |
920 | --- src/platforms/mirserver/offscreensurface.h 1970-01-01 00:00:00 +0000 |
921 | +++ src/platforms/mirserver/offscreensurface.h 2015-08-07 12:06:18 +0000 |
922 | @@ -0,0 +1,43 @@ |
923 | +/* |
924 | + * Copyright (C) 2015 Canonical, Ltd. |
925 | + * |
926 | + * This program is free software: you can redistribute it and/or modify it under |
927 | + * the terms of the GNU Lesser General Public License version 3, as published by |
928 | + * the Free Software Foundation. |
929 | + * |
930 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
931 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
932 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
933 | + * Lesser General Public License for more details. |
934 | + * |
935 | + * You should have received a copy of the GNU Lesser General Public License |
936 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
937 | + */ |
938 | + |
939 | +#ifndef OFFSCREENSURFACE_H |
940 | +#define OFFSCREENSURFACE_H |
941 | + |
942 | +#include <qpa/qplatformoffscreensurface.h> |
943 | +#include <QSurfaceFormat> |
944 | +#include <QSharedPointer> |
945 | + |
946 | +class MirServer; |
947 | +class QOpenGLFramebufferObject; |
948 | + |
949 | +class OffscreenSurface : public QPlatformOffscreenSurface |
950 | +{ |
951 | +public: |
952 | + OffscreenSurface(QOffscreenSurface *offscreenSurface); |
953 | + |
954 | + QSurfaceFormat format() const override; |
955 | + bool isValid() const override; |
956 | + |
957 | + QOpenGLFramebufferObject* buffer() const; |
958 | + void setBuffer(QOpenGLFramebufferObject *buffer); |
959 | + |
960 | +private: |
961 | + QOpenGLFramebufferObject *m_buffer; |
962 | + QSurfaceFormat m_format; |
963 | +}; |
964 | + |
965 | +#endif // OFFSCREENSURFACE_H |
966 | |
967 | === modified file 'src/platforms/mirserver/qmirserver.cpp' |
968 | --- src/platforms/mirserver/qmirserver.cpp 2015-05-19 15:36:17 +0000 |
969 | +++ src/platforms/mirserver/qmirserver.cpp 2015-08-07 12:06:18 +0000 |
970 | @@ -23,7 +23,8 @@ |
971 | #include "mirserver.h" |
972 | #include "qmirserver.h" |
973 | #include "qmirserver_p.h" |
974 | - |
975 | +#include "screencontroller.h" |
976 | +#include "screen.h" |
977 | |
978 | QMirServer::QMirServer(const QStringList &arguments, QObject *parent) |
979 | : QObject(parent) |
980 | @@ -40,7 +41,9 @@ |
981 | } |
982 | argv[argc] = '\0'; |
983 | |
984 | - d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv))); |
985 | + d->screenController = QSharedPointer<ScreenController>(new ScreenController()); |
986 | + |
987 | + d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv), d->screenController)); |
988 | |
989 | d->serverThread = new MirServerThread(d->server); |
990 | |
991 | @@ -63,6 +66,7 @@ |
992 | qCritical() << "ERROR: QMirServer - Mir failed to start"; |
993 | return false; |
994 | } |
995 | + d->screenController->update(); |
996 | |
997 | Q_EMIT started(); |
998 | return true; |
999 | @@ -93,3 +97,9 @@ |
1000 | Q_D(const QMirServer); |
1001 | return d->server.toWeakRef(); |
1002 | } |
1003 | + |
1004 | +QWeakPointer<ScreenController> QMirServer::screenController() const |
1005 | +{ |
1006 | + Q_D(const QMirServer); |
1007 | + return d->screenController; |
1008 | +} |
1009 | |
1010 | === modified file 'src/platforms/mirserver/qmirserver.h' |
1011 | --- src/platforms/mirserver/qmirserver.h 2015-05-18 20:39:09 +0000 |
1012 | +++ src/platforms/mirserver/qmirserver.h 2015-08-07 12:06:18 +0000 |
1013 | @@ -23,6 +23,7 @@ |
1014 | |
1015 | class QMirServerPrivate; |
1016 | class MirServer; |
1017 | +class ScreenController; |
1018 | |
1019 | class QMirServer: public QObject |
1020 | { |
1021 | @@ -38,6 +39,8 @@ |
1022 | |
1023 | QWeakPointer<MirServer> mirServer() const; |
1024 | |
1025 | + QWeakPointer<ScreenController> screenController() const; |
1026 | + |
1027 | Q_SIGNALS: |
1028 | void started(); |
1029 | void stopped(); |
1030 | |
1031 | === modified file 'src/platforms/mirserver/qmirserver_p.h' |
1032 | --- src/platforms/mirserver/qmirserver_p.h 2015-05-18 18:30:33 +0000 |
1033 | +++ src/platforms/mirserver/qmirserver_p.h 2015-08-07 12:06:18 +0000 |
1034 | @@ -27,6 +27,7 @@ |
1035 | |
1036 | // local |
1037 | #include "mirserver.h" |
1038 | +#include "screencontroller.h" |
1039 | |
1040 | class QMirServer; |
1041 | class MirServerThread; |
1042 | @@ -34,6 +35,7 @@ |
1043 | struct QMirServerPrivate |
1044 | { |
1045 | QSharedPointer<MirServer> server; |
1046 | + QSharedPointer<ScreenController> screenController; |
1047 | MirServerThread *serverThread; |
1048 | }; |
1049 | |
1050 | |
1051 | === modified file 'src/platforms/mirserver/qtcompositor.cpp' |
1052 | --- src/platforms/mirserver/qtcompositor.cpp 2014-07-16 22:10:40 +0000 |
1053 | +++ src/platforms/mirserver/qtcompositor.cpp 2015-08-07 12:06:18 +0000 |
1054 | @@ -1,5 +1,5 @@ |
1055 | /* |
1056 | - * Copyright (C) 2013,2014 Canonical, Ltd. |
1057 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
1058 | * |
1059 | * This program is free software: you can redistribute it and/or modify it under |
1060 | * the terms of the GNU Lesser General Public License version 3, as published by |
1061 | @@ -18,44 +18,19 @@ |
1062 | */ |
1063 | |
1064 | #include "qtcompositor.h" |
1065 | -#include "displaywindow.h" |
1066 | - |
1067 | -#include <QGuiApplication> |
1068 | -#include <QWindow> |
1069 | - |
1070 | -#include <QDebug> |
1071 | - |
1072 | -QtCompositor::QtCompositor() |
1073 | -{ |
1074 | - |
1075 | -} |
1076 | - |
1077 | +#include "logging.h" |
1078 | + |
1079 | +// Lives in a Mir thread |
1080 | void QtCompositor::start() |
1081 | { |
1082 | - // (Re)Start Qt's render thread by setting all its windows to exposed |
1083 | - setAllWindowsExposed(true); |
1084 | + qCDebug(QTMIR_SCREENS) << "QtCompositor::start"; |
1085 | + |
1086 | + Q_EMIT starting(); // blocks |
1087 | } |
1088 | |
1089 | void QtCompositor::stop() |
1090 | { |
1091 | - // Stop Qt's render threads by setting all its windows it obscured |
1092 | - setAllWindowsExposed(false); |
1093 | -} |
1094 | - |
1095 | -void QtCompositor::setAllWindowsExposed(const bool exposed) |
1096 | -{ |
1097 | - qDebug() << "QtCompositor::setAllWindowsExposed" << exposed; |
1098 | - QList<QWindow *> windowList = QGuiApplication::allWindows(); |
1099 | - |
1100 | - // manipulate Qt object's indirectly via posted events as we're not in Qt's GUI thread |
1101 | - auto iterator = windowList.constBegin(); |
1102 | - while (iterator != windowList.constEnd()) { |
1103 | - QWindow *window = *iterator; |
1104 | - DisplayWindow *displayWindow = static_cast<DisplayWindow*>(window->handle()); |
1105 | - if (displayWindow) { |
1106 | - QCoreApplication::postEvent(displayWindow, |
1107 | - new QEvent( (exposed) ? QEvent::Show : QEvent::Hide)); |
1108 | - } |
1109 | - iterator++; |
1110 | - } |
1111 | + qCDebug(QTMIR_SCREENS) << "QtCompositor::stop"; |
1112 | + |
1113 | + Q_EMIT stopping(); // blocks |
1114 | } |
1115 | |
1116 | === modified file 'src/platforms/mirserver/qtcompositor.h' |
1117 | --- src/platforms/mirserver/qtcompositor.h 2014-07-16 22:10:40 +0000 |
1118 | +++ src/platforms/mirserver/qtcompositor.h 2015-08-07 12:06:18 +0000 |
1119 | @@ -1,5 +1,5 @@ |
1120 | /* |
1121 | - * Copyright (C) 2013 Canonical, Ltd. |
1122 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
1123 | * |
1124 | * This program is free software: you can redistribute it and/or modify it under |
1125 | * the terms of the GNU Lesser General Public License version 3, as published by |
1126 | @@ -19,18 +19,26 @@ |
1127 | #ifndef QTCOMPOSITOR_H |
1128 | #define QTCOMPOSITOR_H |
1129 | |
1130 | -#include "mir/compositor/compositor.h" |
1131 | - |
1132 | -class QtCompositor : public mir::compositor::Compositor |
1133 | +#include <mir/compositor/compositor.h> |
1134 | + |
1135 | +// Qt |
1136 | +#include <QObject> |
1137 | + |
1138 | +class QtCompositor : public QObject, public mir::compositor::Compositor |
1139 | { |
1140 | + Q_OBJECT |
1141 | public: |
1142 | - QtCompositor(); |
1143 | + QtCompositor() = default; |
1144 | + virtual ~QtCompositor() noexcept = default; |
1145 | |
1146 | void start(); |
1147 | void stop(); |
1148 | |
1149 | +Q_SIGNALS: |
1150 | + void starting(); |
1151 | + void stopping(); |
1152 | + |
1153 | private: |
1154 | - void setAllWindowsExposed(const bool exposed); |
1155 | }; |
1156 | |
1157 | #endif // QTCOMPOSITOR_H |
1158 | |
1159 | === modified file 'src/platforms/mirserver/qteventfeeder.cpp' |
1160 | --- src/platforms/mirserver/qteventfeeder.cpp 2015-06-24 23:08:44 +0000 |
1161 | +++ src/platforms/mirserver/qteventfeeder.cpp 2015-08-07 12:06:18 +0000 |
1162 | @@ -19,6 +19,7 @@ |
1163 | |
1164 | #include "qteventfeeder.h" |
1165 | #include "logging.h" |
1166 | +#include "screencontroller.h" |
1167 | |
1168 | #include <qpa/qplatforminputcontext.h> |
1169 | #include <qpa/qplatformintegration.h> |
1170 | @@ -140,20 +141,21 @@ |
1171 | |
1172 | namespace { |
1173 | |
1174 | -class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface { |
1175 | - |
1176 | - bool hasTargetWindow() override |
1177 | - { |
1178 | - if (mTopLevelWindow.isNull() && !QGuiApplication::topLevelWindows().isEmpty()) { |
1179 | - mTopLevelWindow = QGuiApplication::topLevelWindows().first(); |
1180 | - } |
1181 | - return !mTopLevelWindow.isNull(); |
1182 | - } |
1183 | - |
1184 | - QRect targetWindowGeometry() override |
1185 | - { |
1186 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
1187 | - return mTopLevelWindow->geometry(); |
1188 | +class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface |
1189 | +{ |
1190 | + void setScreenController(const QSharedPointer<ScreenController> &sc) override |
1191 | + { |
1192 | + m_screenController = sc; |
1193 | + } |
1194 | + |
1195 | + virtual QWindow* focusedWindow() override |
1196 | + { |
1197 | + return QGuiApplication::focusWindow(); |
1198 | + } |
1199 | + |
1200 | + QWindow* getWindowForTouchPoint(const QPoint &point) override //FIXME: not efficient, not updating focused window |
1201 | + { |
1202 | + return m_screenController->getWindowForPoint(point); |
1203 | } |
1204 | |
1205 | void registerTouchDevice(QTouchDevice *device) override |
1206 | @@ -161,47 +163,44 @@ |
1207 | QWindowSystemInterface::registerTouchDevice(device); |
1208 | } |
1209 | |
1210 | - void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key, |
1211 | + void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key, |
1212 | Qt::KeyboardModifiers modifiers, |
1213 | quint32 nativeScanCode, quint32 nativeVirtualKey, |
1214 | quint32 nativeModifiers, |
1215 | const QString& text, bool autorep, ushort count) override |
1216 | { |
1217 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
1218 | - QWindowSystemInterface::handleExtendedKeyEvent(mTopLevelWindow.data(), timestamp, type, key, modifiers, |
1219 | + QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, type, key, modifiers, |
1220 | nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); |
1221 | } |
1222 | |
1223 | - void handleTouchEvent(ulong timestamp, QTouchDevice *device, |
1224 | + void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device, |
1225 | const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override |
1226 | { |
1227 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
1228 | - QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods); |
1229 | - } |
1230 | + QWindowSystemInterface::handleTouchEvent(window, timestamp, device, points, mods); |
1231 | + } |
1232 | |
1233 | - void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) override |
1234 | + void handleMouseEvent(QWindow *window, ulong timestamp, QPointF point, Qt::MouseButton buttons, |
1235 | + Qt::KeyboardModifiers modifiers) override |
1236 | { |
1237 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
1238 | - QWindowSystemInterface::handleMouseEvent(mTopLevelWindow.data(), timestamp, point, point, // local and global point are the same |
1239 | + QWindowSystemInterface::handleMouseEvent(window, timestamp, point, point, // local and global point are the same |
1240 | buttons, modifiers); |
1241 | } |
1242 | |
1243 | - |
1244 | private: |
1245 | - QPointer<QWindow> mTopLevelWindow; |
1246 | + QSharedPointer<ScreenController> m_screenController; |
1247 | }; |
1248 | |
1249 | } // anonymous namespace |
1250 | |
1251 | - |
1252 | -QtEventFeeder::QtEventFeeder(QtEventFeeder::QtWindowSystemInterface *windowSystem) |
1253 | -{ |
1254 | - if (windowSystem) { |
1255 | - mQtWindowSystem = windowSystem; |
1256 | - } else { |
1257 | - mQtWindowSystem = new QtWindowSystem; |
1258 | - } |
1259 | - |
1260 | +QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController) |
1261 | + : QtEventFeeder(screenController, new QtWindowSystem) |
1262 | +{ |
1263 | +} |
1264 | + |
1265 | +QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController, |
1266 | + QtEventFeeder::QtWindowSystemInterface *windowSystem) |
1267 | + : mQtWindowSystem(windowSystem) |
1268 | +{ |
1269 | // Initialize touch device. Hardcoded just like in qtubuntu |
1270 | // TODO: Create them from info gathered from Mir and store things like device id and source |
1271 | // in a QTouchDevice-derived class created by us. So that we can properly assemble back |
1272 | @@ -211,6 +210,7 @@ |
1273 | mTouchDevice->setCapabilities( |
1274 | QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | |
1275 | QTouchDevice::NormalizedPosition); |
1276 | + mQtWindowSystem->setScreenController(screenController); |
1277 | mQtWindowSystem->registerTouchDevice(mTouchDevice); |
1278 | } |
1279 | |
1280 | @@ -224,6 +224,7 @@ |
1281 | auto type = mir_event_get_type(&event); |
1282 | if (type != mir_event_type_input) |
1283 | return false; |
1284 | + |
1285 | auto iev = mir_event_get_input_event(&event); |
1286 | |
1287 | switch (mir_input_event_get_type(iev)) { |
1288 | @@ -281,27 +282,24 @@ |
1289 | |
1290 | void QtEventFeeder::dispatchPointer(MirInputEvent const* ev) |
1291 | { |
1292 | - if (!mQtWindowSystem->hasTargetWindow()) |
1293 | - return; |
1294 | - |
1295 | auto timestamp = mir_input_event_get_event_time(ev) / 1000000; |
1296 | |
1297 | auto pev = mir_input_event_get_pointer_event(ev); |
1298 | auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev)); |
1299 | auto buttons = getQtMouseButtonsfromMirPointerEvent(pev); |
1300 | |
1301 | - auto local_point = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), |
1302 | + auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), |
1303 | mir_pointer_event_axis_value(pev, mir_pointer_axis_y)); |
1304 | |
1305 | - mQtWindowSystem->handleMouseEvent(timestamp, local_point, |
1306 | + auto window = mQtWindowSystem->getWindowForTouchPoint(localPoint.toPoint()); |
1307 | + localPoint -= window->geometry().topLeft(); // make position relative to window |
1308 | + |
1309 | + mQtWindowSystem->handleMouseEvent(window, timestamp, localPoint, |
1310 | buttons, modifiers); |
1311 | } |
1312 | |
1313 | void QtEventFeeder::dispatchKey(MirInputEvent const* event) |
1314 | { |
1315 | - if (!mQtWindowSystem->hasTargetWindow()) |
1316 | - return; |
1317 | - |
1318 | ulong timestamp = mir_input_event_get_event_time(event) / 1000000; |
1319 | |
1320 | auto kev = mir_input_event_get_keyboard_event(event); |
1321 | @@ -348,7 +346,8 @@ |
1322 | } |
1323 | } |
1324 | |
1325 | - mQtWindowSystem->handleExtendedKeyEvent(timestamp, keyType, keyCode, modifiers, |
1326 | + mQtWindowSystem->handleExtendedKeyEvent(mQtWindowSystem->focusedWindow(), |
1327 | + timestamp, keyType, keyCode, modifiers, |
1328 | mir_keyboard_event_scan_code(kev), |
1329 | mir_keyboard_event_key_code(kev), |
1330 | mir_keyboard_event_modifiers(kev), text, is_auto_rep); |
1331 | @@ -356,59 +355,69 @@ |
1332 | |
1333 | void QtEventFeeder::dispatchTouch(MirInputEvent const* event) |
1334 | { |
1335 | - if (!mQtWindowSystem->hasTargetWindow()) |
1336 | - return; |
1337 | - |
1338 | auto tev = mir_input_event_get_touch_event(event); |
1339 | qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev)); |
1340 | |
1341 | // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That |
1342 | // needs to be fixed as soon as the compat input lib adds query support. |
1343 | const float kMaxPressure = 1.28; |
1344 | - const QRect kWindowGeometry = mQtWindowSystem->targetWindowGeometry(); |
1345 | + const int kPointerCount = mir_touch_event_point_count(tev); |
1346 | QList<QWindowSystemInterface::TouchPoint> touchPoints; |
1347 | - |
1348 | - // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left |
1349 | - // as Qt::TouchPointMoved |
1350 | - const int kPointerCount = mir_touch_event_point_count(tev); |
1351 | - for (int i = 0; i < kPointerCount; ++i) { |
1352 | - QWindowSystemInterface::TouchPoint touchPoint; |
1353 | - |
1354 | - const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x); |
1355 | - const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y); |
1356 | - const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major); |
1357 | - const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor); |
1358 | - const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure); |
1359 | - touchPoint.id = mir_touch_event_id(tev, i); |
1360 | - |
1361 | - touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height()); |
1362 | - touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH); |
1363 | - touchPoint.pressure = kP / kMaxPressure; |
1364 | - switch (mir_touch_event_action(tev, i)) |
1365 | - { |
1366 | - case mir_touch_action_up: |
1367 | - touchPoint.state = Qt::TouchPointReleased; |
1368 | - break; |
1369 | - case mir_touch_action_down: |
1370 | - touchPoint.state = Qt::TouchPointPressed; |
1371 | - break; |
1372 | - case mir_touch_action_change: |
1373 | - touchPoint.state = Qt::TouchPointMoved; |
1374 | - break; |
1375 | - default: |
1376 | - break; |
1377 | - } |
1378 | - |
1379 | - touchPoints.append(touchPoint); |
1380 | + QWindow *window = nullptr; |
1381 | + |
1382 | + if (kPointerCount > 0) { |
1383 | + window = mQtWindowSystem->getWindowForTouchPoint( |
1384 | + QPoint(mir_touch_event_axis_value(tev, 0, mir_touch_axis_x), |
1385 | + mir_touch_event_axis_value(tev, 0, mir_touch_axis_y))); |
1386 | + |
1387 | + if (!window) { |
1388 | + qCDebug(QTMIR_MIR_INPUT) << "REJECTING INPUT EVENT, no matching window"; |
1389 | + return; |
1390 | + } |
1391 | + |
1392 | + const QRect kWindowGeometry = window->geometry(); |
1393 | + |
1394 | + // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left |
1395 | + // as Qt::TouchPointMoved |
1396 | + for (int i = 0; i < kPointerCount; ++i) { |
1397 | + QWindowSystemInterface::TouchPoint touchPoint; |
1398 | + |
1399 | + const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x); |
1400 | + const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y); |
1401 | + const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major); |
1402 | + const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor); |
1403 | + const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure); |
1404 | + touchPoint.id = mir_touch_event_id(tev, i); |
1405 | + |
1406 | + touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height()); |
1407 | + touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH); |
1408 | + touchPoint.pressure = kP / kMaxPressure; |
1409 | + switch (mir_touch_event_action(tev, i)) |
1410 | + { |
1411 | + case mir_touch_action_up: |
1412 | + touchPoint.state = Qt::TouchPointReleased; |
1413 | + break; |
1414 | + case mir_touch_action_down: |
1415 | + touchPoint.state = Qt::TouchPointPressed; |
1416 | + break; |
1417 | + case mir_touch_action_change: |
1418 | + touchPoint.state = Qt::TouchPointMoved; |
1419 | + break; |
1420 | + default: |
1421 | + break; |
1422 | + } |
1423 | + |
1424 | + touchPoints.append(touchPoint); |
1425 | + } |
1426 | } |
1427 | |
1428 | // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding |
1429 | // any insanity. |
1430 | - validateTouches(mir_input_event_get_event_time(event) / 1000000, touchPoints); |
1431 | + validateTouches(window, mir_input_event_get_event_time(event) / 1000000, touchPoints); |
1432 | |
1433 | // Touch event propagation. |
1434 | qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints)); |
1435 | - mQtWindowSystem->handleTouchEvent( |
1436 | + mQtWindowSystem->handleTouchEvent(window, |
1437 | //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable |
1438 | mir_input_event_get_event_time(event) / 1000000, |
1439 | mTouchDevice, |
1440 | @@ -425,7 +434,7 @@ |
1441 | // not used |
1442 | } |
1443 | |
1444 | -void QtEventFeeder::validateTouches(ulong timestamp, |
1445 | +void QtEventFeeder::validateTouches(QWindow *window, ulong timestamp, |
1446 | QList<QWindowSystemInterface::TouchPoint> &touchPoints) |
1447 | { |
1448 | QSet<int> updatedTouches; |
1449 | @@ -449,7 +458,7 @@ |
1450 | if (!updatedTouches.contains(it.key())) { |
1451 | qCWarning(QTMIR_MIR_INPUT) |
1452 | << "There's a touch (id =" << it.key() << ") missing. Releasing it."; |
1453 | - sendActiveTouchRelease(timestamp, it.key()); |
1454 | + sendActiveTouchRelease(window, timestamp, it.key()); |
1455 | it = mActiveTouches.erase(it); |
1456 | } else { |
1457 | ++it; |
1458 | @@ -467,7 +476,7 @@ |
1459 | } |
1460 | } |
1461 | |
1462 | -void QtEventFeeder::sendActiveTouchRelease(ulong timestamp, int id) |
1463 | +void QtEventFeeder::sendActiveTouchRelease(QWindow *window, ulong timestamp, int id) |
1464 | { |
1465 | QList<QWindowSystemInterface::TouchPoint> touchPoints = mActiveTouches.values(); |
1466 | |
1467 | @@ -481,7 +490,7 @@ |
1468 | } |
1469 | |
1470 | qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints)); |
1471 | - mQtWindowSystem->handleTouchEvent(timestamp, mTouchDevice, touchPoints); |
1472 | + mQtWindowSystem->handleTouchEvent(window, timestamp, mTouchDevice, touchPoints); |
1473 | } |
1474 | |
1475 | bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint) |
1476 | |
1477 | === modified file 'src/platforms/mirserver/qteventfeeder.h' |
1478 | --- src/platforms/mirserver/qteventfeeder.h 2015-06-24 23:08:44 +0000 |
1479 | +++ src/platforms/mirserver/qteventfeeder.h 2015-08-07 12:06:18 +0000 |
1480 | @@ -25,6 +25,7 @@ |
1481 | #include <qpa/qwindowsysteminterface.h> |
1482 | |
1483 | class QTouchDevice; |
1484 | +class ScreenController; |
1485 | |
1486 | /* |
1487 | Fills Qt's event loop with input events from Mir |
1488 | @@ -35,26 +36,29 @@ |
1489 | // Interface between QtEventFeeder and the actual QWindowSystemInterface functions |
1490 | // and other related Qt methods and objects to enable replacing them with mocks in |
1491 | // pure unit tests. |
1492 | - // TODO - Make it work with multimonitor scenarios |
1493 | class QtWindowSystemInterface { |
1494 | public: |
1495 | virtual ~QtWindowSystemInterface() {} |
1496 | - virtual bool hasTargetWindow() = 0; |
1497 | - virtual QRect targetWindowGeometry() = 0; |
1498 | + virtual void setScreenController(const QSharedPointer<ScreenController> &sc) = 0; |
1499 | + virtual QWindow* getWindowForTouchPoint(const QPoint &point) = 0; |
1500 | + virtual QWindow* focusedWindow() = 0; |
1501 | virtual void registerTouchDevice(QTouchDevice *device) = 0; |
1502 | - virtual void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key, |
1503 | + virtual void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key, |
1504 | Qt::KeyboardModifiers modifiers, |
1505 | quint32 nativeScanCode, quint32 nativeVirtualKey, |
1506 | quint32 nativeModifiers, |
1507 | const QString& text = QString(), bool autorep = false, |
1508 | ushort count = 1) = 0; |
1509 | - virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device, |
1510 | + virtual void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device, |
1511 | const QList<struct QWindowSystemInterface::TouchPoint> &points, |
1512 | Qt::KeyboardModifiers mods = Qt::NoModifier) = 0; |
1513 | - virtual void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0; |
1514 | + virtual void handleMouseEvent(QWindow *window, ulong timestamp, QPointF point, |
1515 | + Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0; |
1516 | }; |
1517 | |
1518 | - QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr); |
1519 | + QtEventFeeder(const QSharedPointer<ScreenController> &screenController); |
1520 | + QtEventFeeder(const QSharedPointer<ScreenController> &screenController, |
1521 | + QtWindowSystemInterface *windowSystem); |
1522 | virtual ~QtEventFeeder(); |
1523 | |
1524 | static const int MirEventActionMask; |
1525 | @@ -69,9 +73,9 @@ |
1526 | void dispatchKey(MirInputEvent const* event); |
1527 | void dispatchTouch(MirInputEvent const* event); |
1528 | void dispatchPointer(MirInputEvent const* event); |
1529 | - void validateTouches(ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints); |
1530 | + void validateTouches(QWindow *window, ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints); |
1531 | bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint); |
1532 | - void sendActiveTouchRelease(ulong timestamp, int id); |
1533 | + void sendActiveTouchRelease(QWindow *window, ulong timestamp, int id); |
1534 | |
1535 | QString touchesToString(const QList<struct QWindowSystemInterface::TouchPoint> &points); |
1536 | |
1537 | |
1538 | === modified file 'src/platforms/mirserver/screen.cpp' |
1539 | --- src/platforms/mirserver/screen.cpp 2014-10-22 15:47:49 +0000 |
1540 | +++ src/platforms/mirserver/screen.cpp 2015-08-07 12:06:18 +0000 |
1541 | @@ -1,5 +1,5 @@ |
1542 | /* |
1543 | - * Copyright (C) 2013,2014 Canonical, Ltd. |
1544 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
1545 | * |
1546 | * This program is free software: you can redistribute it and/or modify it under |
1547 | * the terms of the GNU Lesser General Public License version 3, as published by |
1548 | @@ -24,12 +24,13 @@ |
1549 | |
1550 | // Mir |
1551 | #include "mir/geometry/size.h" |
1552 | +#include "mir/graphics/buffer.h" |
1553 | +#include "mir/graphics/display_buffer.h" |
1554 | +#include "mir/graphics/display.h" |
1555 | |
1556 | // Qt |
1557 | #include <QCoreApplication> |
1558 | #include <qpa/qwindowsysteminterface.h> |
1559 | -#include <QtSensors/QOrientationSensor> |
1560 | -#include <QtSensors/QOrientationReading> |
1561 | #include <QThread> |
1562 | |
1563 | // Qt sensors |
1564 | @@ -106,12 +107,15 @@ |
1565 | |
1566 | bool Screen::skipDBusRegistration = false; |
1567 | |
1568 | -Screen::Screen(mir::graphics::DisplayConfigurationOutput const &screen) |
1569 | +Screen::Screen(const mir::graphics::DisplayConfigurationOutput &screen) |
1570 | : QObject(nullptr) |
1571 | + , m_displayBuffer(nullptr) |
1572 | + , m_displayGroup(nullptr) |
1573 | , m_orientationSensor(new QOrientationSensor(this)) |
1574 | + , m_screenWindow(nullptr) |
1575 | , m_unityScreen(nullptr) |
1576 | { |
1577 | - readMirDisplayConfiguration(screen); |
1578 | + setMirDisplayConfiguration(screen); |
1579 | |
1580 | // Set the default orientation based on the initial screen dimmensions. |
1581 | m_nativeOrientation = (m_geometry.width() >= m_geometry.height()) |
1582 | @@ -143,6 +147,14 @@ |
1583 | } |
1584 | } |
1585 | |
1586 | +Screen::~Screen() |
1587 | +{ |
1588 | + //if a ScreenWindow associated with this screen, kill it |
1589 | + if (m_screenWindow) { |
1590 | + m_screenWindow->window()->destroy(); // ends up destroying m_ScreenWindow |
1591 | + } |
1592 | +} |
1593 | + |
1594 | bool Screen::orientationSensorEnabled() |
1595 | { |
1596 | return m_orientationSensor->isActive(); |
1597 | @@ -154,8 +166,15 @@ |
1598 | toggleSensors(status); |
1599 | } |
1600 | |
1601 | -void Screen::readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const &screen) |
1602 | +void Screen::setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &screen) |
1603 | { |
1604 | + // Note: DisplayConfigurationOutput will be destroyed after this function returns |
1605 | + |
1606 | + // Output data - each output has a unique id and corresponding type. Can be multiple cards. |
1607 | + m_outputId = screen.id; |
1608 | + m_cardId = screen.card_id; |
1609 | + m_type = screen.type; |
1610 | + |
1611 | // Physical screen size |
1612 | m_physicalSize.setWidth(screen.physical_size_mm.width.as_float()); |
1613 | m_physicalSize.setHeight(screen.physical_size_mm.height.as_float()); |
1614 | @@ -166,12 +185,34 @@ |
1615 | // Pixel depth |
1616 | m_depth = 8 * MIR_BYTES_PER_PIXEL(screen.current_format); |
1617 | |
1618 | - // Mode = Resolution & refresh rate |
1619 | + // Power mode |
1620 | + m_powerMode = screen.power_mode; |
1621 | + |
1622 | + QRect oldGeometry = m_geometry; |
1623 | + // Position of screen in virtual desktop coordinate space |
1624 | + m_geometry.setTop(screen.top_left.y.as_int()); |
1625 | + m_geometry.setLeft(screen.top_left.x.as_int()); |
1626 | + |
1627 | + // Mode = current resolution & refresh rate |
1628 | mir::graphics::DisplayConfigurationMode mode = screen.modes.at(screen.current_mode_index); |
1629 | m_geometry.setWidth(mode.size.width.as_int()); |
1630 | m_geometry.setHeight(mode.size.height.as_int()); |
1631 | |
1632 | - m_refreshRate = mode.vrefresh_hz; |
1633 | + // DPI - unnecessary to calculate, default implementation in QPlatformScreen is sufficient |
1634 | + |
1635 | + // Check for Screen geometry change |
1636 | + if (m_geometry != oldGeometry) { |
1637 | + QWindowSystemInterface::handleScreenGeometryChange(this->screen(), m_geometry, m_geometry); |
1638 | + if (m_screenWindow) { // resize corresponding window immediately |
1639 | + m_screenWindow->setGeometry(m_geometry); |
1640 | + } |
1641 | + } |
1642 | + |
1643 | + // Refresh rate |
1644 | + if (m_refreshRate != mode.vrefresh_hz) { |
1645 | + m_refreshRate = mode.vrefresh_hz; |
1646 | + QWindowSystemInterface::handleScreenRefreshRateChange(this->screen(), mode.vrefresh_hz); |
1647 | + } |
1648 | } |
1649 | |
1650 | void Screen::toggleSensors(const bool enable) const |
1651 | @@ -230,3 +271,51 @@ |
1652 | OrientationReadingEvent::m_type, |
1653 | m_orientationSensor->reading()->orientation())); |
1654 | } |
1655 | + |
1656 | +ScreenWindow* Screen::window() const |
1657 | +{ |
1658 | + return m_screenWindow; |
1659 | +} |
1660 | + |
1661 | +void Screen::setWindow(ScreenWindow *window) |
1662 | +{ |
1663 | + if (m_screenWindow) { |
1664 | + qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen::setWindow - overwriting existing ScreenWindow"; |
1665 | + } |
1666 | + m_screenWindow = window; |
1667 | +} |
1668 | + |
1669 | +void Screen::setMirDisplayBuffer(mir::graphics::DisplayBuffer *buffer, mir::graphics::DisplaySyncGroup *group) |
1670 | +{ |
1671 | + // This operation should only be performed while rendering is stopped |
1672 | + m_displayBuffer = buffer; |
1673 | + m_displayGroup = group; |
1674 | +} |
1675 | + |
1676 | +void Screen::swapBuffers() |
1677 | +{ |
1678 | + m_displayBuffer->gl_swap_buffers(); |
1679 | + |
1680 | + /* FIXME this exposes a QtMir architecture problem, as Screen is supposed to wrap a mg::DisplayBuffer. |
1681 | + * We use Qt's multithreaded renderer, where each Screen is rendered to relatively independently, and |
1682 | + * post() called also individually. |
1683 | + * |
1684 | + * But if this is a native server on Android, in the multimonitor case a DisplaySyncGroup can contain |
1685 | + * 2+ DisplayBuffers, one post() call will submit all mg::DisplayBuffers in the group for flipping. |
1686 | + * This will cause just one Screen to be updated, blocking the swap call for the other Screens, which |
1687 | + * will slow rendering dramatically. |
1688 | + * |
1689 | + * Integrating the Qt Scenegraph renderer as a Mir renderer should solve this issue. |
1690 | + */ |
1691 | + m_displayGroup->post(); |
1692 | +} |
1693 | + |
1694 | +void Screen::makeCurrent() |
1695 | +{ |
1696 | + m_displayBuffer->make_current(); |
1697 | +} |
1698 | + |
1699 | +void Screen::doneCurrent() |
1700 | +{ |
1701 | + m_displayBuffer->release_current(); |
1702 | +} |
1703 | |
1704 | === modified file 'src/platforms/mirserver/screen.h' |
1705 | --- src/platforms/mirserver/screen.h 2014-10-22 15:47:49 +0000 |
1706 | +++ src/platforms/mirserver/screen.h 2015-08-07 12:06:18 +0000 |
1707 | @@ -1,5 +1,5 @@ |
1708 | /* |
1709 | - * Copyright (C) 2013,2014 Canonical, Ltd. |
1710 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
1711 | * |
1712 | * This program is free software: you can redistribute it and/or modify it under |
1713 | * the terms of the GNU Lesser General Public License version 3, as published by |
1714 | @@ -20,20 +20,27 @@ |
1715 | #ifndef SCREEN_H |
1716 | #define SCREEN_H |
1717 | |
1718 | +// Qt |
1719 | #include <QObject> |
1720 | #include <QTimer> |
1721 | #include <QtDBus/QDBusInterface> |
1722 | #include <qpa/qplatformscreen.h> |
1723 | |
1724 | +// Mir |
1725 | #include "mir/graphics/display_configuration.h" |
1726 | |
1727 | +// local |
1728 | +#include "screenwindow.h" |
1729 | + |
1730 | class QOrientationSensor; |
1731 | +namespace mir { namespace graphics { class DisplayBuffer; class DisplaySyncGroup; }} |
1732 | |
1733 | class Screen : public QObject, public QPlatformScreen |
1734 | { |
1735 | Q_OBJECT |
1736 | public: |
1737 | - Screen(mir::graphics::DisplayConfigurationOutput const&); |
1738 | + Screen(const mir::graphics::DisplayConfigurationOutput &); |
1739 | + ~Screen(); |
1740 | |
1741 | // QPlatformScreen methods. |
1742 | QRect geometry() const override { return m_geometry; } |
1743 | @@ -45,6 +52,9 @@ |
1744 | Qt::ScreenOrientation orientation() const override { return m_currentOrientation; } |
1745 | |
1746 | void toggleSensors(const bool enable) const; |
1747 | + mir::graphics::DisplayConfigurationOutputType outputType() const { return m_type; } |
1748 | + |
1749 | + ScreenWindow* window() const; |
1750 | |
1751 | // QObject methods. |
1752 | void customEvent(QEvent* event) override; |
1753 | @@ -57,20 +67,38 @@ |
1754 | void onDisplayPowerStateChanged(int, int); |
1755 | void onOrientationReadingChanged(); |
1756 | |
1757 | +protected: |
1758 | + void setWindow(ScreenWindow *window); |
1759 | + |
1760 | + void setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &); |
1761 | + void setMirDisplayBuffer(mir::graphics::DisplayBuffer *, mir::graphics::DisplaySyncGroup *); |
1762 | + void swapBuffers(); |
1763 | + void makeCurrent(); |
1764 | + void doneCurrent(); |
1765 | + |
1766 | private: |
1767 | - void readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const&); |
1768 | - |
1769 | QRect m_geometry; |
1770 | int m_depth; |
1771 | QImage::Format m_format; |
1772 | QSizeF m_physicalSize; |
1773 | qreal m_refreshRate; |
1774 | |
1775 | + mir::graphics::DisplayBuffer *m_displayBuffer; |
1776 | + mir::graphics::DisplaySyncGroup *m_displayGroup; |
1777 | + mir::graphics::DisplayConfigurationOutputId m_outputId; |
1778 | + mir::graphics::DisplayConfigurationCardId m_cardId; |
1779 | + mir::graphics::DisplayConfigurationOutputType m_type; |
1780 | + MirPowerMode m_powerMode; |
1781 | + |
1782 | Qt::ScreenOrientation m_nativeOrientation; |
1783 | Qt::ScreenOrientation m_currentOrientation; |
1784 | QOrientationSensor *m_orientationSensor; |
1785 | |
1786 | + ScreenWindow *m_screenWindow; |
1787 | QDBusInterface *m_unityScreen; |
1788 | + |
1789 | + friend class ScreenController; |
1790 | + friend class ScreenWindow; |
1791 | }; |
1792 | |
1793 | #endif // SCREEN_H |
1794 | |
1795 | === added file 'src/platforms/mirserver/screencontroller.cpp' |
1796 | --- src/platforms/mirserver/screencontroller.cpp 1970-01-01 00:00:00 +0000 |
1797 | +++ src/platforms/mirserver/screencontroller.cpp 2015-08-07 12:06:18 +0000 |
1798 | @@ -0,0 +1,261 @@ |
1799 | +/* |
1800 | + * Copyright (C) 2015 Canonical, Ltd. |
1801 | + * |
1802 | + * This program is free software: you can redistribute it and/or modify it under |
1803 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1804 | + * the Free Software Foundation. |
1805 | + * |
1806 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1807 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1808 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1809 | + * Lesser General Public License for more details. |
1810 | + * |
1811 | + * You should have received a copy of the GNU Lesser General Public License |
1812 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1813 | + */ |
1814 | + |
1815 | +#include "screencontroller.h" |
1816 | + |
1817 | +#include "screenwindow.h" |
1818 | +#include "qtcompositor.h" |
1819 | +#include "logging.h" |
1820 | +#include "mirserverintegration.h" |
1821 | +#include "screen.h" |
1822 | + |
1823 | +// Mir |
1824 | +#include <mir/graphics/display.h> |
1825 | +#include <mir/graphics/display_buffer.h> |
1826 | +#include <mir/main_loop.h> |
1827 | + |
1828 | +// Qt |
1829 | +#include <QScreen> |
1830 | +#include <QQuickWindow> |
1831 | +#include <qpa/qwindowsysteminterface.h> |
1832 | + |
1833 | +// std |
1834 | +#include <memory> |
1835 | + |
1836 | +Q_LOGGING_CATEGORY(QTMIR_SCREENS, "qtmir.screens") |
1837 | + |
1838 | +namespace mg = mir::graphics; |
1839 | + |
1840 | + |
1841 | +ScreenController::ScreenController(QObject *parent) |
1842 | + : QObject(parent) |
1843 | +{ |
1844 | + qCDebug(QTMIR_SCREENS) << "ScreenController::ScreenController"; |
1845 | +} |
1846 | + |
1847 | +// init only after MirServer has initialized - runs on MirServerThread!!! |
1848 | +void ScreenController::init(const std::shared_ptr<mir::graphics::Display> &display, |
1849 | + const std::shared_ptr<mir::compositor::Compositor> &compositor, |
1850 | + const std::shared_ptr<mir::MainLoop> &mainLoop) |
1851 | +{ |
1852 | + m_display = display; |
1853 | + m_compositor = compositor; |
1854 | + |
1855 | + // Use a Blocking Queued Connection to enforce synchronization of Qt GUI thread with Mir thread(s) |
1856 | + // on compositor shutdown. Compositor startup can be lazy. |
1857 | + // Queued connections work because the thread affinity of this class is with the Qt GUI thread. |
1858 | + auto qtCompositor = static_cast<QtCompositor *>(compositor.get()); |
1859 | + connect(qtCompositor, &QtCompositor::starting, |
1860 | + this, &ScreenController::onCompositorStarting); |
1861 | + connect(qtCompositor, &QtCompositor::stopping, |
1862 | + this, &ScreenController::onCompositorStopping, Qt::BlockingQueuedConnection); |
1863 | + |
1864 | + |
1865 | + display->register_configuration_change_handler(*mainLoop, [this]() { |
1866 | + // display hardware configuration changed, update! - not called when we set new configuration |
1867 | + QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); |
1868 | + }); |
1869 | +} |
1870 | + |
1871 | +// terminate before shutting down the Mir server, or else liable to deadlock with the blocking connection above |
1872 | +// Runs on MirServerThread!!! |
1873 | +void ScreenController::terminate() |
1874 | +{ |
1875 | + auto qtCompositor = static_cast<QtCompositor *>(m_compositor.get()); |
1876 | + qtCompositor->disconnect(); |
1877 | +} |
1878 | + |
1879 | +void ScreenController::onCompositorStarting() |
1880 | +{ |
1881 | + qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStarting"; |
1882 | + |
1883 | + update(); |
1884 | + |
1885 | + // (Re)Start Qt's render thread by setting all windows with a corresponding screen to exposed. |
1886 | + for (auto screen : m_screenList) { |
1887 | + auto window = static_cast<ScreenWindow *>(screen->window()); |
1888 | + if (window && window->window()) { |
1889 | + window->window()->show(); |
1890 | + } |
1891 | + } |
1892 | +} |
1893 | + |
1894 | +void ScreenController::onCompositorStopping() |
1895 | +{ |
1896 | + qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStopping"; |
1897 | + |
1898 | + // Stop Qt's render threads by setting all its windows it obscured. Must |
1899 | + // block until all windows have their GL contexts released. |
1900 | + for (auto screen : m_screenList) { |
1901 | + auto window = static_cast<ScreenWindow *>(screen->window()); |
1902 | + if (window && window->window()) { |
1903 | + window->window()->hide(); |
1904 | + } |
1905 | + } |
1906 | + |
1907 | + update(); |
1908 | +} |
1909 | + |
1910 | +void ScreenController::update() |
1911 | +{ |
1912 | + qCDebug(QTMIR_SCREENS) << "ScreenController::update"; |
1913 | + auto display = m_display.lock(); |
1914 | + if (!display) |
1915 | + return; |
1916 | + auto displayConfig = display->configuration(); |
1917 | + |
1918 | + // Mir only tells us something changed, it is up to us to figure out what. |
1919 | + QList<Screen*> newScreenList; |
1920 | + QList<Screen*> oldScreenList = m_screenList; |
1921 | + m_screenList.clear(); |
1922 | + |
1923 | + displayConfig->for_each_output( |
1924 | + [this, &oldScreenList, &newScreenList](const mg::DisplayConfigurationOutput &output) { |
1925 | + if (output.used && output.connected) { |
1926 | + Screen *screen = findScreenWithId(oldScreenList, output.id); |
1927 | + if (screen) { // we've already set up this display before, refresh its internals |
1928 | + screen->setMirDisplayConfiguration(output); |
1929 | + oldScreenList.removeAll(screen); |
1930 | + } else { |
1931 | + // new display, so create Screen for it |
1932 | + screen = this->createScreen(output); |
1933 | + newScreenList.append(screen); |
1934 | + qCDebug(QTMIR_SCREENS) << "Added Screen with id" << output.id.as_value() |
1935 | + << "and geometry" << screen->geometry(); |
1936 | + } |
1937 | + m_screenList.append(screen); |
1938 | + } |
1939 | + } |
1940 | + ); |
1941 | + |
1942 | + // Delete any old & unused Screens |
1943 | + for (auto screen: oldScreenList) { |
1944 | + qCDebug(QTMIR_SCREENS) << "Removed Screen with id" << screen->m_outputId.as_value() |
1945 | + << "and geometry" << screen->geometry(); |
1946 | + // The screen is automatically removed from Qt's internal list by the QPlatformScreen destructor. |
1947 | + auto window = static_cast<ScreenWindow *>(screen->window()); |
1948 | + if (window && window->window() && window->isExposed()) { |
1949 | + window->window()->hide(); |
1950 | + } |
1951 | + delete screen; |
1952 | + } |
1953 | + |
1954 | + // Match up the new Mir DisplayBuffers with each Screen |
1955 | + display->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) { |
1956 | + group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) { |
1957 | + // only way to match Screen to a DisplayBuffer is by matching the geometry |
1958 | + QRect dbGeom(buffer.view_area().top_left.x.as_int(), |
1959 | + buffer.view_area().top_left.y.as_int(), |
1960 | + buffer.view_area().size.width.as_int(), |
1961 | + buffer.view_area().size.height.as_int()); |
1962 | + |
1963 | + for (auto screen : m_screenList) { |
1964 | + if (dbGeom == screen->geometry()) { |
1965 | + screen->setMirDisplayBuffer(&buffer, &group); |
1966 | + } |
1967 | + } |
1968 | + }); |
1969 | + }); |
1970 | + |
1971 | + qCDebug(QTMIR_SCREENS) << "======================================="; |
1972 | + for (auto screen: m_screenList) { |
1973 | + qCDebug(QTMIR_SCREENS) << "Screen - id:" << screen->m_outputId.as_value() |
1974 | + << "geometry:" << screen->geometry() |
1975 | + << "window:" << screen->window() |
1976 | + << "type" << static_cast<int>(screen->outputType()); |
1977 | + } |
1978 | + qCDebug(QTMIR_SCREENS) << "======================================="; |
1979 | + |
1980 | + for (auto screen : newScreenList) { |
1981 | + Q_EMIT screenAdded(screen); |
1982 | + } |
1983 | +} |
1984 | + |
1985 | +Screen* ScreenController::createScreen(const mir::graphics::DisplayConfigurationOutput &output) const |
1986 | +{ |
1987 | + return new Screen(output); |
1988 | +} |
1989 | + |
1990 | +Screen* ScreenController::getUnusedScreen() |
1991 | +{ |
1992 | + if (m_screenList.empty()) { |
1993 | + return nullptr; |
1994 | + } else if (m_screenList.size() == 1) { |
1995 | + return m_screenList.at(0); |
1996 | + } |
1997 | + |
1998 | + // FIXME: Until we have better way of identifying screens, prioritize outputs based on their output type. |
1999 | + // Note the priorities defined here are nothing more than guesses. It tries to select internal displays first, |
2000 | + // then digital outputs, and finally analogue. |
2001 | + QMap <int, Screen*> priorityList; |
2002 | + auto prioritize = [](const mg::DisplayConfigurationOutputType &type) { |
2003 | + using out = mg::DisplayConfigurationOutputType; |
2004 | + switch(type) { |
2005 | + case out::lvds: |
2006 | + case out::edp: |
2007 | + return 0; |
2008 | + case out::displayport: |
2009 | + case out::hdmia: |
2010 | + case out::hdmib: |
2011 | + return 1; |
2012 | + case out::dvii: |
2013 | + case out::dvid: |
2014 | + case out::dvia: |
2015 | + return 2; |
2016 | + case out::vga: |
2017 | + return 3; |
2018 | + case out::ninepindin: |
2019 | + return 4; |
2020 | + case out::component: |
2021 | + case out::composite: |
2022 | + case out::svideo: |
2023 | + return 5; |
2024 | + case out::tv: |
2025 | + return 6; |
2026 | + case out::unknown: |
2027 | + default: |
2028 | + return 9; |
2029 | + } |
2030 | + }; |
2031 | + |
2032 | + for (auto screen : m_screenList) { |
2033 | + if (!screen->window()) { |
2034 | + priorityList.insert(prioritize(screen->outputType()), screen); |
2035 | + } |
2036 | + } |
2037 | + |
2038 | + return priorityList.first(); // Map sorted by key, so first is the key with highest priority. |
2039 | +} |
2040 | + |
2041 | +Screen* ScreenController::findScreenWithId(const QList<Screen *> &list, const mg::DisplayConfigurationOutputId id) |
2042 | +{ |
2043 | + for (Screen *screen : list) { |
2044 | + if (screen->m_outputId == id) { |
2045 | + return screen; |
2046 | + } |
2047 | + } |
2048 | + return nullptr; |
2049 | +} |
2050 | + |
2051 | +QWindow* ScreenController::getWindowForPoint(const QPoint &point) //FIXME - not thread safe & not efficient |
2052 | +{ |
2053 | + for (Screen *screen : m_screenList) { |
2054 | + if (screen->window() && screen->geometry().contains(point)) { |
2055 | + return screen->window()->window(); |
2056 | + } |
2057 | + } |
2058 | + return nullptr; |
2059 | +} |
2060 | |
2061 | === added file 'src/platforms/mirserver/screencontroller.h' |
2062 | --- src/platforms/mirserver/screencontroller.h 1970-01-01 00:00:00 +0000 |
2063 | +++ src/platforms/mirserver/screencontroller.h 2015-08-07 12:06:18 +0000 |
2064 | @@ -0,0 +1,96 @@ |
2065 | +/* |
2066 | + * Copyright (C) 2015 Canonical, Ltd. |
2067 | + * |
2068 | + * This program is free software: you can redistribute it and/or modify it under |
2069 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2070 | + * the Free Software Foundation. |
2071 | + * |
2072 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2073 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2074 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2075 | + * Lesser General Public License for more details. |
2076 | + * |
2077 | + * You should have received a copy of the GNU Lesser General Public License |
2078 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2079 | + */ |
2080 | + |
2081 | +#ifndef SCREENCONTROLLER_H |
2082 | +#define SCREENCONTROLLER_H |
2083 | + |
2084 | +#include <QObject> |
2085 | +#include <QPoint> |
2086 | + |
2087 | +// Mir |
2088 | +#include <mir/graphics/display_configuration.h> |
2089 | + |
2090 | +// std |
2091 | +#include <memory> |
2092 | + |
2093 | +namespace mir { |
2094 | + class MainLoop; |
2095 | + namespace graphics { class Display; } |
2096 | + namespace compositor { class Compositor; } |
2097 | +} |
2098 | +class Screen; |
2099 | +class QWindow; |
2100 | + |
2101 | +/* |
2102 | + * ScreenController monitors the Mir display configuration and compositor status, and updates |
2103 | + * the relevant QScreen and QWindow states accordingly. |
2104 | + * |
2105 | + * Primary purposes are: |
2106 | + * 1. to update QScreen state on Mir display configuration changes |
2107 | + * 2. to stop the Qt renderer by hiding its QWindow when Mir wants to stop all compositing, |
2108 | + * and resume Qt's renderer by showing its QWindow when Mir wants to resume compositing. |
2109 | + * |
2110 | + * |
2111 | + * Threading Note: |
2112 | + * This object must have affinity to the main Qt GUI thread, as it creates & destroys Platform |
2113 | + * objects which Qt uses internally. However beware as the init() & terminate() methods need to |
2114 | + * be called on the MirServerThread thread, as we need to monitor the screen state *after* |
2115 | + * Mir has initialized but before Qt's event loop has started, and tear down before Mir terminates. |
2116 | + * Also note the MirServerThread does not have an QEventLoop. |
2117 | + * |
2118 | + * All other methods must be called on the Qt GUI thread. |
2119 | + */ |
2120 | + |
2121 | +class ScreenController : public QObject |
2122 | +{ |
2123 | + Q_OBJECT |
2124 | +public: |
2125 | + explicit ScreenController(QObject *parent = 0); |
2126 | + |
2127 | + Screen* getUnusedScreen(); |
2128 | + QList<Screen*> screens() const { return m_screenList; } |
2129 | + |
2130 | + QWindow* getWindowForPoint(const QPoint &point); |
2131 | + |
2132 | +Q_SIGNALS: |
2133 | + void screenAdded(Screen *screen); |
2134 | + |
2135 | +public Q_SLOTS: |
2136 | + void update(); |
2137 | + |
2138 | +public: |
2139 | + // called by MirServer |
2140 | + void init(const std::shared_ptr<mir::graphics::Display> &display, |
2141 | + const std::shared_ptr<mir::compositor::Compositor> &compositor, |
2142 | + const std::shared_ptr<mir::MainLoop> &mainLoop); |
2143 | + void terminate(); |
2144 | + |
2145 | + // override for testing purposes |
2146 | + virtual Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const; |
2147 | + |
2148 | +protected Q_SLOTS: |
2149 | + void onCompositorStarting(); |
2150 | + void onCompositorStopping(); |
2151 | + |
2152 | +private: |
2153 | + Screen* findScreenWithId(const QList<Screen*> &list, const mir::graphics::DisplayConfigurationOutputId id); |
2154 | + |
2155 | + std::weak_ptr<mir::graphics::Display> m_display; |
2156 | + std::shared_ptr<mir::compositor::Compositor> m_compositor; |
2157 | + QList<Screen*> m_screenList; |
2158 | +}; |
2159 | + |
2160 | +#endif // SCREENCONTROLLER_H |
2161 | |
2162 | === renamed file 'src/platforms/mirserver/displaywindow.cpp' => 'src/platforms/mirserver/screenwindow.cpp' |
2163 | --- src/platforms/mirserver/displaywindow.cpp 2015-03-25 14:58:57 +0000 |
2164 | +++ src/platforms/mirserver/screenwindow.cpp 2015-08-07 12:06:18 +0000 |
2165 | @@ -1,5 +1,5 @@ |
2166 | /* |
2167 | - * Copyright (C) 2013,2014 Canonical, Ltd. |
2168 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
2169 | * |
2170 | * This program is free software: you can redistribute it and/or modify it under |
2171 | * the terms of the GNU Lesser General Public License version 3, as published by |
2172 | @@ -12,19 +12,18 @@ |
2173 | * |
2174 | * You should have received a copy of the GNU Lesser General Public License |
2175 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2176 | - * |
2177 | - * Authors: Gerry Boland <gerry.boland@canonical.com> |
2178 | - * Daniel d'Andrada <daniel.dandrada@canonical.com> |
2179 | */ |
2180 | |
2181 | -#include "displaywindow.h" |
2182 | +#include "screenwindow.h" |
2183 | +#include "screen.h" |
2184 | |
2185 | -#include "mir/geometry/size.h" |
2186 | +#include <mir/geometry/size.h> |
2187 | +#include <mir/graphics/display_buffer.h> |
2188 | |
2189 | #include <qpa/qwindowsysteminterface.h> |
2190 | #include <qpa/qplatformscreen.h> |
2191 | |
2192 | -#include <QDebug> |
2193 | +#include "logging.h" |
2194 | |
2195 | static WId newWId() |
2196 | { |
2197 | @@ -36,18 +35,16 @@ |
2198 | return ++id; |
2199 | } |
2200 | |
2201 | -DisplayWindow::DisplayWindow( |
2202 | - QWindow *window, |
2203 | - mir::graphics::DisplaySyncGroup *displayGroup, |
2204 | - mir::graphics::DisplayBuffer *displayBuffer) |
2205 | - : QObject(nullptr), QPlatformWindow(window) |
2206 | - , m_isExposed(true) |
2207 | +ScreenWindow::ScreenWindow(QWindow *window) |
2208 | + : QPlatformWindow(window) |
2209 | , m_winId(newWId()) |
2210 | - , m_displayGroup(displayGroup) |
2211 | - , m_displayBuffer(displayBuffer) |
2212 | { |
2213 | - qDebug() << "DisplayWindow::DisplayWindow"; |
2214 | - qWarning("Window %p: %p 0x%x\n", this, window, uint(m_winId)); |
2215 | + qCDebug(QTMIR_SCREENS) << "Window" << this << "with window ID" << uint(m_winId); |
2216 | + |
2217 | + // Register with the Screen it is associated with |
2218 | + auto myScreen = static_cast<Screen *>(screen()); |
2219 | + Q_ASSERT(myScreen); |
2220 | + myScreen->setWindow(this); |
2221 | |
2222 | QRect screenGeometry(screen()->availableGeometry()); |
2223 | if (window->geometry() != screenGeometry) { |
2224 | @@ -60,70 +57,22 @@ |
2225 | requestActivateWindow(); |
2226 | } |
2227 | |
2228 | -QRect DisplayWindow::geometry() const |
2229 | -{ |
2230 | - // For yet-to-become-fullscreen windows report the geometry covering the entire |
2231 | - // screen. This is particularly important for Quick where the root object may get |
2232 | - // sized to some geometry queried before calling create(). |
2233 | - return screen()->availableGeometry(); |
2234 | -} |
2235 | - |
2236 | -void DisplayWindow::setGeometry(const QRect &) |
2237 | -{ |
2238 | - // We only support full-screen windows |
2239 | - QRect rect(screen()->availableGeometry()); |
2240 | - QWindowSystemInterface::handleGeometryChange(window(), rect); |
2241 | - QPlatformWindow::setGeometry(rect); |
2242 | -} |
2243 | - |
2244 | -bool DisplayWindow::isExposed() const |
2245 | -{ |
2246 | - return m_isExposed; |
2247 | -} |
2248 | - |
2249 | -bool DisplayWindow::event(QEvent *event) |
2250 | -{ |
2251 | - // Intercept Hide event and convert to Expose event, as Hide causes Qt to release GL |
2252 | - // resources, which we don't want. Must intercept Show to un-do hide. |
2253 | - if (event->type() == QEvent::Hide) { |
2254 | - qDebug() << "DisplayWindow::event got QEvent::Hide"; |
2255 | - m_isExposed = false; |
2256 | - QWindowSystemInterface::handleExposeEvent(window(), QRect()); |
2257 | - QWindowSystemInterface::flushWindowSystemEvents(); |
2258 | - return true; |
2259 | - } else if (event->type() == QEvent::Show) { |
2260 | - qDebug() << "DisplayWindow::event got QEvent::Show"; |
2261 | - m_isExposed = true; |
2262 | - QRect rect(QPoint(), geometry().size()); |
2263 | - QWindowSystemInterface::handleExposeEvent(window(), rect); |
2264 | - QWindowSystemInterface::flushWindowSystemEvents(); |
2265 | - return true; |
2266 | - } |
2267 | - return QObject::event(event); |
2268 | -} |
2269 | - |
2270 | -void DisplayWindow::swapBuffers() |
2271 | -{ |
2272 | - m_displayBuffer->gl_swap_buffers(); |
2273 | - |
2274 | - // FIXME this exposes a QtMir architecture problem now, as DisplayWindow |
2275 | - // is supposed to wrap a mg::DisplayBuffer. We use Qt's multithreaded |
2276 | - // renderer, where each DisplayWindow is rendered to relatively |
2277 | - // independently, and post() called also individually. |
2278 | - // |
2279 | - // But in multimonitor case where a DisplaySyncGroup contains 2 |
2280 | - // DisplayBuffers, one post() call will submit both |
2281 | - // mg::DisplayBuffers for flipping, which can happen before the other |
2282 | - // DisplayWindow has been rendered to, causing visual artifacts |
2283 | - m_displayGroup->post(); |
2284 | -} |
2285 | - |
2286 | -void DisplayWindow::makeCurrent() |
2287 | -{ |
2288 | - m_displayBuffer->make_current(); |
2289 | -} |
2290 | - |
2291 | -void DisplayWindow::doneCurrent() |
2292 | -{ |
2293 | - m_displayBuffer->release_current(); |
2294 | +ScreenWindow::~ScreenWindow() |
2295 | +{ |
2296 | + static_cast<Screen *>(screen())->setWindow(nullptr); |
2297 | +} |
2298 | + |
2299 | +void ScreenWindow::swapBuffers() |
2300 | +{ |
2301 | + static_cast<Screen *>(screen())->swapBuffers(); |
2302 | +} |
2303 | + |
2304 | +void ScreenWindow::makeCurrent() |
2305 | +{ |
2306 | + static_cast<Screen *>(screen())->makeCurrent(); |
2307 | +} |
2308 | + |
2309 | +void ScreenWindow::doneCurrent() |
2310 | +{ |
2311 | + static_cast<Screen *>(screen())->doneCurrent(); |
2312 | } |
2313 | |
2314 | === renamed file 'src/platforms/mirserver/displaywindow.h' => 'src/platforms/mirserver/screenwindow.h' |
2315 | --- src/platforms/mirserver/displaywindow.h 2015-03-11 14:53:34 +0000 |
2316 | +++ src/platforms/mirserver/screenwindow.h 2015-08-07 12:06:18 +0000 |
2317 | @@ -1,5 +1,5 @@ |
2318 | /* |
2319 | - * Copyright (C) 2013 Canonical, Ltd. |
2320 | + * Copyright (C) 2015 Canonical, Ltd. |
2321 | * |
2322 | * This program is free software: you can redistribute it and/or modify it under |
2323 | * the terms of the GNU Lesser General Public License version 3, as published by |
2324 | @@ -12,47 +12,31 @@ |
2325 | * |
2326 | * You should have received a copy of the GNU Lesser General Public License |
2327 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2328 | - * |
2329 | - * Author: Gerry Boland <gerry.boland@canonical.com> |
2330 | */ |
2331 | |
2332 | -#ifndef DISPLAYWINDOW_H |
2333 | -#define DISPLAYWINDOW_H |
2334 | +#ifndef SCREENWINDOW_H |
2335 | +#define SCREENWINDOW_H |
2336 | |
2337 | #include <qpa/qplatformwindow.h> |
2338 | |
2339 | -#include <mir/graphics/display.h> |
2340 | -#include <mir/graphics/display_buffer.h> |
2341 | - |
2342 | -#include <QObject> |
2343 | - |
2344 | -// DisplayWindow wraps the whatever implementation Mir creates of a DisplayBuffer, |
2345 | -// which is the buffer output for an individual display. |
2346 | - |
2347 | -class DisplayWindow : public QObject, public QPlatformWindow |
2348 | +// ScreenWindow implements the basics of a QPlatformWindow. |
2349 | +// QtMir enforces one Window per Screen, so Window and Screen are tightly coupled. |
2350 | +// All Mir specifics live in the associated Screen object. |
2351 | + |
2352 | +class ScreenWindow : public QPlatformWindow |
2353 | { |
2354 | - Q_OBJECT |
2355 | public: |
2356 | - explicit DisplayWindow(QWindow *window, mir::graphics::DisplaySyncGroup*, mir::graphics::DisplayBuffer*); |
2357 | - |
2358 | - QRect geometry() const override; |
2359 | - void setGeometry(const QRect &rect) override; |
2360 | + explicit ScreenWindow(QWindow *window); |
2361 | + virtual ~ScreenWindow(); |
2362 | |
2363 | WId winId() const override { return m_winId; } |
2364 | |
2365 | - bool isExposed() const override; |
2366 | - |
2367 | - bool event(QEvent *event) override; |
2368 | - |
2369 | void swapBuffers(); |
2370 | void makeCurrent(); |
2371 | void doneCurrent(); |
2372 | |
2373 | private: |
2374 | - bool m_isExposed; |
2375 | WId m_winId; |
2376 | - mir::graphics::DisplaySyncGroup *m_displayGroup; |
2377 | - mir::graphics::DisplayBuffer *m_displayBuffer; |
2378 | }; |
2379 | |
2380 | -#endif // DISPLAYWINDOW_H |
2381 | +#endif // SCREENWINDOW_H |
2382 | |
2383 | === added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp' |
2384 | --- src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 1970-01-01 00:00:00 +0000 |
2385 | +++ src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 2015-08-07 12:06:18 +0000 |
2386 | @@ -0,0 +1,44 @@ |
2387 | +/* |
2388 | + * Copyright (C) 2015 Canonical, Ltd. |
2389 | + * |
2390 | + * This program is free software: you can redistribute it and/or modify it under |
2391 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2392 | + * the Free Software Foundation. |
2393 | + * |
2394 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2395 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2396 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2397 | + * Lesser General Public License for more details. |
2398 | + * |
2399 | + * You should have received a copy of the GNU Lesser General Public License |
2400 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2401 | + */ |
2402 | + |
2403 | +#include "tileddisplayconfigurationpolicy.h" |
2404 | + |
2405 | +#include <mir/graphics/display_configuration.h> |
2406 | +#include <mir/geometry/point.h> |
2407 | + |
2408 | +namespace mg = mir::graphics; |
2409 | + |
2410 | +TiledDisplayConfigurationPolicy::TiledDisplayConfigurationPolicy( |
2411 | + const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped) |
2412 | + : m_wrapped(wrapped) |
2413 | +{ |
2414 | +} |
2415 | + |
2416 | +void TiledDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) |
2417 | +{ |
2418 | + int nextTopLeftPosition = 0; |
2419 | + |
2420 | + m_wrapped->apply_to(conf); |
2421 | + |
2422 | + conf.for_each_output( |
2423 | + [&](mg::UserDisplayConfigurationOutput& output) |
2424 | + { |
2425 | + if (output.connected && output.used) { |
2426 | + output.top_left = mir::geometry::Point{nextTopLeftPosition, 0}; |
2427 | + nextTopLeftPosition += output.modes[output.preferred_mode_index].size.width.as_int(); |
2428 | + } |
2429 | + }); |
2430 | +} |
2431 | |
2432 | === added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.h' |
2433 | --- src/platforms/mirserver/tileddisplayconfigurationpolicy.h 1970-01-01 00:00:00 +0000 |
2434 | +++ src/platforms/mirserver/tileddisplayconfigurationpolicy.h 2015-08-07 12:06:18 +0000 |
2435 | @@ -0,0 +1,35 @@ |
2436 | +/* |
2437 | + * Copyright (C) 2015 Canonical, Ltd. |
2438 | + * |
2439 | + * This program is free software: you can redistribute it and/or modify it under |
2440 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2441 | + * the Free Software Foundation. |
2442 | + * |
2443 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2444 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2445 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2446 | + * Lesser General Public License for more details. |
2447 | + * |
2448 | + * You should have received a copy of the GNU Lesser General Public License |
2449 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2450 | + */ |
2451 | + |
2452 | +#ifndef TILEDDISPLAYCONFIGURATIONPOLICY_H |
2453 | +#define TILEDDISPLAYCONFIGURATIONPOLICY_H |
2454 | + |
2455 | +#include <mir/graphics/display_configuration_policy.h> |
2456 | + |
2457 | +#include <memory> |
2458 | + |
2459 | +class TiledDisplayConfigurationPolicy : public mir::graphics::DisplayConfigurationPolicy |
2460 | +{ |
2461 | +public: |
2462 | + TiledDisplayConfigurationPolicy(const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped); |
2463 | + |
2464 | + void apply_to(mir::graphics::DisplayConfiguration& conf) override; |
2465 | + |
2466 | +private: |
2467 | + const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> m_wrapped; |
2468 | +}; |
2469 | + |
2470 | +#endif // TILEDDISPLAYCONFIGURATIONPOLICY_H |
2471 | |
2472 | === added directory 'tests/common' |
2473 | === added file 'tests/common/fake_displayconfigurationoutput.h' |
2474 | --- tests/common/fake_displayconfigurationoutput.h 1970-01-01 00:00:00 +0000 |
2475 | +++ tests/common/fake_displayconfigurationoutput.h 2015-08-07 12:06:18 +0000 |
2476 | @@ -0,0 +1,73 @@ |
2477 | +/* |
2478 | + * Copyright (C) 2015 Canonical, Ltd. |
2479 | + * |
2480 | + * This program is free software: you can redistribute it and/or modify it under |
2481 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2482 | + * the Free Software Foundation. |
2483 | + * |
2484 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2485 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2486 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2487 | + * Lesser General Public License for more details. |
2488 | + * |
2489 | + * You should have received a copy of the GNU Lesser General Public License |
2490 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2491 | + */ |
2492 | + |
2493 | +#ifndef FAKE_DISPLAYCONFIGURATIONOUTPUT_H |
2494 | +#define FAKE_DISPLAYCONFIGURATIONOUTPUT_H |
2495 | + |
2496 | +#include <mir/graphics/display_configuration.h> |
2497 | + |
2498 | +namespace mg = mir::graphics; |
2499 | +namespace geom = mir::geometry; |
2500 | + |
2501 | +const mg::DisplayConfigurationOutput fakeOutput1 |
2502 | +{ |
2503 | + mg::DisplayConfigurationOutputId{3}, |
2504 | + mg::DisplayConfigurationCardId{2}, |
2505 | + mg::DisplayConfigurationOutputType::dvid, |
2506 | + { |
2507 | + mir_pixel_format_abgr_8888 |
2508 | + }, |
2509 | + { |
2510 | + {geom::Size{100, 200}, 60.0}, |
2511 | + {geom::Size{100, 200}, 59.0}, |
2512 | + {geom::Size{150, 200}, 59.0} |
2513 | + }, |
2514 | + 0, |
2515 | + geom::Size{1111, 2222}, |
2516 | + true, |
2517 | + true, |
2518 | + geom::Point(), |
2519 | + 2, |
2520 | + mir_pixel_format_abgr_8888, |
2521 | + mir_power_mode_on, |
2522 | + mir_orientation_normal |
2523 | +}; |
2524 | + |
2525 | +const mg::DisplayConfigurationOutput fakeOutput2 |
2526 | +{ |
2527 | + mg::DisplayConfigurationOutputId{2}, |
2528 | + mg::DisplayConfigurationCardId{4}, |
2529 | + mg::DisplayConfigurationOutputType::lvds, |
2530 | + { |
2531 | + mir_pixel_format_xbgr_8888 |
2532 | + }, |
2533 | + { |
2534 | + {geom::Size{800, 1200}, 90.0}, |
2535 | + {geom::Size{1600, 2400}, 60.0}, |
2536 | + {geom::Size{1500, 2000}, 75.0} |
2537 | + }, |
2538 | + 0, |
2539 | + geom::Size{1000, 2000}, |
2540 | + true, |
2541 | + true, |
2542 | + geom::Point(500, 600), |
2543 | + 2, |
2544 | + mir_pixel_format_xbgr_8888, |
2545 | + mir_power_mode_on, |
2546 | + mir_orientation_left |
2547 | +}; |
2548 | + |
2549 | +#endif // FAKE_DISPLAYCONFIGURATIONOUTPUT_H |
2550 | |
2551 | === added file 'tests/common/gmock_fixes.h' |
2552 | --- tests/common/gmock_fixes.h 1970-01-01 00:00:00 +0000 |
2553 | +++ tests/common/gmock_fixes.h 2015-08-07 12:06:18 +0000 |
2554 | @@ -0,0 +1,124 @@ |
2555 | +// |
2556 | +// Copyright © 2012 Canonical Ltd. Copyright 2007, Google Inc. |
2557 | +// |
2558 | +// All rights reserved. |
2559 | +// |
2560 | +// Redistribution and use in source and binary forms, with or without |
2561 | +// modification, are permitted provided that the following conditions are |
2562 | +// met: |
2563 | +// |
2564 | +// * Redistributions of source code must retain the above copyright |
2565 | +// notice, this list of conditions and the following disclaimer. |
2566 | +// * Redistributions in binary form must reproduce the above |
2567 | +// copyright notice, this list of conditions and the following disclaimer |
2568 | +// in the documentation and/or other materials provided with the |
2569 | +// distribution. |
2570 | +// * Neither the name of Google Inc. nor the names of its |
2571 | +// contributors may be used to endorse or promote products derived from |
2572 | +// this software without specific prior written permission. |
2573 | +// |
2574 | +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
2575 | +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
2576 | +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
2577 | +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
2578 | +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
2579 | +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
2580 | +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
2581 | +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
2582 | +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
2583 | +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
2584 | +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
2585 | +// |
2586 | +// Author: wan@google.com (Zhanyong Wan) |
2587 | +// Authored by: Alan Griffiths <alan@octopull.co.uk> |
2588 | + |
2589 | +#ifndef MIR_TEST_GMOCK_FIXES_H_ |
2590 | +#define MIR_TEST_GMOCK_FIXES_H_ |
2591 | + |
2592 | +#include <memory> |
2593 | +#include <gmock/gmock.h> |
2594 | + |
2595 | +namespace testing |
2596 | +{ |
2597 | +namespace internal |
2598 | +{ |
2599 | + |
2600 | +template<typename T> |
2601 | +class ActionResultHolder<std::unique_ptr<T>> |
2602 | +: public UntypedActionResultHolderBase { |
2603 | + public: |
2604 | + explicit ActionResultHolder(std::unique_ptr<T>&& a_value) : |
2605 | + value_(std::move(a_value)) {} |
2606 | + |
2607 | + // The compiler-generated copy constructor and assignment operator |
2608 | + // are exactly what we need, so we don't need to define them. |
2609 | + |
2610 | + // Returns the held value and deletes this object. |
2611 | + std::unique_ptr<T> GetValueAndDelete() const { |
2612 | + std::unique_ptr<T> retval(std::move(value_)); |
2613 | + delete this; |
2614 | + return retval; |
2615 | + } |
2616 | + |
2617 | + // Prints the held value as an action's result to os. |
2618 | + virtual void PrintAsActionResult(::std::ostream* os) const { |
2619 | + *os << "\n Returns: "; |
2620 | + // T may be a reference type, so we don't use UniversalPrint(). |
2621 | + UniversalPrinter<std::unique_ptr<T>>::Print(value_, os); |
2622 | + } |
2623 | + |
2624 | + // Performs the given mock function's default action and returns the |
2625 | + // result in a new-ed ActionResultHolder. |
2626 | + template <typename F> |
2627 | + static ActionResultHolder* PerformDefaultAction( |
2628 | + const FunctionMockerBase<F>* func_mocker, |
2629 | + const typename Function<F>::ArgumentTuple& args, |
2630 | + const string& call_description) { |
2631 | + return new ActionResultHolder( |
2632 | + func_mocker->PerformDefaultAction(args, call_description)); |
2633 | + } |
2634 | + |
2635 | + // Performs the given action and returns the result in a new-ed |
2636 | + // ActionResultHolder. |
2637 | + template <typename F> |
2638 | + static ActionResultHolder* |
2639 | + PerformAction(const Action<F>& action, |
2640 | + const typename Function<F>::ArgumentTuple& args) { |
2641 | + return new ActionResultHolder(action.Perform(args)); |
2642 | + } |
2643 | + |
2644 | + private: |
2645 | + std::unique_ptr<T> mutable value_; |
2646 | + |
2647 | + // T could be a reference type, so = isn't supported. |
2648 | + GTEST_DISALLOW_ASSIGN_(ActionResultHolder); |
2649 | +}; |
2650 | + |
2651 | +} |
2652 | + |
2653 | +template<typename T> |
2654 | +class DefaultValue<std::unique_ptr<T>> { |
2655 | + public: |
2656 | + // Unsets the default value for type T. |
2657 | + static void Clear() {} |
2658 | + |
2659 | + // Returns true iff the user has set the default value for type T. |
2660 | + static bool IsSet() { return false; } |
2661 | + |
2662 | + // Returns true if T has a default return value set by the user or there |
2663 | + // exists a built-in default value. |
2664 | + static bool Exists() { |
2665 | + return true; |
2666 | + } |
2667 | + |
2668 | + // Returns the default value for type T if the user has set one; |
2669 | + // otherwise returns the built-in default value if there is one; |
2670 | + // otherwise aborts the process. |
2671 | + static std::unique_ptr<T> Get() { |
2672 | + return std::unique_ptr<T>(); |
2673 | + } |
2674 | +}; |
2675 | + |
2676 | +} |
2677 | + |
2678 | +#endif /* MIR_TEST_GMOCK_FIXES_H_ */ |
2679 | |
2680 | === added file 'tests/common/mock_display.h' |
2681 | --- tests/common/mock_display.h 1970-01-01 00:00:00 +0000 |
2682 | +++ tests/common/mock_display.h 2015-08-07 12:06:18 +0000 |
2683 | @@ -0,0 +1,53 @@ |
2684 | +/* |
2685 | + * Copyright (C) 2015 Canonical, Ltd. |
2686 | + * |
2687 | + * This program is free software: you can redistribute it and/or modify it under |
2688 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2689 | + * the Free Software Foundation. |
2690 | + * |
2691 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2692 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2693 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2694 | + * Lesser General Public License for more details. |
2695 | + * |
2696 | + * You should have received a copy of the GNU Lesser General Public License |
2697 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2698 | + */ |
2699 | + |
2700 | +#ifndef MOCKDISPLAY_H |
2701 | +#define MOCKDISPLAY_H |
2702 | + |
2703 | +#include <mir/graphics/display.h> |
2704 | +#include <mir/graphics/gl_context.h> |
2705 | + |
2706 | +#include <gmock/gmock.h> |
2707 | +#include "gmock_fixes.h" |
2708 | + |
2709 | +class MockDisplaySyncGroup : public mir::graphics::DisplaySyncGroup |
2710 | +{ |
2711 | +public: |
2712 | + MOCK_METHOD1(for_each_display_buffer, void(std::function<void(mir::graphics::DisplayBuffer&)> const& f)); |
2713 | + MOCK_METHOD0(post, void()); |
2714 | +}; |
2715 | + |
2716 | +struct MockDisplay : public mir::graphics::Display |
2717 | +{ |
2718 | +public: |
2719 | + MOCK_METHOD1(for_each_display_sync_group, void(std::function<void(mir::graphics::DisplaySyncGroup&)> const&)); |
2720 | + MOCK_CONST_METHOD0(configuration, std::unique_ptr<mir::graphics::DisplayConfiguration>()); |
2721 | + MOCK_METHOD1(configure, void(mir::graphics::DisplayConfiguration const&)); |
2722 | + MOCK_METHOD2(register_configuration_change_handler, |
2723 | + void(mir::graphics::EventHandlerRegister&, mir::graphics::DisplayConfigurationChangeHandler const&)); |
2724 | + |
2725 | + MOCK_METHOD3(register_pause_resume_handlers, void(mir::graphics::EventHandlerRegister&, |
2726 | + mir::graphics::DisplayPauseHandler const&, |
2727 | + mir::graphics::DisplayResumeHandler const&)); |
2728 | + MOCK_METHOD0(pause, void()); |
2729 | + MOCK_METHOD0(resume, void()); |
2730 | + MOCK_METHOD1(create_hardware_cursor, std::shared_ptr<mir::graphics::Cursor>(std::shared_ptr<mir::graphics::CursorImage> const&)); |
2731 | + MOCK_METHOD0(create_gl_context, std::unique_ptr<mir::graphics::GLContext>()); |
2732 | +}; |
2733 | + |
2734 | + |
2735 | + |
2736 | +#endif // MOCKDISPLAY_H |
2737 | |
2738 | === added file 'tests/common/mock_display_buffer.h' |
2739 | --- tests/common/mock_display_buffer.h 1970-01-01 00:00:00 +0000 |
2740 | +++ tests/common/mock_display_buffer.h 2015-08-07 12:06:18 +0000 |
2741 | @@ -0,0 +1,43 @@ |
2742 | +/* |
2743 | + * Copyright (C) 2015 Canonical, Ltd. |
2744 | + * |
2745 | + * This program is free software: you can redistribute it and/or modify it under |
2746 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2747 | + * the Free Software Foundation. |
2748 | + * |
2749 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2750 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2751 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2752 | + * Lesser General Public License for more details. |
2753 | + * |
2754 | + * You should have received a copy of the GNU Lesser General Public License |
2755 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2756 | + */ |
2757 | + |
2758 | +#ifndef MOCK_DISPLAY_BUFFER_H |
2759 | +#define MOCK_DISPLAY_BUFFER_H |
2760 | + |
2761 | +#include <mir/graphics/display_buffer.h> |
2762 | + |
2763 | +#include <gmock/gmock.h> |
2764 | + |
2765 | +class MockDisplayBuffer : public mir::graphics::DisplayBuffer |
2766 | +{ |
2767 | +public: |
2768 | + MockDisplayBuffer() |
2769 | + { |
2770 | + using namespace testing; |
2771 | + ON_CALL(*this, view_area()) |
2772 | + .WillByDefault(Return(mir::geometry::Rectangle{{0,0},{0,0}})); |
2773 | + } |
2774 | + MOCK_CONST_METHOD0(view_area, mir::geometry::Rectangle()); |
2775 | + MOCK_METHOD0(make_current, void()); |
2776 | + MOCK_METHOD0(release_current, void()); |
2777 | + MOCK_METHOD0(gl_swap_buffers, void()); |
2778 | + MOCK_METHOD1(post_renderables_if_optimizable, bool(mir::graphics::RenderableList const&)); |
2779 | + MOCK_CONST_METHOD0(orientation, MirOrientation()); |
2780 | + MOCK_CONST_METHOD0(uses_alpha, bool()); |
2781 | +}; |
2782 | + |
2783 | + |
2784 | +#endif // MOCK_DISPLAY_BUFFER_H |
2785 | |
2786 | === added file 'tests/common/mock_display_configuration.h' |
2787 | --- tests/common/mock_display_configuration.h 1970-01-01 00:00:00 +0000 |
2788 | +++ tests/common/mock_display_configuration.h 2015-08-07 12:06:18 +0000 |
2789 | @@ -0,0 +1,35 @@ |
2790 | +/* |
2791 | + * Copyright (C) 2015 Canonical, Ltd. |
2792 | + * |
2793 | + * This program is free software: you can redistribute it and/or modify it under |
2794 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2795 | + * the Free Software Foundation. |
2796 | + * |
2797 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2798 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2799 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2800 | + * Lesser General Public License for more details. |
2801 | + * |
2802 | + * You should have received a copy of the GNU Lesser General Public License |
2803 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2804 | + */ |
2805 | + |
2806 | +#ifndef MOCK_DISPLAY_CONFIGURATION_H |
2807 | +#define MOCK_DISPLAY_CONFIGURATION_H |
2808 | + |
2809 | +#include <mir/graphics/display_configuration.h> |
2810 | + |
2811 | +#include <gmock/gmock.h> |
2812 | +#include "gmock_fixes.h" |
2813 | + |
2814 | +class MockDisplayConfiguration : public mir::graphics::DisplayConfiguration |
2815 | +{ |
2816 | +public: |
2817 | + MOCK_CONST_METHOD1(for_each_card, void(std::function<void(mir::graphics::DisplayConfigurationCard const&)>)); |
2818 | + |
2819 | + MOCK_CONST_METHOD1(for_each_output, void(std::function<void(mir::graphics::DisplayConfigurationOutput const&)>)); |
2820 | + MOCK_METHOD1(for_each_output, void(std::function<void(mir::graphics::UserDisplayConfigurationOutput&)>)); |
2821 | + |
2822 | + MOCK_CONST_METHOD0(valid, bool()); |
2823 | +}; |
2824 | +#endif // MOCK_DISPLAY_CONFIGURATION_H |
2825 | |
2826 | === added file 'tests/common/mock_main_loop.h' |
2827 | --- tests/common/mock_main_loop.h 1970-01-01 00:00:00 +0000 |
2828 | +++ tests/common/mock_main_loop.h 2015-08-07 12:06:18 +0000 |
2829 | @@ -0,0 +1,53 @@ |
2830 | +/* |
2831 | + * Copyright (C) 2015 Canonical, Ltd. |
2832 | + * |
2833 | + * This program is free software: you can redistribute it and/or modify it under |
2834 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2835 | + * the Free Software Foundation. |
2836 | + * |
2837 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2838 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2839 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2840 | + * Lesser General Public License for more details. |
2841 | + * |
2842 | + * You should have received a copy of the GNU Lesser General Public License |
2843 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2844 | + */ |
2845 | + |
2846 | +#ifndef MOCKMAINLOOP_H |
2847 | +#define MOCKMAINLOOP_H |
2848 | + |
2849 | +#include <gmock/gmock.h> |
2850 | + |
2851 | +#include <mir/main_loop.h> |
2852 | + |
2853 | +#include <memory> |
2854 | + |
2855 | +class MockMainLoop : public mir::MainLoop |
2856 | +{ |
2857 | +public: |
2858 | + ~MockMainLoop() noexcept {} |
2859 | + |
2860 | + void run() override {} |
2861 | + void stop() override {} |
2862 | + |
2863 | + MOCK_METHOD2(register_signal_handler, |
2864 | + void(std::initializer_list<int>, |
2865 | + std::function<void(int)> const&)); |
2866 | + |
2867 | + MOCK_METHOD3(register_fd_handler, |
2868 | + void(std::initializer_list<int>, void const*, |
2869 | + std::function<void(int)> const&)); |
2870 | + |
2871 | + MOCK_METHOD1(unregister_fd_handler, void(void const*)); |
2872 | + |
2873 | + MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&)); |
2874 | + MOCK_METHOD1(pause_processing_for,void (void const*)); |
2875 | + MOCK_METHOD1(resume_processing_for,void (void const*)); |
2876 | + |
2877 | + MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::function<void()> const& callback)); |
2878 | + MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::shared_ptr<mir::LockableCallback> const& callback)); |
2879 | +}; |
2880 | + |
2881 | + |
2882 | +#endif // MOCKMAINLOOP_H |
2883 | |
2884 | === modified file 'tests/mirserver/CMakeLists.txt' |
2885 | --- tests/mirserver/CMakeLists.txt 2014-11-13 15:47:30 +0000 |
2886 | +++ tests/mirserver/CMakeLists.txt 2015-08-07 12:06:18 +0000 |
2887 | @@ -1,3 +1,4 @@ |
2888 | add_subdirectory(QtEventFeeder) |
2889 | add_subdirectory(Clipboard) |
2890 | add_subdirectory(Screen) |
2891 | +add_subdirectory(ScreenController) |
2892 | |
2893 | === modified file 'tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h' |
2894 | --- tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-04-01 15:02:36 +0000 |
2895 | +++ tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-08-07 12:06:18 +0000 |
2896 | @@ -19,22 +19,29 @@ |
2897 | #define MOCK_QTWINDOWSYSTEM_H |
2898 | |
2899 | #include <qteventfeeder.h> |
2900 | +#include <QWindow> |
2901 | |
2902 | class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface { |
2903 | public: |
2904 | - MOCK_METHOD0(hasTargetWindow, bool()); |
2905 | - MOCK_METHOD0(targetWindowGeometry, QRect()); |
2906 | + MOCK_CONST_METHOD0(ready, bool()); |
2907 | + MOCK_METHOD1(setScreenController, void(const QSharedPointer<ScreenController> &)); |
2908 | + MOCK_METHOD1(getWindowForTouchPoint, QWindow*(const QPoint &point)); |
2909 | + MOCK_METHOD0(lastWindow, QWindow*()); |
2910 | + MOCK_METHOD0(focusedWindow, QWindow*()); |
2911 | MOCK_METHOD1(registerTouchDevice, void(QTouchDevice* device)); |
2912 | - MOCK_METHOD10(handleExtendedKeyEvent, void(ulong timestamp, QEvent::Type type, int key, |
2913 | - Qt::KeyboardModifiers modifiers, |
2914 | - quint32 nativeScanCode, quint32 nativeVirtualKey, |
2915 | - quint32 nativeModifiers, |
2916 | - const QString& text, bool autorep, |
2917 | - ushort count)); |
2918 | - MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device, |
2919 | + |
2920 | + // Wanted to use GMock, but MOCK_METHOD11 not implemented |
2921 | + void handleExtendedKeyEvent(QWindow */*window*/, ulong /*timestamp*/, QEvent::Type /*type*/, int /*key*/, |
2922 | + Qt::KeyboardModifiers /*modifiers*/, |
2923 | + quint32 /*nativeScanCode*/, quint32 /*nativeVirtualKey*/, |
2924 | + quint32 /*nativeModifiers*/, |
2925 | + const QString& /*text*/ = QString(), bool /*autorep*/ = false, |
2926 | + ushort /*count*/ = 1) {} |
2927 | + |
2928 | + MOCK_METHOD5(handleTouchEvent, void(QWindow *window, ulong timestamp, QTouchDevice *device, |
2929 | const QList<struct QWindowSystemInterface::TouchPoint> &points, |
2930 | Qt::KeyboardModifiers mods)); |
2931 | - MOCK_METHOD4(handleMouseEvent, void(ulong, QPointF, Qt::MouseButton, Qt::KeyboardModifiers)); |
2932 | + MOCK_METHOD5(handleMouseEvent, void(QWindow *window, ulong, QPointF, Qt::MouseButton, Qt::KeyboardModifiers)); |
2933 | }; |
2934 | |
2935 | namespace testing |
2936 | |
2937 | === modified file 'tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp' |
2938 | --- tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-06-24 23:08:44 +0000 |
2939 | +++ tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-08-07 12:06:18 +0000 |
2940 | @@ -70,33 +70,44 @@ |
2941 | |
2942 | MockQtWindowSystem *mockWindowSystem; |
2943 | QtEventFeeder *qtEventFeeder; |
2944 | + QWindow *window; |
2945 | + QGuiApplication *app; |
2946 | }; |
2947 | |
2948 | void QtEventFeederTest::SetUp() |
2949 | { |
2950 | mockWindowSystem = new MockQtWindowSystem; |
2951 | + auto screens = QSharedPointer<ScreenController>(); |
2952 | |
2953 | EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_)); |
2954 | |
2955 | - qtEventFeeder = new QtEventFeeder(mockWindowSystem); |
2956 | + qtEventFeeder = new QtEventFeeder(screens, mockWindowSystem); |
2957 | |
2958 | ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem)); |
2959 | + |
2960 | + int argc = 0; |
2961 | + char **argv = nullptr; |
2962 | + setenv("QT_QPA_PLATFORM", "minimal", 1); |
2963 | + app = new QGuiApplication(argc, argv); |
2964 | + window = new QWindow; |
2965 | } |
2966 | |
2967 | void QtEventFeederTest::TearDown() |
2968 | { |
2969 | // mockWindowSystem will be deleted by QtEventFeeder |
2970 | delete qtEventFeeder; |
2971 | + delete window; |
2972 | + delete app; |
2973 | } |
2974 | |
2975 | void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations() |
2976 | { |
2977 | - EXPECT_CALL(*mockWindowSystem, hasTargetWindow()) |
2978 | - .Times(AnyNumber()) |
2979 | - .WillRepeatedly(Return(true)); |
2980 | - EXPECT_CALL(*mockWindowSystem, targetWindowGeometry()) |
2981 | - .Times(AnyNumber()) |
2982 | - .WillRepeatedly(Return(QRect(0,0,100,100))); |
2983 | + EXPECT_CALL(*mockWindowSystem, getWindowForTouchPoint(_)) |
2984 | + .Times(AnyNumber()) |
2985 | + .WillRepeatedly(Return(window)); |
2986 | + EXPECT_CALL(*mockWindowSystem, focusedWindow()) |
2987 | + .Times(AnyNumber()) |
2988 | + .WillRepeatedly(Return(window)); |
2989 | } |
2990 | |
2991 | |
2992 | @@ -114,7 +125,7 @@ |
2993 | |
2994 | setIrrelevantMockWindowSystemExpectations(); |
2995 | |
2996 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
2997 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
2998 | Contains(AllOf(HasId(0), |
2999 | IsPressed()))),_)).Times(1); |
3000 | |
3001 | @@ -133,12 +144,12 @@ |
3002 | InSequence sequence; |
3003 | |
3004 | EXPECT_CALL(*mockWindowSystem, |
3005 | - handleTouchEvent(_,_,AllOf(SizeIs(1), |
3006 | + handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3007 | Contains(AllOf(HasId(0),IsReleased())) |
3008 | ),_)).Times(1); |
3009 | |
3010 | EXPECT_CALL(*mockWindowSystem, |
3011 | - handleTouchEvent(_,_,AllOf(SizeIs(1), |
3012 | + handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3013 | Contains(AllOf(HasId(1),IsPressed())) |
3014 | ),_)).Times(1); |
3015 | } |
3016 | @@ -162,7 +173,7 @@ |
3017 | 10, 10, 10 /* x, y, pressure*/, |
3018 | 1, 1, 10 /* touch major, minor, size */); |
3019 | |
3020 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
3021 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3022 | Contains(AllOf(HasId(0), |
3023 | IsPressed()))),_)).Times(1); |
3024 | qtEventFeeder->dispatch(*ev1); |
3025 | @@ -182,7 +193,7 @@ |
3026 | 1, 1, 10 /* touch major, minor, size */); |
3027 | |
3028 | EXPECT_CALL(*mockWindowSystem, |
3029 | - handleTouchEvent(_,_,AllOf(SizeIs(2), |
3030 | + handleTouchEvent(_,_,_,AllOf(SizeIs(2), |
3031 | Contains(AllOf(HasId(0), StateIsMoved())), |
3032 | Contains(AllOf(HasId(1), IsPressed())) |
3033 | ),_)).Times(1); |
3034 | @@ -209,14 +220,14 @@ |
3035 | |
3036 | // first release touch 0 |
3037 | EXPECT_CALL(*mockWindowSystem, |
3038 | - handleTouchEvent(_,_,AllOf(SizeIs(2), |
3039 | + handleTouchEvent(_,_,_,AllOf(SizeIs(2), |
3040 | Contains(AllOf(HasId(0), IsReleased())), |
3041 | Contains(AllOf(HasId(1), IsStationary())) |
3042 | ),_)).Times(1); |
3043 | |
3044 | // then press touch 2 |
3045 | EXPECT_CALL(*mockWindowSystem, |
3046 | - handleTouchEvent(_,_,AllOf(SizeIs(2), |
3047 | + handleTouchEvent(_,_,_,AllOf(SizeIs(2), |
3048 | Contains(AllOf(HasId(1), StateIsMoved())), |
3049 | Contains(AllOf(HasId(2), IsPressed())) |
3050 | ),_)).Times(1); |
3051 | @@ -231,7 +242,7 @@ |
3052 | { |
3053 | setIrrelevantMockWindowSystemExpectations(); |
3054 | |
3055 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
3056 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3057 | Contains(AllOf(HasId(0), |
3058 | IsPressed()))),_)).Times(1); |
3059 | |
3060 | @@ -244,7 +255,7 @@ |
3061 | |
3062 | setIrrelevantMockWindowSystemExpectations(); |
3063 | |
3064 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
3065 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3066 | Contains(AllOf(HasId(0), StateIsMoved())) |
3067 | ),_)).Times(1); |
3068 | |
3069 | |
3070 | === modified file 'tests/mirserver/Screen/CMakeLists.txt' |
3071 | --- tests/mirserver/Screen/CMakeLists.txt 2014-12-03 08:56:35 +0000 |
3072 | +++ tests/mirserver/Screen/CMakeLists.txt 2015-08-07 12:06:18 +0000 |
3073 | @@ -5,6 +5,7 @@ |
3074 | ) |
3075 | |
3076 | include_directories( |
3077 | + ${CMAKE_SOURCE_DIR}/tests/common |
3078 | ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
3079 | ${CMAKE_SOURCE_DIR}/src/common |
3080 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
3081 | |
3082 | === modified file 'tests/mirserver/Screen/screen_test.cpp' |
3083 | --- tests/mirserver/Screen/screen_test.cpp 2015-03-05 16:23:47 +0000 |
3084 | +++ tests/mirserver/Screen/screen_test.cpp 2015-08-07 12:06:18 +0000 |
3085 | @@ -19,37 +19,21 @@ |
3086 | #include <gtest/gtest.h> |
3087 | |
3088 | #include "mir/graphics/display_configuration.h" |
3089 | +#include "fake_displayconfigurationoutput.h" |
3090 | |
3091 | #include <screen.h> |
3092 | |
3093 | +using namespace ::testing; |
3094 | + |
3095 | namespace mg = mir::graphics; |
3096 | namespace geom = mir::geometry; |
3097 | |
3098 | -mg::DisplayConfigurationOutput const fake_output |
3099 | -{ |
3100 | - mg::DisplayConfigurationOutputId{3}, |
3101 | - mg::DisplayConfigurationCardId{2}, |
3102 | - mg::DisplayConfigurationOutputType::dvid, |
3103 | - { |
3104 | - mir_pixel_format_abgr_8888 |
3105 | - }, |
3106 | - { |
3107 | - {geom::Size{10, 20}, 60.0}, |
3108 | - {geom::Size{10, 20}, 59.0}, |
3109 | - {geom::Size{15, 20}, 59.0} |
3110 | - }, |
3111 | - 0, |
3112 | - geom::Size{10, 20}, |
3113 | - true, |
3114 | - true, |
3115 | - geom::Point(), |
3116 | - 2, |
3117 | - mir_pixel_format_abgr_8888, |
3118 | - mir_power_mode_on, |
3119 | - mir_orientation_normal |
3120 | +class ScreenTest : public ::testing::Test { |
3121 | +protected: |
3122 | + void SetUp() override; |
3123 | }; |
3124 | |
3125 | -TEST(ScreenTest, OrientationSensor) |
3126 | +void ScreenTest::SetUp() |
3127 | { |
3128 | if (!qEnvironmentVariableIsSet("QT_ACCEL_FILEPATH")) { |
3129 | // Trick Qt >= 5.4.1 to load the generic sensors |
3130 | @@ -57,7 +41,11 @@ |
3131 | } |
3132 | |
3133 | Screen::skipDBusRegistration = true; |
3134 | - Screen *screen = new Screen(fake_output); |
3135 | +} |
3136 | + |
3137 | +TEST_F(ScreenTest, OrientationSensor) |
3138 | +{ |
3139 | + Screen *screen = new Screen(fakeOutput1); |
3140 | |
3141 | // Default state should be active |
3142 | ASSERT_TRUE(screen->orientationSensorEnabled()); |
3143 | @@ -68,3 +56,29 @@ |
3144 | screen->onDisplayPowerStateChanged(1,0); |
3145 | ASSERT_TRUE(screen->orientationSensorEnabled()); |
3146 | } |
3147 | + |
3148 | +TEST_F(ScreenTest, ReadConfigurationFromDisplayConfig) |
3149 | +{ |
3150 | + Screen *screen = new Screen(fakeOutput1); |
3151 | + |
3152 | + EXPECT_EQ(screen->geometry(), QRect(0, 0, 150, 200)); |
3153 | + EXPECT_EQ(screen->availableGeometry(), QRect(0, 0, 150, 200)); |
3154 | + EXPECT_EQ(screen->depth(), 32); |
3155 | + EXPECT_EQ(screen->format(), QImage::Format_RGBA8888); |
3156 | + EXPECT_EQ(screen->refreshRate(), 59); |
3157 | + EXPECT_EQ(screen->physicalSize(), QSize(1111, 2222)); |
3158 | + EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::dvid); |
3159 | +} |
3160 | + |
3161 | +TEST_F(ScreenTest, ReadDifferentConfigurationFromDisplayConfig) |
3162 | +{ |
3163 | + Screen *screen = new Screen(fakeOutput2); |
3164 | + |
3165 | + EXPECT_EQ(screen->geometry(), QRect(500, 600, 1500, 2000)); |
3166 | + EXPECT_EQ(screen->availableGeometry(), QRect(500, 600, 1500, 2000)); |
3167 | + EXPECT_EQ(screen->depth(), 32); |
3168 | + EXPECT_EQ(screen->format(), QImage::Format_RGBX8888); |
3169 | + EXPECT_EQ(screen->refreshRate(), 75); |
3170 | + EXPECT_EQ(screen->physicalSize(), QSize(1000, 2000)); |
3171 | + EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::lvds); |
3172 | +} |
3173 | |
3174 | === added directory 'tests/mirserver/ScreenController' |
3175 | === added file 'tests/mirserver/ScreenController/CMakeLists.txt' |
3176 | --- tests/mirserver/ScreenController/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
3177 | +++ tests/mirserver/ScreenController/CMakeLists.txt 2015-08-07 12:06:18 +0000 |
3178 | @@ -0,0 +1,28 @@ |
3179 | +set( |
3180 | + SCREENCONTROLLER_TEST_SOURCES |
3181 | + screencontroller_test.cpp |
3182 | + ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
3183 | + # to be moc-ed |
3184 | + stub_screen.h |
3185 | + testable_screencontroller.h |
3186 | +) |
3187 | + |
3188 | +include_directories( |
3189 | + ${CMAKE_SOURCE_DIR}/tests/common |
3190 | + ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
3191 | + ${CMAKE_SOURCE_DIR}/src/common |
3192 | + ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
3193 | + ${MIRSERVER_INCLUDE_DIRS} |
3194 | +) |
3195 | + |
3196 | +add_executable(ScreenControllerTest ${SCREENCONTROLLER_TEST_SOURCES}) |
3197 | + |
3198 | +target_link_libraries( |
3199 | + ScreenControllerTest |
3200 | + qpa-mirserver |
3201 | + |
3202 | + ${GTEST_BOTH_LIBRARIES} |
3203 | + ${GMOCK_LIBRARIES} |
3204 | +) |
3205 | + |
3206 | +add_test(ScreenController, ScreenControllerTest) |
3207 | |
3208 | === added file 'tests/mirserver/ScreenController/screencontroller_test.cpp' |
3209 | --- tests/mirserver/ScreenController/screencontroller_test.cpp 1970-01-01 00:00:00 +0000 |
3210 | +++ tests/mirserver/ScreenController/screencontroller_test.cpp 2015-08-07 12:06:18 +0000 |
3211 | @@ -0,0 +1,193 @@ |
3212 | +/* |
3213 | + * Copyright (C) 2015 Canonical, Ltd. |
3214 | + * |
3215 | + * This program is free software: you can redistribute it and/or modify it under |
3216 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3217 | + * the Free Software Foundation. |
3218 | + * |
3219 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3220 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3221 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3222 | + * Lesser General Public License for more details. |
3223 | + * |
3224 | + * You should have received a copy of the GNU Lesser General Public License |
3225 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3226 | + */ |
3227 | + |
3228 | +#include <gtest/gtest.h> |
3229 | +#include "gmock_fixes.h" |
3230 | + |
3231 | +#include "stub_display.h" |
3232 | +#include "mock_main_loop.h" |
3233 | +#include "qtcompositor.h" |
3234 | +#include "fake_displayconfigurationoutput.h" |
3235 | + |
3236 | +#include "testable_screencontroller.h" |
3237 | +#include "screen.h" |
3238 | +#include "screenwindow.h" |
3239 | + |
3240 | +#include <QGuiApplication> |
3241 | + |
3242 | +using namespace ::testing; |
3243 | + |
3244 | +namespace mg = mir::graphics; |
3245 | +namespace geom = mir::geometry; |
3246 | + |
3247 | +class ScreenControllerTest : public ::testing::Test { |
3248 | +protected: |
3249 | + void SetUp() override; |
3250 | + void TearDown() override; |
3251 | + |
3252 | + ScreenController *screenController; |
3253 | + std::shared_ptr<StubDisplay> display; |
3254 | + std::shared_ptr<QtCompositor> compositor; |
3255 | + QGuiApplication *app; |
3256 | +}; |
3257 | + |
3258 | +void ScreenControllerTest::SetUp() |
3259 | +{ |
3260 | + setenv("QT_QPA_PLATFORM", "minimal", 1); |
3261 | + Screen::skipDBusRegistration = true; |
3262 | + |
3263 | + screenController = new TestableScreenController; |
3264 | + display = std::make_shared<StubDisplay>(); |
3265 | + compositor = std::make_shared<QtCompositor>(); |
3266 | + auto mainLoop = std::make_shared<MockMainLoop>(); |
3267 | + |
3268 | + EXPECT_CALL(*display, register_configuration_change_handler(_,_)) |
3269 | + .Times(1); |
3270 | + |
3271 | + static_cast<TestableScreenController*>(screenController)->do_init(display, compositor, mainLoop); |
3272 | + |
3273 | + int argc = 0; |
3274 | + char **argv = nullptr; |
3275 | + setenv("QT_QPA_PLATFORM", "minimal", 1); |
3276 | + app = new QGuiApplication(argc, argv); |
3277 | +} |
3278 | + |
3279 | +void ScreenControllerTest::TearDown() |
3280 | +{ |
3281 | + delete screenController; |
3282 | +} |
3283 | + |
3284 | +TEST_F(ScreenControllerTest, SingleScreenFound) |
3285 | +{ |
3286 | + // Set up display state |
3287 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1}; |
3288 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
3289 | + display->setFakeConfiguration(config, bufferConfig); |
3290 | + |
3291 | + screenController->update(); |
3292 | + |
3293 | + ASSERT_EQ(1, screenController->screens().count()); |
3294 | + Screen* screen = screenController->screens().first(); |
3295 | + EXPECT_EQ(QRect(0, 0, 150, 200), screen->geometry()); |
3296 | +} |
3297 | + |
3298 | +TEST_F(ScreenControllerTest, MultipleScreenFound) |
3299 | +{ |
3300 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2}; |
3301 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
3302 | + display->setFakeConfiguration(config, bufferConfig); |
3303 | + |
3304 | + screenController->update(); |
3305 | + |
3306 | + ASSERT_EQ(2, screenController->screens().count()); |
3307 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry()); |
3308 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry()); |
3309 | +} |
3310 | + |
3311 | +TEST_F(ScreenControllerTest, ScreenAdded) |
3312 | +{ |
3313 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1}; |
3314 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
3315 | + display->setFakeConfiguration(config, bufferConfig); |
3316 | + |
3317 | + screenController->update(); |
3318 | + |
3319 | + config.push_back(fakeOutput2); |
3320 | + display->setFakeConfiguration(config, bufferConfig); |
3321 | + |
3322 | + ASSERT_EQ(1, screenController->screens().count()); |
3323 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry()); |
3324 | + |
3325 | + screenController->update(); |
3326 | + |
3327 | + ASSERT_EQ(2, screenController->screens().count()); |
3328 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry()); |
3329 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry()); |
3330 | +} |
3331 | + |
3332 | +TEST_F(ScreenControllerTest, ScreenRemoved) |
3333 | +{ |
3334 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput2, fakeOutput1}; |
3335 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
3336 | + display->setFakeConfiguration(config, bufferConfig); |
3337 | + |
3338 | + screenController->update(); |
3339 | + |
3340 | + config.pop_back(); |
3341 | + display->setFakeConfiguration(config, bufferConfig); |
3342 | + |
3343 | + ASSERT_EQ(2, screenController->screens().count()); |
3344 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry()); |
3345 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(1)->geometry()); |
3346 | + |
3347 | + screenController->update(); |
3348 | + |
3349 | + ASSERT_EQ(1, screenController->screens().count()); |
3350 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry()); |
3351 | +} |
3352 | + |
3353 | +TEST_F(ScreenControllerTest, CheckPrioritizedGetUnusedScreen) |
3354 | +{ |
3355 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput2, fakeOutput1}; |
3356 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
3357 | + display->setFakeConfiguration(config, bufferConfig); |
3358 | + |
3359 | + screenController->update(); |
3360 | + |
3361 | + auto screen = screenController->getUnusedScreen(); |
3362 | + EXPECT_EQ(mg::DisplayConfigurationOutputType::lvds, screen->outputType()); |
3363 | +} |
3364 | + |
3365 | +TEST_F(ScreenControllerTest, MatchBufferWithDisplay) |
3366 | +{ |
3367 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1}; |
3368 | + MockDisplayBuffer buffer1; |
3369 | + std::vector<MockDisplayBuffer*> buffers {&buffer1}; |
3370 | + |
3371 | + geom::Rectangle buffer1Geom{{0, 0}, {150, 200}}; |
3372 | + EXPECT_CALL(buffer1, view_area()) |
3373 | + .WillRepeatedly(Return(buffer1Geom)); |
3374 | + |
3375 | + display->setFakeConfiguration(config, buffers); |
3376 | + screenController->update(); |
3377 | + |
3378 | + ASSERT_EQ(1, screenController->screens().count()); |
3379 | + EXPECT_CALL(buffer1, make_current()); |
3380 | + static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent(); |
3381 | +} |
3382 | + |
3383 | +TEST_F(ScreenControllerTest, MultipleMatchBuffersWithDisplays) |
3384 | +{ |
3385 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2}; |
3386 | + MockDisplayBuffer buffer1, buffer2; |
3387 | + std::vector<MockDisplayBuffer*> buffers {&buffer1, &buffer2}; |
3388 | + |
3389 | + geom::Rectangle buffer1Geom{{500, 600}, {1500, 2000}}; |
3390 | + geom::Rectangle buffer2Geom{{0, 0}, {150, 200}}; |
3391 | + EXPECT_CALL(buffer1, view_area()) |
3392 | + .WillRepeatedly(Return(buffer1Geom)); |
3393 | + EXPECT_CALL(buffer2, view_area()) |
3394 | + .WillRepeatedly(Return(buffer2Geom)); |
3395 | + |
3396 | + display->setFakeConfiguration(config, buffers); |
3397 | + screenController->update(); |
3398 | + |
3399 | + ASSERT_EQ(2, screenController->screens().count()); |
3400 | + EXPECT_CALL(buffer1, make_current()); |
3401 | + EXPECT_CALL(buffer2, make_current()); |
3402 | + static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent(); |
3403 | + static_cast<StubScreen*>(screenController->screens().at(1))->makeCurrent(); |
3404 | +} |
3405 | |
3406 | === added file 'tests/mirserver/ScreenController/stub_display.h' |
3407 | --- tests/mirserver/ScreenController/stub_display.h 1970-01-01 00:00:00 +0000 |
3408 | +++ tests/mirserver/ScreenController/stub_display.h 2015-08-07 12:06:18 +0000 |
3409 | @@ -0,0 +1,91 @@ |
3410 | +/* |
3411 | + * Copyright (C) 2015 Canonical, Ltd. |
3412 | + * |
3413 | + * This program is free software: you can redistribute it and/or modify it under |
3414 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3415 | + * the Free Software Foundation. |
3416 | + * |
3417 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3418 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3419 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3420 | + * Lesser General Public License for more details. |
3421 | + * |
3422 | + * You should have received a copy of the GNU Lesser General Public License |
3423 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3424 | + */ |
3425 | + |
3426 | +#ifndef STUB_DISPLAY_H |
3427 | +#define STUB_DISPLAY_H |
3428 | + |
3429 | +#include "mock_display.h" |
3430 | +#include "mock_display_buffer.h" |
3431 | +#include "mock_display_configuration.h" |
3432 | + |
3433 | +namespace mg = mir::graphics; |
3434 | +namespace geom = mir::geometry; |
3435 | + |
3436 | +class StubDisplayConfiguration : public MockDisplayConfiguration |
3437 | +{ |
3438 | +public: |
3439 | + StubDisplayConfiguration(const std::vector<mg::DisplayConfigurationOutput> &config) |
3440 | + : m_config(config) |
3441 | + {} |
3442 | + |
3443 | + void for_each_output(std::function<void(mg::DisplayConfigurationOutput const&)> f) const override |
3444 | + { |
3445 | + for (auto config : m_config) { |
3446 | + f(config); |
3447 | + } |
3448 | + } |
3449 | + |
3450 | +private: |
3451 | + const std::vector<mg::DisplayConfigurationOutput> m_config; |
3452 | +}; |
3453 | + |
3454 | + |
3455 | +class StubDisplaySyncGroup : public MockDisplaySyncGroup |
3456 | +{ |
3457 | +public: |
3458 | + StubDisplaySyncGroup(MockDisplayBuffer *buffer) : buffer(buffer) {} |
3459 | + |
3460 | + void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override |
3461 | + { |
3462 | + f(*buffer); |
3463 | + } |
3464 | +private: |
3465 | + MockDisplayBuffer *buffer; |
3466 | +}; |
3467 | + |
3468 | + |
3469 | +class StubDisplay : public MockDisplay |
3470 | +{ |
3471 | +public: |
3472 | + // Note, GMock cannot mock functions which return non-copyable objects, so stubbing needed |
3473 | + std::unique_ptr<mg::DisplayConfiguration> configuration() const override |
3474 | + { |
3475 | + return std::unique_ptr<mg::DisplayConfiguration>( |
3476 | + new StubDisplayConfiguration(m_config) |
3477 | + ); |
3478 | + } |
3479 | + |
3480 | + void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override |
3481 | + { |
3482 | + for (auto displayBuffer : m_displayBuffers) { |
3483 | + StubDisplaySyncGroup b(displayBuffer); |
3484 | + f(b); |
3485 | + } |
3486 | + } |
3487 | + |
3488 | + void setFakeConfiguration(std::vector<mg::DisplayConfigurationOutput> &config, |
3489 | + std::vector<MockDisplayBuffer*> &displayBuffers) |
3490 | + { |
3491 | + m_config = config; |
3492 | + m_displayBuffers = displayBuffers; |
3493 | + } |
3494 | + |
3495 | +private: |
3496 | + std::vector<mg::DisplayConfigurationOutput> m_config; |
3497 | + std::vector<MockDisplayBuffer*> m_displayBuffers; |
3498 | +}; |
3499 | + |
3500 | +#endif // STUB_DISPLAY_H |
3501 | |
3502 | === added file 'tests/mirserver/ScreenController/stub_screen.h' |
3503 | --- tests/mirserver/ScreenController/stub_screen.h 1970-01-01 00:00:00 +0000 |
3504 | +++ tests/mirserver/ScreenController/stub_screen.h 2015-08-07 12:06:18 +0000 |
3505 | @@ -0,0 +1,31 @@ |
3506 | +/* |
3507 | + * Copyright (C) 2015 Canonical, Ltd. |
3508 | + * |
3509 | + * This program is free software: you can redistribute it and/or modify it under |
3510 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3511 | + * the Free Software Foundation. |
3512 | + * |
3513 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3514 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3515 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3516 | + * Lesser General Public License for more details. |
3517 | + * |
3518 | + * You should have received a copy of the GNU Lesser General Public License |
3519 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3520 | + */ |
3521 | + |
3522 | +#ifndef STUBSCREEN_H |
3523 | +#define STUBSCREEN_H |
3524 | + |
3525 | +#include "screen.h" |
3526 | + |
3527 | +class StubScreen : public Screen |
3528 | +{ |
3529 | + Q_OBJECT |
3530 | +public: |
3531 | + StubScreen(const mir::graphics::DisplayConfigurationOutput &output) : Screen(output) {} |
3532 | + |
3533 | + void makeCurrent() { Screen::makeCurrent(); } |
3534 | +}; |
3535 | + |
3536 | +#endif // STUBSCREEN_H |
3537 | |
3538 | === added file 'tests/mirserver/ScreenController/testable_screencontroller.h' |
3539 | --- tests/mirserver/ScreenController/testable_screencontroller.h 1970-01-01 00:00:00 +0000 |
3540 | +++ tests/mirserver/ScreenController/testable_screencontroller.h 2015-08-07 12:06:18 +0000 |
3541 | @@ -0,0 +1,38 @@ |
3542 | +/* |
3543 | + * Copyright (C) 2015 Canonical, Ltd. |
3544 | + * |
3545 | + * This program is free software: you can redistribute it and/or modify it under |
3546 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3547 | + * the Free Software Foundation. |
3548 | + * |
3549 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3550 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3551 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3552 | + * Lesser General Public License for more details. |
3553 | + * |
3554 | + * You should have received a copy of the GNU Lesser General Public License |
3555 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3556 | + */ |
3557 | + |
3558 | +#include "screencontroller.h" |
3559 | +#include "stub_screen.h" |
3560 | + |
3561 | +struct TestableScreenController : public ScreenController |
3562 | +{ |
3563 | + Q_OBJECT |
3564 | + |
3565 | +public: |
3566 | + Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const override |
3567 | + { |
3568 | + return new StubScreen(output); |
3569 | + } |
3570 | + |
3571 | + void do_init(const std::shared_ptr<mir::graphics::Display> &display, |
3572 | + const std::shared_ptr<mir::compositor::Compositor> &compositor, |
3573 | + const std::shared_ptr<mir::MainLoop> &mainLoop) |
3574 | + { |
3575 | + init(display, compositor, mainLoop); |
3576 | + } |
3577 | + |
3578 | + void do_terminate() { terminate(); } |
3579 | +}; |
3580 | |
3581 | === modified file 'tests/modules/common/qtmir_test.h' |
3582 | --- tests/modules/common/qtmir_test.h 2015-03-24 23:38:33 +0000 |
3583 | +++ tests/modules/common/qtmir_test.h 2015-08-07 12:06:18 +0000 |
3584 | @@ -68,7 +68,7 @@ |
3585 | { |
3586 | public: |
3587 | FakeMirServer() |
3588 | - : MirServer(0, nullptr) |
3589 | + : MirServer(0, nullptr, QSharedPointer<ScreenController>()) |
3590 | { |
3591 | } |
3592 |
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.