Merge lp:~dandrader/qtmir/mousePointer into lp:qtmir
- mousePointer
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~dandrader/qtmir/mousePointer |
Merge into: | lp:qtmir |
Diff against target: |
4388 lines (+2662/-538) 63 files modified
CMakeLists.txt (+1/-1) debian/control (+1/-1) demos/qml-demo-shell/ResizeArea.qml (+128/-0) demos/qml-demo-shell/Shell.qml (+21/-1) demos/qml-demo-shell/TitleBar.qml (+4/-1) demos/qml-demo-shell/Window.qml (+4/-81) demos/qml-demo-shell/qml-demo-shell.qml (+19/-0) src/modules/Unity/Application/CMakeLists.txt (+0/-1) src/modules/Unity/Application/plugin.cpp (+8/-1) src/modules/Unity/CMakeLists.txt (+1/-0) src/modules/Unity/Screens/CMakeLists.txt (+24/-0) src/modules/Unity/Screens/plugin.cpp (+41/-0) src/modules/Unity/Screens/qmldir (+2/-0) src/modules/Unity/Screens/screens.cpp (+107/-0) src/modules/Unity/Screens/screens.h (+82/-0) src/platforms/mirserver/CMakeLists.txt (+10/-3) src/platforms/mirserver/cursor.cpp (+152/-0) src/platforms/mirserver/cursor.h (+66/-0) src/platforms/mirserver/display.cpp (+0/-44) src/platforms/mirserver/display.h (+0/-37) src/platforms/mirserver/logging.h (+1/-0) src/platforms/mirserver/miropenglcontext.cpp (+28/-11) src/platforms/mirserver/miropenglcontext.h (+5/-0) src/platforms/mirserver/mirserver.cpp (+38/-4) src/platforms/mirserver/mirserver.h (+8/-2) src/platforms/mirserver/mirserverintegration.cpp (+51/-40) src/platforms/mirserver/mirserverintegration.h (+4/-7) src/platforms/mirserver/mirsingleton.cpp (+33/-0) src/platforms/mirserver/mirsingleton.h (+45/-0) 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 (+9/-34) src/platforms/mirserver/qtcompositor.h (+13/-5) src/platforms/mirserver/qteventfeeder.cpp (+116/-89) src/platforms/mirserver/qteventfeeder.h (+13/-9) src/platforms/mirserver/screen.cpp (+104/-7) src/platforms/mirserver/screen.h (+36/-4) src/platforms/mirserver/screencontroller.cpp (+257/-0) src/platforms/mirserver/screencontroller.h (+97/-0) src/platforms/mirserver/screenwindow.cpp (+68/-80) src/platforms/mirserver/screenwindow.h (+13/-23) 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 (+16/-9) 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 (+192/-0) tests/mirserver/ScreenController/stub_display.h (+99/-0) tests/mirserver/ScreenController/stub_screen.h (+31/-0) tests/mirserver/ScreenController/testable_screencontroller.h (+37/-0) tests/modules/common/qtmir_test.h (+1/-1) |
To merge this branch: | bzr merge lp:~dandrader/qtmir/mousePointer |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gerry Boland (community) | Needs Fixing | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Review via email: mp+269787@code.launchpad.net |
This proposal has been superseded by a proposal from 2015-09-09.
Commit message
Shell draws its own cursor using the new Cursor QML element
Description of the change
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
https:/
Needs lp:~dandrader/mir/0.14+mouse or Mir 0.15 (not yet released in vivid+overlay)
* Did you perform an exploratory manual test run of your code change and any related functionality?
Not applicable.
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Not applicable.
PS Jenkins bot (ps-jenkins) wrote : | # |
Gerry Boland (gerboland) wrote : | # |
=== added file 'src/modules/
=== added file 'src/modules/
I'm beginning to wonder if most of this code needs to live in qtmir at all. Since Unity8 draws it, why does QtMir need to do this work to find the image for it?
I also don't think it's QtMir's job to know anything about cursor themes.
Why doesn't QtMir just inform the shell of:
1. the position the cursor should be located at
2. the name of the desired cursor
Then unity8 can find the themed cursor image, figure out the hotspot and draw the cursor itself.
Gerry Boland (gerboland) wrote : | # |
=== added file 'demos/
I like your code, neat and clean as always. But if I was writing this, I would have a single MouseArea behind the surface, instead of 8. It's ok for a demo, but that's a lot for a real shell.
Daniel d'Andrada (dandrader) wrote : | # |
> === added file 'demos/
> I like your code, neat and clean as always. But if I was writing this, I would
> have a single MouseArea behind the surface, instead of 8. It's ok for a demo,
> but that's a lot for a real shell.
If I recall correctly, the main reason was because of the MouseArea.
But later on the cursor shape enumeration proved insufficient for exposing all the different shapes unity uses, forcing me to introduce the Mir.cursorName API.
So yeah, now that I've given up using MouseArea.
Daniel d'Andrada (dandrader) wrote : | # |
> > === added file 'demos/
> > I like your code, neat and clean as always. But if I was writing this, I
> would
> > have a single MouseArea behind the surface, instead of 8. It's ok for a
> demo,
> > but that's a lot for a real shell.
>
> If I recall correctly, the main reason was because of the
> MouseArea.
> assume the given shape when hovering the mouse area. So I cannot be a single
> one.
>
> But later on the cursor shape enumeration proved insufficient for exposing all
> the different shapes unity uses, forcing me to introduce the Mir.cursorName
> API.
>
> So yeah, now that I've given up using MouseArea.
> a single mouse area.
FYI: I also copy-pasted ResizeArea.qml into unity8/mousePointer
Daniel d'Andrada (dandrader) wrote : | # |
> === added file 'src/modules/
> === added file 'src/modules/
> I'm beginning to wonder if most of this code needs to live in qtmir at all.
> Since Unity8 draws it, why does QtMir need to do this work to find the image
> for it?
>
> I also don't think it's QtMir's job to know anything about cursor themes.
>
>
> Why doesn't QtMir just inform the shell of:
> 1. the position the cursor should be located at
> 2. the name of the desired cursor
> Then unity8 can find the themed cursor image, figure out the hotspot and draw
> the cursor itself.
Following the same rationale, one might also argue: "Why does qtmir has to know about application processes and upstart at all? let unity8 figure it out. qtmir should just spit out Sessions, MirSurfaces and MirSurfaceItems".
Also, by having this in qtmir, we pretty much shield unity8 from architectural changes down the road, once we ditch the QML cursor approach in favor of a unity-system-
Daniel d'Andrada (dandrader) wrote : | # |
On 02/09/15 13:16, Gerry Boland wrote:
> === added file 'demos/
> I like your code, neat and clean as always. But if I was writing this, I would have a single MouseArea behind the surface, instead of 8. It's ok for a demo, but that's a lot for a real shell.
>
>
Fixed. Will do likewise in untiy8 tomorrow.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:371
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
> > === added file 'src/modules/
> > === added file 'src/modules/
> > I'm beginning to wonder if most of this code needs to live in qtmir at all.
> > Since Unity8 draws it, why does QtMir need to do this work to find the image
> > for it?
> >
> > I also don't think it's QtMir's job to know anything about cursor themes.
> >
> >
> > Why doesn't QtMir just inform the shell of:
> > 1. the position the cursor should be located at
> > 2. the name of the desired cursor
> > Then unity8 can find the themed cursor image, figure out the hotspot and
> draw
> > the cursor itself.
>
> Following the same rationale, one might also argue: "Why does qtmir has to
> know about application processes and upstart at all? let unity8 figure it out.
> qtmir should just spit out Sessions, MirSurfaces and MirSurfaceItems".
Actually that's the longer-term goal.
https:/
Zanetti wants to move such logic into Unity itself. This will make QtMir a thin wrapper of Mir functionality for Qt users, which is a much clearer purpose than what it currently has.
If somebody would like to make their own shell, then can make use of QtMir without being forced to use upstart for instance. If they want to use upstart, then they can use the Unity.Application plugin.
> Also, by having this in qtmir, we pretty much shield unity8 from architectural
> changes down the road, once we ditch the QML cursor approach in favor of a
> unity-system-
I don't think that will happen. We need the shell to manage the cursor position, in order to do fancy things like edge-push detection, slowing cursor over buttons (a11y) or moving cursor with keyboard (a11y).
My main reasons for wanting USC to draw cursor were:
1. latency, cursor will react as quickly as possible
2. hardware compositing, cursor lives in a special hardware buffer which the hardware composites on top of everything. Means moving cursor doesn't require entire screen re-renders.
Mir team have plans for both problems
1. not use the mir protobuf for input, but have unity8 open socket with event stream coming in. Should reduce latency
2. Mir adding API to allow shell to designate certain buffers/surfaces as being hardware composable. Cursor will definitely be one of those, if available.
Daniel d'Andrada (dandrader) wrote : | # |
Ok, moved all Cursor stuff from qtmir to unity8.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:372
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
=== modified file 'debian/copyright'
can undo this.
Daniel d'Andrada (dandrader) wrote : | # |
On 09/09/15 07:57, Gerry Boland wrote:
> === modified file 'debian/copyright'
> can undo this.
Done.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:373
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
Ok ignore my relativeMovement thing. I'll not object to the usual terminology.
However I fear I need to ask you to rebase on top of
https:/
as there's a few conflicts, and the concept of multiple qwindows does make this more complex.
+ // We will draw our own cursor.
+ add_init_
This isn't great, as the mir cursor object is still being created. Can we replace Mir's implementation with our own one? -- not a blocker on this MR, can consider this later.
++ src/platforms/
+qtmir::Mir::~Mir()
+{
+ m_instance = nullptr;
+}
You're not deleting what you potentially "new"ed. QScopedPointer helps prevent such accidents...
+++ src/platforms/
+private:
+ Mir();
maybe http://
Using this Mir singleton to save the cursorName will do fine for now, but I'm wary of it being a dumping ground for lots of little things.
- 370. By Michał Sawicz
-
No-change rebuild to resync vivid+overlay and wily
Approved by: Michael Zanetti - 371. By CI Train Bot Account
-
Releasing 0.4.6+15.
10.20150904- 0ubuntu1
Daniel d'Andrada (dandrader) wrote : | # |
On 09/09/15 10:36, Gerry Boland wrote:
> Review: Needs Fixing
>
> Ok ignore my relativeMovement thing. I'll not object to the usual terminology.
>
> However I fear I need to ask you to rebase on top of
> https:/
> as there's a few conflicts, and the concept of multiple qwindows does make this more complex.
Done.
>
> + // We will draw our own cursor.
> + add_init_
> This isn't great, as the mir cursor object is still being created. Can we replace Mir's implementation with our own one? -- not a blocker on this MR, can consider this later.
This will be the u-s-c cursor, and u-s-c will always have its own cursor
no matter what, I think. Don't think it's worth investigating this idea.
>
> ++ src/platforms/
> +qtmir::Mir::~Mir()
> +{
> + m_instance = nullptr;
> +}
> You're not deleting what you potentially "new"ed. QScopedPointer helps prevent such accidents...
I am. The only place that does "new Mir" is Mir::instance() and it's
done only once. This is a simple, no-nonsense, singleton implementation
that does its job AFAICT. You want the global, static, Mir::m_instance
to be a QScopedPointer? I fail to see how would that work and how it
would be better than the current code. If you really want to see a
QScopedPointer there please give me a diff as I didn't get the point.
>
> +++ src/platforms/
> +private:
> + Mir();
> maybe http://
Done.
> Using this Mir singleton to save the cursorName will do fine for now, but I'm wary of it being a dumping ground for lots of little things.
Yes, Mir.cursorName is surely not the best solution but anything better
would require way more work. This is like a stop-gap measure. Also given
the uncertainty of the current cursor approach (as we will eventually
move to u-s-c cursor) I didn't want to invest a lot of effort on
something that could evaporate in the near term.
- 372. By Daniel van Vugt
-
Stop waking up every 200ms if there's nothing to wake up for.
It's just wasting battery.This solves at least half of LP: #1479250. Although the regular
wakeup problem is solved by this, Unity8 continues to use noticeable
CPU while idle (obviously in much less frequent intervals now). Fixes: #1479250
Approved by: Gerry Boland - 373. By Daniel d'Andrada
-
MirSurfaceItem gets dirty when it's set to draw a different (or no) surface Fixes: #1492185
Approved by: Gerry Boland - 374. By Daniel d'Andrada
-
QtEventFeeder: log the pointer events it gets from Mir
Approved by: PS Jenkins bot, Gerry Boland - 375. By CI Train Bot Account
-
Releasing 0.4.6+15.
10.20150914- 0ubuntu1 - 376. By Daniel d'Andrada
-
Shell draws its own cursor using the new Cursor QML element
- 377. By Daniel d'Andrada
-
Merge trunk
- 378. By Daniel d'Andrada
-
Update unity-applicati
on-impl in debian/control - 379. By Daniel d'Andrada
-
Merge trunk
- 380. By Daniel d'Andrada
-
s/Qt::MouseButt
on/Qt:: MouseButtons
Unmerged revisions
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2015-08-27 13:58:50 +0000 |
3 | +++ CMakeLists.txt 2015-09-09 18:37:39 +0000 |
4 | @@ -74,7 +74,7 @@ |
5 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
6 | pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED) |
7 | pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED) |
8 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=8) |
9 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=9) |
10 | |
11 | include_directories(${APPLICATION_API_INCLUDE_DIRS}) |
12 | |
13 | |
14 | === modified file 'debian/control' |
15 | --- debian/control 2015-08-27 13:58:50 +0000 |
16 | +++ debian/control 2015-09-09 18:37:39 +0000 |
17 | @@ -22,7 +22,7 @@ |
18 | libubuntu-app-launch2-dev, |
19 | libubuntu-application-api-dev (>= 2.1.0), |
20 | libudev-dev, |
21 | - libunity-api-dev (>= 7.100), |
22 | + libunity-api-dev (>= 7.101), |
23 | liburl-dispatcher1-dev, |
24 | libxkbcommon-dev, |
25 | libxrender-dev, |
26 | |
27 | === added file 'demos/qml-demo-shell/ResizeArea.qml' |
28 | --- demos/qml-demo-shell/ResizeArea.qml 1970-01-01 00:00:00 +0000 |
29 | +++ demos/qml-demo-shell/ResizeArea.qml 2015-09-09 18:37:39 +0000 |
30 | @@ -0,0 +1,128 @@ |
31 | +import QtQuick 2.4 |
32 | +import Unity.Application 0.1 |
33 | + |
34 | +MouseArea { |
35 | + id: root |
36 | + |
37 | + // to be set from outside |
38 | + property Item target |
39 | + property real borderThickness |
40 | + |
41 | + property bool leftBorder: false |
42 | + property bool rightBorder: false |
43 | + property bool topBorder: false |
44 | + property bool bottomBorder: false |
45 | + |
46 | + property bool dragging: false |
47 | + property real startX |
48 | + property real startY |
49 | + property real startWidth |
50 | + property real startHeight |
51 | + |
52 | + hoverEnabled: true |
53 | + |
54 | + property string cursorName: { |
55 | + if (containsMouse || pressed) { |
56 | + if (leftBorder && !topBorder && !bottomBorder) { |
57 | + return "left_side"; |
58 | + } else if (rightBorder && !topBorder && !bottomBorder) { |
59 | + return "right_side"; |
60 | + } else if (topBorder && !leftBorder && !rightBorder) { |
61 | + return "top_side"; |
62 | + } else if (bottomBorder && !leftBorder && !rightBorder) { |
63 | + return "bottom_side"; |
64 | + } else if (leftBorder && topBorder) { |
65 | + return "top_left_corner"; |
66 | + } else if (leftBorder && bottomBorder) { |
67 | + return "bottom_left_corner"; |
68 | + } else if (rightBorder && topBorder) { |
69 | + return "top_right_corner"; |
70 | + } else if (rightBorder && bottomBorder) { |
71 | + return "bottom_right_corner"; |
72 | + } else { |
73 | + return ""; |
74 | + } |
75 | + } else { |
76 | + return ""; |
77 | + } |
78 | + } |
79 | + onCursorNameChanged: { |
80 | + Mir.cursorName = cursorName; |
81 | + } |
82 | + |
83 | + function updateBorders() { |
84 | + leftBorder = mouseX <= borderThickness; |
85 | + rightBorder = mouseX >= width - borderThickness; |
86 | + topBorder = mouseY <= borderThickness; |
87 | + bottomBorder = mouseY >= height - borderThickness; |
88 | + } |
89 | + |
90 | + onPressedChanged: { |
91 | + if (pressed) { |
92 | + var pos = mapToItem(target.parent, mouseX, mouseY); |
93 | + startX = pos.x; |
94 | + startY = pos.y; |
95 | + startWidth = target.width; |
96 | + startHeight = target.height; |
97 | + dragging = true; |
98 | + } else { |
99 | + dragging = false; |
100 | + if (containsMouse) { |
101 | + updateBorders(); |
102 | + } |
103 | + } |
104 | + } |
105 | + |
106 | + onEntered: { |
107 | + if (!pressed) { |
108 | + updateBorders(); |
109 | + } |
110 | + } |
111 | + |
112 | + onPositionChanged: { |
113 | + if (!pressed) { |
114 | + updateBorders(); |
115 | + } |
116 | + |
117 | + if (!dragging) { |
118 | + return; |
119 | + } |
120 | + |
121 | + var pos = mapToItem(target.parent, mouse.x, mouse.y); |
122 | + |
123 | + if (leftBorder) { |
124 | + if (startX + startWidth - pos.x > target.minWidth) { |
125 | + target.x = pos.x; |
126 | + target.width = startX + startWidth - target.x; |
127 | + startX = target.x; |
128 | + startWidth = target.width; |
129 | + } |
130 | + |
131 | + } else if (rightBorder) { |
132 | + var deltaX = pos.x - startX; |
133 | + if (startWidth + deltaX >= target.minWidth) { |
134 | + target.width = startWidth + deltaX; |
135 | + } else { |
136 | + target.width = target.minWidth; |
137 | + } |
138 | + } |
139 | + |
140 | + if (topBorder) { |
141 | + if (startY + startHeight - pos.y > target.minHeight) { |
142 | + target.y = pos.y; |
143 | + target.height = startY + startHeight - target.y; |
144 | + startY = target.y; |
145 | + startHeight = target.height; |
146 | + } |
147 | + |
148 | + } else if (bottomBorder) { |
149 | + var deltaY = pos.y - startY; |
150 | + if (startHeight + deltaY >= target.minHeight) { |
151 | + target.height = startHeight + deltaY; |
152 | + } else { |
153 | + target.height = target.minHeight; |
154 | + } |
155 | + } |
156 | + } |
157 | +} |
158 | + |
159 | |
160 | === renamed file 'demos/qml-demo-shell/qml-demo-shell.qml' => 'demos/qml-demo-shell/Shell.qml' |
161 | --- demos/qml-demo-shell/qml-demo-shell.qml 2015-08-24 12:43:01 +0000 |
162 | +++ demos/qml-demo-shell/Shell.qml 2015-09-09 18:37:39 +0000 |
163 | @@ -1,4 +1,4 @@ |
164 | -import QtQuick 2.0 |
165 | +import QtQuick 2.4 |
166 | import Unity.Application 0.1 |
167 | |
168 | Rectangle { |
169 | @@ -88,6 +88,7 @@ |
170 | } |
171 | |
172 | Rectangle { |
173 | + id: resizeButton |
174 | width: 90 |
175 | height: 40 |
176 | color: "blue" |
177 | @@ -103,6 +104,23 @@ |
178 | } |
179 | } |
180 | |
181 | + Rectangle { |
182 | + width: 40 |
183 | + height: 40 |
184 | + color: "green" |
185 | + anchors { right: resizeButton.left; bottom: parent.bottom } |
186 | + Text { |
187 | + anchors.centerIn: parent |
188 | + text: "⟳" |
189 | + color: "white" |
190 | + font.pixelSize: 35 |
191 | + } |
192 | + MouseArea { |
193 | + anchors.fill: parent |
194 | + onClicked: { root.rotation += 180; } |
195 | + } |
196 | + } |
197 | + |
198 | Component { |
199 | id: windowStretchComponent |
200 | Window { |
201 | @@ -161,4 +179,6 @@ |
202 | from: root.width; to: 10; |
203 | duration: 1200; easing.type: Easing.InOutQuad |
204 | } |
205 | + |
206 | + Cursor {} |
207 | } |
208 | |
209 | === modified file 'demos/qml-demo-shell/TitleBar.qml' |
210 | --- demos/qml-demo-shell/TitleBar.qml 2015-08-24 12:43:01 +0000 |
211 | +++ demos/qml-demo-shell/TitleBar.qml 2015-09-09 18:37:39 +0000 |
212 | @@ -1,4 +1,5 @@ |
213 | -import QtQuick 2.0 |
214 | +import QtQuick 2.4 |
215 | +import Unity.Application 0.1 |
216 | |
217 | Rectangle { |
218 | id: root |
219 | @@ -21,8 +22,10 @@ |
220 | distanceX = pos.x; |
221 | distanceY = pos.y; |
222 | dragging = true; |
223 | + Mir.cursorName = "grabbing"; |
224 | } else { |
225 | dragging = false; |
226 | + Mir.cursorName = ""; |
227 | } |
228 | } |
229 | onMouseXChanged: { |
230 | |
231 | === modified file 'demos/qml-demo-shell/Window.qml' |
232 | --- demos/qml-demo-shell/Window.qml 2015-08-24 12:43:01 +0000 |
233 | +++ demos/qml-demo-shell/Window.qml 2015-09-09 18:37:39 +0000 |
234 | @@ -58,87 +58,10 @@ |
235 | } |
236 | ] |
237 | |
238 | - |
239 | - MouseArea { |
240 | - anchors.fill: parent |
241 | - |
242 | - property real startX |
243 | - property real startY |
244 | - property real startWidth |
245 | - property real startHeight |
246 | - property bool leftBorder |
247 | - property bool rightBorder |
248 | - property bool topBorder |
249 | - property bool bottomBorder |
250 | - property bool dragging |
251 | - onPressedChanged: { |
252 | - if (pressed) { |
253 | - var pos = mapToItem(root.parent, mouseX, mouseY); |
254 | - startX = pos.x; |
255 | - startY = pos.y; |
256 | - startWidth = width; |
257 | - startHeight = height; |
258 | - leftBorder = mouseX > 0 && mouseX < root.borderThickness; |
259 | - rightBorder = mouseX > (root.width - root.borderThickness) && mouseX < root.width; |
260 | - topBorder = mouseY > 0 && mouseY < root.borderThickness; |
261 | - bottomBorder = mouseY > (root.height - root.borderThickness) && mouseY < root.height; |
262 | - dragging = true; |
263 | - } else { |
264 | - dragging = false; |
265 | - } |
266 | - } |
267 | - |
268 | - onMouseXChanged: { |
269 | - if (!pressed || !dragging) { |
270 | - return; |
271 | - } |
272 | - |
273 | - var pos = mapToItem(root.parent, mouseX, mouseY); |
274 | - |
275 | - if (leftBorder) { |
276 | - |
277 | - if (startX + startWidth - pos.x > root.minWidth) { |
278 | - root.x = pos.x; |
279 | - root.width = startX + startWidth - root.x; |
280 | - startX = root.x; |
281 | - startWidth = root.width; |
282 | - } |
283 | - |
284 | - } else if (rightBorder) { |
285 | - var deltaX = pos.x - startX; |
286 | - if (startWidth + deltaX >= root.minWidth) { |
287 | - root.width = startWidth + deltaX; |
288 | - } else { |
289 | - root.width = root.minWidth; |
290 | - } |
291 | - } |
292 | - } |
293 | - |
294 | - onMouseYChanged: { |
295 | - if (!pressed || !dragging) { |
296 | - return; |
297 | - } |
298 | - |
299 | - var pos = mapToItem(root.parent, mouseX, mouseY); |
300 | - |
301 | - if (topBorder) { |
302 | - |
303 | - if (startY + startHeight - pos.y > root.minHeight) { |
304 | - root.y = pos.y; |
305 | - root.height = startY + startHeight - root.y; |
306 | - startY = root.y; |
307 | - startHeight = root.height; |
308 | - } |
309 | - |
310 | - } else if (bottomBorder) { |
311 | - var deltaY = pos.y - startY; |
312 | - if (startHeight + deltaY >= root.minHeight) { |
313 | - root.height = startHeight + deltaY; |
314 | - } else { |
315 | - root.height = root.minHeight; |
316 | - } |
317 | - } |
318 | - } |
319 | + ResizeArea { |
320 | + anchors.fill: root |
321 | + borderThickness: root.borderThickness |
322 | + target: root |
323 | } |
324 | |
325 | TitleBar { |
326 | |
327 | === added file 'demos/qml-demo-shell/qml-demo-shell.qml' |
328 | --- demos/qml-demo-shell/qml-demo-shell.qml 1970-01-01 00:00:00 +0000 |
329 | +++ demos/qml-demo-shell/qml-demo-shell.qml 2015-09-09 18:37:39 +0000 |
330 | @@ -0,0 +1,19 @@ |
331 | +import QtQuick 2.3 |
332 | +import QtQuick.Window 2.2 as QQW |
333 | +import Unity.Screens 0.1 |
334 | + |
335 | +Instantiator { |
336 | + id: root |
337 | + |
338 | + property var screens: Screens{} |
339 | + |
340 | + model: screens |
341 | + QQW.Window { |
342 | + id: window |
343 | + visible: true |
344 | + Shell{ anchors.fill: parent } |
345 | + Component.onCompleted: { |
346 | + print("HEY", screen, screen.geometry, outputType, Screens.HDMIA) |
347 | + } |
348 | + } |
349 | +} |
350 | |
351 | === modified file 'src/modules/Unity/Application/CMakeLists.txt' |
352 | --- src/modules/Unity/Application/CMakeLists.txt 2015-08-24 12:43:01 +0000 |
353 | +++ src/modules/Unity/Application/CMakeLists.txt 2015-09-09 18:37:39 +0000 |
354 | @@ -91,4 +91,3 @@ |
355 | # install |
356 | add_qml_plugin(Unity.Application 0.1 Unity/Application TARGETS unityapplicationplugin) |
357 | install(FILES com.canonical.qtmir.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas) |
358 | - |
359 | |
360 | === modified file 'src/modules/Unity/Application/plugin.cpp' |
361 | --- src/modules/Unity/Application/plugin.cpp 2015-08-24 12:43:01 +0000 |
362 | +++ src/modules/Unity/Application/plugin.cpp 2015-09-09 18:37:39 +0000 |
363 | @@ -27,6 +27,9 @@ |
364 | #include "sessionmanager.h" |
365 | #include "ubuntukeyboardinfo.h" |
366 | |
367 | +// platforms/mirserver |
368 | +#include <mirsingleton.h> |
369 | + |
370 | // qtmir |
371 | #include "logging.h" |
372 | |
373 | @@ -64,6 +67,10 @@ |
374 | } |
375 | return UbuntuKeyboardInfo::instance(); |
376 | } |
377 | + |
378 | +QObject* mirSingleton(QQmlEngine* /*engine*/, QJSEngine* /*scriptEngine*/) { |
379 | + return qtmir::Mir::instance(); |
380 | +} |
381 | } // anonymous namespace |
382 | |
383 | class UnityApplicationPlugin : public QQmlExtensionPlugin { |
384 | @@ -102,7 +109,7 @@ |
385 | uri, 0, 1, "Session", "Session can't be instantiated from QML"); |
386 | qmlRegisterSingletonType<qtmir::UbuntuKeyboardInfo>( |
387 | uri, 0, 1, "UbuntuKeyboardInfo", ubuntuKeyboardInfoSingleton); |
388 | - qmlRegisterUncreatableType<Mir>(uri, 0, 1, "Mir", "Mir provides enum values, it can't be instantiated"); |
389 | + qmlRegisterSingletonType<qtmir::Mir>(uri, 0, 1, "Mir", mirSingleton); |
390 | } |
391 | |
392 | virtual void initializeEngine(QQmlEngine *engine, const char *uri) |
393 | |
394 | === modified file 'src/modules/Unity/CMakeLists.txt' |
395 | --- src/modules/Unity/CMakeLists.txt 2014-09-22 18:06:58 +0000 |
396 | +++ src/modules/Unity/CMakeLists.txt 2015-09-09 18:37:39 +0000 |
397 | @@ -1,1 +1,2 @@ |
398 | add_subdirectory(Application) |
399 | +add_subdirectory(Screens) |
400 | |
401 | === added directory 'src/modules/Unity/Screens' |
402 | === added file 'src/modules/Unity/Screens/CMakeLists.txt' |
403 | --- src/modules/Unity/Screens/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
404 | +++ src/modules/Unity/Screens/CMakeLists.txt 2015-09-09 18:37:39 +0000 |
405 | @@ -0,0 +1,24 @@ |
406 | +include_directories( |
407 | + ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
408 | + ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
409 | + ${MIRSERVER_INCLUDE_DIRS} |
410 | + ) |
411 | + |
412 | +set(SCREENSPLUGIN_SRC |
413 | + plugin.cpp |
414 | + screens.cpp |
415 | + ) |
416 | + |
417 | +add_library(unityscreensplugin SHARED |
418 | + ${SCREENSPLUGIN_SRC} |
419 | +) |
420 | + |
421 | +target_link_libraries( |
422 | + unityscreensplugin |
423 | + |
424 | + Qt5::Gui |
425 | + Qt5::Qml |
426 | +) |
427 | + |
428 | +# install |
429 | +add_qml_plugin(Unity.Screens 0.1 Unity/Screens TARGETS unityscreensplugin) |
430 | |
431 | === added file 'src/modules/Unity/Screens/plugin.cpp' |
432 | --- src/modules/Unity/Screens/plugin.cpp 1970-01-01 00:00:00 +0000 |
433 | +++ src/modules/Unity/Screens/plugin.cpp 2015-09-09 18:37:39 +0000 |
434 | @@ -0,0 +1,41 @@ |
435 | +/* |
436 | + * Copyright (C) 2015 Canonical, Ltd. |
437 | + * |
438 | + * This program is free software: you can redistribute it and/or modify it under |
439 | + * the terms of the GNU Lesser General Public License version 3, as published by |
440 | + * the Free Software Foundation. |
441 | + * |
442 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
443 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
444 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
445 | + * Lesser General Public License for more details. |
446 | + * |
447 | + * You should have received a copy of the GNU Lesser General Public License |
448 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
449 | + */ |
450 | + |
451 | +// Qt |
452 | +#include <QQmlExtensionPlugin> |
453 | +#include <QtQml/qqml.h> |
454 | +#include <QScreen> |
455 | + |
456 | +// local |
457 | +#include "screens.h" |
458 | + |
459 | +using namespace qtmir; |
460 | + |
461 | +class UnityScreensPlugin : public QQmlExtensionPlugin { |
462 | + Q_OBJECT |
463 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") |
464 | + |
465 | + virtual void registerTypes(const char* uri) |
466 | + { |
467 | + Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Screens")); |
468 | + |
469 | + qRegisterMetaType<QScreen*>("QScreen*"); |
470 | + |
471 | + qmlRegisterType<qtmir::Screens>(uri, 0, 1, "Screens"); |
472 | + } |
473 | +}; |
474 | + |
475 | +#include "plugin.moc" |
476 | |
477 | === added file 'src/modules/Unity/Screens/qmldir' |
478 | --- src/modules/Unity/Screens/qmldir 1970-01-01 00:00:00 +0000 |
479 | +++ src/modules/Unity/Screens/qmldir 2015-09-09 18:37:39 +0000 |
480 | @@ -0,0 +1,2 @@ |
481 | +module Unity.Screens |
482 | +plugin unityscreensplugin |
483 | |
484 | === added file 'src/modules/Unity/Screens/screens.cpp' |
485 | --- src/modules/Unity/Screens/screens.cpp 1970-01-01 00:00:00 +0000 |
486 | +++ src/modules/Unity/Screens/screens.cpp 2015-09-09 18:37:39 +0000 |
487 | @@ -0,0 +1,107 @@ |
488 | +/* |
489 | + * Copyright (C) 2015 Canonical, Ltd. |
490 | + * |
491 | + * This program is free software: you can redistribute it and/or modify it under |
492 | + * the terms of the GNU Lesser General Public License version 3, as published by |
493 | + * the Free Software Foundation. |
494 | + * |
495 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
496 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
497 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
498 | + * Lesser General Public License for more details. |
499 | + * |
500 | + * You should have received a copy of the GNU Lesser General Public License |
501 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
502 | + */ |
503 | + |
504 | +#include "screens.h" |
505 | + |
506 | +// mirserver |
507 | +#include "screen.h" |
508 | + |
509 | +// Qt |
510 | +#include <QGuiApplication> |
511 | +#include <QScreen> |
512 | + |
513 | +Q_DECLARE_METATYPE(QScreen*) |
514 | + |
515 | +namespace qtmir { |
516 | + |
517 | +Screens::Screens(QObject *parent) : |
518 | + QAbstractListModel(parent) |
519 | +{ |
520 | + auto app = static_cast<QGuiApplication *>(QGuiApplication::instance()); |
521 | + if (!app) { |
522 | + return; |
523 | + } |
524 | + connect(app, &QGuiApplication::screenAdded, this, &Screens::onScreenAdded); |
525 | + connect(app, &QGuiApplication::screenRemoved, this, &Screens::onScreenRemoved); |
526 | + |
527 | + m_screenList = QGuiApplication::screens(); |
528 | +} |
529 | + |
530 | +QHash<int, QByteArray> Screens::roleNames() const |
531 | +{ |
532 | + QHash<int, QByteArray> roles; |
533 | + roles[ScreenRole] = "screen"; |
534 | + roles[OutputTypeRole] = "outputType"; |
535 | + return roles; |
536 | +} |
537 | + |
538 | +QVariant Screens::data(const QModelIndex &index, int role) const |
539 | +{ |
540 | + if (!index.isValid() || index.row() >= m_screenList.size()) { |
541 | + return QVariant(); |
542 | + } |
543 | + |
544 | + switch(role) { |
545 | + case ScreenRole: |
546 | + return QVariant::fromValue(m_screenList.at(index.row())); |
547 | + case OutputTypeRole: |
548 | + auto screen = static_cast<Screen*>(m_screenList.at(index.row())->handle()); |
549 | + if (screen) { |
550 | + return QVariant(static_cast<OutputTypes>(screen->outputType())); //FIXME: cheeky |
551 | + } else |
552 | + return OutputTypes::Unknown; |
553 | + } |
554 | + |
555 | + return QVariant(); |
556 | +} |
557 | + |
558 | +int Screens::rowCount(const QModelIndex &) const |
559 | +{ |
560 | + return count(); |
561 | +} |
562 | + |
563 | +int Screens::count() const |
564 | +{ |
565 | + return m_screenList.size(); |
566 | +} |
567 | + |
568 | +void Screens::onScreenAdded(QScreen *screen) |
569 | +{ |
570 | + if (m_screenList.contains(screen)) |
571 | + return; |
572 | + |
573 | + beginInsertRows(QModelIndex(), count(), count()); |
574 | + m_screenList.push_back(screen); |
575 | + endInsertRows(); |
576 | + Q_EMIT screenAdded(screen); |
577 | + Q_EMIT countChanged(); |
578 | +} |
579 | + |
580 | +void Screens::onScreenRemoved(QScreen *screen) |
581 | +{ |
582 | + int index = m_screenList.indexOf(screen); |
583 | + if (index < 0) |
584 | + return; |
585 | + |
586 | + beginRemoveRows(QModelIndex(), index, index); |
587 | + m_screenList.removeAt(index); |
588 | + endRemoveRows(); |
589 | + Q_EMIT screenRemoved(screen); |
590 | + Q_EMIT countChanged(); |
591 | +} |
592 | + |
593 | + |
594 | +} // namespace qtmir |
595 | |
596 | === added file 'src/modules/Unity/Screens/screens.h' |
597 | --- src/modules/Unity/Screens/screens.h 1970-01-01 00:00:00 +0000 |
598 | +++ src/modules/Unity/Screens/screens.h 2015-09-09 18:37:39 +0000 |
599 | @@ -0,0 +1,82 @@ |
600 | +/* |
601 | + * Copyright (C) 2015 Canonical, Ltd. |
602 | + * |
603 | + * This program is free software: you can redistribute it and/or modify it under |
604 | + * the terms of the GNU Lesser General Public License version 3, as published by |
605 | + * the Free Software Foundation. |
606 | + * |
607 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
608 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
609 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
610 | + * Lesser General Public License for more details. |
611 | + * |
612 | + * You should have received a copy of the GNU Lesser General Public License |
613 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
614 | + */ |
615 | + |
616 | +#ifndef SCREENS_H |
617 | +#define SCREENS_H |
618 | + |
619 | +#include <QAbstractListModel> |
620 | + |
621 | +class QScreen; |
622 | + |
623 | +namespace qtmir { |
624 | + |
625 | +class Screens : public QAbstractListModel |
626 | +{ |
627 | + Q_OBJECT |
628 | + Q_ENUMS(OutputTypes) |
629 | + |
630 | + Q_PROPERTY(int count READ count NOTIFY countChanged) |
631 | + |
632 | +public: |
633 | + enum ItemRoles { |
634 | + ScreenRole = Qt::UserRole + 1, |
635 | + OutputTypeRole |
636 | + }; |
637 | + |
638 | + enum OutputTypes { |
639 | + Unknown, |
640 | + VGA, |
641 | + DVII, |
642 | + DVID, |
643 | + DVIA, |
644 | + Composite, |
645 | + SVideo, |
646 | + LVDS, |
647 | + Component, |
648 | + NinePinDIN, |
649 | + DisplayPort, |
650 | + HDMIA, |
651 | + HDMIB, |
652 | + TV, |
653 | + EDP |
654 | + }; |
655 | + |
656 | + explicit Screens(QObject *parent = 0); |
657 | + virtual ~Screens() noexcept = default; |
658 | + |
659 | + /* QAbstractItemModel */ |
660 | + QHash<int, QByteArray> roleNames() const override; |
661 | + QVariant data(const QModelIndex &index, int role = ScreenRole) const override; |
662 | + int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
663 | + |
664 | + int count() const; |
665 | + |
666 | +Q_SIGNALS: |
667 | + void countChanged(); |
668 | + void screenAdded(QScreen *screen); |
669 | + void screenRemoved(QScreen *screen); |
670 | + |
671 | +private Q_SLOTS: |
672 | + void onScreenAdded(QScreen *screen); |
673 | + void onScreenRemoved(QScreen *screen); |
674 | + |
675 | +private: |
676 | + QList<QScreen *> m_screenList; |
677 | +}; |
678 | + |
679 | +} // namespace qtmir |
680 | + |
681 | +#endif // SCREENS_H |
682 | |
683 | === modified file 'src/platforms/mirserver/CMakeLists.txt' |
684 | --- src/platforms/mirserver/CMakeLists.txt 2015-08-11 19:25:04 +0000 |
685 | +++ src/platforms/mirserver/CMakeLists.txt 2015-09-09 18:37:39 +0000 |
686 | @@ -30,6 +30,7 @@ |
687 | ${QT5PLATFORM_SUPPORT_INCLUDE_DIRS} |
688 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
689 | ${QT5_PLATFORMSUPPORT_INCLUDE_DIRS} |
690 | + ${Qt5Quick_PRIVATE_INCLUDE_DIRS} |
691 | |
692 | ${APPLICATION_API_INCLUDE_DIRS} |
693 | ) |
694 | @@ -41,7 +42,9 @@ |
695 | |
696 | set(MIRSERVER_QPA_PLUGIN_SRC |
697 | ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
698 | + cursor.cpp |
699 | mirwindowmanager.cpp |
700 | + mirsingleton.cpp |
701 | qteventfeeder.cpp |
702 | plugin.cpp |
703 | qmirserver.cpp |
704 | @@ -52,17 +55,21 @@ |
705 | promptsessionlistener.cpp |
706 | mirserver.cpp |
707 | mirserverstatuslistener.cpp |
708 | - display.cpp |
709 | screen.cpp |
710 | - displaywindow.cpp |
711 | + screencontroller.cpp |
712 | + screenwindow.cpp |
713 | mirserverintegration.cpp |
714 | miropenglcontext.cpp |
715 | nativeinterface.cpp |
716 | + offscreensurface.cpp |
717 | qtcompositor.cpp |
718 | services.cpp |
719 | ubuntutheme.cpp |
720 | clipboard.cpp |
721 | + tileddisplayconfigurationpolicy.cpp |
722 | tracepoints.c |
723 | +# We need to run moc on these headers |
724 | + ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h |
725 | ) |
726 | |
727 | add_library(qpa-mirserver SHARED |
728 | @@ -82,7 +89,7 @@ |
729 | ${QT5PLATFORM_SUPPORT_LDFLAGS} |
730 | # TODO Qt5Platform support LDFLAGS dont provide actual required ldflags... |
731 | # I found these were needed...perhaps there is some way to query qmake/qconfig? |
732 | - -lfreetype |
733 | + -lfreetype |
734 | ${GIO_LDFLAGS} |
735 | ${FONTCONFIG_LDFLAGS} |
736 | |
737 | |
738 | === added file 'src/platforms/mirserver/cursor.cpp' |
739 | --- src/platforms/mirserver/cursor.cpp 1970-01-01 00:00:00 +0000 |
740 | +++ src/platforms/mirserver/cursor.cpp 2015-09-09 18:37:39 +0000 |
741 | @@ -0,0 +1,152 @@ |
742 | +/* |
743 | + * Copyright (C) 2015 Canonical, Ltd. |
744 | + * |
745 | + * This program is free software: you can redistribute it and/or modify it under |
746 | + * the terms of the GNU Lesser General Public License version 3, as published by |
747 | + * the Free Software Foundation. |
748 | + * |
749 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
750 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
751 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
752 | + * Lesser General Public License for more details. |
753 | + * |
754 | + * You should have received a copy of the GNU Lesser General Public License |
755 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
756 | + * |
757 | + */ |
758 | + |
759 | +#include "cursor.h" |
760 | +#include "logging.h" |
761 | + |
762 | +#include "mirsingleton.h" |
763 | + |
764 | +// Unity API |
765 | +#include <unity/shell/application/MirMousePointerInterface.h> |
766 | + |
767 | +using namespace qtmir; |
768 | + |
769 | +Cursor::Cursor() |
770 | +{ |
771 | + m_shapeToCursorName[Qt::ArrowCursor] = "left_ptr"; |
772 | + m_shapeToCursorName[Qt::UpArrowCursor] = "up_arrow"; |
773 | + m_shapeToCursorName[Qt::CrossCursor] = "cross"; |
774 | + m_shapeToCursorName[Qt::WaitCursor] = "watch"; |
775 | + m_shapeToCursorName[Qt::IBeamCursor] = "xterm"; |
776 | + m_shapeToCursorName[Qt::SizeVerCursor] = "size_ver"; |
777 | + m_shapeToCursorName[Qt::SizeHorCursor] = "size_hor"; |
778 | + m_shapeToCursorName[Qt::SizeBDiagCursor] = "size_bdiag"; |
779 | + m_shapeToCursorName[Qt::SizeFDiagCursor] = "size_fdiag"; |
780 | + m_shapeToCursorName[Qt::SizeAllCursor] = "size_all"; |
781 | + m_shapeToCursorName[Qt::BlankCursor] = "blank"; |
782 | + m_shapeToCursorName[Qt::SplitVCursor] = "split_v"; |
783 | + m_shapeToCursorName[Qt::SplitHCursor] = "split_h"; |
784 | + m_shapeToCursorName[Qt::PointingHandCursor] = "pointing_hand"; |
785 | + m_shapeToCursorName[Qt::ForbiddenCursor] = "forbidden"; |
786 | + m_shapeToCursorName[Qt::WhatsThisCursor] = "whats_this"; |
787 | + m_shapeToCursorName[Qt::BusyCursor] = "left_ptr_watch"; |
788 | + m_shapeToCursorName[Qt::OpenHandCursor] = "openhand"; |
789 | + m_shapeToCursorName[Qt::ClosedHandCursor] = "closedhand"; |
790 | + m_shapeToCursorName[Qt::DragCopyCursor] = "copy"; |
791 | + m_shapeToCursorName[Qt::DragMoveCursor] = "move"; |
792 | + m_shapeToCursorName[Qt::DragLinkCursor] = "link"; |
793 | + |
794 | + connect(Mir::instance(), &Mir::cursorNameChanged, this, &Cursor::setMirCursorName); |
795 | +} |
796 | + |
797 | +void Cursor::changeCursor(QCursor *windowCursor, QWindow * /*window*/) |
798 | +{ |
799 | + if (m_mousePointer.isNull()) { |
800 | + return; |
801 | + } |
802 | + |
803 | + if (windowCursor) { |
804 | + m_qtCursorName = m_shapeToCursorName.value(windowCursor->shape(), QString("left_ptr")); |
805 | + } else { |
806 | + m_qtCursorName.clear(); |
807 | + } |
808 | + |
809 | + updateMousePointerCursorName(); |
810 | +} |
811 | + |
812 | +void Cursor::setMirCursorName(const QString &mirCursorName) |
813 | +{ |
814 | + m_mirCursorName = mirCursorName; |
815 | + updateMousePointerCursorName(); |
816 | +} |
817 | + |
818 | +void Cursor::setMousePointer(MirMousePointerInterface *mousePointer) |
819 | +{ |
820 | + QMutexLocker locker(&m_mutex); |
821 | + |
822 | + if (mousePointer && !m_mousePointer.isNull()) { |
823 | + qFatal("QPA mirserver: Only one MousePointer per screen is allowed!"); |
824 | + } |
825 | + |
826 | + m_mousePointer = mousePointer; |
827 | + updateMousePointerCursorName(); |
828 | +} |
829 | + |
830 | +bool Cursor::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons, |
831 | + Qt::KeyboardModifiers modifiers) |
832 | +{ |
833 | + QMutexLocker locker(&m_mutex); |
834 | + |
835 | + if (!m_mousePointer || !m_mousePointer->isVisible()) { |
836 | + return false; |
837 | + } |
838 | + |
839 | + // Must not be called directly as we're most likely not in Qt's GUI (main) thread. |
840 | + bool ok = QMetaObject::invokeMethod(m_mousePointer, "handleMouseEvent", Qt::AutoConnection, |
841 | + Q_ARG(ulong, timestamp), |
842 | + Q_ARG(QPointF, movement), |
843 | + Q_ARG(Qt::MouseButton, buttons), |
844 | + Q_ARG(Qt::KeyboardModifiers, modifiers)); |
845 | + |
846 | + if (!ok) { |
847 | + qCWarning(QTMIR_MIR_INPUT) << "Failed to invoke MousePointer::handleMouseEvent"; |
848 | + } |
849 | + |
850 | + return ok; |
851 | +} |
852 | + |
853 | +void Cursor::setPos(const QPoint &pos) |
854 | +{ |
855 | + if (!m_mousePointer) { |
856 | + QPlatformCursor::setPos(pos); |
857 | + return; |
858 | + } |
859 | + |
860 | + QPointF movement; |
861 | + QPointF mouseScenePos = m_mousePointer->mapToItem(nullptr, QPointF(0, 0)); |
862 | + |
863 | + movement.setX(pos.x() - mouseScenePos.x()); |
864 | + movement.setY(pos.y() - mouseScenePos.y()); |
865 | + |
866 | + m_mousePointer->handleMouseEvent(0 /*timestamp*/, movement, Qt::NoButton, Qt::NoModifier); |
867 | +} |
868 | + |
869 | +QPoint Cursor::pos() const |
870 | +{ |
871 | + if (m_mousePointer) { |
872 | + return m_mousePointer->mapToItem(nullptr, QPointF(0, 0)).toPoint(); |
873 | + } else { |
874 | + return QPlatformCursor::pos(); |
875 | + } |
876 | +} |
877 | + |
878 | +void Cursor::updateMousePointerCursorName() |
879 | +{ |
880 | + if (!m_mousePointer) { |
881 | + return; |
882 | + } |
883 | + |
884 | + if (m_mirCursorName.isEmpty()) { |
885 | + if (m_qtCursorName.isEmpty()) { |
886 | + m_mousePointer->setCursorName("left_ptr"); |
887 | + } else { |
888 | + m_mousePointer->setCursorName(m_qtCursorName); |
889 | + } |
890 | + } else { |
891 | + m_mousePointer->setCursorName(m_mirCursorName); |
892 | + } |
893 | +} |
894 | |
895 | === added file 'src/platforms/mirserver/cursor.h' |
896 | --- src/platforms/mirserver/cursor.h 1970-01-01 00:00:00 +0000 |
897 | +++ src/platforms/mirserver/cursor.h 2015-09-09 18:37:39 +0000 |
898 | @@ -0,0 +1,66 @@ |
899 | +/* |
900 | + * Copyright (C) 2015 Canonical, Ltd. |
901 | + * |
902 | + * This program is free software: you can redistribute it and/or modify it under |
903 | + * the terms of the GNU Lesser General Public License version 3, as published by |
904 | + * the Free Software Foundation. |
905 | + * |
906 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
907 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
908 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
909 | + * Lesser General Public License for more details. |
910 | + * |
911 | + * You should have received a copy of the GNU Lesser General Public License |
912 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
913 | + * |
914 | + */ |
915 | + |
916 | +#ifndef QTMIR_CURSOR_H |
917 | +#define QTMIR_CURSOR_H |
918 | + |
919 | +#include <QMutex> |
920 | +#include <QPointer> |
921 | + |
922 | +// Unity API |
923 | +#include <unity/shell/application/MirPlatformCursor.h> |
924 | + |
925 | +namespace qtmir { |
926 | + |
927 | +class Cursor : public MirPlatformCursor |
928 | +{ |
929 | +public: |
930 | + Cursor(); |
931 | + |
932 | + // Called form Mir input thread |
933 | + bool handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons, |
934 | + Qt::KeyboardModifiers modifiers); |
935 | + |
936 | + //// |
937 | + // MirPlatformCursor |
938 | + |
939 | + // Called from Qt's GUI thread |
940 | + void setMousePointer(MirMousePointerInterface *mousePointer) override; |
941 | + |
942 | + //// |
943 | + // QPlatformCursor |
944 | + |
945 | + void changeCursor(QCursor *windowCursor, QWindow *window) override; |
946 | + |
947 | + void setPos(const QPoint &pos) override; |
948 | + QPoint pos() const override; |
949 | + |
950 | +private Q_SLOTS: |
951 | + void setMirCursorName(const QString &mirCursorName); |
952 | + |
953 | +private: |
954 | + void updateMousePointerCursorName(); |
955 | + QMutex m_mutex; |
956 | + QPointer<MirMousePointerInterface> m_mousePointer; |
957 | + QMap<int,QString> m_shapeToCursorName; |
958 | + QString m_qtCursorName; |
959 | + QString m_mirCursorName; |
960 | +}; |
961 | + |
962 | +} // namespace qtmir |
963 | + |
964 | +#endif // QTMIR_CURSOR_H |
965 | |
966 | === removed file 'src/platforms/mirserver/display.cpp' |
967 | --- src/platforms/mirserver/display.cpp 2015-08-11 12:08:32 +0000 |
968 | +++ src/platforms/mirserver/display.cpp 1970-01-01 00:00:00 +0000 |
969 | @@ -1,44 +0,0 @@ |
970 | -/* |
971 | - * Copyright (C) 2013-2015 Canonical, Ltd. |
972 | - * |
973 | - * This program is free software: you can redistribute it and/or modify it under |
974 | - * the terms of the GNU Lesser General Public License version 3, as published by |
975 | - * the Free Software Foundation. |
976 | - * |
977 | - * This program is distributed in the hope that it will be useful, but WITHOUT |
978 | - * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
979 | - * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
980 | - * Lesser General Public License for more details. |
981 | - * |
982 | - * You should have received a copy of the GNU Lesser General Public License |
983 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
984 | - */ |
985 | - |
986 | -#include "display.h" |
987 | - |
988 | -#include "screen.h" |
989 | -#include "mirserver.h" |
990 | - |
991 | -#include <mir/graphics/display.h> |
992 | -#include <mir/graphics/display_configuration.h> |
993 | - |
994 | -namespace mg = mir::graphics; |
995 | - |
996 | -// TODO: Listen for display changes and update the list accordingly |
997 | - |
998 | -Display::Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig) |
999 | -{ |
1000 | - displayConfig->for_each_output([this](mg::DisplayConfigurationOutput const& output) { |
1001 | - if (output.used) { |
1002 | - auto screen = new Screen(output); |
1003 | - m_screens.push_back(screen); |
1004 | - } |
1005 | - }); |
1006 | -} |
1007 | - |
1008 | -Display::~Display() |
1009 | -{ |
1010 | - for (auto screen : m_screens) |
1011 | - delete screen; |
1012 | - m_screens.clear(); |
1013 | -} |
1014 | |
1015 | === removed file 'src/platforms/mirserver/display.h' |
1016 | --- src/platforms/mirserver/display.h 2015-08-11 12:08:32 +0000 |
1017 | +++ src/platforms/mirserver/display.h 1970-01-01 00:00:00 +0000 |
1018 | @@ -1,37 +0,0 @@ |
1019 | -/* |
1020 | - * Copyright (C) 2013-2015 Canonical, Ltd. |
1021 | - * |
1022 | - * This program is free software: you can redistribute it and/or modify it under |
1023 | - * the terms of the GNU Lesser General Public License version 3, as published by |
1024 | - * the Free Software Foundation. |
1025 | - * |
1026 | - * This program is distributed in the hope that it will be useful, but WITHOUT |
1027 | - * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1028 | - * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1029 | - * Lesser General Public License for more details. |
1030 | - * |
1031 | - * You should have received a copy of the GNU Lesser General Public License |
1032 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1033 | - */ |
1034 | - |
1035 | -#ifndef DISPLAY_H |
1036 | -#define DISPLAY_H |
1037 | - |
1038 | -#include <qpa/qplatformscreen.h> |
1039 | -#include <memory> |
1040 | - |
1041 | -namespace mir { namespace graphics { class DisplayConfiguration; }} |
1042 | - |
1043 | -class Display |
1044 | -{ |
1045 | -public: |
1046 | - Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig); |
1047 | - virtual ~Display(); |
1048 | - |
1049 | - QList<QPlatformScreen *> screens() const { return m_screens; } |
1050 | - |
1051 | -private: |
1052 | - QList<QPlatformScreen *> m_screens; |
1053 | -}; |
1054 | - |
1055 | -#endif // DISPLAY_H |
1056 | |
1057 | === modified file 'src/platforms/mirserver/logging.h' |
1058 | --- src/platforms/mirserver/logging.h 2014-10-01 18:42:26 +0000 |
1059 | +++ src/platforms/mirserver/logging.h 2015-09-09 18:37:39 +0000 |
1060 | @@ -25,5 +25,6 @@ |
1061 | Q_DECLARE_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES) |
1062 | Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_INPUT) |
1063 | Q_DECLARE_LOGGING_CATEGORY(QTMIR_CLIPBOARD) |
1064 | +Q_DECLARE_LOGGING_CATEGORY(QTMIR_SCREENS) |
1065 | |
1066 | #endif // UBUNTU_APPLICATION_PLUGIN_LOGGING_H |
1067 | |
1068 | === modified file 'src/platforms/mirserver/miropenglcontext.cpp' |
1069 | --- src/platforms/mirserver/miropenglcontext.cpp 2015-08-11 12:08:32 +0000 |
1070 | +++ src/platforms/mirserver/miropenglcontext.cpp 2015-09-09 18:37:39 +0000 |
1071 | @@ -16,12 +16,14 @@ |
1072 | |
1073 | #include "miropenglcontext.h" |
1074 | |
1075 | -#include "displaywindow.h" |
1076 | +#include "offscreensurface.h" |
1077 | +#include "mirglconfig.h" |
1078 | #include "mirserver.h" |
1079 | -#include "mirglconfig.h" |
1080 | +#include "screenwindow.h" |
1081 | |
1082 | #include <QDebug> |
1083 | |
1084 | +#include <QOpenGLFramebufferObject> |
1085 | #include <QSurfaceFormat> |
1086 | #include <QtPlatformSupport/private/qeglconvenience_p.h> |
1087 | |
1088 | @@ -38,10 +40,10 @@ |
1089 | : m_logger(new QOpenGLDebugLogger(this)) |
1090 | #endif |
1091 | { |
1092 | - std::shared_ptr<mir::graphics::Display> display = server->the_display(); |
1093 | + m_display = server->the_display(); |
1094 | |
1095 | // create a temporary GL context to fetch the EGL display and config, so Qt can determine the surface format |
1096 | - std::unique_ptr<mir::graphics::GLContext> mirContext = display->create_gl_context(); |
1097 | + std::unique_ptr<mir::graphics::GLContext> mirContext = m_display->create_gl_context(); |
1098 | mirContext->make_current(); |
1099 | |
1100 | EGLDisplay eglDisplay = eglGetCurrentDisplay(); |
1101 | @@ -106,17 +108,30 @@ |
1102 | |
1103 | void MirOpenGLContext::swapBuffers(QPlatformSurface *surface) |
1104 | { |
1105 | - // ultimately calls Mir's DisplayBuffer::post_update() |
1106 | - DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface); |
1107 | - displayBuffer->swapBuffers(); //blocks for vsync |
1108 | + if (surface->surface()->surfaceClass() == QSurface::Offscreen) { |
1109 | + // NOOP |
1110 | + } else { |
1111 | + // ultimately calls Mir's DisplayBuffer::post_update() |
1112 | + ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface); |
1113 | + screenWindow->swapBuffers(); //blocks for vsync |
1114 | + } |
1115 | } |
1116 | |
1117 | bool MirOpenGLContext::makeCurrent(QPlatformSurface *surface) |
1118 | { |
1119 | + if (surface->surface()->surfaceClass() == QSurface::Offscreen) { |
1120 | + auto offscreen = static_cast<OffscreenSurface *>(surface); |
1121 | + if (!offscreen->buffer()) { |
1122 | + auto buffer = new QOpenGLFramebufferObject(surface->surface()->size()); |
1123 | + offscreen->setBuffer(buffer); |
1124 | + } |
1125 | + return offscreen->buffer()->bind(); |
1126 | + } |
1127 | + |
1128 | // ultimately calls Mir's DisplayBuffer::make_current() |
1129 | - DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface); |
1130 | - if (displayBuffer) { |
1131 | - displayBuffer->makeCurrent(); |
1132 | + ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface); |
1133 | + if (screenWindow) { |
1134 | + screenWindow->makeCurrent(); |
1135 | |
1136 | #ifndef QT_NO_DEBUG |
1137 | if (!m_logger->isLogging() && m_logger->initialize()) { |
1138 | @@ -133,7 +148,9 @@ |
1139 | |
1140 | void MirOpenGLContext::doneCurrent() |
1141 | { |
1142 | - // could call Mir's DisplayBuffer::release_current(), but for what DisplayBuffer? |
1143 | + // FIXME: create a temporary GL context just to release? Would be better to get existing one. |
1144 | + std::unique_ptr<mir::graphics::GLContext> mirContext = m_display->create_gl_context(); |
1145 | + mirContext->release_current(); |
1146 | } |
1147 | |
1148 | QFunctionPointer MirOpenGLContext::getProcAddress(const QByteArray &procName) |
1149 | |
1150 | === modified file 'src/platforms/mirserver/miropenglcontext.h' |
1151 | --- src/platforms/mirserver/miropenglcontext.h 2015-08-11 12:08:32 +0000 |
1152 | +++ src/platforms/mirserver/miropenglcontext.h 2015-09-09 18:37:39 +0000 |
1153 | @@ -23,6 +23,10 @@ |
1154 | #include <QOpenGLDebugLogger> |
1155 | #endif |
1156 | |
1157 | +#include <memory> |
1158 | + |
1159 | +namespace mir { namespace graphics { class Display; }} |
1160 | + |
1161 | class MirServer; |
1162 | |
1163 | class MirOpenGLContext : public QObject, public QPlatformOpenGLContext |
1164 | @@ -47,6 +51,7 @@ |
1165 | #endif |
1166 | |
1167 | private: |
1168 | + std::shared_ptr<mir::graphics::Display> m_display; |
1169 | QSurfaceFormat m_format; |
1170 | #ifndef QT_NO_DEBUG |
1171 | QOpenGLDebugLogger *m_logger; |
1172 | |
1173 | === modified file 'src/platforms/mirserver/mirserver.cpp' |
1174 | --- src/platforms/mirserver/mirserver.cpp 2015-08-11 12:08:32 +0000 |
1175 | +++ src/platforms/mirserver/mirserver.cpp 2015-09-09 18:37:39 +0000 |
1176 | @@ -23,15 +23,25 @@ |
1177 | #include "mirglconfig.h" |
1178 | #include "mirserverstatuslistener.h" |
1179 | #include "promptsessionlistener.h" |
1180 | +#include "screencontroller.h" |
1181 | #include "sessionlistener.h" |
1182 | #include "sessionauthorizer.h" |
1183 | #include "qtcompositor.h" |
1184 | #include "qteventfeeder.h" |
1185 | +#include "tileddisplayconfigurationpolicy.h" |
1186 | #include "logging.h" |
1187 | |
1188 | +// std |
1189 | +#include <memory> |
1190 | + |
1191 | // egl |
1192 | +#define MESA_EGL_NO_X11_HEADERS |
1193 | #include <EGL/egl.h> |
1194 | |
1195 | +// mir |
1196 | +#include <mir/graphics/cursor.h> |
1197 | + |
1198 | +namespace mg = mir::graphics; |
1199 | namespace mo = mir::options; |
1200 | namespace msh = mir::shell; |
1201 | namespace ms = mir::scene; |
1202 | @@ -45,8 +55,10 @@ |
1203 | |
1204 | Q_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES, "qtmir.mir") |
1205 | |
1206 | -MirServer::MirServer(int argc, char const* argv[], QObject* parent) |
1207 | +MirServer::MirServer(int argc, char const* argv[], |
1208 | + const QSharedPointer<ScreenController> &screenController, QObject* parent) |
1209 | : QObject(parent) |
1210 | + , m_screenController(screenController) |
1211 | { |
1212 | set_command_line_handler(&ignore_unparsed_arguments); |
1213 | set_command_line(argc, argv); |
1214 | @@ -71,9 +83,9 @@ |
1215 | return std::make_shared<QtCompositor>(); |
1216 | }); |
1217 | |
1218 | - override_the_input_dispatcher([] |
1219 | + override_the_input_dispatcher([&screenController] |
1220 | { |
1221 | - return std::make_shared<QtEventFeeder>(); |
1222 | + return std::make_shared<QtEventFeeder>(screenController); |
1223 | }); |
1224 | |
1225 | override_the_gl_config([] |
1226 | @@ -92,17 +104,39 @@ |
1227 | return std::make_shared<MirWindowManager>(the_shell_display_layout()); |
1228 | }); |
1229 | |
1230 | - set_terminator([&](int) |
1231 | + wrap_display_configuration_policy( |
1232 | + [](const std::shared_ptr<mg::DisplayConfigurationPolicy> &wrapped) |
1233 | + -> std::shared_ptr<mg::DisplayConfigurationPolicy> |
1234 | + { |
1235 | + return std::make_shared<TiledDisplayConfigurationPolicy>(wrapped); |
1236 | + }); |
1237 | + |
1238 | + set_terminator([](int) |
1239 | { |
1240 | qDebug() << "Signal caught by Mir, stopping Mir server.."; |
1241 | QCoreApplication::quit(); |
1242 | }); |
1243 | |
1244 | + add_init_callback([this, &screenController] { |
1245 | + screenController->init(the_display(), the_compositor()); |
1246 | + }); |
1247 | + |
1248 | apply_settings(); |
1249 | |
1250 | + // We will draw our own cursor. |
1251 | + add_init_callback([this](){ the_cursor()->hide(); }); |
1252 | + |
1253 | qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created"; |
1254 | } |
1255 | |
1256 | +// Override default implementation to ensure we terminate the ScreenController first. |
1257 | +// Code path followed when Qt tries to shutdown the server. |
1258 | +void MirServer::stop() |
1259 | +{ |
1260 | + m_screenController->terminate(); |
1261 | + mir::Server::stop(); |
1262 | +} |
1263 | + |
1264 | |
1265 | /************************************ Shell side ************************************/ |
1266 | |
1267 | |
1268 | === modified file 'src/platforms/mirserver/mirserver.h' |
1269 | --- src/platforms/mirserver/mirserver.h 2015-08-11 12:08:32 +0000 |
1270 | +++ src/platforms/mirserver/mirserver.h 2015-09-09 18:37:39 +0000 |
1271 | @@ -18,6 +18,7 @@ |
1272 | #define MIRSERVER_H |
1273 | |
1274 | #include <QObject> |
1275 | +#include <QSharedPointer> |
1276 | #include <mir/server.h> |
1277 | |
1278 | class QtEventFeeder; |
1279 | @@ -25,6 +26,7 @@ |
1280 | class SessionAuthorizer; |
1281 | using MirShell = mir::shell::Shell; |
1282 | class PromptSessionListener; |
1283 | +class ScreenController; |
1284 | |
1285 | // We use virtual inheritance of mir::Server to facilitate derived classes (e.g. testing) |
1286 | // calling initialization functions before MirServer is constructed. |
1287 | @@ -38,12 +40,12 @@ |
1288 | Q_PROPERTY(PromptSessionListener* promptSessionListener READ promptSessionListener CONSTANT) |
1289 | |
1290 | public: |
1291 | - MirServer(int argc, char const* argv[], QObject* parent = 0); |
1292 | + MirServer(int argc, char const* argv[], const QSharedPointer<ScreenController> &, QObject* parent = 0); |
1293 | ~MirServer() = default; |
1294 | |
1295 | /* mir specific */ |
1296 | using mir::Server::run; |
1297 | - using mir::Server::stop; |
1298 | + using mir::Server::the_compositor; |
1299 | using mir::Server::the_display; |
1300 | using mir::Server::the_gl_config; |
1301 | using mir::Server::the_main_loop; |
1302 | @@ -52,6 +54,8 @@ |
1303 | using mir::Server::the_session_authorizer; |
1304 | using mir::Server::the_session_listener; |
1305 | |
1306 | + void stop(); |
1307 | + |
1308 | /* qt specific */ |
1309 | // getters |
1310 | SessionAuthorizer *sessionAuthorizer(); |
1311 | @@ -60,7 +64,9 @@ |
1312 | MirShell *shell(); |
1313 | |
1314 | private: |
1315 | + std::weak_ptr<MirShell> m_shell; |
1316 | std::shared_ptr<QtEventFeeder> m_qtEventFeeder; |
1317 | + const QSharedPointer<ScreenController> m_screenController; |
1318 | }; |
1319 | |
1320 | #endif // MIRSERVER_H |
1321 | |
1322 | === modified file 'src/platforms/mirserver/mirserverintegration.cpp' |
1323 | --- src/platforms/mirserver/mirserverintegration.cpp 2015-08-11 12:08:32 +0000 |
1324 | +++ src/platforms/mirserver/mirserverintegration.cpp 2015-09-09 18:37:39 +0000 |
1325 | @@ -26,7 +26,8 @@ |
1326 | #include <qpa/qplatforminputcontextfactory_p.h> |
1327 | #include <qpa/qwindowsysteminterface.h> |
1328 | |
1329 | -#include <QCoreApplication> |
1330 | +#include <QGuiApplication> |
1331 | +#include <QStringList> |
1332 | #include <QOpenGLContext> |
1333 | #include <QDebug> |
1334 | |
1335 | @@ -36,13 +37,16 @@ |
1336 | |
1337 | // local |
1338 | #include "clipboard.h" |
1339 | -#include "display.h" |
1340 | -#include "displaywindow.h" |
1341 | #include "miropenglcontext.h" |
1342 | #include "nativeinterface.h" |
1343 | +#include "offscreensurface.h" |
1344 | #include "qmirserver.h" |
1345 | +#include "screen.h" |
1346 | +#include "screencontroller.h" |
1347 | +#include "screenwindow.h" |
1348 | #include "services.h" |
1349 | #include "ubuntutheme.h" |
1350 | +#include "logging.h" |
1351 | |
1352 | namespace mg = mir::graphics; |
1353 | using qtmir::Clipboard; |
1354 | @@ -52,7 +56,6 @@ |
1355 | , m_fontDb(new QGenericUnixFontDatabase()) |
1356 | , m_services(new Services) |
1357 | , m_mirServer(new QMirServer(QCoreApplication::arguments())) |
1358 | - , m_display(nullptr) |
1359 | , m_nativeInterface(nullptr) |
1360 | , m_clipboard(new Clipboard) |
1361 | { |
1362 | @@ -72,12 +75,14 @@ |
1363 | QCoreApplication::instance(), &QCoreApplication::quit); |
1364 | |
1365 | m_inputContext = QPlatformInputContextFactory::create(); |
1366 | + |
1367 | + // Default Qt behaviour doesn't match a shell's intentions, so customize: |
1368 | + qGuiApp->setQuitOnLastWindowClosed(false); |
1369 | } |
1370 | |
1371 | MirServerIntegration::~MirServerIntegration() |
1372 | { |
1373 | delete m_nativeInterface; |
1374 | - delete m_display; |
1375 | } |
1376 | |
1377 | bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const |
1378 | @@ -87,7 +92,7 @@ |
1379 | case OpenGL: return true; |
1380 | case ThreadedOpenGL: return true; |
1381 | case BufferQueueingOpenGL: return true; |
1382 | - case MultipleWindows: return false; // multi-monitor support |
1383 | + case MultipleWindows: return true; // multi-monitor support |
1384 | case WindowManagement: return false; // platform has no WM, as this implements the WM! |
1385 | case NonFullScreenWindows: return false; |
1386 | default: return QPlatformIntegration::hasCapability(cap); |
1387 | @@ -98,44 +103,38 @@ |
1388 | { |
1389 | QWindowSystemInterface::flushWindowSystemEvents(); |
1390 | |
1391 | - DisplayWindow* displayWindow = nullptr; |
1392 | - |
1393 | - auto const mirServer = m_mirServer->mirServer().lock(); |
1394 | - mg::DisplayBuffer* first_buffer{nullptr}; |
1395 | - mg::DisplaySyncGroup* first_group{nullptr}; |
1396 | - if (mirServer) { |
1397 | - mirServer->the_display()->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) { |
1398 | - if (!first_group) { |
1399 | - first_group = &group; |
1400 | - } |
1401 | - group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) { |
1402 | - if (!first_buffer) { |
1403 | - first_buffer = &buffer; |
1404 | - } |
1405 | - }); |
1406 | - }); |
1407 | - } |
1408 | - |
1409 | - // FIXME(gerry) this will go very bad for >1 display buffer |
1410 | - if (first_group && first_buffer) |
1411 | - displayWindow = new DisplayWindow(window, first_group, first_buffer); |
1412 | - |
1413 | - if (!displayWindow) |
1414 | - return nullptr; |
1415 | - |
1416 | - //displayWindow->requestActivateWindow(); |
1417 | - return displayWindow; |
1418 | + // FIXME: QWindow can be created specifying a destination QScreen. For now we |
1419 | + // will ignore it and just associate any unused Screen, if available. |
1420 | + auto screens = m_mirServer->screenController().lock(); |
1421 | + if (!screens) { |
1422 | + qCritical("Screens are not initialized, unable to create a new QWindow/ScreenWindow"); |
1423 | + return nullptr; |
1424 | + } |
1425 | + Screen *screen = screens->getUnusedScreen(); |
1426 | + if (!screen) { |
1427 | + qCritical("No available Screens to create a new QWindow/ScreenWindow for"); |
1428 | + return nullptr; |
1429 | + } |
1430 | + QScreen *qscreen = screen->screen(); |
1431 | + window->setScreen(qscreen); |
1432 | + |
1433 | + auto platformWindow = new ScreenWindow(window); |
1434 | + if (screens->compositing()) { |
1435 | + platformWindow->setExposed(true); |
1436 | + } |
1437 | + |
1438 | + qCDebug(QTMIR_SCREENS) << "New" << window << "with geom" << window->geometry() |
1439 | + << "is backed by a" << screen << "with geometry" << screen->geometry(); |
1440 | + return platformWindow; |
1441 | } |
1442 | |
1443 | -QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow *window) const |
1444 | +QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow */*window*/) const |
1445 | { |
1446 | - qDebug() << "createPlatformBackingStore" << window; |
1447 | return nullptr; |
1448 | } |
1449 | |
1450 | QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const |
1451 | { |
1452 | - qDebug() << "createPlatformOpenGLContext" << context; |
1453 | return new MirOpenGLContext(m_mirServer->mirServer(), context->format()); |
1454 | } |
1455 | |
1456 | @@ -151,12 +150,18 @@ |
1457 | exit(2); |
1458 | } |
1459 | |
1460 | - m_display = new Display(m_mirServer->mirServer().data()->the_display()->configuration()); |
1461 | + auto screens = m_mirServer->screenController().lock(); |
1462 | + if (!screens) { |
1463 | + qFatal("ScreenController not initialized"); |
1464 | + } |
1465 | + QObject::connect(screens.data(), &ScreenController::screenAdded, |
1466 | + [this](Screen *screen) { this->screenAdded(screen); }); |
1467 | + Q_FOREACH(auto screen, screens->screens()) { |
1468 | + screenAdded(screen); |
1469 | + } |
1470 | + |
1471 | m_nativeInterface = new NativeInterface(m_mirServer->mirServer()); |
1472 | |
1473 | - for (QPlatformScreen *screen : m_display->screens()) |
1474 | - screenAdded(screen); |
1475 | - |
1476 | m_clipboard->setupDBusService(); |
1477 | } |
1478 | |
1479 | @@ -195,3 +200,9 @@ |
1480 | { |
1481 | return m_clipboard.data(); |
1482 | } |
1483 | + |
1484 | +QPlatformOffscreenSurface *MirServerIntegration::createPlatformOffscreenSurface( |
1485 | + QOffscreenSurface *surface) const |
1486 | +{ |
1487 | + return new OffscreenSurface(surface); |
1488 | +} |
1489 | |
1490 | === modified file 'src/platforms/mirserver/mirserverintegration.h' |
1491 | --- src/platforms/mirserver/mirserverintegration.h 2015-08-11 12:08:32 +0000 |
1492 | +++ src/platforms/mirserver/mirserverintegration.h 2015-09-09 18:37:39 +0000 |
1493 | @@ -19,13 +19,9 @@ |
1494 | |
1495 | // qt |
1496 | #include <qpa/qplatformintegration.h> |
1497 | - |
1498 | -// local |
1499 | -#include "mirserver.h" |
1500 | - |
1501 | -class Display; |
1502 | +#include <QScopedPointer> |
1503 | + |
1504 | class NativeInterface; |
1505 | -class MirServer; |
1506 | class QMirServer; |
1507 | |
1508 | namespace qtmir { |
1509 | @@ -60,6 +56,8 @@ |
1510 | |
1511 | QPlatformNativeInterface *nativeInterface() const override; |
1512 | |
1513 | + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; |
1514 | + |
1515 | private: |
1516 | QScopedPointer<QPlatformAccessibility> m_accessibility; |
1517 | QScopedPointer<QPlatformFontDatabase> m_fontDb; |
1518 | @@ -67,7 +65,6 @@ |
1519 | |
1520 | QScopedPointer<QMirServer> m_mirServer; |
1521 | |
1522 | - Display *m_display; |
1523 | NativeInterface *m_nativeInterface; |
1524 | QPlatformInputContext* m_inputContext; |
1525 | QScopedPointer<qtmir::Clipboard> m_clipboard; |
1526 | |
1527 | === added file 'src/platforms/mirserver/mirsingleton.cpp' |
1528 | --- src/platforms/mirserver/mirsingleton.cpp 1970-01-01 00:00:00 +0000 |
1529 | +++ src/platforms/mirserver/mirsingleton.cpp 2015-09-09 18:37:39 +0000 |
1530 | @@ -0,0 +1,33 @@ |
1531 | +#include "mirsingleton.h" |
1532 | + |
1533 | +qtmir::Mir *qtmir::Mir::m_instance = nullptr; |
1534 | + |
1535 | +qtmir::Mir::Mir() |
1536 | +{ |
1537 | +} |
1538 | + |
1539 | +qtmir::Mir::~Mir() |
1540 | +{ |
1541 | + m_instance = nullptr; |
1542 | +} |
1543 | + |
1544 | +qtmir::Mir *qtmir::Mir::instance() |
1545 | +{ |
1546 | + if (!m_instance) { |
1547 | + m_instance = new qtmir::Mir; |
1548 | + } |
1549 | + return m_instance; |
1550 | +} |
1551 | + |
1552 | +void qtmir::Mir::setCursorName(const QString &cursorName) |
1553 | +{ |
1554 | + if (m_cursorName != cursorName) { |
1555 | + m_cursorName = cursorName; |
1556 | + Q_EMIT cursorNameChanged(m_cursorName); |
1557 | + } |
1558 | +} |
1559 | + |
1560 | +QString qtmir::Mir::cursorName() const |
1561 | +{ |
1562 | + return m_cursorName; |
1563 | +} |
1564 | |
1565 | === added file 'src/platforms/mirserver/mirsingleton.h' |
1566 | --- src/platforms/mirserver/mirsingleton.h 1970-01-01 00:00:00 +0000 |
1567 | +++ src/platforms/mirserver/mirsingleton.h 2015-09-09 18:37:39 +0000 |
1568 | @@ -0,0 +1,45 @@ |
1569 | +/* |
1570 | + * Copyright (C) 2015 Canonical, Ltd. |
1571 | + * |
1572 | + * This program is free software: you can redistribute it and/or modify it under |
1573 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1574 | + * the Free Software Foundation. |
1575 | + * |
1576 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1577 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1578 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1579 | + * Lesser General Public License for more details. |
1580 | + * |
1581 | + * You should have received a copy of the GNU Lesser General Public License |
1582 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1583 | + */ |
1584 | + |
1585 | +#ifndef QTMIR_MIRSINGLETON_H |
1586 | +#define QTMIR_MIRSINGLETON_H |
1587 | + |
1588 | +// unity-api |
1589 | +#include <unity/shell/application/Mir.h> |
1590 | + |
1591 | +namespace qtmir { |
1592 | + |
1593 | +class Mir : public ::Mir |
1594 | +{ |
1595 | + Q_OBJECT |
1596 | +public: |
1597 | + virtual ~Mir(); |
1598 | + |
1599 | + static Mir *instance(); |
1600 | + |
1601 | + void setCursorName(const QString &cursorName) override; |
1602 | + QString cursorName() const override; |
1603 | + |
1604 | +private: |
1605 | + Mir(); |
1606 | + |
1607 | + QString m_cursorName; |
1608 | + static qtmir::Mir *m_instance; |
1609 | +}; |
1610 | + |
1611 | +} // namespace qtmir |
1612 | + |
1613 | +#endif // QTMIR_MIRSINGLETON_H |
1614 | |
1615 | === added file 'src/platforms/mirserver/offscreensurface.cpp' |
1616 | --- src/platforms/mirserver/offscreensurface.cpp 1970-01-01 00:00:00 +0000 |
1617 | +++ src/platforms/mirserver/offscreensurface.cpp 2015-09-09 18:37:39 +0000 |
1618 | @@ -0,0 +1,61 @@ |
1619 | +/* |
1620 | + * Copyright (C) 2015 Canonical, Ltd. |
1621 | + * |
1622 | + * This program is free software: you can redistribute it and/or modify it under |
1623 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1624 | + * the Free Software Foundation. |
1625 | + * |
1626 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1627 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1628 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1629 | + * Lesser General Public License for more details. |
1630 | + * |
1631 | + * You should have received a copy of the GNU Lesser General Public License |
1632 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1633 | + */ |
1634 | + |
1635 | +#include "offscreensurface.h" |
1636 | + |
1637 | +#include "mirserver.h" |
1638 | + |
1639 | +// Mir |
1640 | +#include <mir/graphics/display.h> |
1641 | +#include <mir/graphics/gl_context.h> |
1642 | + |
1643 | +//Qt |
1644 | +#include <QOffscreenSurface> |
1645 | +#include <QOpenGLFramebufferObject> |
1646 | +#include <QSurfaceFormat> |
1647 | +#include <QtPlatformSupport/private/qeglconvenience_p.h> |
1648 | + |
1649 | +namespace mg = mir::graphics; |
1650 | + |
1651 | +OffscreenSurface::OffscreenSurface(QOffscreenSurface *offscreenSurface) |
1652 | + : QPlatformOffscreenSurface(offscreenSurface) |
1653 | + , m_buffer(nullptr) |
1654 | + , m_format(offscreenSurface->requestedFormat()) |
1655 | +{ |
1656 | +} |
1657 | + |
1658 | +QSurfaceFormat OffscreenSurface::format() const |
1659 | +{ |
1660 | + return m_format; |
1661 | +} |
1662 | + |
1663 | +bool OffscreenSurface::isValid() const |
1664 | +{ |
1665 | + if (m_buffer) { |
1666 | + return m_buffer->isValid(); |
1667 | + } |
1668 | + return false; |
1669 | +} |
1670 | + |
1671 | +QOpenGLFramebufferObject* OffscreenSurface::buffer() const |
1672 | +{ |
1673 | + return m_buffer; |
1674 | +} |
1675 | + |
1676 | +void OffscreenSurface::setBuffer(QOpenGLFramebufferObject *buffer) |
1677 | +{ |
1678 | + m_buffer = buffer; |
1679 | +} |
1680 | |
1681 | === added file 'src/platforms/mirserver/offscreensurface.h' |
1682 | --- src/platforms/mirserver/offscreensurface.h 1970-01-01 00:00:00 +0000 |
1683 | +++ src/platforms/mirserver/offscreensurface.h 2015-09-09 18:37:39 +0000 |
1684 | @@ -0,0 +1,43 @@ |
1685 | +/* |
1686 | + * Copyright (C) 2015 Canonical, Ltd. |
1687 | + * |
1688 | + * This program is free software: you can redistribute it and/or modify it under |
1689 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1690 | + * the Free Software Foundation. |
1691 | + * |
1692 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1693 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1694 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1695 | + * Lesser General Public License for more details. |
1696 | + * |
1697 | + * You should have received a copy of the GNU Lesser General Public License |
1698 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1699 | + */ |
1700 | + |
1701 | +#ifndef OFFSCREENSURFACE_H |
1702 | +#define OFFSCREENSURFACE_H |
1703 | + |
1704 | +#include <qpa/qplatformoffscreensurface.h> |
1705 | +#include <QSurfaceFormat> |
1706 | +#include <QSharedPointer> |
1707 | + |
1708 | +class MirServer; |
1709 | +class QOpenGLFramebufferObject; |
1710 | + |
1711 | +class OffscreenSurface : public QPlatformOffscreenSurface |
1712 | +{ |
1713 | +public: |
1714 | + OffscreenSurface(QOffscreenSurface *offscreenSurface); |
1715 | + |
1716 | + QSurfaceFormat format() const override; |
1717 | + bool isValid() const override; |
1718 | + |
1719 | + QOpenGLFramebufferObject* buffer() const; |
1720 | + void setBuffer(QOpenGLFramebufferObject *buffer); |
1721 | + |
1722 | +private: |
1723 | + QOpenGLFramebufferObject *m_buffer; |
1724 | + QSurfaceFormat m_format; |
1725 | +}; |
1726 | + |
1727 | +#endif // OFFSCREENSURFACE_H |
1728 | |
1729 | === modified file 'src/platforms/mirserver/qmirserver.cpp' |
1730 | --- src/platforms/mirserver/qmirserver.cpp 2015-05-19 15:36:17 +0000 |
1731 | +++ src/platforms/mirserver/qmirserver.cpp 2015-09-09 18:37:39 +0000 |
1732 | @@ -23,7 +23,8 @@ |
1733 | #include "mirserver.h" |
1734 | #include "qmirserver.h" |
1735 | #include "qmirserver_p.h" |
1736 | - |
1737 | +#include "screencontroller.h" |
1738 | +#include "screen.h" |
1739 | |
1740 | QMirServer::QMirServer(const QStringList &arguments, QObject *parent) |
1741 | : QObject(parent) |
1742 | @@ -40,7 +41,9 @@ |
1743 | } |
1744 | argv[argc] = '\0'; |
1745 | |
1746 | - d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv))); |
1747 | + d->screenController = QSharedPointer<ScreenController>(new ScreenController()); |
1748 | + |
1749 | + d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv), d->screenController)); |
1750 | |
1751 | d->serverThread = new MirServerThread(d->server); |
1752 | |
1753 | @@ -63,6 +66,7 @@ |
1754 | qCritical() << "ERROR: QMirServer - Mir failed to start"; |
1755 | return false; |
1756 | } |
1757 | + d->screenController->update(); |
1758 | |
1759 | Q_EMIT started(); |
1760 | return true; |
1761 | @@ -93,3 +97,9 @@ |
1762 | Q_D(const QMirServer); |
1763 | return d->server.toWeakRef(); |
1764 | } |
1765 | + |
1766 | +QWeakPointer<ScreenController> QMirServer::screenController() const |
1767 | +{ |
1768 | + Q_D(const QMirServer); |
1769 | + return d->screenController; |
1770 | +} |
1771 | |
1772 | === modified file 'src/platforms/mirserver/qmirserver.h' |
1773 | --- src/platforms/mirserver/qmirserver.h 2015-05-18 20:39:09 +0000 |
1774 | +++ src/platforms/mirserver/qmirserver.h 2015-09-09 18:37:39 +0000 |
1775 | @@ -23,6 +23,7 @@ |
1776 | |
1777 | class QMirServerPrivate; |
1778 | class MirServer; |
1779 | +class ScreenController; |
1780 | |
1781 | class QMirServer: public QObject |
1782 | { |
1783 | @@ -38,6 +39,8 @@ |
1784 | |
1785 | QWeakPointer<MirServer> mirServer() const; |
1786 | |
1787 | + QWeakPointer<ScreenController> screenController() const; |
1788 | + |
1789 | Q_SIGNALS: |
1790 | void started(); |
1791 | void stopped(); |
1792 | |
1793 | === modified file 'src/platforms/mirserver/qmirserver_p.h' |
1794 | --- src/platforms/mirserver/qmirserver_p.h 2015-05-18 18:30:33 +0000 |
1795 | +++ src/platforms/mirserver/qmirserver_p.h 2015-09-09 18:37:39 +0000 |
1796 | @@ -27,6 +27,7 @@ |
1797 | |
1798 | // local |
1799 | #include "mirserver.h" |
1800 | +#include "screencontroller.h" |
1801 | |
1802 | class QMirServer; |
1803 | class MirServerThread; |
1804 | @@ -34,6 +35,7 @@ |
1805 | struct QMirServerPrivate |
1806 | { |
1807 | QSharedPointer<MirServer> server; |
1808 | + QSharedPointer<ScreenController> screenController; |
1809 | MirServerThread *serverThread; |
1810 | }; |
1811 | |
1812 | |
1813 | === modified file 'src/platforms/mirserver/qtcompositor.cpp' |
1814 | --- src/platforms/mirserver/qtcompositor.cpp 2015-08-11 12:08:32 +0000 |
1815 | +++ src/platforms/mirserver/qtcompositor.cpp 2015-09-09 18:37:39 +0000 |
1816 | @@ -15,44 +15,19 @@ |
1817 | */ |
1818 | |
1819 | #include "qtcompositor.h" |
1820 | -#include "displaywindow.h" |
1821 | - |
1822 | -#include <QGuiApplication> |
1823 | -#include <QWindow> |
1824 | - |
1825 | -#include <QDebug> |
1826 | - |
1827 | -QtCompositor::QtCompositor() |
1828 | -{ |
1829 | - |
1830 | -} |
1831 | - |
1832 | +#include "logging.h" |
1833 | + |
1834 | +// Lives in a Mir thread |
1835 | void QtCompositor::start() |
1836 | { |
1837 | - // (Re)Start Qt's render thread by setting all its windows to exposed |
1838 | - setAllWindowsExposed(true); |
1839 | + qCDebug(QTMIR_SCREENS) << "QtCompositor::start"; |
1840 | + |
1841 | + Q_EMIT starting(); // blocks |
1842 | } |
1843 | |
1844 | void QtCompositor::stop() |
1845 | { |
1846 | - // Stop Qt's render threads by setting all its windows it obscured |
1847 | - setAllWindowsExposed(false); |
1848 | -} |
1849 | - |
1850 | -void QtCompositor::setAllWindowsExposed(const bool exposed) |
1851 | -{ |
1852 | - qDebug() << "QtCompositor::setAllWindowsExposed" << exposed; |
1853 | - QList<QWindow *> windowList = QGuiApplication::allWindows(); |
1854 | - |
1855 | - // manipulate Qt object's indirectly via posted events as we're not in Qt's GUI thread |
1856 | - auto iterator = windowList.constBegin(); |
1857 | - while (iterator != windowList.constEnd()) { |
1858 | - QWindow *window = *iterator; |
1859 | - DisplayWindow *displayWindow = static_cast<DisplayWindow*>(window->handle()); |
1860 | - if (displayWindow) { |
1861 | - QCoreApplication::postEvent(displayWindow, |
1862 | - new QEvent( (exposed) ? QEvent::Show : QEvent::Hide)); |
1863 | - } |
1864 | - iterator++; |
1865 | - } |
1866 | + qCDebug(QTMIR_SCREENS) << "QtCompositor::stop"; |
1867 | + |
1868 | + Q_EMIT stopping(); // blocks |
1869 | } |
1870 | |
1871 | === modified file 'src/platforms/mirserver/qtcompositor.h' |
1872 | --- src/platforms/mirserver/qtcompositor.h 2015-08-11 12:08:32 +0000 |
1873 | +++ src/platforms/mirserver/qtcompositor.h 2015-09-09 18:37:39 +0000 |
1874 | @@ -17,18 +17,26 @@ |
1875 | #ifndef QTCOMPOSITOR_H |
1876 | #define QTCOMPOSITOR_H |
1877 | |
1878 | -#include "mir/compositor/compositor.h" |
1879 | - |
1880 | -class QtCompositor : public mir::compositor::Compositor |
1881 | +#include <mir/compositor/compositor.h> |
1882 | + |
1883 | +// Qt |
1884 | +#include <QObject> |
1885 | + |
1886 | +class QtCompositor : public QObject, public mir::compositor::Compositor |
1887 | { |
1888 | + Q_OBJECT |
1889 | public: |
1890 | - QtCompositor(); |
1891 | + QtCompositor() = default; |
1892 | + virtual ~QtCompositor() noexcept = default; |
1893 | |
1894 | void start(); |
1895 | void stop(); |
1896 | |
1897 | +Q_SIGNALS: |
1898 | + void starting(); |
1899 | + void stopping(); |
1900 | + |
1901 | private: |
1902 | - void setAllWindowsExposed(const bool exposed); |
1903 | }; |
1904 | |
1905 | #endif // QTCOMPOSITOR_H |
1906 | |
1907 | === modified file 'src/platforms/mirserver/qteventfeeder.cpp' |
1908 | --- src/platforms/mirserver/qteventfeeder.cpp 2015-08-11 12:08:32 +0000 |
1909 | +++ src/platforms/mirserver/qteventfeeder.cpp 2015-09-09 18:37:39 +0000 |
1910 | @@ -15,7 +15,10 @@ |
1911 | */ |
1912 | |
1913 | #include "qteventfeeder.h" |
1914 | +#include "cursor.h" |
1915 | #include "logging.h" |
1916 | +#include "screencontroller.h" |
1917 | +#include "screen.h" |
1918 | |
1919 | #include <qpa/qplatforminputcontext.h> |
1920 | #include <qpa/qplatformintegration.h> |
1921 | @@ -365,20 +368,29 @@ |
1922 | |
1923 | namespace { |
1924 | |
1925 | -class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface { |
1926 | - |
1927 | - bool hasTargetWindow() override |
1928 | - { |
1929 | - if (mTopLevelWindow.isNull() && !QGuiApplication::topLevelWindows().isEmpty()) { |
1930 | - mTopLevelWindow = QGuiApplication::topLevelWindows().first(); |
1931 | - } |
1932 | - return !mTopLevelWindow.isNull(); |
1933 | - } |
1934 | - |
1935 | - QRect targetWindowGeometry() override |
1936 | - { |
1937 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
1938 | - return mTopLevelWindow->geometry(); |
1939 | +class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface |
1940 | +{ |
1941 | +public: |
1942 | + QtWindowSystem() |
1943 | + { |
1944 | + // because we're using QMetaObject::invoke with arguments of those types |
1945 | + qRegisterMetaType<Qt::KeyboardModifiers>("Qt::KeyboardModifiers"); |
1946 | + qRegisterMetaType<Qt::MouseButton>("Qt::MouseButton"); |
1947 | + } |
1948 | + |
1949 | + void setScreenController(const QSharedPointer<ScreenController> &sc) override |
1950 | + { |
1951 | + m_screenController = sc; |
1952 | + } |
1953 | + |
1954 | + virtual QWindow* focusedWindow() override |
1955 | + { |
1956 | + return QGuiApplication::focusWindow(); |
1957 | + } |
1958 | + |
1959 | + QWindow* getWindowForTouchPoint(const QPoint &point) override //FIXME: not efficient, not updating focused window |
1960 | + { |
1961 | + return m_screenController->getWindowForPoint(point); |
1962 | } |
1963 | |
1964 | void registerTouchDevice(QTouchDevice *device) override |
1965 | @@ -386,47 +398,56 @@ |
1966 | QWindowSystemInterface::registerTouchDevice(device); |
1967 | } |
1968 | |
1969 | - void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key, |
1970 | + void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key, |
1971 | Qt::KeyboardModifiers modifiers, |
1972 | quint32 nativeScanCode, quint32 nativeVirtualKey, |
1973 | quint32 nativeModifiers, |
1974 | const QString& text, bool autorep, ushort count) override |
1975 | { |
1976 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
1977 | - QWindowSystemInterface::handleExtendedKeyEvent(mTopLevelWindow.data(), timestamp, type, key, modifiers, |
1978 | + QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, type, key, modifiers, |
1979 | nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); |
1980 | } |
1981 | |
1982 | - void handleTouchEvent(ulong timestamp, QTouchDevice *device, |
1983 | + void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device, |
1984 | const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override |
1985 | { |
1986 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
1987 | - QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods); |
1988 | + QWindowSystemInterface::handleTouchEvent(window, timestamp, device, points, mods); |
1989 | } |
1990 | |
1991 | - void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) override |
1992 | + void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons, |
1993 | + Qt::KeyboardModifiers modifiers) override |
1994 | { |
1995 | - Q_ASSERT(!mTopLevelWindow.isNull()); |
1996 | - QWindowSystemInterface::handleMouseEvent(mTopLevelWindow.data(), timestamp, point, point, // local and global point are the same |
1997 | - buttons, modifiers); |
1998 | + // Send to the first screen that handles the mouse event |
1999 | + // TODO: Have a mechanism to tell which screen currently has the logical mouse pointer |
2000 | + // (because they all might have their own separate graphical mouse pointer item) |
2001 | + // This will probably come once we implement the feature of having the mouse pointer |
2002 | + // crossing adjacent screens. |
2003 | + |
2004 | + QList<Screen*> screens = m_screenController->screens(); |
2005 | + bool eventHandled = false; |
2006 | + int i = 0; |
2007 | + while (i < screens.count() && !eventHandled) { |
2008 | + auto platformCursor = static_cast<qtmir::Cursor*>(screens[i]->cursor()); |
2009 | + eventHandled = platformCursor->handleMouseEvent(timestamp, movement, buttons, modifiers); |
2010 | + ++i; |
2011 | + } |
2012 | } |
2013 | |
2014 | - |
2015 | private: |
2016 | - QPointer<QWindow> mTopLevelWindow; |
2017 | + QSharedPointer<ScreenController> m_screenController; |
2018 | }; |
2019 | |
2020 | } // anonymous namespace |
2021 | |
2022 | - |
2023 | -QtEventFeeder::QtEventFeeder(QtEventFeeder::QtWindowSystemInterface *windowSystem) |
2024 | -{ |
2025 | - if (windowSystem) { |
2026 | - mQtWindowSystem = windowSystem; |
2027 | - } else { |
2028 | - mQtWindowSystem = new QtWindowSystem; |
2029 | - } |
2030 | - |
2031 | +QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController) |
2032 | + : QtEventFeeder(screenController, new QtWindowSystem) |
2033 | +{ |
2034 | +} |
2035 | + |
2036 | +QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController, |
2037 | + QtEventFeeder::QtWindowSystemInterface *windowSystem) |
2038 | + : mQtWindowSystem(windowSystem) |
2039 | +{ |
2040 | // Initialize touch device. Hardcoded just like in qtubuntu |
2041 | // TODO: Create them from info gathered from Mir and store things like device id and source |
2042 | // in a QTouchDevice-derived class created by us. So that we can properly assemble back |
2043 | @@ -436,6 +457,7 @@ |
2044 | mTouchDevice->setCapabilities( |
2045 | QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | |
2046 | QTouchDevice::NormalizedPosition); |
2047 | + mQtWindowSystem->setScreenController(screenController); |
2048 | mQtWindowSystem->registerTouchDevice(mTouchDevice); |
2049 | } |
2050 | |
2051 | @@ -449,6 +471,7 @@ |
2052 | auto type = mir_event_get_type(&event); |
2053 | if (type != mir_event_type_input) |
2054 | return false; |
2055 | + |
2056 | auto iev = mir_event_get_input_event(&event); |
2057 | |
2058 | switch (mir_input_event_get_type(iev)) { |
2059 | @@ -508,27 +531,20 @@ |
2060 | |
2061 | void QtEventFeeder::dispatchPointer(MirInputEvent const* ev) |
2062 | { |
2063 | - if (!mQtWindowSystem->hasTargetWindow()) |
2064 | - return; |
2065 | - |
2066 | auto timestamp = mir_input_event_get_event_time(ev) / 1000000; |
2067 | |
2068 | auto pev = mir_input_event_get_pointer_event(ev); |
2069 | auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev)); |
2070 | auto buttons = getQtMouseButtonsfromMirPointerEvent(pev); |
2071 | |
2072 | - auto local_point = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), |
2073 | - mir_pointer_event_axis_value(pev, mir_pointer_axis_y)); |
2074 | + auto movement = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x), |
2075 | + mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y)); |
2076 | |
2077 | - mQtWindowSystem->handleMouseEvent(timestamp, local_point, |
2078 | - buttons, modifiers); |
2079 | + mQtWindowSystem->handleMouseEvent(timestamp, movement, buttons, modifiers); |
2080 | } |
2081 | |
2082 | void QtEventFeeder::dispatchKey(MirInputEvent const* event) |
2083 | { |
2084 | - if (!mQtWindowSystem->hasTargetWindow()) |
2085 | - return; |
2086 | - |
2087 | ulong timestamp = mir_input_event_get_event_time(event) / 1000000; |
2088 | |
2089 | auto kev = mir_input_event_get_keyboard_event(event); |
2090 | @@ -575,7 +591,8 @@ |
2091 | } |
2092 | } |
2093 | |
2094 | - mQtWindowSystem->handleExtendedKeyEvent(timestamp, keyType, keyCode, modifiers, |
2095 | + mQtWindowSystem->handleExtendedKeyEvent(mQtWindowSystem->focusedWindow(), |
2096 | + timestamp, keyType, keyCode, modifiers, |
2097 | mir_keyboard_event_scan_code(kev), |
2098 | mir_keyboard_event_key_code(kev), |
2099 | mir_keyboard_event_modifiers(kev), text, is_auto_rep); |
2100 | @@ -583,59 +600,69 @@ |
2101 | |
2102 | void QtEventFeeder::dispatchTouch(MirInputEvent const* event) |
2103 | { |
2104 | - if (!mQtWindowSystem->hasTargetWindow()) |
2105 | - return; |
2106 | - |
2107 | auto tev = mir_input_event_get_touch_event(event); |
2108 | qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev)); |
2109 | |
2110 | // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That |
2111 | // needs to be fixed as soon as the compat input lib adds query support. |
2112 | const float kMaxPressure = 1.28; |
2113 | - const QRect kWindowGeometry = mQtWindowSystem->targetWindowGeometry(); |
2114 | + const int kPointerCount = mir_touch_event_point_count(tev); |
2115 | QList<QWindowSystemInterface::TouchPoint> touchPoints; |
2116 | - |
2117 | - // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left |
2118 | - // as Qt::TouchPointMoved |
2119 | - const int kPointerCount = mir_touch_event_point_count(tev); |
2120 | - for (int i = 0; i < kPointerCount; ++i) { |
2121 | - QWindowSystemInterface::TouchPoint touchPoint; |
2122 | - |
2123 | - const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x); |
2124 | - const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y); |
2125 | - const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major); |
2126 | - const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor); |
2127 | - const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure); |
2128 | - touchPoint.id = mir_touch_event_id(tev, i); |
2129 | - |
2130 | - touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height()); |
2131 | - touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH); |
2132 | - touchPoint.pressure = kP / kMaxPressure; |
2133 | - switch (mir_touch_event_action(tev, i)) |
2134 | - { |
2135 | - case mir_touch_action_up: |
2136 | - touchPoint.state = Qt::TouchPointReleased; |
2137 | - break; |
2138 | - case mir_touch_action_down: |
2139 | - touchPoint.state = Qt::TouchPointPressed; |
2140 | - break; |
2141 | - case mir_touch_action_change: |
2142 | - touchPoint.state = Qt::TouchPointMoved; |
2143 | - break; |
2144 | - default: |
2145 | - break; |
2146 | - } |
2147 | - |
2148 | - touchPoints.append(touchPoint); |
2149 | + QWindow *window = nullptr; |
2150 | + |
2151 | + if (kPointerCount > 0) { |
2152 | + window = mQtWindowSystem->getWindowForTouchPoint( |
2153 | + QPoint(mir_touch_event_axis_value(tev, 0, mir_touch_axis_x), |
2154 | + mir_touch_event_axis_value(tev, 0, mir_touch_axis_y))); |
2155 | + |
2156 | + if (!window) { |
2157 | + qCDebug(QTMIR_MIR_INPUT) << "REJECTING INPUT EVENT, no matching window"; |
2158 | + return; |
2159 | + } |
2160 | + |
2161 | + const QRect kWindowGeometry = window->geometry(); |
2162 | + |
2163 | + // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left |
2164 | + // as Qt::TouchPointMoved |
2165 | + for (int i = 0; i < kPointerCount; ++i) { |
2166 | + QWindowSystemInterface::TouchPoint touchPoint; |
2167 | + |
2168 | + const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x); |
2169 | + const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y); |
2170 | + const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major); |
2171 | + const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor); |
2172 | + const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure); |
2173 | + touchPoint.id = mir_touch_event_id(tev, i); |
2174 | + |
2175 | + touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height()); |
2176 | + touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH); |
2177 | + touchPoint.pressure = kP / kMaxPressure; |
2178 | + switch (mir_touch_event_action(tev, i)) |
2179 | + { |
2180 | + case mir_touch_action_up: |
2181 | + touchPoint.state = Qt::TouchPointReleased; |
2182 | + break; |
2183 | + case mir_touch_action_down: |
2184 | + touchPoint.state = Qt::TouchPointPressed; |
2185 | + break; |
2186 | + case mir_touch_action_change: |
2187 | + touchPoint.state = Qt::TouchPointMoved; |
2188 | + break; |
2189 | + default: |
2190 | + break; |
2191 | + } |
2192 | + |
2193 | + touchPoints.append(touchPoint); |
2194 | + } |
2195 | } |
2196 | |
2197 | // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding |
2198 | // any insanity. |
2199 | - validateTouches(mir_input_event_get_event_time(event) / 1000000, touchPoints); |
2200 | + validateTouches(window, mir_input_event_get_event_time(event) / 1000000, touchPoints); |
2201 | |
2202 | // Touch event propagation. |
2203 | qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints)); |
2204 | - mQtWindowSystem->handleTouchEvent( |
2205 | + mQtWindowSystem->handleTouchEvent(window, |
2206 | //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable |
2207 | mir_input_event_get_event_time(event) / 1000000, |
2208 | mTouchDevice, |
2209 | @@ -652,7 +679,7 @@ |
2210 | // not used |
2211 | } |
2212 | |
2213 | -void QtEventFeeder::validateTouches(ulong timestamp, |
2214 | +void QtEventFeeder::validateTouches(QWindow *window, ulong timestamp, |
2215 | QList<QWindowSystemInterface::TouchPoint> &touchPoints) |
2216 | { |
2217 | QSet<int> updatedTouches; |
2218 | @@ -676,7 +703,7 @@ |
2219 | if (!updatedTouches.contains(it.key())) { |
2220 | qCWarning(QTMIR_MIR_INPUT) |
2221 | << "There's a touch (id =" << it.key() << ") missing. Releasing it."; |
2222 | - sendActiveTouchRelease(timestamp, it.key()); |
2223 | + sendActiveTouchRelease(window, timestamp, it.key()); |
2224 | it = mActiveTouches.erase(it); |
2225 | } else { |
2226 | ++it; |
2227 | @@ -694,7 +721,7 @@ |
2228 | } |
2229 | } |
2230 | |
2231 | -void QtEventFeeder::sendActiveTouchRelease(ulong timestamp, int id) |
2232 | +void QtEventFeeder::sendActiveTouchRelease(QWindow *window, ulong timestamp, int id) |
2233 | { |
2234 | QList<QWindowSystemInterface::TouchPoint> touchPoints = mActiveTouches.values(); |
2235 | |
2236 | @@ -708,7 +735,7 @@ |
2237 | } |
2238 | |
2239 | qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints)); |
2240 | - mQtWindowSystem->handleTouchEvent(timestamp, mTouchDevice, touchPoints); |
2241 | + mQtWindowSystem->handleTouchEvent(window, timestamp, mTouchDevice, touchPoints); |
2242 | } |
2243 | |
2244 | bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint) |
2245 | |
2246 | === modified file 'src/platforms/mirserver/qteventfeeder.h' |
2247 | --- src/platforms/mirserver/qteventfeeder.h 2015-08-11 12:08:32 +0000 |
2248 | +++ src/platforms/mirserver/qteventfeeder.h 2015-09-09 18:37:39 +0000 |
2249 | @@ -23,6 +23,7 @@ |
2250 | #include <qpa/qwindowsysteminterface.h> |
2251 | |
2252 | class QTouchDevice; |
2253 | +class ScreenController; |
2254 | |
2255 | /* |
2256 | Fills Qt's event loop with input events from Mir |
2257 | @@ -33,26 +34,29 @@ |
2258 | // Interface between QtEventFeeder and the actual QWindowSystemInterface functions |
2259 | // and other related Qt methods and objects to enable replacing them with mocks in |
2260 | // pure unit tests. |
2261 | - // TODO - Make it work with multimonitor scenarios |
2262 | class QtWindowSystemInterface { |
2263 | public: |
2264 | virtual ~QtWindowSystemInterface() {} |
2265 | - virtual bool hasTargetWindow() = 0; |
2266 | - virtual QRect targetWindowGeometry() = 0; |
2267 | + virtual void setScreenController(const QSharedPointer<ScreenController> &sc) = 0; |
2268 | + virtual QWindow* getWindowForTouchPoint(const QPoint &point) = 0; |
2269 | + virtual QWindow* focusedWindow() = 0; |
2270 | virtual void registerTouchDevice(QTouchDevice *device) = 0; |
2271 | - virtual void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key, |
2272 | + virtual void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key, |
2273 | Qt::KeyboardModifiers modifiers, |
2274 | quint32 nativeScanCode, quint32 nativeVirtualKey, |
2275 | quint32 nativeModifiers, |
2276 | const QString& text = QString(), bool autorep = false, |
2277 | ushort count = 1) = 0; |
2278 | - virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device, |
2279 | + virtual void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device, |
2280 | const QList<struct QWindowSystemInterface::TouchPoint> &points, |
2281 | Qt::KeyboardModifiers mods = Qt::NoModifier) = 0; |
2282 | - virtual void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0; |
2283 | + virtual void handleMouseEvent(ulong timestamp, QPointF movement, |
2284 | + Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0; |
2285 | }; |
2286 | |
2287 | - QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr); |
2288 | + QtEventFeeder(const QSharedPointer<ScreenController> &screenController); |
2289 | + QtEventFeeder(const QSharedPointer<ScreenController> &screenController, |
2290 | + QtWindowSystemInterface *windowSystem); |
2291 | virtual ~QtEventFeeder(); |
2292 | |
2293 | static const int MirEventActionMask; |
2294 | @@ -67,9 +71,9 @@ |
2295 | void dispatchKey(MirInputEvent const* event); |
2296 | void dispatchTouch(MirInputEvent const* event); |
2297 | void dispatchPointer(MirInputEvent const* event); |
2298 | - void validateTouches(ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints); |
2299 | + void validateTouches(QWindow *window, ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints); |
2300 | bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint); |
2301 | - void sendActiveTouchRelease(ulong timestamp, int id); |
2302 | + void sendActiveTouchRelease(QWindow *window, ulong timestamp, int id); |
2303 | |
2304 | QString touchesToString(const QList<struct QWindowSystemInterface::TouchPoint> &points); |
2305 | |
2306 | |
2307 | === modified file 'src/platforms/mirserver/screen.cpp' |
2308 | --- src/platforms/mirserver/screen.cpp 2015-08-11 12:08:32 +0000 |
2309 | +++ src/platforms/mirserver/screen.cpp 2015-09-09 18:37:39 +0000 |
2310 | @@ -20,18 +20,21 @@ |
2311 | |
2312 | // Mir |
2313 | #include "mir/geometry/size.h" |
2314 | +#include "mir/graphics/buffer.h" |
2315 | +#include "mir/graphics/display_buffer.h" |
2316 | +#include "mir/graphics/display.h" |
2317 | |
2318 | // Qt |
2319 | #include <QCoreApplication> |
2320 | #include <qpa/qwindowsysteminterface.h> |
2321 | -#include <QtSensors/QOrientationSensor> |
2322 | -#include <QtSensors/QOrientationReading> |
2323 | #include <QThread> |
2324 | |
2325 | // Qt sensors |
2326 | #include <QtSensors/QOrientationReading> |
2327 | #include <QtSensors/QOrientationSensor> |
2328 | |
2329 | +using namespace qtmir; |
2330 | + |
2331 | namespace mg = mir::geometry; |
2332 | |
2333 | Q_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES, "qtmir.sensor") |
2334 | @@ -102,12 +105,15 @@ |
2335 | |
2336 | bool Screen::skipDBusRegistration = false; |
2337 | |
2338 | -Screen::Screen(mir::graphics::DisplayConfigurationOutput const &screen) |
2339 | +Screen::Screen(const mir::graphics::DisplayConfigurationOutput &screen) |
2340 | : QObject(nullptr) |
2341 | + , m_displayBuffer(nullptr) |
2342 | + , m_displayGroup(nullptr) |
2343 | , m_orientationSensor(new QOrientationSensor(this)) |
2344 | + , m_screenWindow(nullptr) |
2345 | , m_unityScreen(nullptr) |
2346 | { |
2347 | - readMirDisplayConfiguration(screen); |
2348 | + setMirDisplayConfiguration(screen); |
2349 | |
2350 | // Set the default orientation based on the initial screen dimmensions. |
2351 | m_nativeOrientation = (m_geometry.width() >= m_geometry.height()) |
2352 | @@ -139,6 +145,14 @@ |
2353 | } |
2354 | } |
2355 | |
2356 | +Screen::~Screen() |
2357 | +{ |
2358 | + //if a ScreenWindow associated with this screen, kill it |
2359 | + if (m_screenWindow) { |
2360 | + m_screenWindow->window()->destroy(); // ends up destroying m_ScreenWindow |
2361 | + } |
2362 | +} |
2363 | + |
2364 | bool Screen::orientationSensorEnabled() |
2365 | { |
2366 | return m_orientationSensor->isActive(); |
2367 | @@ -150,8 +164,15 @@ |
2368 | toggleSensors(status); |
2369 | } |
2370 | |
2371 | -void Screen::readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const &screen) |
2372 | +void Screen::setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &screen) |
2373 | { |
2374 | + // Note: DisplayConfigurationOutput will be destroyed after this function returns |
2375 | + |
2376 | + // Output data - each output has a unique id and corresponding type. Can be multiple cards. |
2377 | + m_outputId = screen.id; |
2378 | + m_cardId = screen.card_id; |
2379 | + m_type = screen.type; |
2380 | + |
2381 | // Physical screen size |
2382 | m_physicalSize.setWidth(screen.physical_size_mm.width.as_float()); |
2383 | m_physicalSize.setHeight(screen.physical_size_mm.height.as_float()); |
2384 | @@ -162,12 +183,34 @@ |
2385 | // Pixel depth |
2386 | m_depth = 8 * MIR_BYTES_PER_PIXEL(screen.current_format); |
2387 | |
2388 | - // Mode = Resolution & refresh rate |
2389 | + // Power mode |
2390 | + m_powerMode = screen.power_mode; |
2391 | + |
2392 | + QRect oldGeometry = m_geometry; |
2393 | + // Position of screen in virtual desktop coordinate space |
2394 | + m_geometry.setTop(screen.top_left.y.as_int()); |
2395 | + m_geometry.setLeft(screen.top_left.x.as_int()); |
2396 | + |
2397 | + // Mode = current resolution & refresh rate |
2398 | mir::graphics::DisplayConfigurationMode mode = screen.modes.at(screen.current_mode_index); |
2399 | m_geometry.setWidth(mode.size.width.as_int()); |
2400 | m_geometry.setHeight(mode.size.height.as_int()); |
2401 | |
2402 | - m_refreshRate = mode.vrefresh_hz; |
2403 | + // DPI - unnecessary to calculate, default implementation in QPlatformScreen is sufficient |
2404 | + |
2405 | + // Check for Screen geometry change |
2406 | + if (m_geometry != oldGeometry) { |
2407 | + QWindowSystemInterface::handleScreenGeometryChange(this->screen(), m_geometry, m_geometry); |
2408 | + if (m_screenWindow) { // resize corresponding window immediately |
2409 | + m_screenWindow->setGeometry(m_geometry); |
2410 | + } |
2411 | + } |
2412 | + |
2413 | + // Refresh rate |
2414 | + if (m_refreshRate != mode.vrefresh_hz) { |
2415 | + m_refreshRate = mode.vrefresh_hz; |
2416 | + QWindowSystemInterface::handleScreenRefreshRateChange(this->screen(), mode.vrefresh_hz); |
2417 | + } |
2418 | } |
2419 | |
2420 | void Screen::toggleSensors(const bool enable) const |
2421 | @@ -226,3 +269,57 @@ |
2422 | OrientationReadingEvent::m_type, |
2423 | m_orientationSensor->reading()->orientation())); |
2424 | } |
2425 | + |
2426 | +ScreenWindow* Screen::window() const |
2427 | +{ |
2428 | + return m_screenWindow; |
2429 | +} |
2430 | + |
2431 | +void Screen::setWindow(ScreenWindow *window) |
2432 | +{ |
2433 | + if (window && m_screenWindow) { |
2434 | + qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen::setWindow - overwriting existing ScreenWindow"; |
2435 | + } |
2436 | + m_screenWindow = window; |
2437 | +} |
2438 | + |
2439 | +void Screen::setMirDisplayBuffer(mir::graphics::DisplayBuffer *buffer, mir::graphics::DisplaySyncGroup *group) |
2440 | +{ |
2441 | + // This operation should only be performed while rendering is stopped |
2442 | + m_displayBuffer = buffer; |
2443 | + m_displayGroup = group; |
2444 | +} |
2445 | + |
2446 | +void Screen::swapBuffers() |
2447 | +{ |
2448 | + m_displayBuffer->gl_swap_buffers(); |
2449 | + |
2450 | + /* FIXME this exposes a QtMir architecture problem, as Screen is supposed to wrap a mg::DisplayBuffer. |
2451 | + * We use Qt's multithreaded renderer, where each Screen is rendered to relatively independently, and |
2452 | + * post() called also individually. |
2453 | + * |
2454 | + * But if this is a native server on Android, in the multimonitor case a DisplaySyncGroup can contain |
2455 | + * 2+ DisplayBuffers, one post() call will submit all mg::DisplayBuffers in the group for flipping. |
2456 | + * This will cause just one Screen to be updated, blocking the swap call for the other Screens, which |
2457 | + * will slow rendering dramatically. |
2458 | + * |
2459 | + * Integrating the Qt Scenegraph renderer as a Mir renderer should solve this issue. |
2460 | + */ |
2461 | + m_displayGroup->post(); |
2462 | +} |
2463 | + |
2464 | +void Screen::makeCurrent() |
2465 | +{ |
2466 | + m_displayBuffer->make_current(); |
2467 | +} |
2468 | + |
2469 | +void Screen::doneCurrent() |
2470 | +{ |
2471 | + m_displayBuffer->release_current(); |
2472 | +} |
2473 | + |
2474 | +QPlatformCursor *Screen::cursor() const |
2475 | +{ |
2476 | + const QPlatformCursor *platformCursor = &m_cursor; |
2477 | + return const_cast<QPlatformCursor *>(platformCursor); |
2478 | +} |
2479 | |
2480 | === modified file 'src/platforms/mirserver/screen.h' |
2481 | --- src/platforms/mirserver/screen.h 2015-08-11 12:08:32 +0000 |
2482 | +++ src/platforms/mirserver/screen.h 2015-09-09 18:37:39 +0000 |
2483 | @@ -17,20 +17,28 @@ |
2484 | #ifndef SCREEN_H |
2485 | #define SCREEN_H |
2486 | |
2487 | +// Qt |
2488 | #include <QObject> |
2489 | #include <QTimer> |
2490 | #include <QtDBus/QDBusInterface> |
2491 | #include <qpa/qplatformscreen.h> |
2492 | |
2493 | -#include "mir/graphics/display_configuration.h" |
2494 | +// Mir |
2495 | +#include <mir/graphics/display_configuration.h> |
2496 | + |
2497 | +// local |
2498 | +#include "cursor.h" |
2499 | +#include "screenwindow.h" |
2500 | |
2501 | class QOrientationSensor; |
2502 | +namespace mir { namespace graphics { class DisplayBuffer; class DisplaySyncGroup; }} |
2503 | |
2504 | class Screen : public QObject, public QPlatformScreen |
2505 | { |
2506 | Q_OBJECT |
2507 | public: |
2508 | - Screen(mir::graphics::DisplayConfigurationOutput const&); |
2509 | + Screen(const mir::graphics::DisplayConfigurationOutput &); |
2510 | + ~Screen(); |
2511 | |
2512 | // QPlatformScreen methods. |
2513 | QRect geometry() const override { return m_geometry; } |
2514 | @@ -40,8 +48,12 @@ |
2515 | qreal refreshRate() const override { return m_refreshRate; } |
2516 | Qt::ScreenOrientation nativeOrientation() const override { return m_nativeOrientation; } |
2517 | Qt::ScreenOrientation orientation() const override { return m_currentOrientation; } |
2518 | + QPlatformCursor *cursor() const override; |
2519 | |
2520 | void toggleSensors(const bool enable) const; |
2521 | + mir::graphics::DisplayConfigurationOutputType outputType() const { return m_type; } |
2522 | + |
2523 | + ScreenWindow* window() const; |
2524 | |
2525 | // QObject methods. |
2526 | void customEvent(QEvent* event) override; |
2527 | @@ -54,20 +66,40 @@ |
2528 | void onDisplayPowerStateChanged(int, int); |
2529 | void onOrientationReadingChanged(); |
2530 | |
2531 | +protected: |
2532 | + void setWindow(ScreenWindow *window); |
2533 | + |
2534 | + void setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &); |
2535 | + void setMirDisplayBuffer(mir::graphics::DisplayBuffer *, mir::graphics::DisplaySyncGroup *); |
2536 | + void swapBuffers(); |
2537 | + void makeCurrent(); |
2538 | + void doneCurrent(); |
2539 | + |
2540 | private: |
2541 | - void readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const&); |
2542 | - |
2543 | QRect m_geometry; |
2544 | int m_depth; |
2545 | QImage::Format m_format; |
2546 | QSizeF m_physicalSize; |
2547 | qreal m_refreshRate; |
2548 | |
2549 | + mir::graphics::DisplayBuffer *m_displayBuffer; |
2550 | + mir::graphics::DisplaySyncGroup *m_displayGroup; |
2551 | + mir::graphics::DisplayConfigurationOutputId m_outputId; |
2552 | + mir::graphics::DisplayConfigurationCardId m_cardId; |
2553 | + mir::graphics::DisplayConfigurationOutputType m_type; |
2554 | + MirPowerMode m_powerMode; |
2555 | + |
2556 | Qt::ScreenOrientation m_nativeOrientation; |
2557 | Qt::ScreenOrientation m_currentOrientation; |
2558 | QOrientationSensor *m_orientationSensor; |
2559 | |
2560 | + ScreenWindow *m_screenWindow; |
2561 | QDBusInterface *m_unityScreen; |
2562 | + |
2563 | + qtmir::Cursor m_cursor; |
2564 | + |
2565 | + friend class ScreenController; |
2566 | + friend class ScreenWindow; |
2567 | }; |
2568 | |
2569 | #endif // SCREEN_H |
2570 | |
2571 | === added file 'src/platforms/mirserver/screencontroller.cpp' |
2572 | --- src/platforms/mirserver/screencontroller.cpp 1970-01-01 00:00:00 +0000 |
2573 | +++ src/platforms/mirserver/screencontroller.cpp 2015-09-09 18:37:39 +0000 |
2574 | @@ -0,0 +1,257 @@ |
2575 | +/* |
2576 | + * Copyright (C) 2015 Canonical, Ltd. |
2577 | + * |
2578 | + * This program is free software: you can redistribute it and/or modify it under |
2579 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2580 | + * the Free Software Foundation. |
2581 | + * |
2582 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2583 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2584 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2585 | + * Lesser General Public License for more details. |
2586 | + * |
2587 | + * You should have received a copy of the GNU Lesser General Public License |
2588 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2589 | + */ |
2590 | + |
2591 | +#include "screencontroller.h" |
2592 | + |
2593 | +#include "screenwindow.h" |
2594 | +#include "qtcompositor.h" |
2595 | +#include "logging.h" |
2596 | +#include "mirserverintegration.h" |
2597 | +#include "screen.h" |
2598 | + |
2599 | +// Mir |
2600 | +#include <mir/graphics/display.h> |
2601 | +#include <mir/graphics/display_buffer.h> |
2602 | + |
2603 | +// Qt |
2604 | +#include <QScreen> |
2605 | +#include <QQuickWindow> |
2606 | +#include <qpa/qwindowsysteminterface.h> |
2607 | + |
2608 | +// std |
2609 | +#include <memory> |
2610 | + |
2611 | +Q_LOGGING_CATEGORY(QTMIR_SCREENS, "qtmir.screens") |
2612 | + |
2613 | +namespace mg = mir::graphics; |
2614 | + |
2615 | +ScreenController::ScreenController(QObject *parent) |
2616 | + : QObject(parent) |
2617 | + , m_compositing(false) |
2618 | +{ |
2619 | + qCDebug(QTMIR_SCREENS) << "ScreenController::ScreenController"; |
2620 | +} |
2621 | + |
2622 | +// init only after MirServer has initialized - runs on MirServerThread!!! |
2623 | +void ScreenController::init(const std::shared_ptr<mir::graphics::Display> &display, |
2624 | + const std::shared_ptr<mir::compositor::Compositor> &compositor) |
2625 | +{ |
2626 | + m_display = display; |
2627 | + m_compositor = compositor; |
2628 | + |
2629 | + // Use a Blocking Queued Connection to enforce synchronization of Qt GUI thread with Mir thread(s) |
2630 | + // on compositor shutdown. Compositor startup can be lazy. |
2631 | + // Queued connections work because the thread affinity of this class is with the Qt GUI thread. |
2632 | + auto qtCompositor = static_cast<QtCompositor *>(compositor.get()); |
2633 | + connect(qtCompositor, &QtCompositor::starting, |
2634 | + this, &ScreenController::onCompositorStarting); |
2635 | + connect(qtCompositor, &QtCompositor::stopping, |
2636 | + this, &ScreenController::onCompositorStopping, Qt::BlockingQueuedConnection); |
2637 | +} |
2638 | + |
2639 | +// terminate before shutting down the Mir server, or else liable to deadlock with the blocking connection above |
2640 | +// Runs on MirServerThread!!! |
2641 | +void ScreenController::terminate() |
2642 | +{ |
2643 | + auto qtCompositor = static_cast<QtCompositor *>(m_compositor.get()); |
2644 | + qtCompositor->disconnect(); |
2645 | +} |
2646 | + |
2647 | +void ScreenController::onCompositorStarting() |
2648 | +{ |
2649 | + qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStarting"; |
2650 | + m_compositing = true; |
2651 | + |
2652 | + update(); |
2653 | + |
2654 | + // (Re)Start Qt's render thread by setting all windows with a corresponding screen to exposed. |
2655 | + for (auto screen : m_screenList) { |
2656 | + auto window = static_cast<ScreenWindow *>(screen->window()); |
2657 | + if (window && window->window()) { |
2658 | + window->setExposed(true); |
2659 | + } |
2660 | + } |
2661 | +} |
2662 | + |
2663 | +void ScreenController::onCompositorStopping() |
2664 | +{ |
2665 | + qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStopping"; |
2666 | + m_compositing = false; |
2667 | + |
2668 | + // Stop Qt's render threads by setting all its windows it obscured. Must |
2669 | + // block until all windows have their GL contexts released. |
2670 | + for (auto screen : m_screenList) { |
2671 | + auto window = static_cast<ScreenWindow *>(screen->window()); |
2672 | + if (window && window->window()) { |
2673 | + window->setExposed(false); |
2674 | + } |
2675 | + } |
2676 | + |
2677 | + update(); |
2678 | +} |
2679 | + |
2680 | +void ScreenController::update() |
2681 | +{ |
2682 | + qCDebug(QTMIR_SCREENS) << "ScreenController::update"; |
2683 | + auto display = m_display.lock(); |
2684 | + if (!display) |
2685 | + return; |
2686 | + auto displayConfig = display->configuration(); |
2687 | + |
2688 | + // Mir only tells us something changed, it is up to us to figure out what. |
2689 | + QList<Screen*> newScreenList; |
2690 | + QList<Screen*> oldScreenList = m_screenList; |
2691 | + m_screenList.clear(); |
2692 | + |
2693 | + displayConfig->for_each_output( |
2694 | + [this, &oldScreenList, &newScreenList](const mg::DisplayConfigurationOutput &output) { |
2695 | + if (output.used && output.connected) { |
2696 | + Screen *screen = findScreenWithId(oldScreenList, output.id); |
2697 | + if (screen) { // we've already set up this display before, refresh its internals |
2698 | + screen->setMirDisplayConfiguration(output); |
2699 | + oldScreenList.removeAll(screen); |
2700 | + } else { |
2701 | + // new display, so create Screen for it |
2702 | + screen = this->createScreen(output); |
2703 | + newScreenList.append(screen); |
2704 | + qCDebug(QTMIR_SCREENS) << "Added Screen with id" << output.id.as_value() |
2705 | + << "and geometry" << screen->geometry(); |
2706 | + } |
2707 | + m_screenList.append(screen); |
2708 | + } |
2709 | + } |
2710 | + ); |
2711 | + |
2712 | + // Delete any old & unused Screens |
2713 | + for (auto screen: oldScreenList) { |
2714 | + qCDebug(QTMIR_SCREENS) << "Removed Screen with id" << screen->m_outputId.as_value() |
2715 | + << "and geometry" << screen->geometry(); |
2716 | + // The screen is automatically removed from Qt's internal list by the QPlatformScreen destructor. |
2717 | + auto window = static_cast<ScreenWindow *>(screen->window()); |
2718 | + if (window && window->window() && window->isExposed()) { |
2719 | + window->window()->hide(); |
2720 | + } |
2721 | + delete screen; |
2722 | + } |
2723 | + |
2724 | + // Match up the new Mir DisplayBuffers with each Screen |
2725 | + display->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) { |
2726 | + group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) { |
2727 | + // only way to match Screen to a DisplayBuffer is by matching the geometry |
2728 | + QRect dbGeom(buffer.view_area().top_left.x.as_int(), |
2729 | + buffer.view_area().top_left.y.as_int(), |
2730 | + buffer.view_area().size.width.as_int(), |
2731 | + buffer.view_area().size.height.as_int()); |
2732 | + |
2733 | + for (auto screen : m_screenList) { |
2734 | + if (dbGeom == screen->geometry()) { |
2735 | + screen->setMirDisplayBuffer(&buffer, &group); |
2736 | + break; |
2737 | + } |
2738 | + } |
2739 | + }); |
2740 | + }); |
2741 | + |
2742 | + qCDebug(QTMIR_SCREENS) << "======================================="; |
2743 | + for (auto screen: m_screenList) { |
2744 | + qCDebug(QTMIR_SCREENS) << screen << "- id:" << screen->m_outputId.as_value() |
2745 | + << "geometry:" << screen->geometry() |
2746 | + << "window:" << screen->window() |
2747 | + << "type" << static_cast<int>(screen->outputType()); |
2748 | + } |
2749 | + qCDebug(QTMIR_SCREENS) << "======================================="; |
2750 | + |
2751 | + for (auto screen : newScreenList) { |
2752 | + Q_EMIT screenAdded(screen); |
2753 | + } |
2754 | +} |
2755 | + |
2756 | +Screen* ScreenController::createScreen(const mir::graphics::DisplayConfigurationOutput &output) const |
2757 | +{ |
2758 | + return new Screen(output); |
2759 | +} |
2760 | + |
2761 | +Screen* ScreenController::getUnusedScreen() |
2762 | +{ |
2763 | + if (m_screenList.empty()) { |
2764 | + return nullptr; |
2765 | + } else if (m_screenList.size() == 1) { |
2766 | + return m_screenList.at(0); |
2767 | + } |
2768 | + |
2769 | + // FIXME: Until we have better way of identifying screens, prioritize outputs based on their output type. |
2770 | + // Note the priorities defined here are nothing more than guesses. It tries to select internal displays first, |
2771 | + // then digital outputs, and finally analogue. |
2772 | + QMap <int, Screen*> priorityList; |
2773 | + auto prioritize = [](const mg::DisplayConfigurationOutputType &type) { |
2774 | + using out = mg::DisplayConfigurationOutputType; |
2775 | + switch(type) { |
2776 | + case out::lvds: |
2777 | + case out::edp: |
2778 | + return 0; |
2779 | + case out::displayport: |
2780 | + case out::hdmia: |
2781 | + case out::hdmib: |
2782 | + return 1; |
2783 | + case out::dvii: |
2784 | + case out::dvid: |
2785 | + case out::dvia: |
2786 | + return 2; |
2787 | + case out::vga: |
2788 | + return 3; |
2789 | + case out::ninepindin: |
2790 | + return 4; |
2791 | + case out::component: |
2792 | + case out::composite: |
2793 | + case out::svideo: |
2794 | + return 5; |
2795 | + case out::tv: |
2796 | + return 6; |
2797 | + case out::unknown: |
2798 | + default: |
2799 | + return 9; |
2800 | + } |
2801 | + }; |
2802 | + |
2803 | + for (auto screen : m_screenList) { |
2804 | + if (!screen->window()) { |
2805 | + priorityList.insert(prioritize(screen->outputType()), screen); |
2806 | + } |
2807 | + } |
2808 | + |
2809 | + qCDebug(QTMIR_SCREENS) << "Prioritized list of available outputs:" << priorityList; |
2810 | + return priorityList.first(); // Map sorted by key, so first is the key with highest priority. |
2811 | +} |
2812 | + |
2813 | +Screen* ScreenController::findScreenWithId(const QList<Screen *> &list, const mg::DisplayConfigurationOutputId id) |
2814 | +{ |
2815 | + for (Screen *screen : list) { |
2816 | + if (screen->m_outputId == id) { |
2817 | + return screen; |
2818 | + } |
2819 | + } |
2820 | + return nullptr; |
2821 | +} |
2822 | + |
2823 | +QWindow* ScreenController::getWindowForPoint(const QPoint &point) //FIXME - not thread safe & not efficient |
2824 | +{ |
2825 | + for (Screen *screen : m_screenList) { |
2826 | + if (screen->window() && screen->geometry().contains(point)) { |
2827 | + return screen->window()->window(); |
2828 | + } |
2829 | + } |
2830 | + return nullptr; |
2831 | +} |
2832 | |
2833 | === added file 'src/platforms/mirserver/screencontroller.h' |
2834 | --- src/platforms/mirserver/screencontroller.h 1970-01-01 00:00:00 +0000 |
2835 | +++ src/platforms/mirserver/screencontroller.h 2015-09-09 18:37:39 +0000 |
2836 | @@ -0,0 +1,97 @@ |
2837 | +/* |
2838 | + * Copyright (C) 2015 Canonical, Ltd. |
2839 | + * |
2840 | + * This program is free software: you can redistribute it and/or modify it under |
2841 | + * the terms of the GNU Lesser General Public License version 3, as published by |
2842 | + * the Free Software Foundation. |
2843 | + * |
2844 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
2845 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
2846 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2847 | + * Lesser General Public License for more details. |
2848 | + * |
2849 | + * You should have received a copy of the GNU Lesser General Public License |
2850 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2851 | + */ |
2852 | + |
2853 | +#ifndef SCREENCONTROLLER_H |
2854 | +#define SCREENCONTROLLER_H |
2855 | + |
2856 | +#include <QObject> |
2857 | +#include <QPoint> |
2858 | + |
2859 | +// Mir |
2860 | +#include <mir/graphics/display_configuration.h> |
2861 | + |
2862 | +// std |
2863 | +#include <memory> |
2864 | + |
2865 | +namespace mir { |
2866 | + namespace graphics { class Display; } |
2867 | + namespace compositor { class Compositor; } |
2868 | +} |
2869 | + |
2870 | +class Screen; |
2871 | +class QWindow; |
2872 | + |
2873 | +/* |
2874 | + * ScreenController monitors the Mir display configuration and compositor status, and updates |
2875 | + * the relevant QScreen and QWindow states accordingly. |
2876 | + * |
2877 | + * Primary purposes are: |
2878 | + * 1. to update QScreen state on Mir display configuration changes |
2879 | + * 2. to stop the Qt renderer by hiding its QWindow when Mir wants to stop all compositing, |
2880 | + * and resume Qt's renderer by showing its QWindow when Mir wants to resume compositing. |
2881 | + * |
2882 | + * |
2883 | + * Threading Note: |
2884 | + * This object must have affinity to the main Qt GUI thread, as it creates & destroys Platform |
2885 | + * objects which Qt uses internally. However beware as the init() & terminate() methods need to |
2886 | + * be called on the MirServerThread thread, as we need to monitor the screen state *after* |
2887 | + * Mir has initialized but before Qt's event loop has started, and tear down before Mir terminates. |
2888 | + * Also note the MirServerThread does not have an QEventLoop. |
2889 | + * |
2890 | + * All other methods must be called on the Qt GUI thread. |
2891 | + */ |
2892 | + |
2893 | +class ScreenController : public QObject |
2894 | +{ |
2895 | + Q_OBJECT |
2896 | +public: |
2897 | + explicit ScreenController(QObject *parent = 0); |
2898 | + |
2899 | + Screen* getUnusedScreen(); |
2900 | + QList<Screen*> screens() const { return m_screenList; } |
2901 | + bool compositing() const { return m_compositing; } |
2902 | + |
2903 | + QWindow* getWindowForPoint(const QPoint &point); |
2904 | + |
2905 | +Q_SIGNALS: |
2906 | + void screenAdded(Screen *screen); |
2907 | + |
2908 | +public Q_SLOTS: |
2909 | + void update(); |
2910 | + |
2911 | +public: |
2912 | + // called by MirServer |
2913 | + void init(const std::shared_ptr<mir::graphics::Display> &display, |
2914 | + const std::shared_ptr<mir::compositor::Compositor> &compositor); |
2915 | + void terminate(); |
2916 | + |
2917 | + // override for testing purposes |
2918 | + virtual Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const; |
2919 | + |
2920 | +protected Q_SLOTS: |
2921 | + void onCompositorStarting(); |
2922 | + void onCompositorStopping(); |
2923 | + |
2924 | +private: |
2925 | + Screen* findScreenWithId(const QList<Screen*> &list, const mir::graphics::DisplayConfigurationOutputId id); |
2926 | + |
2927 | + std::weak_ptr<mir::graphics::Display> m_display; |
2928 | + std::shared_ptr<mir::compositor::Compositor> m_compositor; |
2929 | + QList<Screen*> m_screenList; |
2930 | + bool m_compositing; |
2931 | +}; |
2932 | + |
2933 | +#endif // SCREENCONTROLLER_H |
2934 | |
2935 | === renamed file 'src/platforms/mirserver/displaywindow.cpp' => 'src/platforms/mirserver/screenwindow.cpp' |
2936 | --- src/platforms/mirserver/displaywindow.cpp 2015-08-11 12:08:32 +0000 |
2937 | +++ src/platforms/mirserver/screenwindow.cpp 2015-09-09 18:37:39 +0000 |
2938 | @@ -14,15 +14,22 @@ |
2939 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2940 | */ |
2941 | |
2942 | -#include "displaywindow.h" |
2943 | - |
2944 | -#include "mir/geometry/size.h" |
2945 | - |
2946 | +#include "screenwindow.h" |
2947 | +#include "screen.h" |
2948 | + |
2949 | +// Mir |
2950 | +#include <mir/geometry/size.h> |
2951 | +#include <mir/graphics/display_buffer.h> |
2952 | + |
2953 | +// Qt |
2954 | #include <qpa/qwindowsysteminterface.h> |
2955 | #include <qpa/qplatformscreen.h> |
2956 | - |
2957 | +#include <QQuickWindow> |
2958 | +#include <QtQuick/private/qsgrenderloop_p.h> |
2959 | #include <QDebug> |
2960 | |
2961 | +#include "logging.h" |
2962 | + |
2963 | static WId newWId() |
2964 | { |
2965 | static WId id = 0; |
2966 | @@ -33,22 +40,22 @@ |
2967 | return ++id; |
2968 | } |
2969 | |
2970 | -DisplayWindow::DisplayWindow( |
2971 | - QWindow *window, |
2972 | - mir::graphics::DisplaySyncGroup *displayGroup, |
2973 | - mir::graphics::DisplayBuffer *displayBuffer) |
2974 | - : QObject(nullptr), QPlatformWindow(window) |
2975 | - , m_isExposed(true) |
2976 | +ScreenWindow::ScreenWindow(QWindow *window) |
2977 | + : QPlatformWindow(window) |
2978 | + , m_exposed(false) |
2979 | , m_winId(newWId()) |
2980 | - , m_displayGroup(displayGroup) |
2981 | - , m_displayBuffer(displayBuffer) |
2982 | { |
2983 | - qDebug() << "DisplayWindow::DisplayWindow"; |
2984 | - qWarning("Window %p: %p 0x%x\n", this, window, uint(m_winId)); |
2985 | + // Register with the Screen it is associated with |
2986 | + auto myScreen = static_cast<Screen *>(screen()); |
2987 | + Q_ASSERT(myScreen); |
2988 | + myScreen->setWindow(this); |
2989 | + |
2990 | + qCDebug(QTMIR_SCREENS) << "ScreenWindow" << this << "with window ID" << uint(m_winId) << "backed by" << myScreen; |
2991 | |
2992 | QRect screenGeometry(screen()->availableGeometry()); |
2993 | if (window->geometry() != screenGeometry) { |
2994 | setGeometry(screenGeometry); |
2995 | + window->setGeometry(screenGeometry); |
2996 | } |
2997 | window->setSurfaceType(QSurface::OpenGLSurface); |
2998 | |
2999 | @@ -57,70 +64,51 @@ |
3000 | requestActivateWindow(); |
3001 | } |
3002 | |
3003 | -QRect DisplayWindow::geometry() const |
3004 | -{ |
3005 | - // For yet-to-become-fullscreen windows report the geometry covering the entire |
3006 | - // screen. This is particularly important for Quick where the root object may get |
3007 | - // sized to some geometry queried before calling create(). |
3008 | - return screen()->availableGeometry(); |
3009 | -} |
3010 | - |
3011 | -void DisplayWindow::setGeometry(const QRect &) |
3012 | -{ |
3013 | - // We only support full-screen windows |
3014 | - QRect rect(screen()->availableGeometry()); |
3015 | - QWindowSystemInterface::handleGeometryChange(window(), rect); |
3016 | - QPlatformWindow::setGeometry(rect); |
3017 | -} |
3018 | - |
3019 | -bool DisplayWindow::isExposed() const |
3020 | -{ |
3021 | - return m_isExposed; |
3022 | -} |
3023 | - |
3024 | -bool DisplayWindow::event(QEvent *event) |
3025 | -{ |
3026 | - // Intercept Hide event and convert to Expose event, as Hide causes Qt to release GL |
3027 | - // resources, which we don't want. Must intercept Show to un-do hide. |
3028 | - if (event->type() == QEvent::Hide) { |
3029 | - qDebug() << "DisplayWindow::event got QEvent::Hide"; |
3030 | - m_isExposed = false; |
3031 | - QWindowSystemInterface::handleExposeEvent(window(), QRect()); |
3032 | - QWindowSystemInterface::flushWindowSystemEvents(); |
3033 | - return true; |
3034 | - } else if (event->type() == QEvent::Show) { |
3035 | - qDebug() << "DisplayWindow::event got QEvent::Show"; |
3036 | - m_isExposed = true; |
3037 | - QRect rect(QPoint(), geometry().size()); |
3038 | - QWindowSystemInterface::handleExposeEvent(window(), rect); |
3039 | - QWindowSystemInterface::flushWindowSystemEvents(); |
3040 | - return true; |
3041 | +ScreenWindow::~ScreenWindow() |
3042 | +{ |
3043 | + qCDebug(QTMIR_SCREENS) << "Destroying ScreenWindow" << this; |
3044 | + static_cast<Screen *>(screen())->setWindow(nullptr); |
3045 | +} |
3046 | + |
3047 | +bool ScreenWindow::isExposed() const |
3048 | +{ |
3049 | + return m_exposed; |
3050 | +} |
3051 | + |
3052 | +void ScreenWindow::setExposed(const bool exposed) |
3053 | +{ |
3054 | + qCDebug(QTMIR_SCREENS) << "ScreenWindow::setExposed" << this << exposed; |
3055 | + if (m_exposed == exposed) |
3056 | + return; |
3057 | + |
3058 | + m_exposed = exposed; |
3059 | + if (!window()) |
3060 | + return; |
3061 | + |
3062 | + // If backing a QQuickWindow, need to stop/start its renderer immediately |
3063 | + auto quickWindow = static_cast<QQuickWindow *>(window()); |
3064 | + if (!quickWindow) |
3065 | + return; |
3066 | + |
3067 | + if (exposed) { |
3068 | + QWindowSystemInterface::handleExposeEvent(window(), QRegion()); |
3069 | + } else { |
3070 | + auto renderer = QSGRenderLoop::instance(); |
3071 | + renderer->hide(quickWindow); // ExposeEvent will arrive too late, need to stop compositor immediately |
3072 | } |
3073 | - return QObject::event(event); |
3074 | -} |
3075 | - |
3076 | -void DisplayWindow::swapBuffers() |
3077 | -{ |
3078 | - m_displayBuffer->gl_swap_buffers(); |
3079 | - |
3080 | - // FIXME this exposes a QtMir architecture problem now, as DisplayWindow |
3081 | - // is supposed to wrap a mg::DisplayBuffer. We use Qt's multithreaded |
3082 | - // renderer, where each DisplayWindow is rendered to relatively |
3083 | - // independently, and post() called also individually. |
3084 | - // |
3085 | - // But in multimonitor case where a DisplaySyncGroup contains 2 |
3086 | - // DisplayBuffers, one post() call will submit both |
3087 | - // mg::DisplayBuffers for flipping, which can happen before the other |
3088 | - // DisplayWindow has been rendered to, causing visual artifacts |
3089 | - m_displayGroup->post(); |
3090 | -} |
3091 | - |
3092 | -void DisplayWindow::makeCurrent() |
3093 | -{ |
3094 | - m_displayBuffer->make_current(); |
3095 | -} |
3096 | - |
3097 | -void DisplayWindow::doneCurrent() |
3098 | -{ |
3099 | - m_displayBuffer->release_current(); |
3100 | +} |
3101 | + |
3102 | +void ScreenWindow::swapBuffers() |
3103 | +{ |
3104 | + static_cast<Screen *>(screen())->swapBuffers(); |
3105 | +} |
3106 | + |
3107 | +void ScreenWindow::makeCurrent() |
3108 | +{ |
3109 | + static_cast<Screen *>(screen())->makeCurrent(); |
3110 | +} |
3111 | + |
3112 | +void ScreenWindow::doneCurrent() |
3113 | +{ |
3114 | + static_cast<Screen *>(screen())->doneCurrent(); |
3115 | } |
3116 | |
3117 | === renamed file 'src/platforms/mirserver/displaywindow.h' => 'src/platforms/mirserver/screenwindow.h' |
3118 | --- src/platforms/mirserver/displaywindow.h 2015-08-11 12:08:32 +0000 |
3119 | +++ src/platforms/mirserver/screenwindow.h 2015-09-09 18:37:39 +0000 |
3120 | @@ -14,43 +14,33 @@ |
3121 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3122 | */ |
3123 | |
3124 | -#ifndef DISPLAYWINDOW_H |
3125 | -#define DISPLAYWINDOW_H |
3126 | +#ifndef SCREENWINDOW_H |
3127 | +#define SCREENWINDOW_H |
3128 | |
3129 | #include <qpa/qplatformwindow.h> |
3130 | |
3131 | -#include <mir/graphics/display.h> |
3132 | -#include <mir/graphics/display_buffer.h> |
3133 | - |
3134 | -#include <QObject> |
3135 | - |
3136 | -// DisplayWindow wraps the whatever implementation Mir creates of a DisplayBuffer, |
3137 | -// which is the buffer output for an individual display. |
3138 | - |
3139 | -class DisplayWindow : public QObject, public QPlatformWindow |
3140 | +// ScreenWindow implements the basics of a QPlatformWindow. |
3141 | +// QtMir enforces one Window per Screen, so Window and Screen are tightly coupled. |
3142 | +// All Mir specifics live in the associated Screen object. |
3143 | + |
3144 | +class ScreenWindow : public QPlatformWindow |
3145 | { |
3146 | - Q_OBJECT |
3147 | public: |
3148 | - explicit DisplayWindow(QWindow *window, mir::graphics::DisplaySyncGroup*, mir::graphics::DisplayBuffer*); |
3149 | + explicit ScreenWindow(QWindow *window); |
3150 | + virtual ~ScreenWindow(); |
3151 | |
3152 | - QRect geometry() const override; |
3153 | - void setGeometry(const QRect &rect) override; |
3154 | + bool isExposed() const override; |
3155 | + void setExposed(const bool exposed); |
3156 | |
3157 | WId winId() const override { return m_winId; } |
3158 | |
3159 | - bool isExposed() const override; |
3160 | - |
3161 | - bool event(QEvent *event) override; |
3162 | - |
3163 | void swapBuffers(); |
3164 | void makeCurrent(); |
3165 | void doneCurrent(); |
3166 | |
3167 | private: |
3168 | - bool m_isExposed; |
3169 | + bool m_exposed; |
3170 | WId m_winId; |
3171 | - mir::graphics::DisplaySyncGroup *m_displayGroup; |
3172 | - mir::graphics::DisplayBuffer *m_displayBuffer; |
3173 | }; |
3174 | |
3175 | -#endif // DISPLAYWINDOW_H |
3176 | +#endif // SCREENWINDOW_H |
3177 | |
3178 | === added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp' |
3179 | --- src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 1970-01-01 00:00:00 +0000 |
3180 | +++ src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 2015-09-09 18:37:39 +0000 |
3181 | @@ -0,0 +1,44 @@ |
3182 | +/* |
3183 | + * Copyright (C) 2015 Canonical, Ltd. |
3184 | + * |
3185 | + * This program is free software: you can redistribute it and/or modify it under |
3186 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3187 | + * the Free Software Foundation. |
3188 | + * |
3189 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3190 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3191 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3192 | + * Lesser General Public License for more details. |
3193 | + * |
3194 | + * You should have received a copy of the GNU Lesser General Public License |
3195 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3196 | + */ |
3197 | + |
3198 | +#include "tileddisplayconfigurationpolicy.h" |
3199 | + |
3200 | +#include <mir/graphics/display_configuration.h> |
3201 | +#include <mir/geometry/point.h> |
3202 | + |
3203 | +namespace mg = mir::graphics; |
3204 | + |
3205 | +TiledDisplayConfigurationPolicy::TiledDisplayConfigurationPolicy( |
3206 | + const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped) |
3207 | + : m_wrapped(wrapped) |
3208 | +{ |
3209 | +} |
3210 | + |
3211 | +void TiledDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf) |
3212 | +{ |
3213 | + int nextTopLeftPosition = 0; |
3214 | + |
3215 | + m_wrapped->apply_to(conf); |
3216 | + |
3217 | + conf.for_each_output( |
3218 | + [&](mg::UserDisplayConfigurationOutput& output) |
3219 | + { |
3220 | + if (output.connected && output.used) { |
3221 | + output.top_left = mir::geometry::Point{nextTopLeftPosition, 0}; |
3222 | + nextTopLeftPosition += output.modes[output.preferred_mode_index].size.width.as_int(); |
3223 | + } |
3224 | + }); |
3225 | +} |
3226 | |
3227 | === added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.h' |
3228 | --- src/platforms/mirserver/tileddisplayconfigurationpolicy.h 1970-01-01 00:00:00 +0000 |
3229 | +++ src/platforms/mirserver/tileddisplayconfigurationpolicy.h 2015-09-09 18:37:39 +0000 |
3230 | @@ -0,0 +1,35 @@ |
3231 | +/* |
3232 | + * Copyright (C) 2015 Canonical, Ltd. |
3233 | + * |
3234 | + * This program is free software: you can redistribute it and/or modify it under |
3235 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3236 | + * the Free Software Foundation. |
3237 | + * |
3238 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3239 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3240 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3241 | + * Lesser General Public License for more details. |
3242 | + * |
3243 | + * You should have received a copy of the GNU Lesser General Public License |
3244 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3245 | + */ |
3246 | + |
3247 | +#ifndef TILEDDISPLAYCONFIGURATIONPOLICY_H |
3248 | +#define TILEDDISPLAYCONFIGURATIONPOLICY_H |
3249 | + |
3250 | +#include <mir/graphics/display_configuration_policy.h> |
3251 | + |
3252 | +#include <memory> |
3253 | + |
3254 | +class TiledDisplayConfigurationPolicy : public mir::graphics::DisplayConfigurationPolicy |
3255 | +{ |
3256 | +public: |
3257 | + TiledDisplayConfigurationPolicy(const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped); |
3258 | + |
3259 | + void apply_to(mir::graphics::DisplayConfiguration& conf) override; |
3260 | + |
3261 | +private: |
3262 | + const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> m_wrapped; |
3263 | +}; |
3264 | + |
3265 | +#endif // TILEDDISPLAYCONFIGURATIONPOLICY_H |
3266 | |
3267 | === added directory 'tests/common' |
3268 | === added file 'tests/common/fake_displayconfigurationoutput.h' |
3269 | --- tests/common/fake_displayconfigurationoutput.h 1970-01-01 00:00:00 +0000 |
3270 | +++ tests/common/fake_displayconfigurationoutput.h 2015-09-09 18:37:39 +0000 |
3271 | @@ -0,0 +1,73 @@ |
3272 | +/* |
3273 | + * Copyright (C) 2015 Canonical, Ltd. |
3274 | + * |
3275 | + * This program is free software: you can redistribute it and/or modify it under |
3276 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3277 | + * the Free Software Foundation. |
3278 | + * |
3279 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3280 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3281 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3282 | + * Lesser General Public License for more details. |
3283 | + * |
3284 | + * You should have received a copy of the GNU Lesser General Public License |
3285 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3286 | + */ |
3287 | + |
3288 | +#ifndef FAKE_DISPLAYCONFIGURATIONOUTPUT_H |
3289 | +#define FAKE_DISPLAYCONFIGURATIONOUTPUT_H |
3290 | + |
3291 | +#include <mir/graphics/display_configuration.h> |
3292 | + |
3293 | +namespace mg = mir::graphics; |
3294 | +namespace geom = mir::geometry; |
3295 | + |
3296 | +const mg::DisplayConfigurationOutput fakeOutput1 |
3297 | +{ |
3298 | + mg::DisplayConfigurationOutputId{3}, |
3299 | + mg::DisplayConfigurationCardId{2}, |
3300 | + mg::DisplayConfigurationOutputType::dvid, |
3301 | + { |
3302 | + mir_pixel_format_abgr_8888 |
3303 | + }, |
3304 | + { |
3305 | + {geom::Size{100, 200}, 60.0}, |
3306 | + {geom::Size{100, 200}, 59.0}, |
3307 | + {geom::Size{150, 200}, 59.0} |
3308 | + }, |
3309 | + 0, |
3310 | + geom::Size{1111, 2222}, |
3311 | + true, |
3312 | + true, |
3313 | + geom::Point(), |
3314 | + 2, |
3315 | + mir_pixel_format_abgr_8888, |
3316 | + mir_power_mode_on, |
3317 | + mir_orientation_normal |
3318 | +}; |
3319 | + |
3320 | +const mg::DisplayConfigurationOutput fakeOutput2 |
3321 | +{ |
3322 | + mg::DisplayConfigurationOutputId{2}, |
3323 | + mg::DisplayConfigurationCardId{4}, |
3324 | + mg::DisplayConfigurationOutputType::lvds, |
3325 | + { |
3326 | + mir_pixel_format_xbgr_8888 |
3327 | + }, |
3328 | + { |
3329 | + {geom::Size{800, 1200}, 90.0}, |
3330 | + {geom::Size{1600, 2400}, 60.0}, |
3331 | + {geom::Size{1500, 2000}, 75.0} |
3332 | + }, |
3333 | + 0, |
3334 | + geom::Size{1000, 2000}, |
3335 | + true, |
3336 | + true, |
3337 | + geom::Point(500, 600), |
3338 | + 2, |
3339 | + mir_pixel_format_xbgr_8888, |
3340 | + mir_power_mode_on, |
3341 | + mir_orientation_left |
3342 | +}; |
3343 | + |
3344 | +#endif // FAKE_DISPLAYCONFIGURATIONOUTPUT_H |
3345 | |
3346 | === added file 'tests/common/gmock_fixes.h' |
3347 | --- tests/common/gmock_fixes.h 1970-01-01 00:00:00 +0000 |
3348 | +++ tests/common/gmock_fixes.h 2015-09-09 18:37:39 +0000 |
3349 | @@ -0,0 +1,124 @@ |
3350 | +// |
3351 | +// Copyright © 2012 Canonical Ltd. Copyright 2007, Google Inc. |
3352 | +// |
3353 | +// All rights reserved. |
3354 | +// |
3355 | +// Redistribution and use in source and binary forms, with or without |
3356 | +// modification, are permitted provided that the following conditions are |
3357 | +// met: |
3358 | +// |
3359 | +// * Redistributions of source code must retain the above copyright |
3360 | +// notice, this list of conditions and the following disclaimer. |
3361 | +// * Redistributions in binary form must reproduce the above |
3362 | +// copyright notice, this list of conditions and the following disclaimer |
3363 | +// in the documentation and/or other materials provided with the |
3364 | +// distribution. |
3365 | +// * Neither the name of Google Inc. nor the names of its |
3366 | +// contributors may be used to endorse or promote products derived from |
3367 | +// this software without specific prior written permission. |
3368 | +// |
3369 | +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
3370 | +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
3371 | +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
3372 | +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
3373 | +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
3374 | +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
3375 | +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
3376 | +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
3377 | +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
3378 | +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
3379 | +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
3380 | +// |
3381 | +// Author: wan@google.com (Zhanyong Wan) |
3382 | +// Authored by: Alan Griffiths <alan@octopull.co.uk> |
3383 | + |
3384 | +#ifndef MIR_TEST_GMOCK_FIXES_H_ |
3385 | +#define MIR_TEST_GMOCK_FIXES_H_ |
3386 | + |
3387 | +#include <memory> |
3388 | +#include <gmock/gmock.h> |
3389 | + |
3390 | +namespace testing |
3391 | +{ |
3392 | +namespace internal |
3393 | +{ |
3394 | + |
3395 | +template<typename T> |
3396 | +class ActionResultHolder<std::unique_ptr<T>> |
3397 | +: public UntypedActionResultHolderBase { |
3398 | + public: |
3399 | + explicit ActionResultHolder(std::unique_ptr<T>&& a_value) : |
3400 | + value_(std::move(a_value)) {} |
3401 | + |
3402 | + // The compiler-generated copy constructor and assignment operator |
3403 | + // are exactly what we need, so we don't need to define them. |
3404 | + |
3405 | + // Returns the held value and deletes this object. |
3406 | + std::unique_ptr<T> GetValueAndDelete() const { |
3407 | + std::unique_ptr<T> retval(std::move(value_)); |
3408 | + delete this; |
3409 | + return retval; |
3410 | + } |
3411 | + |
3412 | + // Prints the held value as an action's result to os. |
3413 | + virtual void PrintAsActionResult(::std::ostream* os) const { |
3414 | + *os << "\n Returns: "; |
3415 | + // T may be a reference type, so we don't use UniversalPrint(). |
3416 | + UniversalPrinter<std::unique_ptr<T>>::Print(value_, os); |
3417 | + } |
3418 | + |
3419 | + // Performs the given mock function's default action and returns the |
3420 | + // result in a new-ed ActionResultHolder. |
3421 | + template <typename F> |
3422 | + static ActionResultHolder* PerformDefaultAction( |
3423 | + const FunctionMockerBase<F>* func_mocker, |
3424 | + const typename Function<F>::ArgumentTuple& args, |
3425 | + const string& call_description) { |
3426 | + return new ActionResultHolder( |
3427 | + func_mocker->PerformDefaultAction(args, call_description)); |
3428 | + } |
3429 | + |
3430 | + // Performs the given action and returns the result in a new-ed |
3431 | + // ActionResultHolder. |
3432 | + template <typename F> |
3433 | + static ActionResultHolder* |
3434 | + PerformAction(const Action<F>& action, |
3435 | + const typename Function<F>::ArgumentTuple& args) { |
3436 | + return new ActionResultHolder(action.Perform(args)); |
3437 | + } |
3438 | + |
3439 | + private: |
3440 | + std::unique_ptr<T> mutable value_; |
3441 | + |
3442 | + // T could be a reference type, so = isn't supported. |
3443 | + GTEST_DISALLOW_ASSIGN_(ActionResultHolder); |
3444 | +}; |
3445 | + |
3446 | +} |
3447 | + |
3448 | +template<typename T> |
3449 | +class DefaultValue<std::unique_ptr<T>> { |
3450 | + public: |
3451 | + // Unsets the default value for type T. |
3452 | + static void Clear() {} |
3453 | + |
3454 | + // Returns true iff the user has set the default value for type T. |
3455 | + static bool IsSet() { return false; } |
3456 | + |
3457 | + // Returns true if T has a default return value set by the user or there |
3458 | + // exists a built-in default value. |
3459 | + static bool Exists() { |
3460 | + return true; |
3461 | + } |
3462 | + |
3463 | + // Returns the default value for type T if the user has set one; |
3464 | + // otherwise returns the built-in default value if there is one; |
3465 | + // otherwise aborts the process. |
3466 | + static std::unique_ptr<T> Get() { |
3467 | + return std::unique_ptr<T>(); |
3468 | + } |
3469 | +}; |
3470 | + |
3471 | +} |
3472 | + |
3473 | +#endif /* MIR_TEST_GMOCK_FIXES_H_ */ |
3474 | |
3475 | === added file 'tests/common/mock_display.h' |
3476 | --- tests/common/mock_display.h 1970-01-01 00:00:00 +0000 |
3477 | +++ tests/common/mock_display.h 2015-09-09 18:37:39 +0000 |
3478 | @@ -0,0 +1,53 @@ |
3479 | +/* |
3480 | + * Copyright (C) 2015 Canonical, Ltd. |
3481 | + * |
3482 | + * This program is free software: you can redistribute it and/or modify it under |
3483 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3484 | + * the Free Software Foundation. |
3485 | + * |
3486 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3487 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3488 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3489 | + * Lesser General Public License for more details. |
3490 | + * |
3491 | + * You should have received a copy of the GNU Lesser General Public License |
3492 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3493 | + */ |
3494 | + |
3495 | +#ifndef MOCKDISPLAY_H |
3496 | +#define MOCKDISPLAY_H |
3497 | + |
3498 | +#include <mir/graphics/display.h> |
3499 | +#include <mir/graphics/gl_context.h> |
3500 | + |
3501 | +#include <gmock/gmock.h> |
3502 | +#include "gmock_fixes.h" |
3503 | + |
3504 | +class MockDisplaySyncGroup : public mir::graphics::DisplaySyncGroup |
3505 | +{ |
3506 | +public: |
3507 | + MOCK_METHOD1(for_each_display_buffer, void(std::function<void(mir::graphics::DisplayBuffer&)> const& f)); |
3508 | + MOCK_METHOD0(post, void()); |
3509 | +}; |
3510 | + |
3511 | +struct MockDisplay : public mir::graphics::Display |
3512 | +{ |
3513 | +public: |
3514 | + MOCK_METHOD1(for_each_display_sync_group, void(std::function<void(mir::graphics::DisplaySyncGroup&)> const&)); |
3515 | + MOCK_CONST_METHOD0(configuration, std::unique_ptr<mir::graphics::DisplayConfiguration>()); |
3516 | + MOCK_METHOD1(configure, void(mir::graphics::DisplayConfiguration const&)); |
3517 | + MOCK_METHOD2(register_configuration_change_handler, |
3518 | + void(mir::graphics::EventHandlerRegister&, mir::graphics::DisplayConfigurationChangeHandler const&)); |
3519 | + |
3520 | + MOCK_METHOD3(register_pause_resume_handlers, void(mir::graphics::EventHandlerRegister&, |
3521 | + mir::graphics::DisplayPauseHandler const&, |
3522 | + mir::graphics::DisplayResumeHandler const&)); |
3523 | + MOCK_METHOD0(pause, void()); |
3524 | + MOCK_METHOD0(resume, void()); |
3525 | + MOCK_METHOD1(create_hardware_cursor, std::shared_ptr<mir::graphics::Cursor>(std::shared_ptr<mir::graphics::CursorImage> const&)); |
3526 | + MOCK_METHOD0(create_gl_context, std::unique_ptr<mir::graphics::GLContext>()); |
3527 | +}; |
3528 | + |
3529 | + |
3530 | + |
3531 | +#endif // MOCKDISPLAY_H |
3532 | |
3533 | === added file 'tests/common/mock_display_buffer.h' |
3534 | --- tests/common/mock_display_buffer.h 1970-01-01 00:00:00 +0000 |
3535 | +++ tests/common/mock_display_buffer.h 2015-09-09 18:37:39 +0000 |
3536 | @@ -0,0 +1,43 @@ |
3537 | +/* |
3538 | + * Copyright (C) 2015 Canonical, Ltd. |
3539 | + * |
3540 | + * This program is free software: you can redistribute it and/or modify it under |
3541 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3542 | + * the Free Software Foundation. |
3543 | + * |
3544 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3545 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3546 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3547 | + * Lesser General Public License for more details. |
3548 | + * |
3549 | + * You should have received a copy of the GNU Lesser General Public License |
3550 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3551 | + */ |
3552 | + |
3553 | +#ifndef MOCK_DISPLAY_BUFFER_H |
3554 | +#define MOCK_DISPLAY_BUFFER_H |
3555 | + |
3556 | +#include <mir/graphics/display_buffer.h> |
3557 | + |
3558 | +#include <gmock/gmock.h> |
3559 | + |
3560 | +class MockDisplayBuffer : public mir::graphics::DisplayBuffer |
3561 | +{ |
3562 | +public: |
3563 | + MockDisplayBuffer() |
3564 | + { |
3565 | + using namespace testing; |
3566 | + ON_CALL(*this, view_area()) |
3567 | + .WillByDefault(Return(mir::geometry::Rectangle{{0,0},{0,0}})); |
3568 | + } |
3569 | + MOCK_CONST_METHOD0(view_area, mir::geometry::Rectangle()); |
3570 | + MOCK_METHOD0(make_current, void()); |
3571 | + MOCK_METHOD0(release_current, void()); |
3572 | + MOCK_METHOD0(gl_swap_buffers, void()); |
3573 | + MOCK_METHOD1(post_renderables_if_optimizable, bool(mir::graphics::RenderableList const&)); |
3574 | + MOCK_CONST_METHOD0(orientation, MirOrientation()); |
3575 | + MOCK_CONST_METHOD0(uses_alpha, bool()); |
3576 | +}; |
3577 | + |
3578 | + |
3579 | +#endif // MOCK_DISPLAY_BUFFER_H |
3580 | |
3581 | === added file 'tests/common/mock_display_configuration.h' |
3582 | --- tests/common/mock_display_configuration.h 1970-01-01 00:00:00 +0000 |
3583 | +++ tests/common/mock_display_configuration.h 2015-09-09 18:37:39 +0000 |
3584 | @@ -0,0 +1,35 @@ |
3585 | +/* |
3586 | + * Copyright (C) 2015 Canonical, Ltd. |
3587 | + * |
3588 | + * This program is free software: you can redistribute it and/or modify it under |
3589 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3590 | + * the Free Software Foundation. |
3591 | + * |
3592 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3593 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3594 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3595 | + * Lesser General Public License for more details. |
3596 | + * |
3597 | + * You should have received a copy of the GNU Lesser General Public License |
3598 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3599 | + */ |
3600 | + |
3601 | +#ifndef MOCK_DISPLAY_CONFIGURATION_H |
3602 | +#define MOCK_DISPLAY_CONFIGURATION_H |
3603 | + |
3604 | +#include <mir/graphics/display_configuration.h> |
3605 | + |
3606 | +#include <gmock/gmock.h> |
3607 | +#include "gmock_fixes.h" |
3608 | + |
3609 | +class MockDisplayConfiguration : public mir::graphics::DisplayConfiguration |
3610 | +{ |
3611 | +public: |
3612 | + MOCK_CONST_METHOD1(for_each_card, void(std::function<void(mir::graphics::DisplayConfigurationCard const&)>)); |
3613 | + |
3614 | + MOCK_CONST_METHOD1(for_each_output, void(std::function<void(mir::graphics::DisplayConfigurationOutput const&)>)); |
3615 | + MOCK_METHOD1(for_each_output, void(std::function<void(mir::graphics::UserDisplayConfigurationOutput&)>)); |
3616 | + |
3617 | + MOCK_CONST_METHOD0(valid, bool()); |
3618 | +}; |
3619 | +#endif // MOCK_DISPLAY_CONFIGURATION_H |
3620 | |
3621 | === added file 'tests/common/mock_main_loop.h' |
3622 | --- tests/common/mock_main_loop.h 1970-01-01 00:00:00 +0000 |
3623 | +++ tests/common/mock_main_loop.h 2015-09-09 18:37:39 +0000 |
3624 | @@ -0,0 +1,53 @@ |
3625 | +/* |
3626 | + * Copyright (C) 2015 Canonical, Ltd. |
3627 | + * |
3628 | + * This program is free software: you can redistribute it and/or modify it under |
3629 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3630 | + * the Free Software Foundation. |
3631 | + * |
3632 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3633 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3634 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3635 | + * Lesser General Public License for more details. |
3636 | + * |
3637 | + * You should have received a copy of the GNU Lesser General Public License |
3638 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3639 | + */ |
3640 | + |
3641 | +#ifndef MOCKMAINLOOP_H |
3642 | +#define MOCKMAINLOOP_H |
3643 | + |
3644 | +#include <gmock/gmock.h> |
3645 | + |
3646 | +#include <mir/main_loop.h> |
3647 | + |
3648 | +#include <memory> |
3649 | + |
3650 | +class MockMainLoop : public mir::MainLoop |
3651 | +{ |
3652 | +public: |
3653 | + ~MockMainLoop() noexcept {} |
3654 | + |
3655 | + void run() override {} |
3656 | + void stop() override {} |
3657 | + |
3658 | + MOCK_METHOD2(register_signal_handler, |
3659 | + void(std::initializer_list<int>, |
3660 | + std::function<void(int)> const&)); |
3661 | + |
3662 | + MOCK_METHOD3(register_fd_handler, |
3663 | + void(std::initializer_list<int>, void const*, |
3664 | + std::function<void(int)> const&)); |
3665 | + |
3666 | + MOCK_METHOD1(unregister_fd_handler, void(void const*)); |
3667 | + |
3668 | + MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&)); |
3669 | + MOCK_METHOD1(pause_processing_for,void (void const*)); |
3670 | + MOCK_METHOD1(resume_processing_for,void (void const*)); |
3671 | + |
3672 | + MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::function<void()> const& callback)); |
3673 | + MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::shared_ptr<mir::LockableCallback> const& callback)); |
3674 | +}; |
3675 | + |
3676 | + |
3677 | +#endif // MOCKMAINLOOP_H |
3678 | |
3679 | === modified file 'tests/mirserver/CMakeLists.txt' |
3680 | --- tests/mirserver/CMakeLists.txt 2014-11-13 15:47:30 +0000 |
3681 | +++ tests/mirserver/CMakeLists.txt 2015-09-09 18:37:39 +0000 |
3682 | @@ -1,3 +1,4 @@ |
3683 | add_subdirectory(QtEventFeeder) |
3684 | add_subdirectory(Clipboard) |
3685 | add_subdirectory(Screen) |
3686 | +add_subdirectory(ScreenController) |
3687 | |
3688 | === modified file 'tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h' |
3689 | --- tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-04-01 15:02:36 +0000 |
3690 | +++ tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-09-09 18:37:39 +0000 |
3691 | @@ -19,19 +19,26 @@ |
3692 | #define MOCK_QTWINDOWSYSTEM_H |
3693 | |
3694 | #include <qteventfeeder.h> |
3695 | +#include <QWindow> |
3696 | |
3697 | class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface { |
3698 | public: |
3699 | - MOCK_METHOD0(hasTargetWindow, bool()); |
3700 | - MOCK_METHOD0(targetWindowGeometry, QRect()); |
3701 | + MOCK_CONST_METHOD0(ready, bool()); |
3702 | + MOCK_METHOD1(setScreenController, void(const QSharedPointer<ScreenController> &)); |
3703 | + MOCK_METHOD1(getWindowForTouchPoint, QWindow*(const QPoint &point)); |
3704 | + MOCK_METHOD0(lastWindow, QWindow*()); |
3705 | + MOCK_METHOD0(focusedWindow, QWindow*()); |
3706 | MOCK_METHOD1(registerTouchDevice, void(QTouchDevice* device)); |
3707 | - MOCK_METHOD10(handleExtendedKeyEvent, void(ulong timestamp, QEvent::Type type, int key, |
3708 | - Qt::KeyboardModifiers modifiers, |
3709 | - quint32 nativeScanCode, quint32 nativeVirtualKey, |
3710 | - quint32 nativeModifiers, |
3711 | - const QString& text, bool autorep, |
3712 | - ushort count)); |
3713 | - MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device, |
3714 | + |
3715 | + // Wanted to use GMock, but MOCK_METHOD11 not implemented |
3716 | + void handleExtendedKeyEvent(QWindow */*window*/, ulong /*timestamp*/, QEvent::Type /*type*/, int /*key*/, |
3717 | + Qt::KeyboardModifiers /*modifiers*/, |
3718 | + quint32 /*nativeScanCode*/, quint32 /*nativeVirtualKey*/, |
3719 | + quint32 /*nativeModifiers*/, |
3720 | + const QString& /*text*/ = QString(), bool /*autorep*/ = false, |
3721 | + ushort /*count*/ = 1) {} |
3722 | + |
3723 | + MOCK_METHOD5(handleTouchEvent, void(QWindow *window, ulong timestamp, QTouchDevice *device, |
3724 | const QList<struct QWindowSystemInterface::TouchPoint> &points, |
3725 | Qt::KeyboardModifiers mods)); |
3726 | MOCK_METHOD4(handleMouseEvent, void(ulong, QPointF, Qt::MouseButton, Qt::KeyboardModifiers)); |
3727 | |
3728 | === modified file 'tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp' |
3729 | --- tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-08-11 12:08:32 +0000 |
3730 | +++ tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-09-09 18:37:39 +0000 |
3731 | @@ -69,33 +69,44 @@ |
3732 | |
3733 | MockQtWindowSystem *mockWindowSystem; |
3734 | QtEventFeeder *qtEventFeeder; |
3735 | + QWindow *window; |
3736 | + QGuiApplication *app; |
3737 | }; |
3738 | |
3739 | void QtEventFeederTest::SetUp() |
3740 | { |
3741 | mockWindowSystem = new MockQtWindowSystem; |
3742 | + auto screens = QSharedPointer<ScreenController>(); |
3743 | |
3744 | EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_)); |
3745 | |
3746 | - qtEventFeeder = new QtEventFeeder(mockWindowSystem); |
3747 | + qtEventFeeder = new QtEventFeeder(screens, mockWindowSystem); |
3748 | |
3749 | ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem)); |
3750 | + |
3751 | + int argc = 0; |
3752 | + char **argv = nullptr; |
3753 | + setenv("QT_QPA_PLATFORM", "minimal", 1); |
3754 | + app = new QGuiApplication(argc, argv); |
3755 | + window = new QWindow; |
3756 | } |
3757 | |
3758 | void QtEventFeederTest::TearDown() |
3759 | { |
3760 | // mockWindowSystem will be deleted by QtEventFeeder |
3761 | delete qtEventFeeder; |
3762 | + delete window; |
3763 | + delete app; |
3764 | } |
3765 | |
3766 | void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations() |
3767 | { |
3768 | - EXPECT_CALL(*mockWindowSystem, hasTargetWindow()) |
3769 | - .Times(AnyNumber()) |
3770 | - .WillRepeatedly(Return(true)); |
3771 | - EXPECT_CALL(*mockWindowSystem, targetWindowGeometry()) |
3772 | - .Times(AnyNumber()) |
3773 | - .WillRepeatedly(Return(QRect(0,0,100,100))); |
3774 | + EXPECT_CALL(*mockWindowSystem, getWindowForTouchPoint(_)) |
3775 | + .Times(AnyNumber()) |
3776 | + .WillRepeatedly(Return(window)); |
3777 | + EXPECT_CALL(*mockWindowSystem, focusedWindow()) |
3778 | + .Times(AnyNumber()) |
3779 | + .WillRepeatedly(Return(window)); |
3780 | } |
3781 | |
3782 | |
3783 | @@ -113,7 +124,7 @@ |
3784 | |
3785 | setIrrelevantMockWindowSystemExpectations(); |
3786 | |
3787 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
3788 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3789 | Contains(AllOf(HasId(0), |
3790 | IsPressed()))),_)).Times(1); |
3791 | |
3792 | @@ -132,12 +143,12 @@ |
3793 | InSequence sequence; |
3794 | |
3795 | EXPECT_CALL(*mockWindowSystem, |
3796 | - handleTouchEvent(_,_,AllOf(SizeIs(1), |
3797 | + handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3798 | Contains(AllOf(HasId(0),IsReleased())) |
3799 | ),_)).Times(1); |
3800 | |
3801 | EXPECT_CALL(*mockWindowSystem, |
3802 | - handleTouchEvent(_,_,AllOf(SizeIs(1), |
3803 | + handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3804 | Contains(AllOf(HasId(1),IsPressed())) |
3805 | ),_)).Times(1); |
3806 | } |
3807 | @@ -161,7 +172,7 @@ |
3808 | 10, 10, 10 /* x, y, pressure*/, |
3809 | 1, 1, 10 /* touch major, minor, size */); |
3810 | |
3811 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
3812 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3813 | Contains(AllOf(HasId(0), |
3814 | IsPressed()))),_)).Times(1); |
3815 | qtEventFeeder->dispatch(*ev1); |
3816 | @@ -181,7 +192,7 @@ |
3817 | 1, 1, 10 /* touch major, minor, size */); |
3818 | |
3819 | EXPECT_CALL(*mockWindowSystem, |
3820 | - handleTouchEvent(_,_,AllOf(SizeIs(2), |
3821 | + handleTouchEvent(_,_,_,AllOf(SizeIs(2), |
3822 | Contains(AllOf(HasId(0), StateIsMoved())), |
3823 | Contains(AllOf(HasId(1), IsPressed())) |
3824 | ),_)).Times(1); |
3825 | @@ -208,14 +219,14 @@ |
3826 | |
3827 | // first release touch 0 |
3828 | EXPECT_CALL(*mockWindowSystem, |
3829 | - handleTouchEvent(_,_,AllOf(SizeIs(2), |
3830 | + handleTouchEvent(_,_,_,AllOf(SizeIs(2), |
3831 | Contains(AllOf(HasId(0), IsReleased())), |
3832 | Contains(AllOf(HasId(1), IsStationary())) |
3833 | ),_)).Times(1); |
3834 | |
3835 | // then press touch 2 |
3836 | EXPECT_CALL(*mockWindowSystem, |
3837 | - handleTouchEvent(_,_,AllOf(SizeIs(2), |
3838 | + handleTouchEvent(_,_,_,AllOf(SizeIs(2), |
3839 | Contains(AllOf(HasId(1), StateIsMoved())), |
3840 | Contains(AllOf(HasId(2), IsPressed())) |
3841 | ),_)).Times(1); |
3842 | @@ -230,7 +241,7 @@ |
3843 | { |
3844 | setIrrelevantMockWindowSystemExpectations(); |
3845 | |
3846 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
3847 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3848 | Contains(AllOf(HasId(0), |
3849 | IsPressed()))),_)).Times(1); |
3850 | |
3851 | @@ -243,7 +254,7 @@ |
3852 | |
3853 | setIrrelevantMockWindowSystemExpectations(); |
3854 | |
3855 | - EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1), |
3856 | + EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1), |
3857 | Contains(AllOf(HasId(0), StateIsMoved())) |
3858 | ),_)).Times(1); |
3859 | |
3860 | |
3861 | === modified file 'tests/mirserver/Screen/CMakeLists.txt' |
3862 | --- tests/mirserver/Screen/CMakeLists.txt 2014-12-03 08:56:35 +0000 |
3863 | +++ tests/mirserver/Screen/CMakeLists.txt 2015-09-09 18:37:39 +0000 |
3864 | @@ -5,6 +5,7 @@ |
3865 | ) |
3866 | |
3867 | include_directories( |
3868 | + ${CMAKE_SOURCE_DIR}/tests/common |
3869 | ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
3870 | ${CMAKE_SOURCE_DIR}/src/common |
3871 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
3872 | |
3873 | === modified file 'tests/mirserver/Screen/screen_test.cpp' |
3874 | --- tests/mirserver/Screen/screen_test.cpp 2015-08-11 12:08:32 +0000 |
3875 | +++ tests/mirserver/Screen/screen_test.cpp 2015-09-09 18:37:39 +0000 |
3876 | @@ -18,37 +18,21 @@ |
3877 | #include <gtest/gtest.h> |
3878 | |
3879 | #include "mir/graphics/display_configuration.h" |
3880 | +#include "fake_displayconfigurationoutput.h" |
3881 | |
3882 | #include <screen.h> |
3883 | |
3884 | +using namespace ::testing; |
3885 | + |
3886 | namespace mg = mir::graphics; |
3887 | namespace geom = mir::geometry; |
3888 | |
3889 | -mg::DisplayConfigurationOutput const fake_output |
3890 | -{ |
3891 | - mg::DisplayConfigurationOutputId{3}, |
3892 | - mg::DisplayConfigurationCardId{2}, |
3893 | - mg::DisplayConfigurationOutputType::dvid, |
3894 | - { |
3895 | - mir_pixel_format_abgr_8888 |
3896 | - }, |
3897 | - { |
3898 | - {geom::Size{10, 20}, 60.0}, |
3899 | - {geom::Size{10, 20}, 59.0}, |
3900 | - {geom::Size{15, 20}, 59.0} |
3901 | - }, |
3902 | - 0, |
3903 | - geom::Size{10, 20}, |
3904 | - true, |
3905 | - true, |
3906 | - geom::Point(), |
3907 | - 2, |
3908 | - mir_pixel_format_abgr_8888, |
3909 | - mir_power_mode_on, |
3910 | - mir_orientation_normal |
3911 | +class ScreenTest : public ::testing::Test { |
3912 | +protected: |
3913 | + void SetUp() override; |
3914 | }; |
3915 | |
3916 | -TEST(ScreenTest, OrientationSensor) |
3917 | +void ScreenTest::SetUp() |
3918 | { |
3919 | if (!qEnvironmentVariableIsSet("QT_ACCEL_FILEPATH")) { |
3920 | // Trick Qt >= 5.4.1 to load the generic sensors |
3921 | @@ -56,7 +40,11 @@ |
3922 | } |
3923 | |
3924 | Screen::skipDBusRegistration = true; |
3925 | - Screen *screen = new Screen(fake_output); |
3926 | +} |
3927 | + |
3928 | +TEST_F(ScreenTest, OrientationSensor) |
3929 | +{ |
3930 | + Screen *screen = new Screen(fakeOutput1); |
3931 | |
3932 | // Default state should be active |
3933 | ASSERT_TRUE(screen->orientationSensorEnabled()); |
3934 | @@ -67,3 +55,29 @@ |
3935 | screen->onDisplayPowerStateChanged(1,0); |
3936 | ASSERT_TRUE(screen->orientationSensorEnabled()); |
3937 | } |
3938 | + |
3939 | +TEST_F(ScreenTest, ReadConfigurationFromDisplayConfig) |
3940 | +{ |
3941 | + Screen *screen = new Screen(fakeOutput1); |
3942 | + |
3943 | + EXPECT_EQ(screen->geometry(), QRect(0, 0, 150, 200)); |
3944 | + EXPECT_EQ(screen->availableGeometry(), QRect(0, 0, 150, 200)); |
3945 | + EXPECT_EQ(screen->depth(), 32); |
3946 | + EXPECT_EQ(screen->format(), QImage::Format_RGBA8888); |
3947 | + EXPECT_EQ(screen->refreshRate(), 59); |
3948 | + EXPECT_EQ(screen->physicalSize(), QSize(1111, 2222)); |
3949 | + EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::dvid); |
3950 | +} |
3951 | + |
3952 | +TEST_F(ScreenTest, ReadDifferentConfigurationFromDisplayConfig) |
3953 | +{ |
3954 | + Screen *screen = new Screen(fakeOutput2); |
3955 | + |
3956 | + EXPECT_EQ(screen->geometry(), QRect(500, 600, 1500, 2000)); |
3957 | + EXPECT_EQ(screen->availableGeometry(), QRect(500, 600, 1500, 2000)); |
3958 | + EXPECT_EQ(screen->depth(), 32); |
3959 | + EXPECT_EQ(screen->format(), QImage::Format_RGBX8888); |
3960 | + EXPECT_EQ(screen->refreshRate(), 75); |
3961 | + EXPECT_EQ(screen->physicalSize(), QSize(1000, 2000)); |
3962 | + EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::lvds); |
3963 | +} |
3964 | |
3965 | === added directory 'tests/mirserver/ScreenController' |
3966 | === added file 'tests/mirserver/ScreenController/CMakeLists.txt' |
3967 | --- tests/mirserver/ScreenController/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
3968 | +++ tests/mirserver/ScreenController/CMakeLists.txt 2015-09-09 18:37:39 +0000 |
3969 | @@ -0,0 +1,28 @@ |
3970 | +set( |
3971 | + SCREENCONTROLLER_TEST_SOURCES |
3972 | + screencontroller_test.cpp |
3973 | + ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
3974 | + # to be moc-ed |
3975 | + stub_screen.h |
3976 | + testable_screencontroller.h |
3977 | +) |
3978 | + |
3979 | +include_directories( |
3980 | + ${CMAKE_SOURCE_DIR}/tests/common |
3981 | + ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
3982 | + ${CMAKE_SOURCE_DIR}/src/common |
3983 | + ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
3984 | + ${MIRSERVER_INCLUDE_DIRS} |
3985 | +) |
3986 | + |
3987 | +add_executable(ScreenControllerTest ${SCREENCONTROLLER_TEST_SOURCES}) |
3988 | + |
3989 | +target_link_libraries( |
3990 | + ScreenControllerTest |
3991 | + qpa-mirserver |
3992 | + |
3993 | + ${GTEST_BOTH_LIBRARIES} |
3994 | + ${GMOCK_LIBRARIES} |
3995 | +) |
3996 | + |
3997 | +add_test(ScreenController, ScreenControllerTest) |
3998 | |
3999 | === added file 'tests/mirserver/ScreenController/screencontroller_test.cpp' |
4000 | --- tests/mirserver/ScreenController/screencontroller_test.cpp 1970-01-01 00:00:00 +0000 |
4001 | +++ tests/mirserver/ScreenController/screencontroller_test.cpp 2015-09-09 18:37:39 +0000 |
4002 | @@ -0,0 +1,192 @@ |
4003 | +/* |
4004 | + * Copyright (C) 2015 Canonical, Ltd. |
4005 | + * |
4006 | + * This program is free software: you can redistribute it and/or modify it under |
4007 | + * the terms of the GNU Lesser General Public License version 3, as published by |
4008 | + * the Free Software Foundation. |
4009 | + * |
4010 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
4011 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
4012 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
4013 | + * Lesser General Public License for more details. |
4014 | + * |
4015 | + * You should have received a copy of the GNU Lesser General Public License |
4016 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4017 | + */ |
4018 | + |
4019 | +#include <gtest/gtest.h> |
4020 | +#include "gmock_fixes.h" |
4021 | + |
4022 | +#include "stub_display.h" |
4023 | +#include "mock_main_loop.h" |
4024 | +#include "qtcompositor.h" |
4025 | +#include "fake_displayconfigurationoutput.h" |
4026 | + |
4027 | +#include "testable_screencontroller.h" |
4028 | +#include "screen.h" |
4029 | +#include "screenwindow.h" |
4030 | + |
4031 | +#include <QGuiApplication> |
4032 | + |
4033 | +using namespace ::testing; |
4034 | + |
4035 | +namespace mg = mir::graphics; |
4036 | +namespace geom = mir::geometry; |
4037 | + |
4038 | +class ScreenControllerTest : public ::testing::Test { |
4039 | +protected: |
4040 | + void SetUp() override; |
4041 | + void TearDown() override; |
4042 | + |
4043 | + ScreenController *screenController; |
4044 | + std::shared_ptr<StubDisplay> display; |
4045 | + std::shared_ptr<QtCompositor> compositor; |
4046 | + QGuiApplication *app; |
4047 | +}; |
4048 | + |
4049 | +void ScreenControllerTest::SetUp() |
4050 | +{ |
4051 | + setenv("QT_QPA_PLATFORM", "minimal", 1); |
4052 | + Screen::skipDBusRegistration = true; |
4053 | + |
4054 | + screenController = new TestableScreenController; |
4055 | + display = std::make_shared<StubDisplay>(); |
4056 | + compositor = std::make_shared<QtCompositor>(); |
4057 | + |
4058 | + EXPECT_CALL(*display, register_configuration_change_handler(_,_)) |
4059 | + .Times(1); |
4060 | + |
4061 | + static_cast<TestableScreenController*>(screenController)->do_init(display, compositor); |
4062 | + |
4063 | + int argc = 0; |
4064 | + char **argv = nullptr; |
4065 | + setenv("QT_QPA_PLATFORM", "minimal", 1); |
4066 | + app = new QGuiApplication(argc, argv); |
4067 | +} |
4068 | + |
4069 | +void ScreenControllerTest::TearDown() |
4070 | +{ |
4071 | + delete screenController; |
4072 | +} |
4073 | + |
4074 | +TEST_F(ScreenControllerTest, SingleScreenFound) |
4075 | +{ |
4076 | + // Set up display state |
4077 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1}; |
4078 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
4079 | + display->setFakeConfiguration(config, bufferConfig); |
4080 | + |
4081 | + screenController->update(); |
4082 | + |
4083 | + ASSERT_EQ(1, screenController->screens().count()); |
4084 | + Screen* screen = screenController->screens().first(); |
4085 | + EXPECT_EQ(QRect(0, 0, 150, 200), screen->geometry()); |
4086 | +} |
4087 | + |
4088 | +TEST_F(ScreenControllerTest, MultipleScreenFound) |
4089 | +{ |
4090 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2}; |
4091 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
4092 | + display->setFakeConfiguration(config, bufferConfig); |
4093 | + |
4094 | + screenController->update(); |
4095 | + |
4096 | + ASSERT_EQ(2, screenController->screens().count()); |
4097 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry()); |
4098 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry()); |
4099 | +} |
4100 | + |
4101 | +TEST_F(ScreenControllerTest, ScreenAdded) |
4102 | +{ |
4103 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1}; |
4104 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
4105 | + display->setFakeConfiguration(config, bufferConfig); |
4106 | + |
4107 | + screenController->update(); |
4108 | + |
4109 | + config.push_back(fakeOutput2); |
4110 | + display->setFakeConfiguration(config, bufferConfig); |
4111 | + |
4112 | + ASSERT_EQ(1, screenController->screens().count()); |
4113 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry()); |
4114 | + |
4115 | + screenController->update(); |
4116 | + |
4117 | + ASSERT_EQ(2, screenController->screens().count()); |
4118 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry()); |
4119 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry()); |
4120 | +} |
4121 | + |
4122 | +TEST_F(ScreenControllerTest, ScreenRemoved) |
4123 | +{ |
4124 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput2, fakeOutput1}; |
4125 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
4126 | + display->setFakeConfiguration(config, bufferConfig); |
4127 | + |
4128 | + screenController->update(); |
4129 | + |
4130 | + config.pop_back(); |
4131 | + display->setFakeConfiguration(config, bufferConfig); |
4132 | + |
4133 | + ASSERT_EQ(2, screenController->screens().count()); |
4134 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry()); |
4135 | + EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(1)->geometry()); |
4136 | + |
4137 | + screenController->update(); |
4138 | + |
4139 | + ASSERT_EQ(1, screenController->screens().count()); |
4140 | + EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry()); |
4141 | +} |
4142 | + |
4143 | +TEST_F(ScreenControllerTest, CheckPrioritizedGetUnusedScreen) |
4144 | +{ |
4145 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput2, fakeOutput1}; |
4146 | + std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here |
4147 | + display->setFakeConfiguration(config, bufferConfig); |
4148 | + |
4149 | + screenController->update(); |
4150 | + |
4151 | + auto screen = screenController->getUnusedScreen(); |
4152 | + EXPECT_EQ(mg::DisplayConfigurationOutputType::lvds, screen->outputType()); |
4153 | +} |
4154 | + |
4155 | +TEST_F(ScreenControllerTest, MatchBufferWithDisplay) |
4156 | +{ |
4157 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1}; |
4158 | + MockDisplayBuffer buffer1; |
4159 | + std::vector<MockDisplayBuffer*> buffers {&buffer1}; |
4160 | + |
4161 | + geom::Rectangle buffer1Geom{{0, 0}, {150, 200}}; |
4162 | + EXPECT_CALL(buffer1, view_area()) |
4163 | + .WillRepeatedly(Return(buffer1Geom)); |
4164 | + |
4165 | + display->setFakeConfiguration(config, buffers); |
4166 | + screenController->update(); |
4167 | + |
4168 | + ASSERT_EQ(1, screenController->screens().count()); |
4169 | + EXPECT_CALL(buffer1, make_current()); |
4170 | + static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent(); |
4171 | +} |
4172 | + |
4173 | +TEST_F(ScreenControllerTest, MultipleMatchBuffersWithDisplays) |
4174 | +{ |
4175 | + std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2}; |
4176 | + MockDisplayBuffer buffer1, buffer2; |
4177 | + std::vector<MockDisplayBuffer*> buffers {&buffer1, &buffer2}; |
4178 | + |
4179 | + geom::Rectangle buffer1Geom{{500, 600}, {1500, 2000}}; |
4180 | + geom::Rectangle buffer2Geom{{0, 0}, {150, 200}}; |
4181 | + EXPECT_CALL(buffer1, view_area()) |
4182 | + .WillRepeatedly(Return(buffer1Geom)); |
4183 | + EXPECT_CALL(buffer2, view_area()) |
4184 | + .WillRepeatedly(Return(buffer2Geom)); |
4185 | + |
4186 | + display->setFakeConfiguration(config, buffers); |
4187 | + screenController->update(); |
4188 | + |
4189 | + ASSERT_EQ(2, screenController->screens().count()); |
4190 | + EXPECT_CALL(buffer1, make_current()); |
4191 | + EXPECT_CALL(buffer2, make_current()); |
4192 | + static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent(); |
4193 | + static_cast<StubScreen*>(screenController->screens().at(1))->makeCurrent(); |
4194 | +} |
4195 | |
4196 | === added file 'tests/mirserver/ScreenController/stub_display.h' |
4197 | --- tests/mirserver/ScreenController/stub_display.h 1970-01-01 00:00:00 +0000 |
4198 | +++ tests/mirserver/ScreenController/stub_display.h 2015-09-09 18:37:39 +0000 |
4199 | @@ -0,0 +1,99 @@ |
4200 | +/* |
4201 | + * Copyright (C) 2015 Canonical, Ltd. |
4202 | + * |
4203 | + * This program is free software: you can redistribute it and/or modify it under |
4204 | + * the terms of the GNU Lesser General Public License version 3, as published by |
4205 | + * the Free Software Foundation. |
4206 | + * |
4207 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
4208 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
4209 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
4210 | + * Lesser General Public License for more details. |
4211 | + * |
4212 | + * You should have received a copy of the GNU Lesser General Public License |
4213 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4214 | + */ |
4215 | + |
4216 | +#ifndef STUB_DISPLAY_H |
4217 | +#define STUB_DISPLAY_H |
4218 | + |
4219 | +#include "mock_display.h" |
4220 | +#include "mock_display_buffer.h" |
4221 | +#include "mock_display_configuration.h" |
4222 | + |
4223 | +// C++ std lib |
4224 | +#include <chrono> |
4225 | + |
4226 | +namespace mg = mir::graphics; |
4227 | +namespace geom = mir::geometry; |
4228 | + |
4229 | +class StubDisplayConfiguration : public MockDisplayConfiguration |
4230 | +{ |
4231 | +public: |
4232 | + StubDisplayConfiguration(const std::vector<mg::DisplayConfigurationOutput> &config) |
4233 | + : m_config(config) |
4234 | + {} |
4235 | + |
4236 | + void for_each_output(std::function<void(mg::DisplayConfigurationOutput const&)> f) const override |
4237 | + { |
4238 | + for (auto config : m_config) { |
4239 | + f(config); |
4240 | + } |
4241 | + } |
4242 | + |
4243 | +private: |
4244 | + const std::vector<mg::DisplayConfigurationOutput> m_config; |
4245 | +}; |
4246 | + |
4247 | + |
4248 | +class StubDisplaySyncGroup : public MockDisplaySyncGroup |
4249 | +{ |
4250 | +public: |
4251 | + StubDisplaySyncGroup(MockDisplayBuffer *buffer) : buffer(buffer) {} |
4252 | + |
4253 | + void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override |
4254 | + { |
4255 | + f(*buffer); |
4256 | + } |
4257 | + std::chrono::milliseconds recommended_sleep() const |
4258 | + { |
4259 | + std::chrono::milliseconds one{1}; |
4260 | + return one; |
4261 | + } |
4262 | +private: |
4263 | + MockDisplayBuffer *buffer; |
4264 | +}; |
4265 | + |
4266 | + |
4267 | +class StubDisplay : public MockDisplay |
4268 | +{ |
4269 | +public: |
4270 | + // Note, GMock cannot mock functions which return non-copyable objects, so stubbing needed |
4271 | + std::unique_ptr<mg::DisplayConfiguration> configuration() const override |
4272 | + { |
4273 | + return std::unique_ptr<mg::DisplayConfiguration>( |
4274 | + new StubDisplayConfiguration(m_config) |
4275 | + ); |
4276 | + } |
4277 | + |
4278 | + void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override |
4279 | + { |
4280 | + for (auto displayBuffer : m_displayBuffers) { |
4281 | + StubDisplaySyncGroup b(displayBuffer); |
4282 | + f(b); |
4283 | + } |
4284 | + } |
4285 | + |
4286 | + void setFakeConfiguration(std::vector<mg::DisplayConfigurationOutput> &config, |
4287 | + std::vector<MockDisplayBuffer*> &displayBuffers) |
4288 | + { |
4289 | + m_config = config; |
4290 | + m_displayBuffers = displayBuffers; |
4291 | + } |
4292 | + |
4293 | +private: |
4294 | + std::vector<mg::DisplayConfigurationOutput> m_config; |
4295 | + std::vector<MockDisplayBuffer*> m_displayBuffers; |
4296 | +}; |
4297 | + |
4298 | +#endif // STUB_DISPLAY_H |
4299 | |
4300 | === added file 'tests/mirserver/ScreenController/stub_screen.h' |
4301 | --- tests/mirserver/ScreenController/stub_screen.h 1970-01-01 00:00:00 +0000 |
4302 | +++ tests/mirserver/ScreenController/stub_screen.h 2015-09-09 18:37:39 +0000 |
4303 | @@ -0,0 +1,31 @@ |
4304 | +/* |
4305 | + * Copyright (C) 2015 Canonical, Ltd. |
4306 | + * |
4307 | + * This program is free software: you can redistribute it and/or modify it under |
4308 | + * the terms of the GNU Lesser General Public License version 3, as published by |
4309 | + * the Free Software Foundation. |
4310 | + * |
4311 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
4312 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
4313 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
4314 | + * Lesser General Public License for more details. |
4315 | + * |
4316 | + * You should have received a copy of the GNU Lesser General Public License |
4317 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4318 | + */ |
4319 | + |
4320 | +#ifndef STUBSCREEN_H |
4321 | +#define STUBSCREEN_H |
4322 | + |
4323 | +#include "screen.h" |
4324 | + |
4325 | +class StubScreen : public Screen |
4326 | +{ |
4327 | + Q_OBJECT |
4328 | +public: |
4329 | + StubScreen(const mir::graphics::DisplayConfigurationOutput &output) : Screen(output) {} |
4330 | + |
4331 | + void makeCurrent() { Screen::makeCurrent(); } |
4332 | +}; |
4333 | + |
4334 | +#endif // STUBSCREEN_H |
4335 | |
4336 | === added file 'tests/mirserver/ScreenController/testable_screencontroller.h' |
4337 | --- tests/mirserver/ScreenController/testable_screencontroller.h 1970-01-01 00:00:00 +0000 |
4338 | +++ tests/mirserver/ScreenController/testable_screencontroller.h 2015-09-09 18:37:39 +0000 |
4339 | @@ -0,0 +1,37 @@ |
4340 | +/* |
4341 | + * Copyright (C) 2015 Canonical, Ltd. |
4342 | + * |
4343 | + * This program is free software: you can redistribute it and/or modify it under |
4344 | + * the terms of the GNU Lesser General Public License version 3, as published by |
4345 | + * the Free Software Foundation. |
4346 | + * |
4347 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
4348 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
4349 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
4350 | + * Lesser General Public License for more details. |
4351 | + * |
4352 | + * You should have received a copy of the GNU Lesser General Public License |
4353 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4354 | + */ |
4355 | + |
4356 | +#include "screencontroller.h" |
4357 | +#include "stub_screen.h" |
4358 | + |
4359 | +struct TestableScreenController : public ScreenController |
4360 | +{ |
4361 | + Q_OBJECT |
4362 | + |
4363 | +public: |
4364 | + Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const override |
4365 | + { |
4366 | + return new StubScreen(output); |
4367 | + } |
4368 | + |
4369 | + void do_init(const std::shared_ptr<mir::graphics::Display> &display, |
4370 | + const std::shared_ptr<mir::compositor::Compositor> &compositor) |
4371 | + { |
4372 | + init(display, compositor); |
4373 | + } |
4374 | + |
4375 | + void do_terminate() { terminate(); } |
4376 | +}; |
4377 | |
4378 | === modified file 'tests/modules/common/qtmir_test.h' |
4379 | --- tests/modules/common/qtmir_test.h 2015-08-11 12:08:32 +0000 |
4380 | +++ tests/modules/common/qtmir_test.h 2015-09-09 18:37:39 +0000 |
4381 | @@ -78,7 +78,7 @@ |
4382 | { |
4383 | public: |
4384 | FakeMirServer() |
4385 | - : MirServer(0, argv) |
4386 | + : MirServer(0, argv, QSharedPointer<ScreenController>()) |
4387 | { |
4388 | } |
4389 |
FAILED: Continuous integration, rev:370 jenkins. qa.ubuntu. com/job/ qtmir-ci/ 386/ jenkins. qa.ubuntu. com/job/ qtmir-wily- amd64-ci/ 119/console jenkins. qa.ubuntu. com/job/ qtmir-wily- armhf-ci/ 119/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/qtmir- ci/386/ rebuild
http://