Merge lp:~dandrader/qtmir/mousePointer into lp:qtmir

Proposed by Daniel d'Andrada
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
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://code.launchpad.net/~dandrader/unity-api/mousePointer/+merge/269783
https://code.launchpad.net/~dandrader/unity8/mousePointer/+merge/269779

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.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

=== added file 'src/modules/Unity/Application/Cursor.qml'
=== added file 'src/modules/Unity/Application/cursorimageprovider.cpp'
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.

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

=== added file 'demos/qml-demo-shell/ResizeArea.qml'
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.

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

> === added file 'demos/qml-demo-shell/ResizeArea.qml'
> 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.cursorShape property. If you set it, the cursor will automatically 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.cursorShape, maybe I could use a single mouse area.

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

> > === added file 'demos/qml-demo-shell/ResizeArea.qml'
> > 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.cursorShape property. If you set it, the cursor will automatically
> 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.cursorShape, maybe I could use
> a single mouse area.

FYI: I also copy-pasted ResizeArea.qml into unity8/mousePointer

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

> === added file 'src/modules/Unity/Application/Cursor.qml'
> === added file 'src/modules/Unity/Application/cursorimageprovider.cpp'
> 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-settings one.

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

On 02/09/15 13:16, Gerry Boland wrote:
> === added file 'demos/qml-demo-shell/ResizeArea.qml'
> 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.

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

> > === added file 'src/modules/Unity/Application/Cursor.qml'
> > === added file 'src/modules/Unity/Application/cursorimageprovider.cpp'
> > 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://trello.com/c/4uBsKNVT/133-split-applicationmanager-out-of-qtmir
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-settings one.

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.

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

Ok, moved all Cursor stuff from qtmir to unity8.

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

=== modified file 'debian/copyright'
can undo this.

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

On 09/09/15 07:57, Gerry Boland wrote:
> === modified file 'debian/copyright'
> can undo this.
Done.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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://code.launchpad.net/~gerboland/qtmir/multimonitor/+merge/269906
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_callback([this](){ the_cursor()->hide(); });
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/mirserver/mirsingleton.cpp
+qtmir::Mir::~Mir()
+{
+ m_instance = nullptr;
+}
You're not deleting what you potentially "new"ed. QScopedPointer helps prevent such accidents...

+++ src/platforms/mirserver/mirsingleton.h
+private:
+ Mir();
maybe http://doc.qt.io/qt-5/qobject.html#Q_DISABLE_COPY

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.

review: Needs Fixing
lp:~dandrader/qtmir/mousePointer updated
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

Revision history for this message
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://code.launchpad.net/~gerboland/qtmir/multimonitor/+merge/269906
> 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_callback([this](){ the_cursor()->hide(); });
> 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/mirserver/mirsingleton.cpp
> +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/mirserver/mirsingleton.h
> +private:
> + Mir();
> maybe http://doc.qt.io/qt-5/qobject.html#Q_DISABLE_COPY

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.

lp:~dandrader/qtmir/mousePointer updated
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-application-impl in debian/control

379. By Daniel d'Andrada

Merge trunk

380. By Daniel d'Andrada

s/Qt::MouseButton/Qt::MouseButtons

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2015-08-27 13:58:50 +0000
+++ CMakeLists.txt 2015-09-09 18:37:39 +0000
@@ -74,7 +74,7 @@
74pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)74pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
75pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED)75pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED)
76pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED)76pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED)
77pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=8)77pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=9)
7878
79include_directories(${APPLICATION_API_INCLUDE_DIRS})79include_directories(${APPLICATION_API_INCLUDE_DIRS})
8080
8181
=== modified file 'debian/control'
--- debian/control 2015-08-27 13:58:50 +0000
+++ debian/control 2015-09-09 18:37:39 +0000
@@ -22,7 +22,7 @@
22 libubuntu-app-launch2-dev,22 libubuntu-app-launch2-dev,
23 libubuntu-application-api-dev (>= 2.1.0),23 libubuntu-application-api-dev (>= 2.1.0),
24 libudev-dev,24 libudev-dev,
25 libunity-api-dev (>= 7.100),25 libunity-api-dev (>= 7.101),
26 liburl-dispatcher1-dev,26 liburl-dispatcher1-dev,
27 libxkbcommon-dev,27 libxkbcommon-dev,
28 libxrender-dev,28 libxrender-dev,
2929
=== added file 'demos/qml-demo-shell/ResizeArea.qml'
--- demos/qml-demo-shell/ResizeArea.qml 1970-01-01 00:00:00 +0000
+++ demos/qml-demo-shell/ResizeArea.qml 2015-09-09 18:37:39 +0000
@@ -0,0 +1,128 @@
1import QtQuick 2.4
2import Unity.Application 0.1
3
4MouseArea {
5 id: root
6
7 // to be set from outside
8 property Item target
9 property real borderThickness
10
11 property bool leftBorder: false
12 property bool rightBorder: false
13 property bool topBorder: false
14 property bool bottomBorder: false
15
16 property bool dragging: false
17 property real startX
18 property real startY
19 property real startWidth
20 property real startHeight
21
22 hoverEnabled: true
23
24 property string cursorName: {
25 if (containsMouse || pressed) {
26 if (leftBorder && !topBorder && !bottomBorder) {
27 return "left_side";
28 } else if (rightBorder && !topBorder && !bottomBorder) {
29 return "right_side";
30 } else if (topBorder && !leftBorder && !rightBorder) {
31 return "top_side";
32 } else if (bottomBorder && !leftBorder && !rightBorder) {
33 return "bottom_side";
34 } else if (leftBorder && topBorder) {
35 return "top_left_corner";
36 } else if (leftBorder && bottomBorder) {
37 return "bottom_left_corner";
38 } else if (rightBorder && topBorder) {
39 return "top_right_corner";
40 } else if (rightBorder && bottomBorder) {
41 return "bottom_right_corner";
42 } else {
43 return "";
44 }
45 } else {
46 return "";
47 }
48 }
49 onCursorNameChanged: {
50 Mir.cursorName = cursorName;
51 }
52
53 function updateBorders() {
54 leftBorder = mouseX <= borderThickness;
55 rightBorder = mouseX >= width - borderThickness;
56 topBorder = mouseY <= borderThickness;
57 bottomBorder = mouseY >= height - borderThickness;
58 }
59
60 onPressedChanged: {
61 if (pressed) {
62 var pos = mapToItem(target.parent, mouseX, mouseY);
63 startX = pos.x;
64 startY = pos.y;
65 startWidth = target.width;
66 startHeight = target.height;
67 dragging = true;
68 } else {
69 dragging = false;
70 if (containsMouse) {
71 updateBorders();
72 }
73 }
74 }
75
76 onEntered: {
77 if (!pressed) {
78 updateBorders();
79 }
80 }
81
82 onPositionChanged: {
83 if (!pressed) {
84 updateBorders();
85 }
86
87 if (!dragging) {
88 return;
89 }
90
91 var pos = mapToItem(target.parent, mouse.x, mouse.y);
92
93 if (leftBorder) {
94 if (startX + startWidth - pos.x > target.minWidth) {
95 target.x = pos.x;
96 target.width = startX + startWidth - target.x;
97 startX = target.x;
98 startWidth = target.width;
99 }
100
101 } else if (rightBorder) {
102 var deltaX = pos.x - startX;
103 if (startWidth + deltaX >= target.minWidth) {
104 target.width = startWidth + deltaX;
105 } else {
106 target.width = target.minWidth;
107 }
108 }
109
110 if (topBorder) {
111 if (startY + startHeight - pos.y > target.minHeight) {
112 target.y = pos.y;
113 target.height = startY + startHeight - target.y;
114 startY = target.y;
115 startHeight = target.height;
116 }
117
118 } else if (bottomBorder) {
119 var deltaY = pos.y - startY;
120 if (startHeight + deltaY >= target.minHeight) {
121 target.height = startHeight + deltaY;
122 } else {
123 target.height = target.minHeight;
124 }
125 }
126 }
127}
128
0129
=== renamed file 'demos/qml-demo-shell/qml-demo-shell.qml' => 'demos/qml-demo-shell/Shell.qml'
--- demos/qml-demo-shell/qml-demo-shell.qml 2015-08-24 12:43:01 +0000
+++ demos/qml-demo-shell/Shell.qml 2015-09-09 18:37:39 +0000
@@ -1,4 +1,4 @@
1import QtQuick 2.01import QtQuick 2.4
2import Unity.Application 0.12import Unity.Application 0.1
33
4Rectangle {4Rectangle {
@@ -88,6 +88,7 @@
88 }88 }
8989
90 Rectangle {90 Rectangle {
91 id: resizeButton
91 width: 9092 width: 90
92 height: 4093 height: 40
93 color: "blue"94 color: "blue"
@@ -103,6 +104,23 @@
103 }104 }
104 }105 }
105106
107 Rectangle {
108 width: 40
109 height: 40
110 color: "green"
111 anchors { right: resizeButton.left; bottom: parent.bottom }
112 Text {
113 anchors.centerIn: parent
114 text: "⟳"
115 color: "white"
116 font.pixelSize: 35
117 }
118 MouseArea {
119 anchors.fill: parent
120 onClicked: { root.rotation += 180; }
121 }
122 }
123
106 Component {124 Component {
107 id: windowStretchComponent125 id: windowStretchComponent
108 Window {126 Window {
@@ -161,4 +179,6 @@
161 from: root.width; to: 10;179 from: root.width; to: 10;
162 duration: 1200; easing.type: Easing.InOutQuad180 duration: 1200; easing.type: Easing.InOutQuad
163 }181 }
182
183 Cursor {}
164}184}
165185
=== modified file 'demos/qml-demo-shell/TitleBar.qml'
--- demos/qml-demo-shell/TitleBar.qml 2015-08-24 12:43:01 +0000
+++ demos/qml-demo-shell/TitleBar.qml 2015-09-09 18:37:39 +0000
@@ -1,4 +1,5 @@
1import QtQuick 2.01import QtQuick 2.4
2import Unity.Application 0.1
23
3Rectangle {4Rectangle {
4 id: root5 id: root
@@ -21,8 +22,10 @@
21 distanceX = pos.x;22 distanceX = pos.x;
22 distanceY = pos.y;23 distanceY = pos.y;
23 dragging = true;24 dragging = true;
25 Mir.cursorName = "grabbing";
24 } else {26 } else {
25 dragging = false;27 dragging = false;
28 Mir.cursorName = "";
26 }29 }
27 }30 }
28 onMouseXChanged: {31 onMouseXChanged: {
2932
=== modified file 'demos/qml-demo-shell/Window.qml'
--- demos/qml-demo-shell/Window.qml 2015-08-24 12:43:01 +0000
+++ demos/qml-demo-shell/Window.qml 2015-09-09 18:37:39 +0000
@@ -58,87 +58,10 @@
58 }58 }
59 ]59 ]
6060
6161 ResizeArea {
62 MouseArea {62 anchors.fill: root
63 anchors.fill: parent63 borderThickness: root.borderThickness
6464 target: root
65 property real startX
66 property real startY
67 property real startWidth
68 property real startHeight
69 property bool leftBorder
70 property bool rightBorder
71 property bool topBorder
72 property bool bottomBorder
73 property bool dragging
74 onPressedChanged: {
75 if (pressed) {
76 var pos = mapToItem(root.parent, mouseX, mouseY);
77 startX = pos.x;
78 startY = pos.y;
79 startWidth = width;
80 startHeight = height;
81 leftBorder = mouseX > 0 && mouseX < root.borderThickness;
82 rightBorder = mouseX > (root.width - root.borderThickness) && mouseX < root.width;
83 topBorder = mouseY > 0 && mouseY < root.borderThickness;
84 bottomBorder = mouseY > (root.height - root.borderThickness) && mouseY < root.height;
85 dragging = true;
86 } else {
87 dragging = false;
88 }
89 }
90
91 onMouseXChanged: {
92 if (!pressed || !dragging) {
93 return;
94 }
95
96 var pos = mapToItem(root.parent, mouseX, mouseY);
97
98 if (leftBorder) {
99
100 if (startX + startWidth - pos.x > root.minWidth) {
101 root.x = pos.x;
102 root.width = startX + startWidth - root.x;
103 startX = root.x;
104 startWidth = root.width;
105 }
106
107 } else if (rightBorder) {
108 var deltaX = pos.x - startX;
109 if (startWidth + deltaX >= root.minWidth) {
110 root.width = startWidth + deltaX;
111 } else {
112 root.width = root.minWidth;
113 }
114 }
115 }
116
117 onMouseYChanged: {
118 if (!pressed || !dragging) {
119 return;
120 }
121
122 var pos = mapToItem(root.parent, mouseX, mouseY);
123
124 if (topBorder) {
125
126 if (startY + startHeight - pos.y > root.minHeight) {
127 root.y = pos.y;
128 root.height = startY + startHeight - root.y;
129 startY = root.y;
130 startHeight = root.height;
131 }
132
133 } else if (bottomBorder) {
134 var deltaY = pos.y - startY;
135 if (startHeight + deltaY >= root.minHeight) {
136 root.height = startHeight + deltaY;
137 } else {
138 root.height = root.minHeight;
139 }
140 }
141 }
142 }65 }
14366
144 TitleBar {67 TitleBar {
14568
=== added file 'demos/qml-demo-shell/qml-demo-shell.qml'
--- demos/qml-demo-shell/qml-demo-shell.qml 1970-01-01 00:00:00 +0000
+++ demos/qml-demo-shell/qml-demo-shell.qml 2015-09-09 18:37:39 +0000
@@ -0,0 +1,19 @@
1import QtQuick 2.3
2import QtQuick.Window 2.2 as QQW
3import Unity.Screens 0.1
4
5Instantiator {
6 id: root
7
8 property var screens: Screens{}
9
10 model: screens
11 QQW.Window {
12 id: window
13 visible: true
14 Shell{ anchors.fill: parent }
15 Component.onCompleted: {
16 print("HEY", screen, screen.geometry, outputType, Screens.HDMIA)
17 }
18 }
19}
020
=== modified file 'src/modules/Unity/Application/CMakeLists.txt'
--- src/modules/Unity/Application/CMakeLists.txt 2015-08-24 12:43:01 +0000
+++ src/modules/Unity/Application/CMakeLists.txt 2015-09-09 18:37:39 +0000
@@ -91,4 +91,3 @@
91# install91# install
92add_qml_plugin(Unity.Application 0.1 Unity/Application TARGETS unityapplicationplugin)92add_qml_plugin(Unity.Application 0.1 Unity/Application TARGETS unityapplicationplugin)
93install(FILES com.canonical.qtmir.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas)93install(FILES com.canonical.qtmir.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas)
94
9594
=== modified file 'src/modules/Unity/Application/plugin.cpp'
--- src/modules/Unity/Application/plugin.cpp 2015-08-24 12:43:01 +0000
+++ src/modules/Unity/Application/plugin.cpp 2015-09-09 18:37:39 +0000
@@ -27,6 +27,9 @@
27#include "sessionmanager.h"27#include "sessionmanager.h"
28#include "ubuntukeyboardinfo.h"28#include "ubuntukeyboardinfo.h"
2929
30// platforms/mirserver
31#include <mirsingleton.h>
32
30// qtmir33// qtmir
31#include "logging.h"34#include "logging.h"
3235
@@ -64,6 +67,10 @@
64 }67 }
65 return UbuntuKeyboardInfo::instance();68 return UbuntuKeyboardInfo::instance();
66}69}
70
71QObject* mirSingleton(QQmlEngine* /*engine*/, QJSEngine* /*scriptEngine*/) {
72 return qtmir::Mir::instance();
73}
67} // anonymous namespace74} // anonymous namespace
6875
69class UnityApplicationPlugin : public QQmlExtensionPlugin {76class UnityApplicationPlugin : public QQmlExtensionPlugin {
@@ -102,7 +109,7 @@
102 uri, 0, 1, "Session", "Session can't be instantiated from QML");109 uri, 0, 1, "Session", "Session can't be instantiated from QML");
103 qmlRegisterSingletonType<qtmir::UbuntuKeyboardInfo>(110 qmlRegisterSingletonType<qtmir::UbuntuKeyboardInfo>(
104 uri, 0, 1, "UbuntuKeyboardInfo", ubuntuKeyboardInfoSingleton);111 uri, 0, 1, "UbuntuKeyboardInfo", ubuntuKeyboardInfoSingleton);
105 qmlRegisterUncreatableType<Mir>(uri, 0, 1, "Mir", "Mir provides enum values, it can't be instantiated");112 qmlRegisterSingletonType<qtmir::Mir>(uri, 0, 1, "Mir", mirSingleton);
106 }113 }
107114
108 virtual void initializeEngine(QQmlEngine *engine, const char *uri)115 virtual void initializeEngine(QQmlEngine *engine, const char *uri)
109116
=== modified file 'src/modules/Unity/CMakeLists.txt'
--- src/modules/Unity/CMakeLists.txt 2014-09-22 18:06:58 +0000
+++ src/modules/Unity/CMakeLists.txt 2015-09-09 18:37:39 +0000
@@ -1,1 +1,2 @@
1add_subdirectory(Application)1add_subdirectory(Application)
2add_subdirectory(Screens)
23
=== added directory 'src/modules/Unity/Screens'
=== added file 'src/modules/Unity/Screens/CMakeLists.txt'
--- src/modules/Unity/Screens/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/CMakeLists.txt 2015-09-09 18:37:39 +0000
@@ -0,0 +1,24 @@
1include_directories(
2 ${CMAKE_SOURCE_DIR}/src/platforms/mirserver
3 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
4 ${MIRSERVER_INCLUDE_DIRS}
5 )
6
7set(SCREENSPLUGIN_SRC
8 plugin.cpp
9 screens.cpp
10 )
11
12add_library(unityscreensplugin SHARED
13 ${SCREENSPLUGIN_SRC}
14)
15
16target_link_libraries(
17 unityscreensplugin
18
19 Qt5::Gui
20 Qt5::Qml
21)
22
23# install
24add_qml_plugin(Unity.Screens 0.1 Unity/Screens TARGETS unityscreensplugin)
025
=== added file 'src/modules/Unity/Screens/plugin.cpp'
--- src/modules/Unity/Screens/plugin.cpp 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/plugin.cpp 2015-09-09 18:37:39 +0000
@@ -0,0 +1,41 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17// Qt
18#include <QQmlExtensionPlugin>
19#include <QtQml/qqml.h>
20#include <QScreen>
21
22// local
23#include "screens.h"
24
25using namespace qtmir;
26
27class UnityScreensPlugin : public QQmlExtensionPlugin {
28 Q_OBJECT
29 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
30
31 virtual void registerTypes(const char* uri)
32 {
33 Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Screens"));
34
35 qRegisterMetaType<QScreen*>("QScreen*");
36
37 qmlRegisterType<qtmir::Screens>(uri, 0, 1, "Screens");
38 }
39};
40
41#include "plugin.moc"
042
=== added file 'src/modules/Unity/Screens/qmldir'
--- src/modules/Unity/Screens/qmldir 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/qmldir 2015-09-09 18:37:39 +0000
@@ -0,0 +1,2 @@
1module Unity.Screens
2plugin unityscreensplugin
03
=== added file 'src/modules/Unity/Screens/screens.cpp'
--- src/modules/Unity/Screens/screens.cpp 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/screens.cpp 2015-09-09 18:37:39 +0000
@@ -0,0 +1,107 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "screens.h"
18
19// mirserver
20#include "screen.h"
21
22// Qt
23#include <QGuiApplication>
24#include <QScreen>
25
26Q_DECLARE_METATYPE(QScreen*)
27
28namespace qtmir {
29
30Screens::Screens(QObject *parent) :
31 QAbstractListModel(parent)
32{
33 auto app = static_cast<QGuiApplication *>(QGuiApplication::instance());
34 if (!app) {
35 return;
36 }
37 connect(app, &QGuiApplication::screenAdded, this, &Screens::onScreenAdded);
38 connect(app, &QGuiApplication::screenRemoved, this, &Screens::onScreenRemoved);
39
40 m_screenList = QGuiApplication::screens();
41}
42
43QHash<int, QByteArray> Screens::roleNames() const
44{
45 QHash<int, QByteArray> roles;
46 roles[ScreenRole] = "screen";
47 roles[OutputTypeRole] = "outputType";
48 return roles;
49}
50
51QVariant Screens::data(const QModelIndex &index, int role) const
52{
53 if (!index.isValid() || index.row() >= m_screenList.size()) {
54 return QVariant();
55 }
56
57 switch(role) {
58 case ScreenRole:
59 return QVariant::fromValue(m_screenList.at(index.row()));
60 case OutputTypeRole:
61 auto screen = static_cast<Screen*>(m_screenList.at(index.row())->handle());
62 if (screen) {
63 return QVariant(static_cast<OutputTypes>(screen->outputType())); //FIXME: cheeky
64 } else
65 return OutputTypes::Unknown;
66 }
67
68 return QVariant();
69}
70
71int Screens::rowCount(const QModelIndex &) const
72{
73 return count();
74}
75
76int Screens::count() const
77{
78 return m_screenList.size();
79}
80
81void Screens::onScreenAdded(QScreen *screen)
82{
83 if (m_screenList.contains(screen))
84 return;
85
86 beginInsertRows(QModelIndex(), count(), count());
87 m_screenList.push_back(screen);
88 endInsertRows();
89 Q_EMIT screenAdded(screen);
90 Q_EMIT countChanged();
91}
92
93void Screens::onScreenRemoved(QScreen *screen)
94{
95 int index = m_screenList.indexOf(screen);
96 if (index < 0)
97 return;
98
99 beginRemoveRows(QModelIndex(), index, index);
100 m_screenList.removeAt(index);
101 endRemoveRows();
102 Q_EMIT screenRemoved(screen);
103 Q_EMIT countChanged();
104}
105
106
107} // namespace qtmir
0108
=== added file 'src/modules/Unity/Screens/screens.h'
--- src/modules/Unity/Screens/screens.h 1970-01-01 00:00:00 +0000
+++ src/modules/Unity/Screens/screens.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,82 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef SCREENS_H
18#define SCREENS_H
19
20#include <QAbstractListModel>
21
22class QScreen;
23
24namespace qtmir {
25
26class Screens : public QAbstractListModel
27{
28 Q_OBJECT
29 Q_ENUMS(OutputTypes)
30
31 Q_PROPERTY(int count READ count NOTIFY countChanged)
32
33public:
34 enum ItemRoles {
35 ScreenRole = Qt::UserRole + 1,
36 OutputTypeRole
37 };
38
39 enum OutputTypes {
40 Unknown,
41 VGA,
42 DVII,
43 DVID,
44 DVIA,
45 Composite,
46 SVideo,
47 LVDS,
48 Component,
49 NinePinDIN,
50 DisplayPort,
51 HDMIA,
52 HDMIB,
53 TV,
54 EDP
55 };
56
57 explicit Screens(QObject *parent = 0);
58 virtual ~Screens() noexcept = default;
59
60 /* QAbstractItemModel */
61 QHash<int, QByteArray> roleNames() const override;
62 QVariant data(const QModelIndex &index, int role = ScreenRole) const override;
63 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
64
65 int count() const;
66
67Q_SIGNALS:
68 void countChanged();
69 void screenAdded(QScreen *screen);
70 void screenRemoved(QScreen *screen);
71
72private Q_SLOTS:
73 void onScreenAdded(QScreen *screen);
74 void onScreenRemoved(QScreen *screen);
75
76private:
77 QList<QScreen *> m_screenList;
78};
79
80} // namespace qtmir
81
82#endif // SCREENS_H
083
=== modified file 'src/platforms/mirserver/CMakeLists.txt'
--- src/platforms/mirserver/CMakeLists.txt 2015-08-11 19:25:04 +0000
+++ src/platforms/mirserver/CMakeLists.txt 2015-09-09 18:37:39 +0000
@@ -30,6 +30,7 @@
30 ${QT5PLATFORM_SUPPORT_INCLUDE_DIRS}30 ${QT5PLATFORM_SUPPORT_INCLUDE_DIRS}
31 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}31 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
32 ${QT5_PLATFORMSUPPORT_INCLUDE_DIRS}32 ${QT5_PLATFORMSUPPORT_INCLUDE_DIRS}
33 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
3334
34 ${APPLICATION_API_INCLUDE_DIRS}35 ${APPLICATION_API_INCLUDE_DIRS}
35)36)
@@ -41,7 +42,9 @@
4142
42set(MIRSERVER_QPA_PLUGIN_SRC43set(MIRSERVER_QPA_PLUGIN_SRC
43 ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp44 ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp
45 cursor.cpp
44 mirwindowmanager.cpp46 mirwindowmanager.cpp
47 mirsingleton.cpp
45 qteventfeeder.cpp48 qteventfeeder.cpp
46 plugin.cpp49 plugin.cpp
47 qmirserver.cpp50 qmirserver.cpp
@@ -52,17 +55,21 @@
52 promptsessionlistener.cpp55 promptsessionlistener.cpp
53 mirserver.cpp56 mirserver.cpp
54 mirserverstatuslistener.cpp57 mirserverstatuslistener.cpp
55 display.cpp
56 screen.cpp58 screen.cpp
57 displaywindow.cpp59 screencontroller.cpp
60 screenwindow.cpp
58 mirserverintegration.cpp61 mirserverintegration.cpp
59 miropenglcontext.cpp62 miropenglcontext.cpp
60 nativeinterface.cpp63 nativeinterface.cpp
64 offscreensurface.cpp
61 qtcompositor.cpp65 qtcompositor.cpp
62 services.cpp66 services.cpp
63 ubuntutheme.cpp67 ubuntutheme.cpp
64 clipboard.cpp68 clipboard.cpp
69 tileddisplayconfigurationpolicy.cpp
65 tracepoints.c70 tracepoints.c
71# We need to run moc on these headers
72 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
66 )73 )
6774
68add_library(qpa-mirserver SHARED75add_library(qpa-mirserver SHARED
@@ -82,7 +89,7 @@
82 ${QT5PLATFORM_SUPPORT_LDFLAGS}89 ${QT5PLATFORM_SUPPORT_LDFLAGS}
83 # TODO Qt5Platform support LDFLAGS dont provide actual required ldflags...90 # TODO Qt5Platform support LDFLAGS dont provide actual required ldflags...
84 # I found these were needed...perhaps there is some way to query qmake/qconfig?91 # I found these were needed...perhaps there is some way to query qmake/qconfig?
85 -lfreetype 92 -lfreetype
86 ${GIO_LDFLAGS}93 ${GIO_LDFLAGS}
87 ${FONTCONFIG_LDFLAGS}94 ${FONTCONFIG_LDFLAGS}
8895
8996
=== added file 'src/platforms/mirserver/cursor.cpp'
--- src/platforms/mirserver/cursor.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/cursor.cpp 2015-09-09 18:37:39 +0000
@@ -0,0 +1,152 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include "cursor.h"
19#include "logging.h"
20
21#include "mirsingleton.h"
22
23// Unity API
24#include <unity/shell/application/MirMousePointerInterface.h>
25
26using namespace qtmir;
27
28Cursor::Cursor()
29{
30 m_shapeToCursorName[Qt::ArrowCursor] = "left_ptr";
31 m_shapeToCursorName[Qt::UpArrowCursor] = "up_arrow";
32 m_shapeToCursorName[Qt::CrossCursor] = "cross";
33 m_shapeToCursorName[Qt::WaitCursor] = "watch";
34 m_shapeToCursorName[Qt::IBeamCursor] = "xterm";
35 m_shapeToCursorName[Qt::SizeVerCursor] = "size_ver";
36 m_shapeToCursorName[Qt::SizeHorCursor] = "size_hor";
37 m_shapeToCursorName[Qt::SizeBDiagCursor] = "size_bdiag";
38 m_shapeToCursorName[Qt::SizeFDiagCursor] = "size_fdiag";
39 m_shapeToCursorName[Qt::SizeAllCursor] = "size_all";
40 m_shapeToCursorName[Qt::BlankCursor] = "blank";
41 m_shapeToCursorName[Qt::SplitVCursor] = "split_v";
42 m_shapeToCursorName[Qt::SplitHCursor] = "split_h";
43 m_shapeToCursorName[Qt::PointingHandCursor] = "pointing_hand";
44 m_shapeToCursorName[Qt::ForbiddenCursor] = "forbidden";
45 m_shapeToCursorName[Qt::WhatsThisCursor] = "whats_this";
46 m_shapeToCursorName[Qt::BusyCursor] = "left_ptr_watch";
47 m_shapeToCursorName[Qt::OpenHandCursor] = "openhand";
48 m_shapeToCursorName[Qt::ClosedHandCursor] = "closedhand";
49 m_shapeToCursorName[Qt::DragCopyCursor] = "copy";
50 m_shapeToCursorName[Qt::DragMoveCursor] = "move";
51 m_shapeToCursorName[Qt::DragLinkCursor] = "link";
52
53 connect(Mir::instance(), &Mir::cursorNameChanged, this, &Cursor::setMirCursorName);
54}
55
56void Cursor::changeCursor(QCursor *windowCursor, QWindow * /*window*/)
57{
58 if (m_mousePointer.isNull()) {
59 return;
60 }
61
62 if (windowCursor) {
63 m_qtCursorName = m_shapeToCursorName.value(windowCursor->shape(), QString("left_ptr"));
64 } else {
65 m_qtCursorName.clear();
66 }
67
68 updateMousePointerCursorName();
69}
70
71void Cursor::setMirCursorName(const QString &mirCursorName)
72{
73 m_mirCursorName = mirCursorName;
74 updateMousePointerCursorName();
75}
76
77void Cursor::setMousePointer(MirMousePointerInterface *mousePointer)
78{
79 QMutexLocker locker(&m_mutex);
80
81 if (mousePointer && !m_mousePointer.isNull()) {
82 qFatal("QPA mirserver: Only one MousePointer per screen is allowed!");
83 }
84
85 m_mousePointer = mousePointer;
86 updateMousePointerCursorName();
87}
88
89bool Cursor::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons,
90 Qt::KeyboardModifiers modifiers)
91{
92 QMutexLocker locker(&m_mutex);
93
94 if (!m_mousePointer || !m_mousePointer->isVisible()) {
95 return false;
96 }
97
98 // Must not be called directly as we're most likely not in Qt's GUI (main) thread.
99 bool ok = QMetaObject::invokeMethod(m_mousePointer, "handleMouseEvent", Qt::AutoConnection,
100 Q_ARG(ulong, timestamp),
101 Q_ARG(QPointF, movement),
102 Q_ARG(Qt::MouseButton, buttons),
103 Q_ARG(Qt::KeyboardModifiers, modifiers));
104
105 if (!ok) {
106 qCWarning(QTMIR_MIR_INPUT) << "Failed to invoke MousePointer::handleMouseEvent";
107 }
108
109 return ok;
110}
111
112void Cursor::setPos(const QPoint &pos)
113{
114 if (!m_mousePointer) {
115 QPlatformCursor::setPos(pos);
116 return;
117 }
118
119 QPointF movement;
120 QPointF mouseScenePos = m_mousePointer->mapToItem(nullptr, QPointF(0, 0));
121
122 movement.setX(pos.x() - mouseScenePos.x());
123 movement.setY(pos.y() - mouseScenePos.y());
124
125 m_mousePointer->handleMouseEvent(0 /*timestamp*/, movement, Qt::NoButton, Qt::NoModifier);
126}
127
128QPoint Cursor::pos() const
129{
130 if (m_mousePointer) {
131 return m_mousePointer->mapToItem(nullptr, QPointF(0, 0)).toPoint();
132 } else {
133 return QPlatformCursor::pos();
134 }
135}
136
137void Cursor::updateMousePointerCursorName()
138{
139 if (!m_mousePointer) {
140 return;
141 }
142
143 if (m_mirCursorName.isEmpty()) {
144 if (m_qtCursorName.isEmpty()) {
145 m_mousePointer->setCursorName("left_ptr");
146 } else {
147 m_mousePointer->setCursorName(m_qtCursorName);
148 }
149 } else {
150 m_mousePointer->setCursorName(m_mirCursorName);
151 }
152}
0153
=== added file 'src/platforms/mirserver/cursor.h'
--- src/platforms/mirserver/cursor.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/cursor.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,66 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef QTMIR_CURSOR_H
19#define QTMIR_CURSOR_H
20
21#include <QMutex>
22#include <QPointer>
23
24// Unity API
25#include <unity/shell/application/MirPlatformCursor.h>
26
27namespace qtmir {
28
29class Cursor : public MirPlatformCursor
30{
31public:
32 Cursor();
33
34 // Called form Mir input thread
35 bool handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons,
36 Qt::KeyboardModifiers modifiers);
37
38 ////
39 // MirPlatformCursor
40
41 // Called from Qt's GUI thread
42 void setMousePointer(MirMousePointerInterface *mousePointer) override;
43
44 ////
45 // QPlatformCursor
46
47 void changeCursor(QCursor *windowCursor, QWindow *window) override;
48
49 void setPos(const QPoint &pos) override;
50 QPoint pos() const override;
51
52private Q_SLOTS:
53 void setMirCursorName(const QString &mirCursorName);
54
55private:
56 void updateMousePointerCursorName();
57 QMutex m_mutex;
58 QPointer<MirMousePointerInterface> m_mousePointer;
59 QMap<int,QString> m_shapeToCursorName;
60 QString m_qtCursorName;
61 QString m_mirCursorName;
62};
63
64} // namespace qtmir
65
66#endif // QTMIR_CURSOR_H
067
=== removed file 'src/platforms/mirserver/display.cpp'
--- src/platforms/mirserver/display.cpp 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/display.cpp 1970-01-01 00:00:00 +0000
@@ -1,44 +0,0 @@
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "display.h"
18
19#include "screen.h"
20#include "mirserver.h"
21
22#include <mir/graphics/display.h>
23#include <mir/graphics/display_configuration.h>
24
25namespace mg = mir::graphics;
26
27// TODO: Listen for display changes and update the list accordingly
28
29Display::Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig)
30{
31 displayConfig->for_each_output([this](mg::DisplayConfigurationOutput const& output) {
32 if (output.used) {
33 auto screen = new Screen(output);
34 m_screens.push_back(screen);
35 }
36 });
37}
38
39Display::~Display()
40{
41 for (auto screen : m_screens)
42 delete screen;
43 m_screens.clear();
44}
450
=== removed file 'src/platforms/mirserver/display.h'
--- src/platforms/mirserver/display.h 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/display.h 1970-01-01 00:00:00 +0000
@@ -1,37 +0,0 @@
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef DISPLAY_H
18#define DISPLAY_H
19
20#include <qpa/qplatformscreen.h>
21#include <memory>
22
23namespace mir { namespace graphics { class DisplayConfiguration; }}
24
25class Display
26{
27public:
28 Display(const std::shared_ptr<mir::graphics::DisplayConfiguration> &displayConfig);
29 virtual ~Display();
30
31 QList<QPlatformScreen *> screens() const { return m_screens; }
32
33private:
34 QList<QPlatformScreen *> m_screens;
35};
36
37#endif // DISPLAY_H
380
=== modified file 'src/platforms/mirserver/logging.h'
--- src/platforms/mirserver/logging.h 2014-10-01 18:42:26 +0000
+++ src/platforms/mirserver/logging.h 2015-09-09 18:37:39 +0000
@@ -25,5 +25,6 @@
25Q_DECLARE_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES)25Q_DECLARE_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES)
26Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_INPUT)26Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_INPUT)
27Q_DECLARE_LOGGING_CATEGORY(QTMIR_CLIPBOARD)27Q_DECLARE_LOGGING_CATEGORY(QTMIR_CLIPBOARD)
28Q_DECLARE_LOGGING_CATEGORY(QTMIR_SCREENS)
2829
29#endif // UBUNTU_APPLICATION_PLUGIN_LOGGING_H30#endif // UBUNTU_APPLICATION_PLUGIN_LOGGING_H
3031
=== modified file 'src/platforms/mirserver/miropenglcontext.cpp'
--- src/platforms/mirserver/miropenglcontext.cpp 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/miropenglcontext.cpp 2015-09-09 18:37:39 +0000
@@ -16,12 +16,14 @@
1616
17#include "miropenglcontext.h"17#include "miropenglcontext.h"
1818
19#include "displaywindow.h"19#include "offscreensurface.h"
20#include "mirglconfig.h"
20#include "mirserver.h"21#include "mirserver.h"
21#include "mirglconfig.h"22#include "screenwindow.h"
2223
23#include <QDebug>24#include <QDebug>
2425
26#include <QOpenGLFramebufferObject>
25#include <QSurfaceFormat>27#include <QSurfaceFormat>
26#include <QtPlatformSupport/private/qeglconvenience_p.h>28#include <QtPlatformSupport/private/qeglconvenience_p.h>
2729
@@ -38,10 +40,10 @@
38 : m_logger(new QOpenGLDebugLogger(this))40 : m_logger(new QOpenGLDebugLogger(this))
39#endif41#endif
40{42{
41 std::shared_ptr<mir::graphics::Display> display = server->the_display();43 m_display = server->the_display();
4244
43 // create a temporary GL context to fetch the EGL display and config, so Qt can determine the surface format45 // create a temporary GL context to fetch the EGL display and config, so Qt can determine the surface format
44 std::unique_ptr<mir::graphics::GLContext> mirContext = display->create_gl_context();46 std::unique_ptr<mir::graphics::GLContext> mirContext = m_display->create_gl_context();
45 mirContext->make_current();47 mirContext->make_current();
4648
47 EGLDisplay eglDisplay = eglGetCurrentDisplay();49 EGLDisplay eglDisplay = eglGetCurrentDisplay();
@@ -106,17 +108,30 @@
106108
107void MirOpenGLContext::swapBuffers(QPlatformSurface *surface)109void MirOpenGLContext::swapBuffers(QPlatformSurface *surface)
108{110{
109 // ultimately calls Mir's DisplayBuffer::post_update()111 if (surface->surface()->surfaceClass() == QSurface::Offscreen) {
110 DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface);112 // NOOP
111 displayBuffer->swapBuffers(); //blocks for vsync113 } else {
114 // ultimately calls Mir's DisplayBuffer::post_update()
115 ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface);
116 screenWindow->swapBuffers(); //blocks for vsync
117 }
112}118}
113119
114bool MirOpenGLContext::makeCurrent(QPlatformSurface *surface)120bool MirOpenGLContext::makeCurrent(QPlatformSurface *surface)
115{121{
122 if (surface->surface()->surfaceClass() == QSurface::Offscreen) {
123 auto offscreen = static_cast<OffscreenSurface *>(surface);
124 if (!offscreen->buffer()) {
125 auto buffer = new QOpenGLFramebufferObject(surface->surface()->size());
126 offscreen->setBuffer(buffer);
127 }
128 return offscreen->buffer()->bind();
129 }
130
116 // ultimately calls Mir's DisplayBuffer::make_current()131 // ultimately calls Mir's DisplayBuffer::make_current()
117 DisplayWindow *displayBuffer = static_cast<DisplayWindow*>(surface);132 ScreenWindow *screenWindow = static_cast<ScreenWindow*>(surface);
118 if (displayBuffer) {133 if (screenWindow) {
119 displayBuffer->makeCurrent();134 screenWindow->makeCurrent();
120135
121#ifndef QT_NO_DEBUG136#ifndef QT_NO_DEBUG
122 if (!m_logger->isLogging() && m_logger->initialize()) {137 if (!m_logger->isLogging() && m_logger->initialize()) {
@@ -133,7 +148,9 @@
133148
134void MirOpenGLContext::doneCurrent()149void MirOpenGLContext::doneCurrent()
135{150{
136 // could call Mir's DisplayBuffer::release_current(), but for what DisplayBuffer?151 // FIXME: create a temporary GL context just to release? Would be better to get existing one.
152 std::unique_ptr<mir::graphics::GLContext> mirContext = m_display->create_gl_context();
153 mirContext->release_current();
137}154}
138155
139QFunctionPointer MirOpenGLContext::getProcAddress(const QByteArray &procName)156QFunctionPointer MirOpenGLContext::getProcAddress(const QByteArray &procName)
140157
=== modified file 'src/platforms/mirserver/miropenglcontext.h'
--- src/platforms/mirserver/miropenglcontext.h 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/miropenglcontext.h 2015-09-09 18:37:39 +0000
@@ -23,6 +23,10 @@
23#include <QOpenGLDebugLogger>23#include <QOpenGLDebugLogger>
24#endif24#endif
2525
26#include <memory>
27
28namespace mir { namespace graphics { class Display; }}
29
26class MirServer;30class MirServer;
2731
28class MirOpenGLContext : public QObject, public QPlatformOpenGLContext32class MirOpenGLContext : public QObject, public QPlatformOpenGLContext
@@ -47,6 +51,7 @@
47#endif51#endif
4852
49private:53private:
54 std::shared_ptr<mir::graphics::Display> m_display;
50 QSurfaceFormat m_format;55 QSurfaceFormat m_format;
51#ifndef QT_NO_DEBUG56#ifndef QT_NO_DEBUG
52 QOpenGLDebugLogger *m_logger;57 QOpenGLDebugLogger *m_logger;
5358
=== modified file 'src/platforms/mirserver/mirserver.cpp'
--- src/platforms/mirserver/mirserver.cpp 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/mirserver.cpp 2015-09-09 18:37:39 +0000
@@ -23,15 +23,25 @@
23#include "mirglconfig.h"23#include "mirglconfig.h"
24#include "mirserverstatuslistener.h"24#include "mirserverstatuslistener.h"
25#include "promptsessionlistener.h"25#include "promptsessionlistener.h"
26#include "screencontroller.h"
26#include "sessionlistener.h"27#include "sessionlistener.h"
27#include "sessionauthorizer.h"28#include "sessionauthorizer.h"
28#include "qtcompositor.h"29#include "qtcompositor.h"
29#include "qteventfeeder.h"30#include "qteventfeeder.h"
31#include "tileddisplayconfigurationpolicy.h"
30#include "logging.h"32#include "logging.h"
3133
34// std
35#include <memory>
36
32// egl37// egl
38#define MESA_EGL_NO_X11_HEADERS
33#include <EGL/egl.h>39#include <EGL/egl.h>
3440
41// mir
42#include <mir/graphics/cursor.h>
43
44namespace mg = mir::graphics;
35namespace mo = mir::options;45namespace mo = mir::options;
36namespace msh = mir::shell;46namespace msh = mir::shell;
37namespace ms = mir::scene;47namespace ms = mir::scene;
@@ -45,8 +55,10 @@
4555
46Q_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES, "qtmir.mir")56Q_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES, "qtmir.mir")
4757
48MirServer::MirServer(int argc, char const* argv[], QObject* parent)58MirServer::MirServer(int argc, char const* argv[],
59 const QSharedPointer<ScreenController> &screenController, QObject* parent)
49 : QObject(parent)60 : QObject(parent)
61 , m_screenController(screenController)
50{62{
51 set_command_line_handler(&ignore_unparsed_arguments);63 set_command_line_handler(&ignore_unparsed_arguments);
52 set_command_line(argc, argv);64 set_command_line(argc, argv);
@@ -71,9 +83,9 @@
71 return std::make_shared<QtCompositor>();83 return std::make_shared<QtCompositor>();
72 });84 });
7385
74 override_the_input_dispatcher([]86 override_the_input_dispatcher([&screenController]
75 {87 {
76 return std::make_shared<QtEventFeeder>();88 return std::make_shared<QtEventFeeder>(screenController);
77 });89 });
7890
79 override_the_gl_config([]91 override_the_gl_config([]
@@ -92,17 +104,39 @@
92 return std::make_shared<MirWindowManager>(the_shell_display_layout());104 return std::make_shared<MirWindowManager>(the_shell_display_layout());
93 });105 });
94106
95 set_terminator([&](int)107 wrap_display_configuration_policy(
108 [](const std::shared_ptr<mg::DisplayConfigurationPolicy> &wrapped)
109 -> std::shared_ptr<mg::DisplayConfigurationPolicy>
110 {
111 return std::make_shared<TiledDisplayConfigurationPolicy>(wrapped);
112 });
113
114 set_terminator([](int)
96 {115 {
97 qDebug() << "Signal caught by Mir, stopping Mir server..";116 qDebug() << "Signal caught by Mir, stopping Mir server..";
98 QCoreApplication::quit();117 QCoreApplication::quit();
99 });118 });
100119
120 add_init_callback([this, &screenController] {
121 screenController->init(the_display(), the_compositor());
122 });
123
101 apply_settings();124 apply_settings();
102125
126 // We will draw our own cursor.
127 add_init_callback([this](){ the_cursor()->hide(); });
128
103 qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created";129 qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created";
104}130}
105131
132// Override default implementation to ensure we terminate the ScreenController first.
133// Code path followed when Qt tries to shutdown the server.
134void MirServer::stop()
135{
136 m_screenController->terminate();
137 mir::Server::stop();
138}
139
106140
107/************************************ Shell side ************************************/141/************************************ Shell side ************************************/
108142
109143
=== modified file 'src/platforms/mirserver/mirserver.h'
--- src/platforms/mirserver/mirserver.h 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/mirserver.h 2015-09-09 18:37:39 +0000
@@ -18,6 +18,7 @@
18#define MIRSERVER_H18#define MIRSERVER_H
1919
20#include <QObject>20#include <QObject>
21#include <QSharedPointer>
21#include <mir/server.h>22#include <mir/server.h>
2223
23class QtEventFeeder;24class QtEventFeeder;
@@ -25,6 +26,7 @@
25class SessionAuthorizer;26class SessionAuthorizer;
26using MirShell = mir::shell::Shell;27using MirShell = mir::shell::Shell;
27class PromptSessionListener;28class PromptSessionListener;
29class ScreenController;
2830
29// We use virtual inheritance of mir::Server to facilitate derived classes (e.g. testing)31// We use virtual inheritance of mir::Server to facilitate derived classes (e.g. testing)
30// calling initialization functions before MirServer is constructed.32// calling initialization functions before MirServer is constructed.
@@ -38,12 +40,12 @@
38 Q_PROPERTY(PromptSessionListener* promptSessionListener READ promptSessionListener CONSTANT)40 Q_PROPERTY(PromptSessionListener* promptSessionListener READ promptSessionListener CONSTANT)
3941
40public:42public:
41 MirServer(int argc, char const* argv[], QObject* parent = 0);43 MirServer(int argc, char const* argv[], const QSharedPointer<ScreenController> &, QObject* parent = 0);
42 ~MirServer() = default;44 ~MirServer() = default;
4345
44 /* mir specific */46 /* mir specific */
45 using mir::Server::run;47 using mir::Server::run;
46 using mir::Server::stop;48 using mir::Server::the_compositor;
47 using mir::Server::the_display;49 using mir::Server::the_display;
48 using mir::Server::the_gl_config;50 using mir::Server::the_gl_config;
49 using mir::Server::the_main_loop;51 using mir::Server::the_main_loop;
@@ -52,6 +54,8 @@
52 using mir::Server::the_session_authorizer;54 using mir::Server::the_session_authorizer;
53 using mir::Server::the_session_listener;55 using mir::Server::the_session_listener;
5456
57 void stop();
58
55 /* qt specific */59 /* qt specific */
56 // getters60 // getters
57 SessionAuthorizer *sessionAuthorizer();61 SessionAuthorizer *sessionAuthorizer();
@@ -60,7 +64,9 @@
60 MirShell *shell();64 MirShell *shell();
6165
62private:66private:
67 std::weak_ptr<MirShell> m_shell;
63 std::shared_ptr<QtEventFeeder> m_qtEventFeeder;68 std::shared_ptr<QtEventFeeder> m_qtEventFeeder;
69 const QSharedPointer<ScreenController> m_screenController;
64};70};
6571
66#endif // MIRSERVER_H72#endif // MIRSERVER_H
6773
=== modified file 'src/platforms/mirserver/mirserverintegration.cpp'
--- src/platforms/mirserver/mirserverintegration.cpp 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/mirserverintegration.cpp 2015-09-09 18:37:39 +0000
@@ -26,7 +26,8 @@
26#include <qpa/qplatforminputcontextfactory_p.h>26#include <qpa/qplatforminputcontextfactory_p.h>
27#include <qpa/qwindowsysteminterface.h>27#include <qpa/qwindowsysteminterface.h>
2828
29#include <QCoreApplication>29#include <QGuiApplication>
30#include <QStringList>
30#include <QOpenGLContext>31#include <QOpenGLContext>
31#include <QDebug>32#include <QDebug>
3233
@@ -36,13 +37,16 @@
3637
37// local38// local
38#include "clipboard.h"39#include "clipboard.h"
39#include "display.h"
40#include "displaywindow.h"
41#include "miropenglcontext.h"40#include "miropenglcontext.h"
42#include "nativeinterface.h"41#include "nativeinterface.h"
42#include "offscreensurface.h"
43#include "qmirserver.h"43#include "qmirserver.h"
44#include "screen.h"
45#include "screencontroller.h"
46#include "screenwindow.h"
44#include "services.h"47#include "services.h"
45#include "ubuntutheme.h"48#include "ubuntutheme.h"
49#include "logging.h"
4650
47namespace mg = mir::graphics;51namespace mg = mir::graphics;
48using qtmir::Clipboard;52using qtmir::Clipboard;
@@ -52,7 +56,6 @@
52 , m_fontDb(new QGenericUnixFontDatabase())56 , m_fontDb(new QGenericUnixFontDatabase())
53 , m_services(new Services)57 , m_services(new Services)
54 , m_mirServer(new QMirServer(QCoreApplication::arguments()))58 , m_mirServer(new QMirServer(QCoreApplication::arguments()))
55 , m_display(nullptr)
56 , m_nativeInterface(nullptr)59 , m_nativeInterface(nullptr)
57 , m_clipboard(new Clipboard)60 , m_clipboard(new Clipboard)
58{61{
@@ -72,12 +75,14 @@
72 QCoreApplication::instance(), &QCoreApplication::quit);75 QCoreApplication::instance(), &QCoreApplication::quit);
7376
74 m_inputContext = QPlatformInputContextFactory::create();77 m_inputContext = QPlatformInputContextFactory::create();
78
79 // Default Qt behaviour doesn't match a shell's intentions, so customize:
80 qGuiApp->setQuitOnLastWindowClosed(false);
75}81}
7682
77MirServerIntegration::~MirServerIntegration()83MirServerIntegration::~MirServerIntegration()
78{84{
79 delete m_nativeInterface;85 delete m_nativeInterface;
80 delete m_display;
81}86}
8287
83bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const88bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -87,7 +92,7 @@
87 case OpenGL: return true;92 case OpenGL: return true;
88 case ThreadedOpenGL: return true;93 case ThreadedOpenGL: return true;
89 case BufferQueueingOpenGL: return true;94 case BufferQueueingOpenGL: return true;
90 case MultipleWindows: return false; // multi-monitor support95 case MultipleWindows: return true; // multi-monitor support
91 case WindowManagement: return false; // platform has no WM, as this implements the WM!96 case WindowManagement: return false; // platform has no WM, as this implements the WM!
92 case NonFullScreenWindows: return false;97 case NonFullScreenWindows: return false;
93 default: return QPlatformIntegration::hasCapability(cap);98 default: return QPlatformIntegration::hasCapability(cap);
@@ -98,44 +103,38 @@
98{103{
99 QWindowSystemInterface::flushWindowSystemEvents();104 QWindowSystemInterface::flushWindowSystemEvents();
100105
101 DisplayWindow* displayWindow = nullptr;106 // FIXME: QWindow can be created specifying a destination QScreen. For now we
102107 // will ignore it and just associate any unused Screen, if available.
103 auto const mirServer = m_mirServer->mirServer().lock();108 auto screens = m_mirServer->screenController().lock();
104 mg::DisplayBuffer* first_buffer{nullptr};109 if (!screens) {
105 mg::DisplaySyncGroup* first_group{nullptr};110 qCritical("Screens are not initialized, unable to create a new QWindow/ScreenWindow");
106 if (mirServer) {111 return nullptr;
107 mirServer->the_display()->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) {112 }
108 if (!first_group) {113 Screen *screen = screens->getUnusedScreen();
109 first_group = &group;114 if (!screen) {
110 }115 qCritical("No available Screens to create a new QWindow/ScreenWindow for");
111 group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) {116 return nullptr;
112 if (!first_buffer) {117 }
113 first_buffer = &buffer;118 QScreen *qscreen = screen->screen();
114 }119 window->setScreen(qscreen);
115 });120
116 });121 auto platformWindow = new ScreenWindow(window);
117 }122 if (screens->compositing()) {
118123 platformWindow->setExposed(true);
119 // FIXME(gerry) this will go very bad for >1 display buffer124 }
120 if (first_group && first_buffer)125
121 displayWindow = new DisplayWindow(window, first_group, first_buffer);126 qCDebug(QTMIR_SCREENS) << "New" << window << "with geom" << window->geometry()
122127 << "is backed by a" << screen << "with geometry" << screen->geometry();
123 if (!displayWindow)128 return platformWindow;
124 return nullptr;
125
126 //displayWindow->requestActivateWindow();
127 return displayWindow;
128}129}
129130
130QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow *window) const131QPlatformBackingStore *MirServerIntegration::createPlatformBackingStore(QWindow */*window*/) const
131{132{
132 qDebug() << "createPlatformBackingStore" << window;
133 return nullptr;133 return nullptr;
134}134}
135135
136QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const136QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
137{137{
138 qDebug() << "createPlatformOpenGLContext" << context;
139 return new MirOpenGLContext(m_mirServer->mirServer(), context->format());138 return new MirOpenGLContext(m_mirServer->mirServer(), context->format());
140}139}
141140
@@ -151,12 +150,18 @@
151 exit(2);150 exit(2);
152 }151 }
153152
154 m_display = new Display(m_mirServer->mirServer().data()->the_display()->configuration());153 auto screens = m_mirServer->screenController().lock();
154 if (!screens) {
155 qFatal("ScreenController not initialized");
156 }
157 QObject::connect(screens.data(), &ScreenController::screenAdded,
158 [this](Screen *screen) { this->screenAdded(screen); });
159 Q_FOREACH(auto screen, screens->screens()) {
160 screenAdded(screen);
161 }
162
155 m_nativeInterface = new NativeInterface(m_mirServer->mirServer());163 m_nativeInterface = new NativeInterface(m_mirServer->mirServer());
156164
157 for (QPlatformScreen *screen : m_display->screens())
158 screenAdded(screen);
159
160 m_clipboard->setupDBusService();165 m_clipboard->setupDBusService();
161}166}
162167
@@ -195,3 +200,9 @@
195{200{
196 return m_clipboard.data();201 return m_clipboard.data();
197}202}
203
204QPlatformOffscreenSurface *MirServerIntegration::createPlatformOffscreenSurface(
205 QOffscreenSurface *surface) const
206{
207 return new OffscreenSurface(surface);
208}
198209
=== modified file 'src/platforms/mirserver/mirserverintegration.h'
--- src/platforms/mirserver/mirserverintegration.h 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/mirserverintegration.h 2015-09-09 18:37:39 +0000
@@ -19,13 +19,9 @@
1919
20// qt20// qt
21#include <qpa/qplatformintegration.h>21#include <qpa/qplatformintegration.h>
2222#include <QScopedPointer>
23// local23
24#include "mirserver.h"
25
26class Display;
27class NativeInterface;24class NativeInterface;
28class MirServer;
29class QMirServer;25class QMirServer;
3026
31namespace qtmir {27namespace qtmir {
@@ -60,6 +56,8 @@
6056
61 QPlatformNativeInterface *nativeInterface() const override;57 QPlatformNativeInterface *nativeInterface() const override;
6258
59 QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
60
63private:61private:
64 QScopedPointer<QPlatformAccessibility> m_accessibility;62 QScopedPointer<QPlatformAccessibility> m_accessibility;
65 QScopedPointer<QPlatformFontDatabase> m_fontDb;63 QScopedPointer<QPlatformFontDatabase> m_fontDb;
@@ -67,7 +65,6 @@
6765
68 QScopedPointer<QMirServer> m_mirServer;66 QScopedPointer<QMirServer> m_mirServer;
6967
70 Display *m_display;
71 NativeInterface *m_nativeInterface;68 NativeInterface *m_nativeInterface;
72 QPlatformInputContext* m_inputContext;69 QPlatformInputContext* m_inputContext;
73 QScopedPointer<qtmir::Clipboard> m_clipboard;70 QScopedPointer<qtmir::Clipboard> m_clipboard;
7471
=== added file 'src/platforms/mirserver/mirsingleton.cpp'
--- src/platforms/mirserver/mirsingleton.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/mirsingleton.cpp 2015-09-09 18:37:39 +0000
@@ -0,0 +1,33 @@
1#include "mirsingleton.h"
2
3qtmir::Mir *qtmir::Mir::m_instance = nullptr;
4
5qtmir::Mir::Mir()
6{
7}
8
9qtmir::Mir::~Mir()
10{
11 m_instance = nullptr;
12}
13
14qtmir::Mir *qtmir::Mir::instance()
15{
16 if (!m_instance) {
17 m_instance = new qtmir::Mir;
18 }
19 return m_instance;
20}
21
22void qtmir::Mir::setCursorName(const QString &cursorName)
23{
24 if (m_cursorName != cursorName) {
25 m_cursorName = cursorName;
26 Q_EMIT cursorNameChanged(m_cursorName);
27 }
28}
29
30QString qtmir::Mir::cursorName() const
31{
32 return m_cursorName;
33}
034
=== added file 'src/platforms/mirserver/mirsingleton.h'
--- src/platforms/mirserver/mirsingleton.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/mirsingleton.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef QTMIR_MIRSINGLETON_H
18#define QTMIR_MIRSINGLETON_H
19
20// unity-api
21#include <unity/shell/application/Mir.h>
22
23namespace qtmir {
24
25class Mir : public ::Mir
26{
27 Q_OBJECT
28public:
29 virtual ~Mir();
30
31 static Mir *instance();
32
33 void setCursorName(const QString &cursorName) override;
34 QString cursorName() const override;
35
36private:
37 Mir();
38
39 QString m_cursorName;
40 static qtmir::Mir *m_instance;
41};
42
43} // namespace qtmir
44
45#endif // QTMIR_MIRSINGLETON_H
046
=== added file 'src/platforms/mirserver/offscreensurface.cpp'
--- src/platforms/mirserver/offscreensurface.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/offscreensurface.cpp 2015-09-09 18:37:39 +0000
@@ -0,0 +1,61 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "offscreensurface.h"
18
19#include "mirserver.h"
20
21// Mir
22#include <mir/graphics/display.h>
23#include <mir/graphics/gl_context.h>
24
25//Qt
26#include <QOffscreenSurface>
27#include <QOpenGLFramebufferObject>
28#include <QSurfaceFormat>
29#include <QtPlatformSupport/private/qeglconvenience_p.h>
30
31namespace mg = mir::graphics;
32
33OffscreenSurface::OffscreenSurface(QOffscreenSurface *offscreenSurface)
34 : QPlatformOffscreenSurface(offscreenSurface)
35 , m_buffer(nullptr)
36 , m_format(offscreenSurface->requestedFormat())
37{
38}
39
40QSurfaceFormat OffscreenSurface::format() const
41{
42 return m_format;
43}
44
45bool OffscreenSurface::isValid() const
46{
47 if (m_buffer) {
48 return m_buffer->isValid();
49 }
50 return false;
51}
52
53QOpenGLFramebufferObject* OffscreenSurface::buffer() const
54{
55 return m_buffer;
56}
57
58void OffscreenSurface::setBuffer(QOpenGLFramebufferObject *buffer)
59{
60 m_buffer = buffer;
61}
062
=== added file 'src/platforms/mirserver/offscreensurface.h'
--- src/platforms/mirserver/offscreensurface.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/offscreensurface.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef OFFSCREENSURFACE_H
18#define OFFSCREENSURFACE_H
19
20#include <qpa/qplatformoffscreensurface.h>
21#include <QSurfaceFormat>
22#include <QSharedPointer>
23
24class MirServer;
25class QOpenGLFramebufferObject;
26
27class OffscreenSurface : public QPlatformOffscreenSurface
28{
29public:
30 OffscreenSurface(QOffscreenSurface *offscreenSurface);
31
32 QSurfaceFormat format() const override;
33 bool isValid() const override;
34
35 QOpenGLFramebufferObject* buffer() const;
36 void setBuffer(QOpenGLFramebufferObject *buffer);
37
38private:
39 QOpenGLFramebufferObject *m_buffer;
40 QSurfaceFormat m_format;
41};
42
43#endif // OFFSCREENSURFACE_H
044
=== modified file 'src/platforms/mirserver/qmirserver.cpp'
--- src/platforms/mirserver/qmirserver.cpp 2015-05-19 15:36:17 +0000
+++ src/platforms/mirserver/qmirserver.cpp 2015-09-09 18:37:39 +0000
@@ -23,7 +23,8 @@
23#include "mirserver.h"23#include "mirserver.h"
24#include "qmirserver.h"24#include "qmirserver.h"
25#include "qmirserver_p.h"25#include "qmirserver_p.h"
2626#include "screencontroller.h"
27#include "screen.h"
2728
28QMirServer::QMirServer(const QStringList &arguments, QObject *parent)29QMirServer::QMirServer(const QStringList &arguments, QObject *parent)
29 : QObject(parent)30 : QObject(parent)
@@ -40,7 +41,9 @@
40 }41 }
41 argv[argc] = '\0';42 argv[argc] = '\0';
4243
43 d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv)));44 d->screenController = QSharedPointer<ScreenController>(new ScreenController());
45
46 d->server = QSharedPointer<MirServer>(new MirServer(argc, const_cast<const char**>(argv), d->screenController));
4447
45 d->serverThread = new MirServerThread(d->server);48 d->serverThread = new MirServerThread(d->server);
4649
@@ -63,6 +66,7 @@
63 qCritical() << "ERROR: QMirServer - Mir failed to start";66 qCritical() << "ERROR: QMirServer - Mir failed to start";
64 return false;67 return false;
65 }68 }
69 d->screenController->update();
6670
67 Q_EMIT started();71 Q_EMIT started();
68 return true;72 return true;
@@ -93,3 +97,9 @@
93 Q_D(const QMirServer);97 Q_D(const QMirServer);
94 return d->server.toWeakRef();98 return d->server.toWeakRef();
95}99}
100
101QWeakPointer<ScreenController> QMirServer::screenController() const
102{
103 Q_D(const QMirServer);
104 return d->screenController;
105}
96106
=== modified file 'src/platforms/mirserver/qmirserver.h'
--- src/platforms/mirserver/qmirserver.h 2015-05-18 20:39:09 +0000
+++ src/platforms/mirserver/qmirserver.h 2015-09-09 18:37:39 +0000
@@ -23,6 +23,7 @@
2323
24class QMirServerPrivate;24class QMirServerPrivate;
25class MirServer;25class MirServer;
26class ScreenController;
2627
27class QMirServer: public QObject28class QMirServer: public QObject
28{29{
@@ -38,6 +39,8 @@
3839
39 QWeakPointer<MirServer> mirServer() const;40 QWeakPointer<MirServer> mirServer() const;
4041
42 QWeakPointer<ScreenController> screenController() const;
43
41Q_SIGNALS:44Q_SIGNALS:
42 void started();45 void started();
43 void stopped();46 void stopped();
4447
=== modified file 'src/platforms/mirserver/qmirserver_p.h'
--- src/platforms/mirserver/qmirserver_p.h 2015-05-18 18:30:33 +0000
+++ src/platforms/mirserver/qmirserver_p.h 2015-09-09 18:37:39 +0000
@@ -27,6 +27,7 @@
2727
28// local28// local
29#include "mirserver.h"29#include "mirserver.h"
30#include "screencontroller.h"
3031
31class QMirServer;32class QMirServer;
32class MirServerThread;33class MirServerThread;
@@ -34,6 +35,7 @@
34struct QMirServerPrivate35struct QMirServerPrivate
35{36{
36 QSharedPointer<MirServer> server;37 QSharedPointer<MirServer> server;
38 QSharedPointer<ScreenController> screenController;
37 MirServerThread *serverThread;39 MirServerThread *serverThread;
38};40};
3941
4042
=== modified file 'src/platforms/mirserver/qtcompositor.cpp'
--- src/platforms/mirserver/qtcompositor.cpp 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/qtcompositor.cpp 2015-09-09 18:37:39 +0000
@@ -15,44 +15,19 @@
15 */15 */
1616
17#include "qtcompositor.h"17#include "qtcompositor.h"
18#include "displaywindow.h"18#include "logging.h"
1919
20#include <QGuiApplication>20// Lives in a Mir thread
21#include <QWindow>
22
23#include <QDebug>
24
25QtCompositor::QtCompositor()
26{
27
28}
29
30void QtCompositor::start()21void QtCompositor::start()
31{22{
32 // (Re)Start Qt's render thread by setting all its windows to exposed23 qCDebug(QTMIR_SCREENS) << "QtCompositor::start";
33 setAllWindowsExposed(true);24
25 Q_EMIT starting(); // blocks
34}26}
3527
36void QtCompositor::stop()28void QtCompositor::stop()
37{29{
38 // Stop Qt's render threads by setting all its windows it obscured30 qCDebug(QTMIR_SCREENS) << "QtCompositor::stop";
39 setAllWindowsExposed(false);31
40}32 Q_EMIT stopping(); // blocks
41
42void QtCompositor::setAllWindowsExposed(const bool exposed)
43{
44 qDebug() << "QtCompositor::setAllWindowsExposed" << exposed;
45 QList<QWindow *> windowList = QGuiApplication::allWindows();
46
47 // manipulate Qt object's indirectly via posted events as we're not in Qt's GUI thread
48 auto iterator = windowList.constBegin();
49 while (iterator != windowList.constEnd()) {
50 QWindow *window = *iterator;
51 DisplayWindow *displayWindow = static_cast<DisplayWindow*>(window->handle());
52 if (displayWindow) {
53 QCoreApplication::postEvent(displayWindow,
54 new QEvent( (exposed) ? QEvent::Show : QEvent::Hide));
55 }
56 iterator++;
57 }
58}33}
5934
=== modified file 'src/platforms/mirserver/qtcompositor.h'
--- src/platforms/mirserver/qtcompositor.h 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/qtcompositor.h 2015-09-09 18:37:39 +0000
@@ -17,18 +17,26 @@
17#ifndef QTCOMPOSITOR_H17#ifndef QTCOMPOSITOR_H
18#define QTCOMPOSITOR_H18#define QTCOMPOSITOR_H
1919
20#include "mir/compositor/compositor.h"20#include <mir/compositor/compositor.h>
2121
22class QtCompositor : public mir::compositor::Compositor22// Qt
23#include <QObject>
24
25class QtCompositor : public QObject, public mir::compositor::Compositor
23{26{
27 Q_OBJECT
24public:28public:
25 QtCompositor();29 QtCompositor() = default;
30 virtual ~QtCompositor() noexcept = default;
2631
27 void start();32 void start();
28 void stop();33 void stop();
2934
35Q_SIGNALS:
36 void starting();
37 void stopping();
38
30private:39private:
31 void setAllWindowsExposed(const bool exposed);
32};40};
3341
34#endif // QTCOMPOSITOR_H42#endif // QTCOMPOSITOR_H
3543
=== modified file 'src/platforms/mirserver/qteventfeeder.cpp'
--- src/platforms/mirserver/qteventfeeder.cpp 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/qteventfeeder.cpp 2015-09-09 18:37:39 +0000
@@ -15,7 +15,10 @@
15 */15 */
1616
17#include "qteventfeeder.h"17#include "qteventfeeder.h"
18#include "cursor.h"
18#include "logging.h"19#include "logging.h"
20#include "screencontroller.h"
21#include "screen.h"
1922
20#include <qpa/qplatforminputcontext.h>23#include <qpa/qplatforminputcontext.h>
21#include <qpa/qplatformintegration.h>24#include <qpa/qplatformintegration.h>
@@ -365,20 +368,29 @@
365368
366namespace {369namespace {
367370
368class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {371class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface
369372{
370 bool hasTargetWindow() override373public:
371 {374 QtWindowSystem()
372 if (mTopLevelWindow.isNull() && !QGuiApplication::topLevelWindows().isEmpty()) {375 {
373 mTopLevelWindow = QGuiApplication::topLevelWindows().first();376 // because we're using QMetaObject::invoke with arguments of those types
374 }377 qRegisterMetaType<Qt::KeyboardModifiers>("Qt::KeyboardModifiers");
375 return !mTopLevelWindow.isNull();378 qRegisterMetaType<Qt::MouseButton>("Qt::MouseButton");
376 }379 }
377380
378 QRect targetWindowGeometry() override381 void setScreenController(const QSharedPointer<ScreenController> &sc) override
379 {382 {
380 Q_ASSERT(!mTopLevelWindow.isNull());383 m_screenController = sc;
381 return mTopLevelWindow->geometry();384 }
385
386 virtual QWindow* focusedWindow() override
387 {
388 return QGuiApplication::focusWindow();
389 }
390
391 QWindow* getWindowForTouchPoint(const QPoint &point) override //FIXME: not efficient, not updating focused window
392 {
393 return m_screenController->getWindowForPoint(point);
382 }394 }
383395
384 void registerTouchDevice(QTouchDevice *device) override396 void registerTouchDevice(QTouchDevice *device) override
@@ -386,47 +398,56 @@
386 QWindowSystemInterface::registerTouchDevice(device);398 QWindowSystemInterface::registerTouchDevice(device);
387 }399 }
388400
389 void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key,401 void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key,
390 Qt::KeyboardModifiers modifiers,402 Qt::KeyboardModifiers modifiers,
391 quint32 nativeScanCode, quint32 nativeVirtualKey,403 quint32 nativeScanCode, quint32 nativeVirtualKey,
392 quint32 nativeModifiers,404 quint32 nativeModifiers,
393 const QString& text, bool autorep, ushort count) override405 const QString& text, bool autorep, ushort count) override
394 {406 {
395 Q_ASSERT(!mTopLevelWindow.isNull());407 QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, type, key, modifiers,
396 QWindowSystemInterface::handleExtendedKeyEvent(mTopLevelWindow.data(), timestamp, type, key, modifiers,
397 nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);408 nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
398 }409 }
399410
400 void handleTouchEvent(ulong timestamp, QTouchDevice *device,411 void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device,
401 const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override412 const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override
402 {413 {
403 Q_ASSERT(!mTopLevelWindow.isNull());414 QWindowSystemInterface::handleTouchEvent(window, timestamp, device, points, mods);
404 QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods);
405 }415 }
406416
407 void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) override417 void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons,
418 Qt::KeyboardModifiers modifiers) override
408 {419 {
409 Q_ASSERT(!mTopLevelWindow.isNull());420 // Send to the first screen that handles the mouse event
410 QWindowSystemInterface::handleMouseEvent(mTopLevelWindow.data(), timestamp, point, point, // local and global point are the same421 // TODO: Have a mechanism to tell which screen currently has the logical mouse pointer
411 buttons, modifiers);422 // (because they all might have their own separate graphical mouse pointer item)
423 // This will probably come once we implement the feature of having the mouse pointer
424 // crossing adjacent screens.
425
426 QList<Screen*> screens = m_screenController->screens();
427 bool eventHandled = false;
428 int i = 0;
429 while (i < screens.count() && !eventHandled) {
430 auto platformCursor = static_cast<qtmir::Cursor*>(screens[i]->cursor());
431 eventHandled = platformCursor->handleMouseEvent(timestamp, movement, buttons, modifiers);
432 ++i;
433 }
412 }434 }
413435
414
415private:436private:
416 QPointer<QWindow> mTopLevelWindow;437 QSharedPointer<ScreenController> m_screenController;
417};438};
418439
419} // anonymous namespace440} // anonymous namespace
420441
421442QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController)
422QtEventFeeder::QtEventFeeder(QtEventFeeder::QtWindowSystemInterface *windowSystem)443 : QtEventFeeder(screenController, new QtWindowSystem)
423{444{
424 if (windowSystem) {445}
425 mQtWindowSystem = windowSystem;446
426 } else {447QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreenController> &screenController,
427 mQtWindowSystem = new QtWindowSystem;448 QtEventFeeder::QtWindowSystemInterface *windowSystem)
428 }449 : mQtWindowSystem(windowSystem)
429450{
430 // Initialize touch device. Hardcoded just like in qtubuntu451 // Initialize touch device. Hardcoded just like in qtubuntu
431 // TODO: Create them from info gathered from Mir and store things like device id and source452 // TODO: Create them from info gathered from Mir and store things like device id and source
432 // in a QTouchDevice-derived class created by us. So that we can properly assemble back453 // in a QTouchDevice-derived class created by us. So that we can properly assemble back
@@ -436,6 +457,7 @@
436 mTouchDevice->setCapabilities(457 mTouchDevice->setCapabilities(
437 QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure |458 QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure |
438 QTouchDevice::NormalizedPosition);459 QTouchDevice::NormalizedPosition);
460 mQtWindowSystem->setScreenController(screenController);
439 mQtWindowSystem->registerTouchDevice(mTouchDevice);461 mQtWindowSystem->registerTouchDevice(mTouchDevice);
440}462}
441463
@@ -449,6 +471,7 @@
449 auto type = mir_event_get_type(&event);471 auto type = mir_event_get_type(&event);
450 if (type != mir_event_type_input)472 if (type != mir_event_type_input)
451 return false;473 return false;
474
452 auto iev = mir_event_get_input_event(&event);475 auto iev = mir_event_get_input_event(&event);
453476
454 switch (mir_input_event_get_type(iev)) {477 switch (mir_input_event_get_type(iev)) {
@@ -508,27 +531,20 @@
508531
509void QtEventFeeder::dispatchPointer(MirInputEvent const* ev)532void QtEventFeeder::dispatchPointer(MirInputEvent const* ev)
510{533{
511 if (!mQtWindowSystem->hasTargetWindow())
512 return;
513
514 auto timestamp = mir_input_event_get_event_time(ev) / 1000000;534 auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
515535
516 auto pev = mir_input_event_get_pointer_event(ev);536 auto pev = mir_input_event_get_pointer_event(ev);
517 auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev));537 auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev));
518 auto buttons = getQtMouseButtonsfromMirPointerEvent(pev);538 auto buttons = getQtMouseButtonsfromMirPointerEvent(pev);
519539
520 auto local_point = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),540 auto movement = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x),
521 mir_pointer_event_axis_value(pev, mir_pointer_axis_y));541 mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y));
522542
523 mQtWindowSystem->handleMouseEvent(timestamp, local_point,543 mQtWindowSystem->handleMouseEvent(timestamp, movement, buttons, modifiers);
524 buttons, modifiers);
525}544}
526545
527void QtEventFeeder::dispatchKey(MirInputEvent const* event)546void QtEventFeeder::dispatchKey(MirInputEvent const* event)
528{547{
529 if (!mQtWindowSystem->hasTargetWindow())
530 return;
531
532 ulong timestamp = mir_input_event_get_event_time(event) / 1000000;548 ulong timestamp = mir_input_event_get_event_time(event) / 1000000;
533549
534 auto kev = mir_input_event_get_keyboard_event(event);550 auto kev = mir_input_event_get_keyboard_event(event);
@@ -575,7 +591,8 @@
575 }591 }
576 }592 }
577593
578 mQtWindowSystem->handleExtendedKeyEvent(timestamp, keyType, keyCode, modifiers,594 mQtWindowSystem->handleExtendedKeyEvent(mQtWindowSystem->focusedWindow(),
595 timestamp, keyType, keyCode, modifiers,
579 mir_keyboard_event_scan_code(kev),596 mir_keyboard_event_scan_code(kev),
580 mir_keyboard_event_key_code(kev),597 mir_keyboard_event_key_code(kev),
581 mir_keyboard_event_modifiers(kev), text, is_auto_rep);598 mir_keyboard_event_modifiers(kev), text, is_auto_rep);
@@ -583,59 +600,69 @@
583600
584void QtEventFeeder::dispatchTouch(MirInputEvent const* event)601void QtEventFeeder::dispatchTouch(MirInputEvent const* event)
585{602{
586 if (!mQtWindowSystem->hasTargetWindow())
587 return;
588
589 auto tev = mir_input_event_get_touch_event(event);603 auto tev = mir_input_event_get_touch_event(event);
590 qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev));604 qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev));
591605
592 // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That606 // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That
593 // needs to be fixed as soon as the compat input lib adds query support.607 // needs to be fixed as soon as the compat input lib adds query support.
594 const float kMaxPressure = 1.28;608 const float kMaxPressure = 1.28;
595 const QRect kWindowGeometry = mQtWindowSystem->targetWindowGeometry();609 const int kPointerCount = mir_touch_event_point_count(tev);
596 QList<QWindowSystemInterface::TouchPoint> touchPoints;610 QList<QWindowSystemInterface::TouchPoint> touchPoints;
597611 QWindow *window = nullptr;
598 // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left612
599 // as Qt::TouchPointMoved613 if (kPointerCount > 0) {
600 const int kPointerCount = mir_touch_event_point_count(tev);614 window = mQtWindowSystem->getWindowForTouchPoint(
601 for (int i = 0; i < kPointerCount; ++i) {615 QPoint(mir_touch_event_axis_value(tev, 0, mir_touch_axis_x),
602 QWindowSystemInterface::TouchPoint touchPoint;616 mir_touch_event_axis_value(tev, 0, mir_touch_axis_y)));
603617
604 const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x);618 if (!window) {
605 const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y);619 qCDebug(QTMIR_MIR_INPUT) << "REJECTING INPUT EVENT, no matching window";
606 const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major);620 return;
607 const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor);621 }
608 const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);622
609 touchPoint.id = mir_touch_event_id(tev, i);623 const QRect kWindowGeometry = window->geometry();
610624
611 touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());625 // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left
612 touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH);626 // as Qt::TouchPointMoved
613 touchPoint.pressure = kP / kMaxPressure;627 for (int i = 0; i < kPointerCount; ++i) {
614 switch (mir_touch_event_action(tev, i))628 QWindowSystemInterface::TouchPoint touchPoint;
615 {629
616 case mir_touch_action_up:630 const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x);
617 touchPoint.state = Qt::TouchPointReleased;631 const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y);
618 break;632 const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major);
619 case mir_touch_action_down:633 const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor);
620 touchPoint.state = Qt::TouchPointPressed;634 const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);
621 break;635 touchPoint.id = mir_touch_event_id(tev, i);
622 case mir_touch_action_change:636
623 touchPoint.state = Qt::TouchPointMoved;637 touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());
624 break;638 touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH);
625 default:639 touchPoint.pressure = kP / kMaxPressure;
626 break;640 switch (mir_touch_event_action(tev, i))
627 }641 {
628642 case mir_touch_action_up:
629 touchPoints.append(touchPoint);643 touchPoint.state = Qt::TouchPointReleased;
644 break;
645 case mir_touch_action_down:
646 touchPoint.state = Qt::TouchPointPressed;
647 break;
648 case mir_touch_action_change:
649 touchPoint.state = Qt::TouchPointMoved;
650 break;
651 default:
652 break;
653 }
654
655 touchPoints.append(touchPoint);
656 }
630 }657 }
631658
632 // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding659 // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding
633 // any insanity.660 // any insanity.
634 validateTouches(mir_input_event_get_event_time(event) / 1000000, touchPoints);661 validateTouches(window, mir_input_event_get_event_time(event) / 1000000, touchPoints);
635662
636 // Touch event propagation.663 // Touch event propagation.
637 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));664 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));
638 mQtWindowSystem->handleTouchEvent(665 mQtWindowSystem->handleTouchEvent(window,
639 //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable666 //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable
640 mir_input_event_get_event_time(event) / 1000000,667 mir_input_event_get_event_time(event) / 1000000,
641 mTouchDevice,668 mTouchDevice,
@@ -652,7 +679,7 @@
652 // not used679 // not used
653}680}
654681
655void QtEventFeeder::validateTouches(ulong timestamp,682void QtEventFeeder::validateTouches(QWindow *window, ulong timestamp,
656 QList<QWindowSystemInterface::TouchPoint> &touchPoints)683 QList<QWindowSystemInterface::TouchPoint> &touchPoints)
657{684{
658 QSet<int> updatedTouches;685 QSet<int> updatedTouches;
@@ -676,7 +703,7 @@
676 if (!updatedTouches.contains(it.key())) {703 if (!updatedTouches.contains(it.key())) {
677 qCWarning(QTMIR_MIR_INPUT)704 qCWarning(QTMIR_MIR_INPUT)
678 << "There's a touch (id =" << it.key() << ") missing. Releasing it.";705 << "There's a touch (id =" << it.key() << ") missing. Releasing it.";
679 sendActiveTouchRelease(timestamp, it.key());706 sendActiveTouchRelease(window, timestamp, it.key());
680 it = mActiveTouches.erase(it);707 it = mActiveTouches.erase(it);
681 } else {708 } else {
682 ++it;709 ++it;
@@ -694,7 +721,7 @@
694 }721 }
695}722}
696723
697void QtEventFeeder::sendActiveTouchRelease(ulong timestamp, int id)724void QtEventFeeder::sendActiveTouchRelease(QWindow *window, ulong timestamp, int id)
698{725{
699 QList<QWindowSystemInterface::TouchPoint> touchPoints = mActiveTouches.values();726 QList<QWindowSystemInterface::TouchPoint> touchPoints = mActiveTouches.values();
700727
@@ -708,7 +735,7 @@
708 }735 }
709736
710 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));737 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));
711 mQtWindowSystem->handleTouchEvent(timestamp, mTouchDevice, touchPoints);738 mQtWindowSystem->handleTouchEvent(window, timestamp, mTouchDevice, touchPoints);
712}739}
713740
714bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint)741bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint)
715742
=== modified file 'src/platforms/mirserver/qteventfeeder.h'
--- src/platforms/mirserver/qteventfeeder.h 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/qteventfeeder.h 2015-09-09 18:37:39 +0000
@@ -23,6 +23,7 @@
23#include <qpa/qwindowsysteminterface.h>23#include <qpa/qwindowsysteminterface.h>
2424
25class QTouchDevice;25class QTouchDevice;
26class ScreenController;
2627
27/*28/*
28 Fills Qt's event loop with input events from Mir29 Fills Qt's event loop with input events from Mir
@@ -33,26 +34,29 @@
33 // Interface between QtEventFeeder and the actual QWindowSystemInterface functions34 // Interface between QtEventFeeder and the actual QWindowSystemInterface functions
34 // and other related Qt methods and objects to enable replacing them with mocks in35 // and other related Qt methods and objects to enable replacing them with mocks in
35 // pure unit tests.36 // pure unit tests.
36 // TODO - Make it work with multimonitor scenarios
37 class QtWindowSystemInterface {37 class QtWindowSystemInterface {
38 public:38 public:
39 virtual ~QtWindowSystemInterface() {}39 virtual ~QtWindowSystemInterface() {}
40 virtual bool hasTargetWindow() = 0;40 virtual void setScreenController(const QSharedPointer<ScreenController> &sc) = 0;
41 virtual QRect targetWindowGeometry() = 0;41 virtual QWindow* getWindowForTouchPoint(const QPoint &point) = 0;
42 virtual QWindow* focusedWindow() = 0;
42 virtual void registerTouchDevice(QTouchDevice *device) = 0;43 virtual void registerTouchDevice(QTouchDevice *device) = 0;
43 virtual void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key,44 virtual void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key,
44 Qt::KeyboardModifiers modifiers,45 Qt::KeyboardModifiers modifiers,
45 quint32 nativeScanCode, quint32 nativeVirtualKey,46 quint32 nativeScanCode, quint32 nativeVirtualKey,
46 quint32 nativeModifiers,47 quint32 nativeModifiers,
47 const QString& text = QString(), bool autorep = false,48 const QString& text = QString(), bool autorep = false,
48 ushort count = 1) = 0;49 ushort count = 1) = 0;
49 virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device,50 virtual void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device,
50 const QList<struct QWindowSystemInterface::TouchPoint> &points,51 const QList<struct QWindowSystemInterface::TouchPoint> &points,
51 Qt::KeyboardModifiers mods = Qt::NoModifier) = 0;52 Qt::KeyboardModifiers mods = Qt::NoModifier) = 0;
52 virtual void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0;53 virtual void handleMouseEvent(ulong timestamp, QPointF movement,
54 Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0;
53 };55 };
5456
55 QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr);57 QtEventFeeder(const QSharedPointer<ScreenController> &screenController);
58 QtEventFeeder(const QSharedPointer<ScreenController> &screenController,
59 QtWindowSystemInterface *windowSystem);
56 virtual ~QtEventFeeder();60 virtual ~QtEventFeeder();
5761
58 static const int MirEventActionMask;62 static const int MirEventActionMask;
@@ -67,9 +71,9 @@
67 void dispatchKey(MirInputEvent const* event);71 void dispatchKey(MirInputEvent const* event);
68 void dispatchTouch(MirInputEvent const* event);72 void dispatchTouch(MirInputEvent const* event);
69 void dispatchPointer(MirInputEvent const* event);73 void dispatchPointer(MirInputEvent const* event);
70 void validateTouches(ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints);74 void validateTouches(QWindow *window, ulong timestamp, QList<QWindowSystemInterface::TouchPoint> &touchPoints);
71 bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint);75 bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint);
72 void sendActiveTouchRelease(ulong timestamp, int id);76 void sendActiveTouchRelease(QWindow *window, ulong timestamp, int id);
7377
74 QString touchesToString(const QList<struct QWindowSystemInterface::TouchPoint> &points);78 QString touchesToString(const QList<struct QWindowSystemInterface::TouchPoint> &points);
7579
7680
=== modified file 'src/platforms/mirserver/screen.cpp'
--- src/platforms/mirserver/screen.cpp 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/screen.cpp 2015-09-09 18:37:39 +0000
@@ -20,18 +20,21 @@
2020
21// Mir21// Mir
22#include "mir/geometry/size.h"22#include "mir/geometry/size.h"
23#include "mir/graphics/buffer.h"
24#include "mir/graphics/display_buffer.h"
25#include "mir/graphics/display.h"
2326
24// Qt27// Qt
25#include <QCoreApplication>28#include <QCoreApplication>
26#include <qpa/qwindowsysteminterface.h>29#include <qpa/qwindowsysteminterface.h>
27#include <QtSensors/QOrientationSensor>
28#include <QtSensors/QOrientationReading>
29#include <QThread>30#include <QThread>
3031
31// Qt sensors32// Qt sensors
32#include <QtSensors/QOrientationReading>33#include <QtSensors/QOrientationReading>
33#include <QtSensors/QOrientationSensor>34#include <QtSensors/QOrientationSensor>
3435
36using namespace qtmir;
37
35namespace mg = mir::geometry;38namespace mg = mir::geometry;
3639
37Q_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES, "qtmir.sensor")40Q_LOGGING_CATEGORY(QTMIR_SENSOR_MESSAGES, "qtmir.sensor")
@@ -102,12 +105,15 @@
102105
103bool Screen::skipDBusRegistration = false;106bool Screen::skipDBusRegistration = false;
104107
105Screen::Screen(mir::graphics::DisplayConfigurationOutput const &screen)108Screen::Screen(const mir::graphics::DisplayConfigurationOutput &screen)
106 : QObject(nullptr)109 : QObject(nullptr)
110 , m_displayBuffer(nullptr)
111 , m_displayGroup(nullptr)
107 , m_orientationSensor(new QOrientationSensor(this))112 , m_orientationSensor(new QOrientationSensor(this))
113 , m_screenWindow(nullptr)
108 , m_unityScreen(nullptr)114 , m_unityScreen(nullptr)
109{115{
110 readMirDisplayConfiguration(screen);116 setMirDisplayConfiguration(screen);
111117
112 // Set the default orientation based on the initial screen dimmensions.118 // Set the default orientation based on the initial screen dimmensions.
113 m_nativeOrientation = (m_geometry.width() >= m_geometry.height())119 m_nativeOrientation = (m_geometry.width() >= m_geometry.height())
@@ -139,6 +145,14 @@
139 }145 }
140}146}
141147
148Screen::~Screen()
149{
150 //if a ScreenWindow associated with this screen, kill it
151 if (m_screenWindow) {
152 m_screenWindow->window()->destroy(); // ends up destroying m_ScreenWindow
153 }
154}
155
142bool Screen::orientationSensorEnabled()156bool Screen::orientationSensorEnabled()
143{157{
144 return m_orientationSensor->isActive();158 return m_orientationSensor->isActive();
@@ -150,8 +164,15 @@
150 toggleSensors(status);164 toggleSensors(status);
151}165}
152166
153void Screen::readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const &screen)167void Screen::setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &screen)
154{168{
169 // Note: DisplayConfigurationOutput will be destroyed after this function returns
170
171 // Output data - each output has a unique id and corresponding type. Can be multiple cards.
172 m_outputId = screen.id;
173 m_cardId = screen.card_id;
174 m_type = screen.type;
175
155 // Physical screen size176 // Physical screen size
156 m_physicalSize.setWidth(screen.physical_size_mm.width.as_float());177 m_physicalSize.setWidth(screen.physical_size_mm.width.as_float());
157 m_physicalSize.setHeight(screen.physical_size_mm.height.as_float());178 m_physicalSize.setHeight(screen.physical_size_mm.height.as_float());
@@ -162,12 +183,34 @@
162 // Pixel depth183 // Pixel depth
163 m_depth = 8 * MIR_BYTES_PER_PIXEL(screen.current_format);184 m_depth = 8 * MIR_BYTES_PER_PIXEL(screen.current_format);
164185
165 // Mode = Resolution & refresh rate186 // Power mode
187 m_powerMode = screen.power_mode;
188
189 QRect oldGeometry = m_geometry;
190 // Position of screen in virtual desktop coordinate space
191 m_geometry.setTop(screen.top_left.y.as_int());
192 m_geometry.setLeft(screen.top_left.x.as_int());
193
194 // Mode = current resolution & refresh rate
166 mir::graphics::DisplayConfigurationMode mode = screen.modes.at(screen.current_mode_index);195 mir::graphics::DisplayConfigurationMode mode = screen.modes.at(screen.current_mode_index);
167 m_geometry.setWidth(mode.size.width.as_int());196 m_geometry.setWidth(mode.size.width.as_int());
168 m_geometry.setHeight(mode.size.height.as_int());197 m_geometry.setHeight(mode.size.height.as_int());
169198
170 m_refreshRate = mode.vrefresh_hz;199 // DPI - unnecessary to calculate, default implementation in QPlatformScreen is sufficient
200
201 // Check for Screen geometry change
202 if (m_geometry != oldGeometry) {
203 QWindowSystemInterface::handleScreenGeometryChange(this->screen(), m_geometry, m_geometry);
204 if (m_screenWindow) { // resize corresponding window immediately
205 m_screenWindow->setGeometry(m_geometry);
206 }
207 }
208
209 // Refresh rate
210 if (m_refreshRate != mode.vrefresh_hz) {
211 m_refreshRate = mode.vrefresh_hz;
212 QWindowSystemInterface::handleScreenRefreshRateChange(this->screen(), mode.vrefresh_hz);
213 }
171}214}
172215
173void Screen::toggleSensors(const bool enable) const216void Screen::toggleSensors(const bool enable) const
@@ -226,3 +269,57 @@
226 OrientationReadingEvent::m_type,269 OrientationReadingEvent::m_type,
227 m_orientationSensor->reading()->orientation()));270 m_orientationSensor->reading()->orientation()));
228}271}
272
273ScreenWindow* Screen::window() const
274{
275 return m_screenWindow;
276}
277
278void Screen::setWindow(ScreenWindow *window)
279{
280 if (window && m_screenWindow) {
281 qCDebug(QTMIR_SENSOR_MESSAGES) << "Screen::setWindow - overwriting existing ScreenWindow";
282 }
283 m_screenWindow = window;
284}
285
286void Screen::setMirDisplayBuffer(mir::graphics::DisplayBuffer *buffer, mir::graphics::DisplaySyncGroup *group)
287{
288 // This operation should only be performed while rendering is stopped
289 m_displayBuffer = buffer;
290 m_displayGroup = group;
291}
292
293void Screen::swapBuffers()
294{
295 m_displayBuffer->gl_swap_buffers();
296
297 /* FIXME this exposes a QtMir architecture problem, as Screen is supposed to wrap a mg::DisplayBuffer.
298 * We use Qt's multithreaded renderer, where each Screen is rendered to relatively independently, and
299 * post() called also individually.
300 *
301 * But if this is a native server on Android, in the multimonitor case a DisplaySyncGroup can contain
302 * 2+ DisplayBuffers, one post() call will submit all mg::DisplayBuffers in the group for flipping.
303 * This will cause just one Screen to be updated, blocking the swap call for the other Screens, which
304 * will slow rendering dramatically.
305 *
306 * Integrating the Qt Scenegraph renderer as a Mir renderer should solve this issue.
307 */
308 m_displayGroup->post();
309}
310
311void Screen::makeCurrent()
312{
313 m_displayBuffer->make_current();
314}
315
316void Screen::doneCurrent()
317{
318 m_displayBuffer->release_current();
319}
320
321QPlatformCursor *Screen::cursor() const
322{
323 const QPlatformCursor *platformCursor = &m_cursor;
324 return const_cast<QPlatformCursor *>(platformCursor);
325}
229326
=== modified file 'src/platforms/mirserver/screen.h'
--- src/platforms/mirserver/screen.h 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/screen.h 2015-09-09 18:37:39 +0000
@@ -17,20 +17,28 @@
17#ifndef SCREEN_H17#ifndef SCREEN_H
18#define SCREEN_H18#define SCREEN_H
1919
20// Qt
20#include <QObject>21#include <QObject>
21#include <QTimer>22#include <QTimer>
22#include <QtDBus/QDBusInterface>23#include <QtDBus/QDBusInterface>
23#include <qpa/qplatformscreen.h>24#include <qpa/qplatformscreen.h>
2425
25#include "mir/graphics/display_configuration.h"26// Mir
27#include <mir/graphics/display_configuration.h>
28
29// local
30#include "cursor.h"
31#include "screenwindow.h"
2632
27class QOrientationSensor;33class QOrientationSensor;
34namespace mir { namespace graphics { class DisplayBuffer; class DisplaySyncGroup; }}
2835
29class Screen : public QObject, public QPlatformScreen36class Screen : public QObject, public QPlatformScreen
30{37{
31 Q_OBJECT38 Q_OBJECT
32public:39public:
33 Screen(mir::graphics::DisplayConfigurationOutput const&);40 Screen(const mir::graphics::DisplayConfigurationOutput &);
41 ~Screen();
3442
35 // QPlatformScreen methods.43 // QPlatformScreen methods.
36 QRect geometry() const override { return m_geometry; }44 QRect geometry() const override { return m_geometry; }
@@ -40,8 +48,12 @@
40 qreal refreshRate() const override { return m_refreshRate; }48 qreal refreshRate() const override { return m_refreshRate; }
41 Qt::ScreenOrientation nativeOrientation() const override { return m_nativeOrientation; }49 Qt::ScreenOrientation nativeOrientation() const override { return m_nativeOrientation; }
42 Qt::ScreenOrientation orientation() const override { return m_currentOrientation; }50 Qt::ScreenOrientation orientation() const override { return m_currentOrientation; }
51 QPlatformCursor *cursor() const override;
4352
44 void toggleSensors(const bool enable) const;53 void toggleSensors(const bool enable) const;
54 mir::graphics::DisplayConfigurationOutputType outputType() const { return m_type; }
55
56 ScreenWindow* window() const;
4557
46 // QObject methods.58 // QObject methods.
47 void customEvent(QEvent* event) override;59 void customEvent(QEvent* event) override;
@@ -54,20 +66,40 @@
54 void onDisplayPowerStateChanged(int, int);66 void onDisplayPowerStateChanged(int, int);
55 void onOrientationReadingChanged();67 void onOrientationReadingChanged();
5668
69protected:
70 void setWindow(ScreenWindow *window);
71
72 void setMirDisplayConfiguration(const mir::graphics::DisplayConfigurationOutput &);
73 void setMirDisplayBuffer(mir::graphics::DisplayBuffer *, mir::graphics::DisplaySyncGroup *);
74 void swapBuffers();
75 void makeCurrent();
76 void doneCurrent();
77
57private:78private:
58 void readMirDisplayConfiguration(mir::graphics::DisplayConfigurationOutput const&);
59
60 QRect m_geometry;79 QRect m_geometry;
61 int m_depth;80 int m_depth;
62 QImage::Format m_format;81 QImage::Format m_format;
63 QSizeF m_physicalSize;82 QSizeF m_physicalSize;
64 qreal m_refreshRate;83 qreal m_refreshRate;
6584
85 mir::graphics::DisplayBuffer *m_displayBuffer;
86 mir::graphics::DisplaySyncGroup *m_displayGroup;
87 mir::graphics::DisplayConfigurationOutputId m_outputId;
88 mir::graphics::DisplayConfigurationCardId m_cardId;
89 mir::graphics::DisplayConfigurationOutputType m_type;
90 MirPowerMode m_powerMode;
91
66 Qt::ScreenOrientation m_nativeOrientation;92 Qt::ScreenOrientation m_nativeOrientation;
67 Qt::ScreenOrientation m_currentOrientation;93 Qt::ScreenOrientation m_currentOrientation;
68 QOrientationSensor *m_orientationSensor;94 QOrientationSensor *m_orientationSensor;
6995
96 ScreenWindow *m_screenWindow;
70 QDBusInterface *m_unityScreen;97 QDBusInterface *m_unityScreen;
98
99 qtmir::Cursor m_cursor;
100
101 friend class ScreenController;
102 friend class ScreenWindow;
71};103};
72104
73#endif // SCREEN_H105#endif // SCREEN_H
74106
=== added file 'src/platforms/mirserver/screencontroller.cpp'
--- src/platforms/mirserver/screencontroller.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/screencontroller.cpp 2015-09-09 18:37:39 +0000
@@ -0,0 +1,257 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "screencontroller.h"
18
19#include "screenwindow.h"
20#include "qtcompositor.h"
21#include "logging.h"
22#include "mirserverintegration.h"
23#include "screen.h"
24
25// Mir
26#include <mir/graphics/display.h>
27#include <mir/graphics/display_buffer.h>
28
29// Qt
30#include <QScreen>
31#include <QQuickWindow>
32#include <qpa/qwindowsysteminterface.h>
33
34// std
35#include <memory>
36
37Q_LOGGING_CATEGORY(QTMIR_SCREENS, "qtmir.screens")
38
39namespace mg = mir::graphics;
40
41ScreenController::ScreenController(QObject *parent)
42 : QObject(parent)
43 , m_compositing(false)
44{
45 qCDebug(QTMIR_SCREENS) << "ScreenController::ScreenController";
46}
47
48// init only after MirServer has initialized - runs on MirServerThread!!!
49void ScreenController::init(const std::shared_ptr<mir::graphics::Display> &display,
50 const std::shared_ptr<mir::compositor::Compositor> &compositor)
51{
52 m_display = display;
53 m_compositor = compositor;
54
55 // Use a Blocking Queued Connection to enforce synchronization of Qt GUI thread with Mir thread(s)
56 // on compositor shutdown. Compositor startup can be lazy.
57 // Queued connections work because the thread affinity of this class is with the Qt GUI thread.
58 auto qtCompositor = static_cast<QtCompositor *>(compositor.get());
59 connect(qtCompositor, &QtCompositor::starting,
60 this, &ScreenController::onCompositorStarting);
61 connect(qtCompositor, &QtCompositor::stopping,
62 this, &ScreenController::onCompositorStopping, Qt::BlockingQueuedConnection);
63}
64
65// terminate before shutting down the Mir server, or else liable to deadlock with the blocking connection above
66// Runs on MirServerThread!!!
67void ScreenController::terminate()
68{
69 auto qtCompositor = static_cast<QtCompositor *>(m_compositor.get());
70 qtCompositor->disconnect();
71}
72
73void ScreenController::onCompositorStarting()
74{
75 qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStarting";
76 m_compositing = true;
77
78 update();
79
80 // (Re)Start Qt's render thread by setting all windows with a corresponding screen to exposed.
81 for (auto screen : m_screenList) {
82 auto window = static_cast<ScreenWindow *>(screen->window());
83 if (window && window->window()) {
84 window->setExposed(true);
85 }
86 }
87}
88
89void ScreenController::onCompositorStopping()
90{
91 qCDebug(QTMIR_SCREENS) << "ScreenController::onCompositorStopping";
92 m_compositing = false;
93
94 // Stop Qt's render threads by setting all its windows it obscured. Must
95 // block until all windows have their GL contexts released.
96 for (auto screen : m_screenList) {
97 auto window = static_cast<ScreenWindow *>(screen->window());
98 if (window && window->window()) {
99 window->setExposed(false);
100 }
101 }
102
103 update();
104}
105
106void ScreenController::update()
107{
108 qCDebug(QTMIR_SCREENS) << "ScreenController::update";
109 auto display = m_display.lock();
110 if (!display)
111 return;
112 auto displayConfig = display->configuration();
113
114 // Mir only tells us something changed, it is up to us to figure out what.
115 QList<Screen*> newScreenList;
116 QList<Screen*> oldScreenList = m_screenList;
117 m_screenList.clear();
118
119 displayConfig->for_each_output(
120 [this, &oldScreenList, &newScreenList](const mg::DisplayConfigurationOutput &output) {
121 if (output.used && output.connected) {
122 Screen *screen = findScreenWithId(oldScreenList, output.id);
123 if (screen) { // we've already set up this display before, refresh its internals
124 screen->setMirDisplayConfiguration(output);
125 oldScreenList.removeAll(screen);
126 } else {
127 // new display, so create Screen for it
128 screen = this->createScreen(output);
129 newScreenList.append(screen);
130 qCDebug(QTMIR_SCREENS) << "Added Screen with id" << output.id.as_value()
131 << "and geometry" << screen->geometry();
132 }
133 m_screenList.append(screen);
134 }
135 }
136 );
137
138 // Delete any old & unused Screens
139 for (auto screen: oldScreenList) {
140 qCDebug(QTMIR_SCREENS) << "Removed Screen with id" << screen->m_outputId.as_value()
141 << "and geometry" << screen->geometry();
142 // The screen is automatically removed from Qt's internal list by the QPlatformScreen destructor.
143 auto window = static_cast<ScreenWindow *>(screen->window());
144 if (window && window->window() && window->isExposed()) {
145 window->window()->hide();
146 }
147 delete screen;
148 }
149
150 // Match up the new Mir DisplayBuffers with each Screen
151 display->for_each_display_sync_group([&](mg::DisplaySyncGroup &group) {
152 group.for_each_display_buffer([&](mg::DisplayBuffer &buffer) {
153 // only way to match Screen to a DisplayBuffer is by matching the geometry
154 QRect dbGeom(buffer.view_area().top_left.x.as_int(),
155 buffer.view_area().top_left.y.as_int(),
156 buffer.view_area().size.width.as_int(),
157 buffer.view_area().size.height.as_int());
158
159 for (auto screen : m_screenList) {
160 if (dbGeom == screen->geometry()) {
161 screen->setMirDisplayBuffer(&buffer, &group);
162 break;
163 }
164 }
165 });
166 });
167
168 qCDebug(QTMIR_SCREENS) << "=======================================";
169 for (auto screen: m_screenList) {
170 qCDebug(QTMIR_SCREENS) << screen << "- id:" << screen->m_outputId.as_value()
171 << "geometry:" << screen->geometry()
172 << "window:" << screen->window()
173 << "type" << static_cast<int>(screen->outputType());
174 }
175 qCDebug(QTMIR_SCREENS) << "=======================================";
176
177 for (auto screen : newScreenList) {
178 Q_EMIT screenAdded(screen);
179 }
180}
181
182Screen* ScreenController::createScreen(const mir::graphics::DisplayConfigurationOutput &output) const
183{
184 return new Screen(output);
185}
186
187Screen* ScreenController::getUnusedScreen()
188{
189 if (m_screenList.empty()) {
190 return nullptr;
191 } else if (m_screenList.size() == 1) {
192 return m_screenList.at(0);
193 }
194
195 // FIXME: Until we have better way of identifying screens, prioritize outputs based on their output type.
196 // Note the priorities defined here are nothing more than guesses. It tries to select internal displays first,
197 // then digital outputs, and finally analogue.
198 QMap <int, Screen*> priorityList;
199 auto prioritize = [](const mg::DisplayConfigurationOutputType &type) {
200 using out = mg::DisplayConfigurationOutputType;
201 switch(type) {
202 case out::lvds:
203 case out::edp:
204 return 0;
205 case out::displayport:
206 case out::hdmia:
207 case out::hdmib:
208 return 1;
209 case out::dvii:
210 case out::dvid:
211 case out::dvia:
212 return 2;
213 case out::vga:
214 return 3;
215 case out::ninepindin:
216 return 4;
217 case out::component:
218 case out::composite:
219 case out::svideo:
220 return 5;
221 case out::tv:
222 return 6;
223 case out::unknown:
224 default:
225 return 9;
226 }
227 };
228
229 for (auto screen : m_screenList) {
230 if (!screen->window()) {
231 priorityList.insert(prioritize(screen->outputType()), screen);
232 }
233 }
234
235 qCDebug(QTMIR_SCREENS) << "Prioritized list of available outputs:" << priorityList;
236 return priorityList.first(); // Map sorted by key, so first is the key with highest priority.
237}
238
239Screen* ScreenController::findScreenWithId(const QList<Screen *> &list, const mg::DisplayConfigurationOutputId id)
240{
241 for (Screen *screen : list) {
242 if (screen->m_outputId == id) {
243 return screen;
244 }
245 }
246 return nullptr;
247}
248
249QWindow* ScreenController::getWindowForPoint(const QPoint &point) //FIXME - not thread safe & not efficient
250{
251 for (Screen *screen : m_screenList) {
252 if (screen->window() && screen->geometry().contains(point)) {
253 return screen->window()->window();
254 }
255 }
256 return nullptr;
257}
0258
=== added file 'src/platforms/mirserver/screencontroller.h'
--- src/platforms/mirserver/screencontroller.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/screencontroller.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,97 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef SCREENCONTROLLER_H
18#define SCREENCONTROLLER_H
19
20#include <QObject>
21#include <QPoint>
22
23// Mir
24#include <mir/graphics/display_configuration.h>
25
26// std
27#include <memory>
28
29namespace mir {
30 namespace graphics { class Display; }
31 namespace compositor { class Compositor; }
32}
33
34class Screen;
35class QWindow;
36
37/*
38 * ScreenController monitors the Mir display configuration and compositor status, and updates
39 * the relevant QScreen and QWindow states accordingly.
40 *
41 * Primary purposes are:
42 * 1. to update QScreen state on Mir display configuration changes
43 * 2. to stop the Qt renderer by hiding its QWindow when Mir wants to stop all compositing,
44 * and resume Qt's renderer by showing its QWindow when Mir wants to resume compositing.
45 *
46 *
47 * Threading Note:
48 * This object must have affinity to the main Qt GUI thread, as it creates & destroys Platform
49 * objects which Qt uses internally. However beware as the init() & terminate() methods need to
50 * be called on the MirServerThread thread, as we need to monitor the screen state *after*
51 * Mir has initialized but before Qt's event loop has started, and tear down before Mir terminates.
52 * Also note the MirServerThread does not have an QEventLoop.
53 *
54 * All other methods must be called on the Qt GUI thread.
55 */
56
57class ScreenController : public QObject
58{
59 Q_OBJECT
60public:
61 explicit ScreenController(QObject *parent = 0);
62
63 Screen* getUnusedScreen();
64 QList<Screen*> screens() const { return m_screenList; }
65 bool compositing() const { return m_compositing; }
66
67 QWindow* getWindowForPoint(const QPoint &point);
68
69Q_SIGNALS:
70 void screenAdded(Screen *screen);
71
72public Q_SLOTS:
73 void update();
74
75public:
76 // called by MirServer
77 void init(const std::shared_ptr<mir::graphics::Display> &display,
78 const std::shared_ptr<mir::compositor::Compositor> &compositor);
79 void terminate();
80
81 // override for testing purposes
82 virtual Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const;
83
84protected Q_SLOTS:
85 void onCompositorStarting();
86 void onCompositorStopping();
87
88private:
89 Screen* findScreenWithId(const QList<Screen*> &list, const mir::graphics::DisplayConfigurationOutputId id);
90
91 std::weak_ptr<mir::graphics::Display> m_display;
92 std::shared_ptr<mir::compositor::Compositor> m_compositor;
93 QList<Screen*> m_screenList;
94 bool m_compositing;
95};
96
97#endif // SCREENCONTROLLER_H
098
=== renamed file 'src/platforms/mirserver/displaywindow.cpp' => 'src/platforms/mirserver/screenwindow.cpp'
--- src/platforms/mirserver/displaywindow.cpp 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/screenwindow.cpp 2015-09-09 18:37:39 +0000
@@ -14,15 +14,22 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */15 */
1616
17#include "displaywindow.h"17#include "screenwindow.h"
1818#include "screen.h"
19#include "mir/geometry/size.h"19
2020// Mir
21#include <mir/geometry/size.h>
22#include <mir/graphics/display_buffer.h>
23
24// Qt
21#include <qpa/qwindowsysteminterface.h>25#include <qpa/qwindowsysteminterface.h>
22#include <qpa/qplatformscreen.h>26#include <qpa/qplatformscreen.h>
2327#include <QQuickWindow>
28#include <QtQuick/private/qsgrenderloop_p.h>
24#include <QDebug>29#include <QDebug>
2530
31#include "logging.h"
32
26static WId newWId()33static WId newWId()
27{34{
28 static WId id = 0;35 static WId id = 0;
@@ -33,22 +40,22 @@
33 return ++id;40 return ++id;
34}41}
3542
36DisplayWindow::DisplayWindow(43ScreenWindow::ScreenWindow(QWindow *window)
37 QWindow *window,44 : QPlatformWindow(window)
38 mir::graphics::DisplaySyncGroup *displayGroup,45 , m_exposed(false)
39 mir::graphics::DisplayBuffer *displayBuffer)
40 : QObject(nullptr), QPlatformWindow(window)
41 , m_isExposed(true)
42 , m_winId(newWId())46 , m_winId(newWId())
43 , m_displayGroup(displayGroup)
44 , m_displayBuffer(displayBuffer)
45{47{
46 qDebug() << "DisplayWindow::DisplayWindow";48 // Register with the Screen it is associated with
47 qWarning("Window %p: %p 0x%x\n", this, window, uint(m_winId));49 auto myScreen = static_cast<Screen *>(screen());
50 Q_ASSERT(myScreen);
51 myScreen->setWindow(this);
52
53 qCDebug(QTMIR_SCREENS) << "ScreenWindow" << this << "with window ID" << uint(m_winId) << "backed by" << myScreen;
4854
49 QRect screenGeometry(screen()->availableGeometry());55 QRect screenGeometry(screen()->availableGeometry());
50 if (window->geometry() != screenGeometry) {56 if (window->geometry() != screenGeometry) {
51 setGeometry(screenGeometry);57 setGeometry(screenGeometry);
58 window->setGeometry(screenGeometry);
52 }59 }
53 window->setSurfaceType(QSurface::OpenGLSurface);60 window->setSurfaceType(QSurface::OpenGLSurface);
5461
@@ -57,70 +64,51 @@
57 requestActivateWindow();64 requestActivateWindow();
58}65}
5966
60QRect DisplayWindow::geometry() const67ScreenWindow::~ScreenWindow()
61{68{
62 // For yet-to-become-fullscreen windows report the geometry covering the entire69 qCDebug(QTMIR_SCREENS) << "Destroying ScreenWindow" << this;
63 // screen. This is particularly important for Quick where the root object may get70 static_cast<Screen *>(screen())->setWindow(nullptr);
64 // sized to some geometry queried before calling create().71}
65 return screen()->availableGeometry();72
66}73bool ScreenWindow::isExposed() const
6774{
68void DisplayWindow::setGeometry(const QRect &)75 return m_exposed;
69{76}
70 // We only support full-screen windows77
71 QRect rect(screen()->availableGeometry());78void ScreenWindow::setExposed(const bool exposed)
72 QWindowSystemInterface::handleGeometryChange(window(), rect);79{
73 QPlatformWindow::setGeometry(rect);80 qCDebug(QTMIR_SCREENS) << "ScreenWindow::setExposed" << this << exposed;
74}81 if (m_exposed == exposed)
7582 return;
76bool DisplayWindow::isExposed() const83
77{84 m_exposed = exposed;
78 return m_isExposed;85 if (!window())
79}86 return;
8087
81bool DisplayWindow::event(QEvent *event)88 // If backing a QQuickWindow, need to stop/start its renderer immediately
82{89 auto quickWindow = static_cast<QQuickWindow *>(window());
83 // Intercept Hide event and convert to Expose event, as Hide causes Qt to release GL90 if (!quickWindow)
84 // resources, which we don't want. Must intercept Show to un-do hide.91 return;
85 if (event->type() == QEvent::Hide) {92
86 qDebug() << "DisplayWindow::event got QEvent::Hide";93 if (exposed) {
87 m_isExposed = false;94 QWindowSystemInterface::handleExposeEvent(window(), QRegion());
88 QWindowSystemInterface::handleExposeEvent(window(), QRect());95 } else {
89 QWindowSystemInterface::flushWindowSystemEvents();96 auto renderer = QSGRenderLoop::instance();
90 return true;97 renderer->hide(quickWindow); // ExposeEvent will arrive too late, need to stop compositor immediately
91 } else if (event->type() == QEvent::Show) {
92 qDebug() << "DisplayWindow::event got QEvent::Show";
93 m_isExposed = true;
94 QRect rect(QPoint(), geometry().size());
95 QWindowSystemInterface::handleExposeEvent(window(), rect);
96 QWindowSystemInterface::flushWindowSystemEvents();
97 return true;
98 }98 }
99 return QObject::event(event);99}
100}100
101101void ScreenWindow::swapBuffers()
102void DisplayWindow::swapBuffers()102{
103{103 static_cast<Screen *>(screen())->swapBuffers();
104 m_displayBuffer->gl_swap_buffers();104}
105105
106 // FIXME this exposes a QtMir architecture problem now, as DisplayWindow106void ScreenWindow::makeCurrent()
107 // is supposed to wrap a mg::DisplayBuffer. We use Qt's multithreaded107{
108 // renderer, where each DisplayWindow is rendered to relatively108 static_cast<Screen *>(screen())->makeCurrent();
109 // independently, and post() called also individually.109}
110 //110
111 // But in multimonitor case where a DisplaySyncGroup contains 2111void ScreenWindow::doneCurrent()
112 // DisplayBuffers, one post() call will submit both112{
113 // mg::DisplayBuffers for flipping, which can happen before the other113 static_cast<Screen *>(screen())->doneCurrent();
114 // DisplayWindow has been rendered to, causing visual artifacts
115 m_displayGroup->post();
116}
117
118void DisplayWindow::makeCurrent()
119{
120 m_displayBuffer->make_current();
121}
122
123void DisplayWindow::doneCurrent()
124{
125 m_displayBuffer->release_current();
126}114}
127115
=== renamed file 'src/platforms/mirserver/displaywindow.h' => 'src/platforms/mirserver/screenwindow.h'
--- src/platforms/mirserver/displaywindow.h 2015-08-11 12:08:32 +0000
+++ src/platforms/mirserver/screenwindow.h 2015-09-09 18:37:39 +0000
@@ -14,43 +14,33 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */15 */
1616
17#ifndef DISPLAYWINDOW_H17#ifndef SCREENWINDOW_H
18#define DISPLAYWINDOW_H18#define SCREENWINDOW_H
1919
20#include <qpa/qplatformwindow.h>20#include <qpa/qplatformwindow.h>
2121
22#include <mir/graphics/display.h>22// ScreenWindow implements the basics of a QPlatformWindow.
23#include <mir/graphics/display_buffer.h>23// QtMir enforces one Window per Screen, so Window and Screen are tightly coupled.
2424// All Mir specifics live in the associated Screen object.
25#include <QObject>25
2626class ScreenWindow : public QPlatformWindow
27// DisplayWindow wraps the whatever implementation Mir creates of a DisplayBuffer,
28// which is the buffer output for an individual display.
29
30class DisplayWindow : public QObject, public QPlatformWindow
31{27{
32 Q_OBJECT
33public:28public:
34 explicit DisplayWindow(QWindow *window, mir::graphics::DisplaySyncGroup*, mir::graphics::DisplayBuffer*);29 explicit ScreenWindow(QWindow *window);
30 virtual ~ScreenWindow();
3531
36 QRect geometry() const override;32 bool isExposed() const override;
37 void setGeometry(const QRect &rect) override;33 void setExposed(const bool exposed);
3834
39 WId winId() const override { return m_winId; }35 WId winId() const override { return m_winId; }
4036
41 bool isExposed() const override;
42
43 bool event(QEvent *event) override;
44
45 void swapBuffers();37 void swapBuffers();
46 void makeCurrent();38 void makeCurrent();
47 void doneCurrent();39 void doneCurrent();
4840
49private:41private:
50 bool m_isExposed;42 bool m_exposed;
51 WId m_winId;43 WId m_winId;
52 mir::graphics::DisplaySyncGroup *m_displayGroup;
53 mir::graphics::DisplayBuffer *m_displayBuffer;
54};44};
5545
56#endif // DISPLAYWINDOW_H46#endif // SCREENWINDOW_H
5747
=== added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp'
--- src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/tileddisplayconfigurationpolicy.cpp 2015-09-09 18:37:39 +0000
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "tileddisplayconfigurationpolicy.h"
18
19#include <mir/graphics/display_configuration.h>
20#include <mir/geometry/point.h>
21
22namespace mg = mir::graphics;
23
24TiledDisplayConfigurationPolicy::TiledDisplayConfigurationPolicy(
25 const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped)
26 : m_wrapped(wrapped)
27{
28}
29
30void TiledDisplayConfigurationPolicy::apply_to(mg::DisplayConfiguration& conf)
31{
32 int nextTopLeftPosition = 0;
33
34 m_wrapped->apply_to(conf);
35
36 conf.for_each_output(
37 [&](mg::UserDisplayConfigurationOutput& output)
38 {
39 if (output.connected && output.used) {
40 output.top_left = mir::geometry::Point{nextTopLeftPosition, 0};
41 nextTopLeftPosition += output.modes[output.preferred_mode_index].size.width.as_int();
42 }
43 });
44}
045
=== added file 'src/platforms/mirserver/tileddisplayconfigurationpolicy.h'
--- src/platforms/mirserver/tileddisplayconfigurationpolicy.h 1970-01-01 00:00:00 +0000
+++ src/platforms/mirserver/tileddisplayconfigurationpolicy.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef TILEDDISPLAYCONFIGURATIONPOLICY_H
18#define TILEDDISPLAYCONFIGURATIONPOLICY_H
19
20#include <mir/graphics/display_configuration_policy.h>
21
22#include <memory>
23
24class TiledDisplayConfigurationPolicy : public mir::graphics::DisplayConfigurationPolicy
25{
26public:
27 TiledDisplayConfigurationPolicy(const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped);
28
29 void apply_to(mir::graphics::DisplayConfiguration& conf) override;
30
31private:
32 const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> m_wrapped;
33};
34
35#endif // TILEDDISPLAYCONFIGURATIONPOLICY_H
036
=== added directory 'tests/common'
=== added file 'tests/common/fake_displayconfigurationoutput.h'
--- tests/common/fake_displayconfigurationoutput.h 1970-01-01 00:00:00 +0000
+++ tests/common/fake_displayconfigurationoutput.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,73 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef FAKE_DISPLAYCONFIGURATIONOUTPUT_H
18#define FAKE_DISPLAYCONFIGURATIONOUTPUT_H
19
20#include <mir/graphics/display_configuration.h>
21
22namespace mg = mir::graphics;
23namespace geom = mir::geometry;
24
25const mg::DisplayConfigurationOutput fakeOutput1
26{
27 mg::DisplayConfigurationOutputId{3},
28 mg::DisplayConfigurationCardId{2},
29 mg::DisplayConfigurationOutputType::dvid,
30 {
31 mir_pixel_format_abgr_8888
32 },
33 {
34 {geom::Size{100, 200}, 60.0},
35 {geom::Size{100, 200}, 59.0},
36 {geom::Size{150, 200}, 59.0}
37 },
38 0,
39 geom::Size{1111, 2222},
40 true,
41 true,
42 geom::Point(),
43 2,
44 mir_pixel_format_abgr_8888,
45 mir_power_mode_on,
46 mir_orientation_normal
47};
48
49const mg::DisplayConfigurationOutput fakeOutput2
50{
51 mg::DisplayConfigurationOutputId{2},
52 mg::DisplayConfigurationCardId{4},
53 mg::DisplayConfigurationOutputType::lvds,
54 {
55 mir_pixel_format_xbgr_8888
56 },
57 {
58 {geom::Size{800, 1200}, 90.0},
59 {geom::Size{1600, 2400}, 60.0},
60 {geom::Size{1500, 2000}, 75.0}
61 },
62 0,
63 geom::Size{1000, 2000},
64 true,
65 true,
66 geom::Point(500, 600),
67 2,
68 mir_pixel_format_xbgr_8888,
69 mir_power_mode_on,
70 mir_orientation_left
71};
72
73#endif // FAKE_DISPLAYCONFIGURATIONOUTPUT_H
074
=== added file 'tests/common/gmock_fixes.h'
--- tests/common/gmock_fixes.h 1970-01-01 00:00:00 +0000
+++ tests/common/gmock_fixes.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,124 @@
1//
2// Copyright © 2012 Canonical Ltd. Copyright 2007, Google Inc.
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31//
32// Author: wan@google.com (Zhanyong Wan)
33// Authored by: Alan Griffiths <alan@octopull.co.uk>
34
35#ifndef MIR_TEST_GMOCK_FIXES_H_
36#define MIR_TEST_GMOCK_FIXES_H_
37
38#include <memory>
39#include <gmock/gmock.h>
40
41namespace testing
42{
43namespace internal
44{
45
46template<typename T>
47class ActionResultHolder<std::unique_ptr<T>>
48: public UntypedActionResultHolderBase {
49 public:
50 explicit ActionResultHolder(std::unique_ptr<T>&& a_value) :
51 value_(std::move(a_value)) {}
52
53 // The compiler-generated copy constructor and assignment operator
54 // are exactly what we need, so we don't need to define them.
55
56 // Returns the held value and deletes this object.
57 std::unique_ptr<T> GetValueAndDelete() const {
58 std::unique_ptr<T> retval(std::move(value_));
59 delete this;
60 return retval;
61 }
62
63 // Prints the held value as an action's result to os.
64 virtual void PrintAsActionResult(::std::ostream* os) const {
65 *os << "\n Returns: ";
66 // T may be a reference type, so we don't use UniversalPrint().
67 UniversalPrinter<std::unique_ptr<T>>::Print(value_, os);
68 }
69
70 // Performs the given mock function's default action and returns the
71 // result in a new-ed ActionResultHolder.
72 template <typename F>
73 static ActionResultHolder* PerformDefaultAction(
74 const FunctionMockerBase<F>* func_mocker,
75 const typename Function<F>::ArgumentTuple& args,
76 const string& call_description) {
77 return new ActionResultHolder(
78 func_mocker->PerformDefaultAction(args, call_description));
79 }
80
81 // Performs the given action and returns the result in a new-ed
82 // ActionResultHolder.
83 template <typename F>
84 static ActionResultHolder*
85 PerformAction(const Action<F>& action,
86 const typename Function<F>::ArgumentTuple& args) {
87 return new ActionResultHolder(action.Perform(args));
88 }
89
90 private:
91 std::unique_ptr<T> mutable value_;
92
93 // T could be a reference type, so = isn't supported.
94 GTEST_DISALLOW_ASSIGN_(ActionResultHolder);
95};
96
97}
98
99template<typename T>
100class DefaultValue<std::unique_ptr<T>> {
101 public:
102 // Unsets the default value for type T.
103 static void Clear() {}
104
105 // Returns true iff the user has set the default value for type T.
106 static bool IsSet() { return false; }
107
108 // Returns true if T has a default return value set by the user or there
109 // exists a built-in default value.
110 static bool Exists() {
111 return true;
112 }
113
114 // Returns the default value for type T if the user has set one;
115 // otherwise returns the built-in default value if there is one;
116 // otherwise aborts the process.
117 static std::unique_ptr<T> Get() {
118 return std::unique_ptr<T>();
119 }
120};
121
122}
123
124#endif /* MIR_TEST_GMOCK_FIXES_H_ */
0125
=== added file 'tests/common/mock_display.h'
--- tests/common/mock_display.h 1970-01-01 00:00:00 +0000
+++ tests/common/mock_display.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MOCKDISPLAY_H
18#define MOCKDISPLAY_H
19
20#include <mir/graphics/display.h>
21#include <mir/graphics/gl_context.h>
22
23#include <gmock/gmock.h>
24#include "gmock_fixes.h"
25
26class MockDisplaySyncGroup : public mir::graphics::DisplaySyncGroup
27{
28public:
29 MOCK_METHOD1(for_each_display_buffer, void(std::function<void(mir::graphics::DisplayBuffer&)> const& f));
30 MOCK_METHOD0(post, void());
31};
32
33struct MockDisplay : public mir::graphics::Display
34{
35public:
36 MOCK_METHOD1(for_each_display_sync_group, void(std::function<void(mir::graphics::DisplaySyncGroup&)> const&));
37 MOCK_CONST_METHOD0(configuration, std::unique_ptr<mir::graphics::DisplayConfiguration>());
38 MOCK_METHOD1(configure, void(mir::graphics::DisplayConfiguration const&));
39 MOCK_METHOD2(register_configuration_change_handler,
40 void(mir::graphics::EventHandlerRegister&, mir::graphics::DisplayConfigurationChangeHandler const&));
41
42 MOCK_METHOD3(register_pause_resume_handlers, void(mir::graphics::EventHandlerRegister&,
43 mir::graphics::DisplayPauseHandler const&,
44 mir::graphics::DisplayResumeHandler const&));
45 MOCK_METHOD0(pause, void());
46 MOCK_METHOD0(resume, void());
47 MOCK_METHOD1(create_hardware_cursor, std::shared_ptr<mir::graphics::Cursor>(std::shared_ptr<mir::graphics::CursorImage> const&));
48 MOCK_METHOD0(create_gl_context, std::unique_ptr<mir::graphics::GLContext>());
49};
50
51
52
53#endif // MOCKDISPLAY_H
054
=== added file 'tests/common/mock_display_buffer.h'
--- tests/common/mock_display_buffer.h 1970-01-01 00:00:00 +0000
+++ tests/common/mock_display_buffer.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MOCK_DISPLAY_BUFFER_H
18#define MOCK_DISPLAY_BUFFER_H
19
20#include <mir/graphics/display_buffer.h>
21
22#include <gmock/gmock.h>
23
24class MockDisplayBuffer : public mir::graphics::DisplayBuffer
25{
26public:
27 MockDisplayBuffer()
28 {
29 using namespace testing;
30 ON_CALL(*this, view_area())
31 .WillByDefault(Return(mir::geometry::Rectangle{{0,0},{0,0}}));
32 }
33 MOCK_CONST_METHOD0(view_area, mir::geometry::Rectangle());
34 MOCK_METHOD0(make_current, void());
35 MOCK_METHOD0(release_current, void());
36 MOCK_METHOD0(gl_swap_buffers, void());
37 MOCK_METHOD1(post_renderables_if_optimizable, bool(mir::graphics::RenderableList const&));
38 MOCK_CONST_METHOD0(orientation, MirOrientation());
39 MOCK_CONST_METHOD0(uses_alpha, bool());
40};
41
42
43#endif // MOCK_DISPLAY_BUFFER_H
044
=== added file 'tests/common/mock_display_configuration.h'
--- tests/common/mock_display_configuration.h 1970-01-01 00:00:00 +0000
+++ tests/common/mock_display_configuration.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MOCK_DISPLAY_CONFIGURATION_H
18#define MOCK_DISPLAY_CONFIGURATION_H
19
20#include <mir/graphics/display_configuration.h>
21
22#include <gmock/gmock.h>
23#include "gmock_fixes.h"
24
25class MockDisplayConfiguration : public mir::graphics::DisplayConfiguration
26{
27public:
28 MOCK_CONST_METHOD1(for_each_card, void(std::function<void(mir::graphics::DisplayConfigurationCard const&)>));
29
30 MOCK_CONST_METHOD1(for_each_output, void(std::function<void(mir::graphics::DisplayConfigurationOutput const&)>));
31 MOCK_METHOD1(for_each_output, void(std::function<void(mir::graphics::UserDisplayConfigurationOutput&)>));
32
33 MOCK_CONST_METHOD0(valid, bool());
34};
35#endif // MOCK_DISPLAY_CONFIGURATION_H
036
=== added file 'tests/common/mock_main_loop.h'
--- tests/common/mock_main_loop.h 1970-01-01 00:00:00 +0000
+++ tests/common/mock_main_loop.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef MOCKMAINLOOP_H
18#define MOCKMAINLOOP_H
19
20#include <gmock/gmock.h>
21
22#include <mir/main_loop.h>
23
24#include <memory>
25
26class MockMainLoop : public mir::MainLoop
27{
28public:
29 ~MockMainLoop() noexcept {}
30
31 void run() override {}
32 void stop() override {}
33
34 MOCK_METHOD2(register_signal_handler,
35 void(std::initializer_list<int>,
36 std::function<void(int)> const&));
37
38 MOCK_METHOD3(register_fd_handler,
39 void(std::initializer_list<int>, void const*,
40 std::function<void(int)> const&));
41
42 MOCK_METHOD1(unregister_fd_handler, void(void const*));
43
44 MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&));
45 MOCK_METHOD1(pause_processing_for,void (void const*));
46 MOCK_METHOD1(resume_processing_for,void (void const*));
47
48 MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::function<void()> const& callback));
49 MOCK_METHOD1(create_alarm, std::unique_ptr<mir::time::Alarm>(std::shared_ptr<mir::LockableCallback> const& callback));
50};
51
52
53#endif // MOCKMAINLOOP_H
054
=== modified file 'tests/mirserver/CMakeLists.txt'
--- tests/mirserver/CMakeLists.txt 2014-11-13 15:47:30 +0000
+++ tests/mirserver/CMakeLists.txt 2015-09-09 18:37:39 +0000
@@ -1,3 +1,4 @@
1add_subdirectory(QtEventFeeder)1add_subdirectory(QtEventFeeder)
2add_subdirectory(Clipboard)2add_subdirectory(Clipboard)
3add_subdirectory(Screen)3add_subdirectory(Screen)
4add_subdirectory(ScreenController)
45
=== modified file 'tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h'
--- tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-04-01 15:02:36 +0000
+++ tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-09-09 18:37:39 +0000
@@ -19,19 +19,26 @@
19#define MOCK_QTWINDOWSYSTEM_H19#define MOCK_QTWINDOWSYSTEM_H
2020
21#include <qteventfeeder.h>21#include <qteventfeeder.h>
22#include <QWindow>
2223
23class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {24class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {
24public:25public:
25 MOCK_METHOD0(hasTargetWindow, bool());26 MOCK_CONST_METHOD0(ready, bool());
26 MOCK_METHOD0(targetWindowGeometry, QRect());27 MOCK_METHOD1(setScreenController, void(const QSharedPointer<ScreenController> &));
28 MOCK_METHOD1(getWindowForTouchPoint, QWindow*(const QPoint &point));
29 MOCK_METHOD0(lastWindow, QWindow*());
30 MOCK_METHOD0(focusedWindow, QWindow*());
27 MOCK_METHOD1(registerTouchDevice, void(QTouchDevice* device));31 MOCK_METHOD1(registerTouchDevice, void(QTouchDevice* device));
28 MOCK_METHOD10(handleExtendedKeyEvent, void(ulong timestamp, QEvent::Type type, int key,32
29 Qt::KeyboardModifiers modifiers,33 // Wanted to use GMock, but MOCK_METHOD11 not implemented
30 quint32 nativeScanCode, quint32 nativeVirtualKey,34 void handleExtendedKeyEvent(QWindow */*window*/, ulong /*timestamp*/, QEvent::Type /*type*/, int /*key*/,
31 quint32 nativeModifiers,35 Qt::KeyboardModifiers /*modifiers*/,
32 const QString& text, bool autorep,36 quint32 /*nativeScanCode*/, quint32 /*nativeVirtualKey*/,
33 ushort count));37 quint32 /*nativeModifiers*/,
34 MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device,38 const QString& /*text*/ = QString(), bool /*autorep*/ = false,
39 ushort /*count*/ = 1) {}
40
41 MOCK_METHOD5(handleTouchEvent, void(QWindow *window, ulong timestamp, QTouchDevice *device,
35 const QList<struct QWindowSystemInterface::TouchPoint> &points,42 const QList<struct QWindowSystemInterface::TouchPoint> &points,
36 Qt::KeyboardModifiers mods));43 Qt::KeyboardModifiers mods));
37 MOCK_METHOD4(handleMouseEvent, void(ulong, QPointF, Qt::MouseButton, Qt::KeyboardModifiers));44 MOCK_METHOD4(handleMouseEvent, void(ulong, QPointF, Qt::MouseButton, Qt::KeyboardModifiers));
3845
=== modified file 'tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp'
--- tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-08-11 12:08:32 +0000
+++ tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2015-09-09 18:37:39 +0000
@@ -69,33 +69,44 @@
6969
70 MockQtWindowSystem *mockWindowSystem;70 MockQtWindowSystem *mockWindowSystem;
71 QtEventFeeder *qtEventFeeder;71 QtEventFeeder *qtEventFeeder;
72 QWindow *window;
73 QGuiApplication *app;
72};74};
7375
74void QtEventFeederTest::SetUp()76void QtEventFeederTest::SetUp()
75{77{
76 mockWindowSystem = new MockQtWindowSystem;78 mockWindowSystem = new MockQtWindowSystem;
79 auto screens = QSharedPointer<ScreenController>();
7780
78 EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_));81 EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_));
7982
80 qtEventFeeder = new QtEventFeeder(mockWindowSystem);83 qtEventFeeder = new QtEventFeeder(screens, mockWindowSystem);
8184
82 ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));85 ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
86
87 int argc = 0;
88 char **argv = nullptr;
89 setenv("QT_QPA_PLATFORM", "minimal", 1);
90 app = new QGuiApplication(argc, argv);
91 window = new QWindow;
83}92}
8493
85void QtEventFeederTest::TearDown()94void QtEventFeederTest::TearDown()
86{95{
87 // mockWindowSystem will be deleted by QtEventFeeder96 // mockWindowSystem will be deleted by QtEventFeeder
88 delete qtEventFeeder;97 delete qtEventFeeder;
98 delete window;
99 delete app;
89}100}
90101
91void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()102void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()
92{103{
93 EXPECT_CALL(*mockWindowSystem, hasTargetWindow())104 EXPECT_CALL(*mockWindowSystem, getWindowForTouchPoint(_))
94 .Times(AnyNumber())105 .Times(AnyNumber())
95 .WillRepeatedly(Return(true));106 .WillRepeatedly(Return(window));
96 EXPECT_CALL(*mockWindowSystem, targetWindowGeometry())107 EXPECT_CALL(*mockWindowSystem, focusedWindow())
97 .Times(AnyNumber())108 .Times(AnyNumber())
98 .WillRepeatedly(Return(QRect(0,0,100,100)));109 .WillRepeatedly(Return(window));
99}110}
100111
101112
@@ -113,7 +124,7 @@
113124
114 setIrrelevantMockWindowSystemExpectations();125 setIrrelevantMockWindowSystemExpectations();
115126
116 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),127 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1),
117 Contains(AllOf(HasId(0),128 Contains(AllOf(HasId(0),
118 IsPressed()))),_)).Times(1);129 IsPressed()))),_)).Times(1);
119130
@@ -132,12 +143,12 @@
132 InSequence sequence;143 InSequence sequence;
133144
134 EXPECT_CALL(*mockWindowSystem,145 EXPECT_CALL(*mockWindowSystem,
135 handleTouchEvent(_,_,AllOf(SizeIs(1),146 handleTouchEvent(_,_,_,AllOf(SizeIs(1),
136 Contains(AllOf(HasId(0),IsReleased()))147 Contains(AllOf(HasId(0),IsReleased()))
137 ),_)).Times(1);148 ),_)).Times(1);
138149
139 EXPECT_CALL(*mockWindowSystem,150 EXPECT_CALL(*mockWindowSystem,
140 handleTouchEvent(_,_,AllOf(SizeIs(1),151 handleTouchEvent(_,_,_,AllOf(SizeIs(1),
141 Contains(AllOf(HasId(1),IsPressed()))152 Contains(AllOf(HasId(1),IsPressed()))
142 ),_)).Times(1);153 ),_)).Times(1);
143 }154 }
@@ -161,7 +172,7 @@
161 10, 10, 10 /* x, y, pressure*/,172 10, 10, 10 /* x, y, pressure*/,
162 1, 1, 10 /* touch major, minor, size */);173 1, 1, 10 /* touch major, minor, size */);
163174
164 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),175 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1),
165 Contains(AllOf(HasId(0),176 Contains(AllOf(HasId(0),
166 IsPressed()))),_)).Times(1);177 IsPressed()))),_)).Times(1);
167 qtEventFeeder->dispatch(*ev1);178 qtEventFeeder->dispatch(*ev1);
@@ -181,7 +192,7 @@
181 1, 1, 10 /* touch major, minor, size */);192 1, 1, 10 /* touch major, minor, size */);
182193
183 EXPECT_CALL(*mockWindowSystem,194 EXPECT_CALL(*mockWindowSystem,
184 handleTouchEvent(_,_,AllOf(SizeIs(2),195 handleTouchEvent(_,_,_,AllOf(SizeIs(2),
185 Contains(AllOf(HasId(0), StateIsMoved())),196 Contains(AllOf(HasId(0), StateIsMoved())),
186 Contains(AllOf(HasId(1), IsPressed()))197 Contains(AllOf(HasId(1), IsPressed()))
187 ),_)).Times(1);198 ),_)).Times(1);
@@ -208,14 +219,14 @@
208219
209 // first release touch 0220 // first release touch 0
210 EXPECT_CALL(*mockWindowSystem,221 EXPECT_CALL(*mockWindowSystem,
211 handleTouchEvent(_,_,AllOf(SizeIs(2),222 handleTouchEvent(_,_,_,AllOf(SizeIs(2),
212 Contains(AllOf(HasId(0), IsReleased())),223 Contains(AllOf(HasId(0), IsReleased())),
213 Contains(AllOf(HasId(1), IsStationary()))224 Contains(AllOf(HasId(1), IsStationary()))
214 ),_)).Times(1);225 ),_)).Times(1);
215226
216 // then press touch 2227 // then press touch 2
217 EXPECT_CALL(*mockWindowSystem,228 EXPECT_CALL(*mockWindowSystem,
218 handleTouchEvent(_,_,AllOf(SizeIs(2),229 handleTouchEvent(_,_,_,AllOf(SizeIs(2),
219 Contains(AllOf(HasId(1), StateIsMoved())),230 Contains(AllOf(HasId(1), StateIsMoved())),
220 Contains(AllOf(HasId(2), IsPressed()))231 Contains(AllOf(HasId(2), IsPressed()))
221 ),_)).Times(1);232 ),_)).Times(1);
@@ -230,7 +241,7 @@
230{241{
231 setIrrelevantMockWindowSystemExpectations();242 setIrrelevantMockWindowSystemExpectations();
232243
233 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),244 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1),
234 Contains(AllOf(HasId(0),245 Contains(AllOf(HasId(0),
235 IsPressed()))),_)).Times(1);246 IsPressed()))),_)).Times(1);
236247
@@ -243,7 +254,7 @@
243254
244 setIrrelevantMockWindowSystemExpectations();255 setIrrelevantMockWindowSystemExpectations();
245256
246 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),257 EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,AllOf(SizeIs(1),
247 Contains(AllOf(HasId(0), StateIsMoved()))258 Contains(AllOf(HasId(0), StateIsMoved()))
248 ),_)).Times(1);259 ),_)).Times(1);
249260
250261
=== modified file 'tests/mirserver/Screen/CMakeLists.txt'
--- tests/mirserver/Screen/CMakeLists.txt 2014-12-03 08:56:35 +0000
+++ tests/mirserver/Screen/CMakeLists.txt 2015-09-09 18:37:39 +0000
@@ -5,6 +5,7 @@
5)5)
66
7include_directories(7include_directories(
8 ${CMAKE_SOURCE_DIR}/tests/common
8 ${CMAKE_SOURCE_DIR}/src/platforms/mirserver9 ${CMAKE_SOURCE_DIR}/src/platforms/mirserver
9 ${CMAKE_SOURCE_DIR}/src/common10 ${CMAKE_SOURCE_DIR}/src/common
10 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}11 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
1112
=== modified file 'tests/mirserver/Screen/screen_test.cpp'
--- tests/mirserver/Screen/screen_test.cpp 2015-08-11 12:08:32 +0000
+++ tests/mirserver/Screen/screen_test.cpp 2015-09-09 18:37:39 +0000
@@ -18,37 +18,21 @@
18#include <gtest/gtest.h>18#include <gtest/gtest.h>
1919
20#include "mir/graphics/display_configuration.h"20#include "mir/graphics/display_configuration.h"
21#include "fake_displayconfigurationoutput.h"
2122
22#include <screen.h>23#include <screen.h>
2324
25using namespace ::testing;
26
24namespace mg = mir::graphics;27namespace mg = mir::graphics;
25namespace geom = mir::geometry;28namespace geom = mir::geometry;
2629
27mg::DisplayConfigurationOutput const fake_output30class ScreenTest : public ::testing::Test {
28{31protected:
29 mg::DisplayConfigurationOutputId{3},32 void SetUp() override;
30 mg::DisplayConfigurationCardId{2},
31 mg::DisplayConfigurationOutputType::dvid,
32 {
33 mir_pixel_format_abgr_8888
34 },
35 {
36 {geom::Size{10, 20}, 60.0},
37 {geom::Size{10, 20}, 59.0},
38 {geom::Size{15, 20}, 59.0}
39 },
40 0,
41 geom::Size{10, 20},
42 true,
43 true,
44 geom::Point(),
45 2,
46 mir_pixel_format_abgr_8888,
47 mir_power_mode_on,
48 mir_orientation_normal
49};33};
5034
51TEST(ScreenTest, OrientationSensor)35void ScreenTest::SetUp()
52{36{
53 if (!qEnvironmentVariableIsSet("QT_ACCEL_FILEPATH")) {37 if (!qEnvironmentVariableIsSet("QT_ACCEL_FILEPATH")) {
54 // Trick Qt >= 5.4.1 to load the generic sensors38 // Trick Qt >= 5.4.1 to load the generic sensors
@@ -56,7 +40,11 @@
56 }40 }
5741
58 Screen::skipDBusRegistration = true;42 Screen::skipDBusRegistration = true;
59 Screen *screen = new Screen(fake_output);43}
44
45TEST_F(ScreenTest, OrientationSensor)
46{
47 Screen *screen = new Screen(fakeOutput1);
6048
61 // Default state should be active49 // Default state should be active
62 ASSERT_TRUE(screen->orientationSensorEnabled());50 ASSERT_TRUE(screen->orientationSensorEnabled());
@@ -67,3 +55,29 @@
67 screen->onDisplayPowerStateChanged(1,0);55 screen->onDisplayPowerStateChanged(1,0);
68 ASSERT_TRUE(screen->orientationSensorEnabled());56 ASSERT_TRUE(screen->orientationSensorEnabled());
69}57}
58
59TEST_F(ScreenTest, ReadConfigurationFromDisplayConfig)
60{
61 Screen *screen = new Screen(fakeOutput1);
62
63 EXPECT_EQ(screen->geometry(), QRect(0, 0, 150, 200));
64 EXPECT_EQ(screen->availableGeometry(), QRect(0, 0, 150, 200));
65 EXPECT_EQ(screen->depth(), 32);
66 EXPECT_EQ(screen->format(), QImage::Format_RGBA8888);
67 EXPECT_EQ(screen->refreshRate(), 59);
68 EXPECT_EQ(screen->physicalSize(), QSize(1111, 2222));
69 EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::dvid);
70}
71
72TEST_F(ScreenTest, ReadDifferentConfigurationFromDisplayConfig)
73{
74 Screen *screen = new Screen(fakeOutput2);
75
76 EXPECT_EQ(screen->geometry(), QRect(500, 600, 1500, 2000));
77 EXPECT_EQ(screen->availableGeometry(), QRect(500, 600, 1500, 2000));
78 EXPECT_EQ(screen->depth(), 32);
79 EXPECT_EQ(screen->format(), QImage::Format_RGBX8888);
80 EXPECT_EQ(screen->refreshRate(), 75);
81 EXPECT_EQ(screen->physicalSize(), QSize(1000, 2000));
82 EXPECT_EQ(screen->outputType(), mg::DisplayConfigurationOutputType::lvds);
83}
7084
=== added directory 'tests/mirserver/ScreenController'
=== added file 'tests/mirserver/ScreenController/CMakeLists.txt'
--- tests/mirserver/ScreenController/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/CMakeLists.txt 2015-09-09 18:37:39 +0000
@@ -0,0 +1,28 @@
1set(
2 SCREENCONTROLLER_TEST_SOURCES
3 screencontroller_test.cpp
4 ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp
5 # to be moc-ed
6 stub_screen.h
7 testable_screencontroller.h
8)
9
10include_directories(
11 ${CMAKE_SOURCE_DIR}/tests/common
12 ${CMAKE_SOURCE_DIR}/src/platforms/mirserver
13 ${CMAKE_SOURCE_DIR}/src/common
14 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
15 ${MIRSERVER_INCLUDE_DIRS}
16)
17
18add_executable(ScreenControllerTest ${SCREENCONTROLLER_TEST_SOURCES})
19
20target_link_libraries(
21 ScreenControllerTest
22 qpa-mirserver
23
24 ${GTEST_BOTH_LIBRARIES}
25 ${GMOCK_LIBRARIES}
26)
27
28add_test(ScreenController, ScreenControllerTest)
029
=== added file 'tests/mirserver/ScreenController/screencontroller_test.cpp'
--- tests/mirserver/ScreenController/screencontroller_test.cpp 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/screencontroller_test.cpp 2015-09-09 18:37:39 +0000
@@ -0,0 +1,192 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <gtest/gtest.h>
18#include "gmock_fixes.h"
19
20#include "stub_display.h"
21#include "mock_main_loop.h"
22#include "qtcompositor.h"
23#include "fake_displayconfigurationoutput.h"
24
25#include "testable_screencontroller.h"
26#include "screen.h"
27#include "screenwindow.h"
28
29#include <QGuiApplication>
30
31using namespace ::testing;
32
33namespace mg = mir::graphics;
34namespace geom = mir::geometry;
35
36class ScreenControllerTest : public ::testing::Test {
37protected:
38 void SetUp() override;
39 void TearDown() override;
40
41 ScreenController *screenController;
42 std::shared_ptr<StubDisplay> display;
43 std::shared_ptr<QtCompositor> compositor;
44 QGuiApplication *app;
45};
46
47void ScreenControllerTest::SetUp()
48{
49 setenv("QT_QPA_PLATFORM", "minimal", 1);
50 Screen::skipDBusRegistration = true;
51
52 screenController = new TestableScreenController;
53 display = std::make_shared<StubDisplay>();
54 compositor = std::make_shared<QtCompositor>();
55
56 EXPECT_CALL(*display, register_configuration_change_handler(_,_))
57 .Times(1);
58
59 static_cast<TestableScreenController*>(screenController)->do_init(display, compositor);
60
61 int argc = 0;
62 char **argv = nullptr;
63 setenv("QT_QPA_PLATFORM", "minimal", 1);
64 app = new QGuiApplication(argc, argv);
65}
66
67void ScreenControllerTest::TearDown()
68{
69 delete screenController;
70}
71
72TEST_F(ScreenControllerTest, SingleScreenFound)
73{
74 // Set up display state
75 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1};
76 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
77 display->setFakeConfiguration(config, bufferConfig);
78
79 screenController->update();
80
81 ASSERT_EQ(1, screenController->screens().count());
82 Screen* screen = screenController->screens().first();
83 EXPECT_EQ(QRect(0, 0, 150, 200), screen->geometry());
84}
85
86TEST_F(ScreenControllerTest, MultipleScreenFound)
87{
88 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2};
89 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
90 display->setFakeConfiguration(config, bufferConfig);
91
92 screenController->update();
93
94 ASSERT_EQ(2, screenController->screens().count());
95 EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry());
96 EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry());
97}
98
99TEST_F(ScreenControllerTest, ScreenAdded)
100{
101 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1};
102 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
103 display->setFakeConfiguration(config, bufferConfig);
104
105 screenController->update();
106
107 config.push_back(fakeOutput2);
108 display->setFakeConfiguration(config, bufferConfig);
109
110 ASSERT_EQ(1, screenController->screens().count());
111 EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry());
112
113 screenController->update();
114
115 ASSERT_EQ(2, screenController->screens().count());
116 EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(0)->geometry());
117 EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(1)->geometry());
118}
119
120TEST_F(ScreenControllerTest, ScreenRemoved)
121{
122 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput2, fakeOutput1};
123 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
124 display->setFakeConfiguration(config, bufferConfig);
125
126 screenController->update();
127
128 config.pop_back();
129 display->setFakeConfiguration(config, bufferConfig);
130
131 ASSERT_EQ(2, screenController->screens().count());
132 EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry());
133 EXPECT_EQ(QRect(0, 0, 150, 200), screenController->screens().at(1)->geometry());
134
135 screenController->update();
136
137 ASSERT_EQ(1, screenController->screens().count());
138 EXPECT_EQ(QRect(500, 600, 1500, 2000), screenController->screens().at(0)->geometry());
139}
140
141TEST_F(ScreenControllerTest, CheckPrioritizedGetUnusedScreen)
142{
143 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput2, fakeOutput1};
144 std::vector<MockDisplayBuffer*> bufferConfig; // only used to match buffer with display, unecessary here
145 display->setFakeConfiguration(config, bufferConfig);
146
147 screenController->update();
148
149 auto screen = screenController->getUnusedScreen();
150 EXPECT_EQ(mg::DisplayConfigurationOutputType::lvds, screen->outputType());
151}
152
153TEST_F(ScreenControllerTest, MatchBufferWithDisplay)
154{
155 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1};
156 MockDisplayBuffer buffer1;
157 std::vector<MockDisplayBuffer*> buffers {&buffer1};
158
159 geom::Rectangle buffer1Geom{{0, 0}, {150, 200}};
160 EXPECT_CALL(buffer1, view_area())
161 .WillRepeatedly(Return(buffer1Geom));
162
163 display->setFakeConfiguration(config, buffers);
164 screenController->update();
165
166 ASSERT_EQ(1, screenController->screens().count());
167 EXPECT_CALL(buffer1, make_current());
168 static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent();
169}
170
171TEST_F(ScreenControllerTest, MultipleMatchBuffersWithDisplays)
172{
173 std::vector<mg::DisplayConfigurationOutput> config{fakeOutput1, fakeOutput2};
174 MockDisplayBuffer buffer1, buffer2;
175 std::vector<MockDisplayBuffer*> buffers {&buffer1, &buffer2};
176
177 geom::Rectangle buffer1Geom{{500, 600}, {1500, 2000}};
178 geom::Rectangle buffer2Geom{{0, 0}, {150, 200}};
179 EXPECT_CALL(buffer1, view_area())
180 .WillRepeatedly(Return(buffer1Geom));
181 EXPECT_CALL(buffer2, view_area())
182 .WillRepeatedly(Return(buffer2Geom));
183
184 display->setFakeConfiguration(config, buffers);
185 screenController->update();
186
187 ASSERT_EQ(2, screenController->screens().count());
188 EXPECT_CALL(buffer1, make_current());
189 EXPECT_CALL(buffer2, make_current());
190 static_cast<StubScreen*>(screenController->screens().at(0))->makeCurrent();
191 static_cast<StubScreen*>(screenController->screens().at(1))->makeCurrent();
192}
0193
=== added file 'tests/mirserver/ScreenController/stub_display.h'
--- tests/mirserver/ScreenController/stub_display.h 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/stub_display.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,99 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef STUB_DISPLAY_H
18#define STUB_DISPLAY_H
19
20#include "mock_display.h"
21#include "mock_display_buffer.h"
22#include "mock_display_configuration.h"
23
24// C++ std lib
25#include <chrono>
26
27namespace mg = mir::graphics;
28namespace geom = mir::geometry;
29
30class StubDisplayConfiguration : public MockDisplayConfiguration
31{
32public:
33 StubDisplayConfiguration(const std::vector<mg::DisplayConfigurationOutput> &config)
34 : m_config(config)
35 {}
36
37 void for_each_output(std::function<void(mg::DisplayConfigurationOutput const&)> f) const override
38 {
39 for (auto config : m_config) {
40 f(config);
41 }
42 }
43
44private:
45 const std::vector<mg::DisplayConfigurationOutput> m_config;
46};
47
48
49class StubDisplaySyncGroup : public MockDisplaySyncGroup
50{
51public:
52 StubDisplaySyncGroup(MockDisplayBuffer *buffer) : buffer(buffer) {}
53
54 void for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f) override
55 {
56 f(*buffer);
57 }
58 std::chrono::milliseconds recommended_sleep() const
59 {
60 std::chrono::milliseconds one{1};
61 return one;
62 }
63private:
64 MockDisplayBuffer *buffer;
65};
66
67
68class StubDisplay : public MockDisplay
69{
70public:
71 // Note, GMock cannot mock functions which return non-copyable objects, so stubbing needed
72 std::unique_ptr<mg::DisplayConfiguration> configuration() const override
73 {
74 return std::unique_ptr<mg::DisplayConfiguration>(
75 new StubDisplayConfiguration(m_config)
76 );
77 }
78
79 void for_each_display_sync_group(std::function<void(mg::DisplaySyncGroup&)> const& f) override
80 {
81 for (auto displayBuffer : m_displayBuffers) {
82 StubDisplaySyncGroup b(displayBuffer);
83 f(b);
84 }
85 }
86
87 void setFakeConfiguration(std::vector<mg::DisplayConfigurationOutput> &config,
88 std::vector<MockDisplayBuffer*> &displayBuffers)
89 {
90 m_config = config;
91 m_displayBuffers = displayBuffers;
92 }
93
94private:
95 std::vector<mg::DisplayConfigurationOutput> m_config;
96 std::vector<MockDisplayBuffer*> m_displayBuffers;
97};
98
99#endif // STUB_DISPLAY_H
0100
=== added file 'tests/mirserver/ScreenController/stub_screen.h'
--- tests/mirserver/ScreenController/stub_screen.h 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/stub_screen.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef STUBSCREEN_H
18#define STUBSCREEN_H
19
20#include "screen.h"
21
22class StubScreen : public Screen
23{
24 Q_OBJECT
25public:
26 StubScreen(const mir::graphics::DisplayConfigurationOutput &output) : Screen(output) {}
27
28 void makeCurrent() { Screen::makeCurrent(); }
29};
30
31#endif // STUBSCREEN_H
032
=== added file 'tests/mirserver/ScreenController/testable_screencontroller.h'
--- tests/mirserver/ScreenController/testable_screencontroller.h 1970-01-01 00:00:00 +0000
+++ tests/mirserver/ScreenController/testable_screencontroller.h 2015-09-09 18:37:39 +0000
@@ -0,0 +1,37 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "screencontroller.h"
18#include "stub_screen.h"
19
20struct TestableScreenController : public ScreenController
21{
22 Q_OBJECT
23
24public:
25 Screen *createScreen(const mir::graphics::DisplayConfigurationOutput &output) const override
26 {
27 return new StubScreen(output);
28 }
29
30 void do_init(const std::shared_ptr<mir::graphics::Display> &display,
31 const std::shared_ptr<mir::compositor::Compositor> &compositor)
32 {
33 init(display, compositor);
34 }
35
36 void do_terminate() { terminate(); }
37};
038
=== modified file 'tests/modules/common/qtmir_test.h'
--- tests/modules/common/qtmir_test.h 2015-08-11 12:08:32 +0000
+++ tests/modules/common/qtmir_test.h 2015-09-09 18:37:39 +0000
@@ -78,7 +78,7 @@
78{78{
79public:79public:
80 FakeMirServer()80 FakeMirServer()
81 : MirServer(0, argv)81 : MirServer(0, argv, QSharedPointer<ScreenController>())
82 {82 {
83 }83 }
8484

Subscribers

People subscribed via source and target branches