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
Prerequisite: lp:~gerboland/qtmir/multimonitor
Diff against target: 862 lines (+503/-100)
18 files modified
CMakeLists.txt (+2/-2)
debian/control (+1/-1)
demos/qml-demo-shell/ResizeArea.qml (+128/-0)
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/-1)
src/modules/Unity/Application/CMakeLists.txt (+0/-1)
src/modules/Unity/Application/plugin.cpp (+8/-1)
src/platforms/mirserver/CMakeLists.txt (+5/-1)
src/platforms/mirserver/cursor.cpp (+152/-0)
src/platforms/mirserver/cursor.h (+66/-0)
src/platforms/mirserver/mirserver.cpp (+6/-0)
src/platforms/mirserver/mirsingleton.cpp (+33/-0)
src/platforms/mirserver/mirsingleton.h (+46/-0)
src/platforms/mirserver/qteventfeeder.cpp (+16/-9)
src/platforms/mirserver/qteventfeeder.h (+1/-1)
src/platforms/mirserver/screen.cpp (+6/-0)
src/platforms/mirserver/screen.h (+6/-1)
To merge this branch: bzr merge lp:~dandrader/qtmir/mousePointer
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Gerry Boland Pending
Review via email: mp+270580@code.launchpad.net

This proposal supersedes a proposal from 2015-09-01.

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

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/271608

* 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 : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

=== 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 : Posted in a previous version of this proposal

=== 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 : Posted in a previous version of this proposal

> === 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 : Posted in a previous version of this proposal

> > === 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 : Posted in a previous version of this proposal

> === 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 : Posted in a previous version of this proposal

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 : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

> > === 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 : Posted in a previous version of this proposal

Ok, moved all Cursor stuff from qtmir to unity8.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

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

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

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 : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

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
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

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
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-08-31 09:51:28 +0000
3+++ CMakeLists.txt 2015-09-22 20:40:38 +0000
4@@ -60,7 +60,7 @@
5
6 find_package(Threads REQUIRED)
7
8-pkg_check_modules(MIRSERVER mirserver>=0.14 REQUIRED)
9+pkg_check_modules(MIRSERVER mirserver>=0.15 REQUIRED)
10 pkg_check_modules(MIRCLIENT mirclient>=0.14 REQUIRED)
11
12 pkg_check_modules(GLIB glib-2.0 REQUIRED)
13@@ -74,7 +74,7 @@
14 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
15 pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED)
16 pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED)
17-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=8)
18+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=9)
19
20 include_directories(${APPLICATION_API_INCLUDE_DIRS})
21
22
23=== modified file 'debian/control'
24--- debian/control 2015-08-31 09:51:28 +0000
25+++ debian/control 2015-09-22 20:40:38 +0000
26@@ -22,7 +22,7 @@
27 libubuntu-app-launch2-dev,
28 libubuntu-application-api-dev (>= 2.1.0),
29 libudev-dev,
30- libunity-api-dev (>= 7.100),
31+ libunity-api-dev (>= 7.101),
32 liburl-dispatcher1-dev,
33 libxkbcommon-dev,
34 libxrender-dev,
35
36=== added file 'demos/qml-demo-shell/ResizeArea.qml'
37--- demos/qml-demo-shell/ResizeArea.qml 1970-01-01 00:00:00 +0000
38+++ demos/qml-demo-shell/ResizeArea.qml 2015-09-22 20:40:38 +0000
39@@ -0,0 +1,128 @@
40+import QtQuick 2.4
41+import Unity.Application 0.1
42+
43+MouseArea {
44+ id: root
45+
46+ // to be set from outside
47+ property Item target
48+ property real borderThickness
49+
50+ property bool leftBorder: false
51+ property bool rightBorder: false
52+ property bool topBorder: false
53+ property bool bottomBorder: false
54+
55+ property bool dragging: false
56+ property real startX
57+ property real startY
58+ property real startWidth
59+ property real startHeight
60+
61+ hoverEnabled: true
62+
63+ property string cursorName: {
64+ if (containsMouse || pressed) {
65+ if (leftBorder && !topBorder && !bottomBorder) {
66+ return "left_side";
67+ } else if (rightBorder && !topBorder && !bottomBorder) {
68+ return "right_side";
69+ } else if (topBorder && !leftBorder && !rightBorder) {
70+ return "top_side";
71+ } else if (bottomBorder && !leftBorder && !rightBorder) {
72+ return "bottom_side";
73+ } else if (leftBorder && topBorder) {
74+ return "top_left_corner";
75+ } else if (leftBorder && bottomBorder) {
76+ return "bottom_left_corner";
77+ } else if (rightBorder && topBorder) {
78+ return "top_right_corner";
79+ } else if (rightBorder && bottomBorder) {
80+ return "bottom_right_corner";
81+ } else {
82+ return "";
83+ }
84+ } else {
85+ return "";
86+ }
87+ }
88+ onCursorNameChanged: {
89+ Mir.cursorName = cursorName;
90+ }
91+
92+ function updateBorders() {
93+ leftBorder = mouseX <= borderThickness;
94+ rightBorder = mouseX >= width - borderThickness;
95+ topBorder = mouseY <= borderThickness;
96+ bottomBorder = mouseY >= height - borderThickness;
97+ }
98+
99+ onPressedChanged: {
100+ if (pressed) {
101+ var pos = mapToItem(target.parent, mouseX, mouseY);
102+ startX = pos.x;
103+ startY = pos.y;
104+ startWidth = target.width;
105+ startHeight = target.height;
106+ dragging = true;
107+ } else {
108+ dragging = false;
109+ if (containsMouse) {
110+ updateBorders();
111+ }
112+ }
113+ }
114+
115+ onEntered: {
116+ if (!pressed) {
117+ updateBorders();
118+ }
119+ }
120+
121+ onPositionChanged: {
122+ if (!pressed) {
123+ updateBorders();
124+ }
125+
126+ if (!dragging) {
127+ return;
128+ }
129+
130+ var pos = mapToItem(target.parent, mouse.x, mouse.y);
131+
132+ if (leftBorder) {
133+ if (startX + startWidth - pos.x > target.minWidth) {
134+ target.x = pos.x;
135+ target.width = startX + startWidth - target.x;
136+ startX = target.x;
137+ startWidth = target.width;
138+ }
139+
140+ } else if (rightBorder) {
141+ var deltaX = pos.x - startX;
142+ if (startWidth + deltaX >= target.minWidth) {
143+ target.width = startWidth + deltaX;
144+ } else {
145+ target.width = target.minWidth;
146+ }
147+ }
148+
149+ if (topBorder) {
150+ if (startY + startHeight - pos.y > target.minHeight) {
151+ target.y = pos.y;
152+ target.height = startY + startHeight - target.y;
153+ startY = target.y;
154+ startHeight = target.height;
155+ }
156+
157+ } else if (bottomBorder) {
158+ var deltaY = pos.y - startY;
159+ if (startHeight + deltaY >= target.minHeight) {
160+ target.height = startHeight + deltaY;
161+ } else {
162+ target.height = target.minHeight;
163+ }
164+ }
165+ }
166+}
167+
168
169=== modified file 'demos/qml-demo-shell/TitleBar.qml'
170--- demos/qml-demo-shell/TitleBar.qml 2015-08-24 12:43:01 +0000
171+++ demos/qml-demo-shell/TitleBar.qml 2015-09-22 20:40:38 +0000
172@@ -1,4 +1,5 @@
173-import QtQuick 2.0
174+import QtQuick 2.4
175+import Unity.Application 0.1
176
177 Rectangle {
178 id: root
179@@ -21,8 +22,10 @@
180 distanceX = pos.x;
181 distanceY = pos.y;
182 dragging = true;
183+ Mir.cursorName = "grabbing";
184 } else {
185 dragging = false;
186+ Mir.cursorName = "";
187 }
188 }
189 onMouseXChanged: {
190
191=== modified file 'demos/qml-demo-shell/Window.qml'
192--- demos/qml-demo-shell/Window.qml 2015-08-31 09:51:28 +0000
193+++ demos/qml-demo-shell/Window.qml 2015-09-22 20:40:38 +0000
194@@ -58,87 +58,10 @@
195 }
196 ]
197
198-
199- MouseArea {
200- anchors.fill: parent
201-
202- property real startX
203- property real startY
204- property real startWidth
205- property real startHeight
206- property bool leftBorder
207- property bool rightBorder
208- property bool topBorder
209- property bool bottomBorder
210- property bool dragging
211- onPressedChanged: {
212- if (pressed) {
213- var pos = mapToItem(root.parent, mouseX, mouseY);
214- startX = pos.x;
215- startY = pos.y;
216- startWidth = width;
217- startHeight = height;
218- leftBorder = mouseX > 0 && mouseX < root.borderThickness;
219- rightBorder = mouseX > (root.width - root.borderThickness) && mouseX < root.width;
220- topBorder = mouseY > 0 && mouseY < root.borderThickness;
221- bottomBorder = mouseY > (root.height - root.borderThickness) && mouseY < root.height;
222- dragging = true;
223- } else {
224- dragging = false;
225- }
226- }
227-
228- onMouseXChanged: {
229- if (!pressed || !dragging) {
230- return;
231- }
232-
233- var pos = mapToItem(root.parent, mouseX, mouseY);
234-
235- if (leftBorder) {
236-
237- if (startX + startWidth - pos.x > root.minWidth) {
238- root.x = pos.x;
239- root.width = startX + startWidth - root.x;
240- startX = root.x;
241- startWidth = root.width;
242- }
243-
244- } else if (rightBorder) {
245- var deltaX = pos.x - startX;
246- if (startWidth + deltaX >= root.minWidth) {
247- root.width = startWidth + deltaX;
248- } else {
249- root.width = root.minWidth;
250- }
251- }
252- }
253-
254- onMouseYChanged: {
255- if (!pressed || !dragging) {
256- return;
257- }
258-
259- var pos = mapToItem(root.parent, mouseX, mouseY);
260-
261- if (topBorder) {
262-
263- if (startY + startHeight - pos.y > root.minHeight) {
264- root.y = pos.y;
265- root.height = startY + startHeight - root.y;
266- startY = root.y;
267- startHeight = root.height;
268- }
269-
270- } else if (bottomBorder) {
271- var deltaY = pos.y - startY;
272- if (startHeight + deltaY >= root.minHeight) {
273- root.height = startHeight + deltaY;
274- } else {
275- root.height = root.minHeight;
276- }
277- }
278- }
279+ ResizeArea {
280+ anchors.fill: root
281+ borderThickness: root.borderThickness
282+ target: root
283 }
284
285 TitleBar {
286
287=== modified file 'demos/qml-demo-shell/qml-demo-shell.qml'
288--- demos/qml-demo-shell/qml-demo-shell.qml 2015-08-31 09:51:28 +0000
289+++ demos/qml-demo-shell/qml-demo-shell.qml 2015-09-22 20:40:38 +0000
290@@ -1,4 +1,4 @@
291-import QtQuick 2.0
292+import QtQuick 2.4
293 import Unity.Application 0.1
294
295 Rectangle {
296@@ -88,6 +88,7 @@
297 }
298
299 Rectangle {
300+ id: resizeButton
301 width: 90
302 height: 40
303 color: "blue"
304@@ -103,6 +104,23 @@
305 }
306 }
307
308+ Rectangle {
309+ width: 40
310+ height: 40
311+ color: "green"
312+ anchors { right: resizeButton.left; bottom: parent.bottom }
313+ Text {
314+ anchors.centerIn: parent
315+ text: "⟳"
316+ color: "white"
317+ font.pixelSize: 35
318+ }
319+ MouseArea {
320+ anchors.fill: parent
321+ onClicked: { root.rotation += 180; }
322+ }
323+ }
324+
325 Component {
326 id: windowStretchComponent
327 Window {
328
329=== modified file 'src/modules/Unity/Application/CMakeLists.txt'
330--- src/modules/Unity/Application/CMakeLists.txt 2015-08-31 09:51:28 +0000
331+++ src/modules/Unity/Application/CMakeLists.txt 2015-09-22 20:40:38 +0000
332@@ -91,4 +91,3 @@
333 # install
334 add_qml_plugin(Unity.Application 0.1 Unity/Application TARGETS unityapplicationplugin)
335 install(FILES com.canonical.qtmir.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas)
336-
337
338=== modified file 'src/modules/Unity/Application/plugin.cpp'
339--- src/modules/Unity/Application/plugin.cpp 2015-08-31 09:51:28 +0000
340+++ src/modules/Unity/Application/plugin.cpp 2015-09-22 20:40:38 +0000
341@@ -27,6 +27,9 @@
342 #include "sessionmanager.h"
343 #include "ubuntukeyboardinfo.h"
344
345+// platforms/mirserver
346+#include <mirsingleton.h>
347+
348 // qtmir
349 #include "logging.h"
350
351@@ -64,6 +67,10 @@
352 }
353 return UbuntuKeyboardInfo::instance();
354 }
355+
356+QObject* mirSingleton(QQmlEngine* /*engine*/, QJSEngine* /*scriptEngine*/) {
357+ return qtmir::Mir::instance();
358+}
359 } // anonymous namespace
360
361 class UnityApplicationPlugin : public QQmlExtensionPlugin {
362@@ -102,7 +109,7 @@
363 uri, 0, 1, "Session", "Session can't be instantiated from QML");
364 qmlRegisterSingletonType<qtmir::UbuntuKeyboardInfo>(
365 uri, 0, 1, "UbuntuKeyboardInfo", ubuntuKeyboardInfoSingleton);
366- qmlRegisterUncreatableType<Mir>(uri, 0, 1, "Mir", "Mir provides enum values, it can't be instantiated");
367+ qmlRegisterSingletonType<qtmir::Mir>(uri, 0, 1, "Mir", mirSingleton);
368 }
369
370 virtual void initializeEngine(QQmlEngine *engine, const char *uri)
371
372=== modified file 'src/platforms/mirserver/CMakeLists.txt'
373--- src/platforms/mirserver/CMakeLists.txt 2015-08-11 19:25:04 +0000
374+++ src/platforms/mirserver/CMakeLists.txt 2015-09-22 20:40:38 +0000
375@@ -41,7 +41,9 @@
376
377 set(MIRSERVER_QPA_PLUGIN_SRC
378 ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp
379+ cursor.cpp
380 mirwindowmanager.cpp
381+ mirsingleton.cpp
382 qteventfeeder.cpp
383 plugin.cpp
384 qmirserver.cpp
385@@ -63,6 +65,8 @@
386 ubuntutheme.cpp
387 clipboard.cpp
388 tracepoints.c
389+# We need to run moc on these headers
390+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
391 )
392
393 add_library(qpa-mirserver SHARED
394@@ -82,7 +86,7 @@
395 ${QT5PLATFORM_SUPPORT_LDFLAGS}
396 # TODO Qt5Platform support LDFLAGS dont provide actual required ldflags...
397 # I found these were needed...perhaps there is some way to query qmake/qconfig?
398- -lfreetype
399+ -lfreetype
400 ${GIO_LDFLAGS}
401 ${FONTCONFIG_LDFLAGS}
402
403
404=== added file 'src/platforms/mirserver/cursor.cpp'
405--- src/platforms/mirserver/cursor.cpp 1970-01-01 00:00:00 +0000
406+++ src/platforms/mirserver/cursor.cpp 2015-09-22 20:40:38 +0000
407@@ -0,0 +1,152 @@
408+/*
409+ * Copyright (C) 2015 Canonical, Ltd.
410+ *
411+ * This program is free software: you can redistribute it and/or modify it under
412+ * the terms of the GNU Lesser General Public License version 3, as published by
413+ * the Free Software Foundation.
414+ *
415+ * This program is distributed in the hope that it will be useful, but WITHOUT
416+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
417+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
418+ * Lesser General Public License for more details.
419+ *
420+ * You should have received a copy of the GNU Lesser General Public License
421+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
422+ *
423+ */
424+
425+#include "cursor.h"
426+#include "logging.h"
427+
428+#include "mirsingleton.h"
429+
430+// Unity API
431+#include <unity/shell/application/MirMousePointerInterface.h>
432+
433+using namespace qtmir;
434+
435+Cursor::Cursor()
436+{
437+ m_shapeToCursorName[Qt::ArrowCursor] = "left_ptr";
438+ m_shapeToCursorName[Qt::UpArrowCursor] = "up_arrow";
439+ m_shapeToCursorName[Qt::CrossCursor] = "cross";
440+ m_shapeToCursorName[Qt::WaitCursor] = "watch";
441+ m_shapeToCursorName[Qt::IBeamCursor] = "xterm";
442+ m_shapeToCursorName[Qt::SizeVerCursor] = "size_ver";
443+ m_shapeToCursorName[Qt::SizeHorCursor] = "size_hor";
444+ m_shapeToCursorName[Qt::SizeBDiagCursor] = "size_bdiag";
445+ m_shapeToCursorName[Qt::SizeFDiagCursor] = "size_fdiag";
446+ m_shapeToCursorName[Qt::SizeAllCursor] = "size_all";
447+ m_shapeToCursorName[Qt::BlankCursor] = "blank";
448+ m_shapeToCursorName[Qt::SplitVCursor] = "split_v";
449+ m_shapeToCursorName[Qt::SplitHCursor] = "split_h";
450+ m_shapeToCursorName[Qt::PointingHandCursor] = "pointing_hand";
451+ m_shapeToCursorName[Qt::ForbiddenCursor] = "forbidden";
452+ m_shapeToCursorName[Qt::WhatsThisCursor] = "whats_this";
453+ m_shapeToCursorName[Qt::BusyCursor] = "left_ptr_watch";
454+ m_shapeToCursorName[Qt::OpenHandCursor] = "openhand";
455+ m_shapeToCursorName[Qt::ClosedHandCursor] = "closedhand";
456+ m_shapeToCursorName[Qt::DragCopyCursor] = "copy";
457+ m_shapeToCursorName[Qt::DragMoveCursor] = "move";
458+ m_shapeToCursorName[Qt::DragLinkCursor] = "link";
459+
460+ connect(Mir::instance(), &Mir::cursorNameChanged, this, &Cursor::setMirCursorName);
461+}
462+
463+void Cursor::changeCursor(QCursor *windowCursor, QWindow * /*window*/)
464+{
465+ if (m_mousePointer.isNull()) {
466+ return;
467+ }
468+
469+ if (windowCursor) {
470+ m_qtCursorName = m_shapeToCursorName.value(windowCursor->shape(), QString("left_ptr"));
471+ } else {
472+ m_qtCursorName.clear();
473+ }
474+
475+ updateMousePointerCursorName();
476+}
477+
478+void Cursor::setMirCursorName(const QString &mirCursorName)
479+{
480+ m_mirCursorName = mirCursorName;
481+ updateMousePointerCursorName();
482+}
483+
484+void Cursor::setMousePointer(MirMousePointerInterface *mousePointer)
485+{
486+ QMutexLocker locker(&m_mutex);
487+
488+ if (mousePointer && !m_mousePointer.isNull()) {
489+ qFatal("QPA mirserver: Only one MousePointer per screen is allowed!");
490+ }
491+
492+ m_mousePointer = mousePointer;
493+ updateMousePointerCursorName();
494+}
495+
496+bool Cursor::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons,
497+ Qt::KeyboardModifiers modifiers)
498+{
499+ QMutexLocker locker(&m_mutex);
500+
501+ if (!m_mousePointer || !m_mousePointer->isVisible()) {
502+ return false;
503+ }
504+
505+ // Must not be called directly as we're most likely not in Qt's GUI (main) thread.
506+ bool ok = QMetaObject::invokeMethod(m_mousePointer, "handleMouseEvent", Qt::AutoConnection,
507+ Q_ARG(ulong, timestamp),
508+ Q_ARG(QPointF, movement),
509+ Q_ARG(Qt::MouseButton, buttons),
510+ Q_ARG(Qt::KeyboardModifiers, modifiers));
511+
512+ if (!ok) {
513+ qCWarning(QTMIR_MIR_INPUT) << "Failed to invoke MousePointer::handleMouseEvent";
514+ }
515+
516+ return ok;
517+}
518+
519+void Cursor::setPos(const QPoint &pos)
520+{
521+ if (!m_mousePointer) {
522+ QPlatformCursor::setPos(pos);
523+ return;
524+ }
525+
526+ QPointF movement;
527+ QPointF mouseScenePos = m_mousePointer->mapToItem(nullptr, QPointF(0, 0));
528+
529+ movement.setX(pos.x() - mouseScenePos.x());
530+ movement.setY(pos.y() - mouseScenePos.y());
531+
532+ m_mousePointer->handleMouseEvent(0 /*timestamp*/, movement, Qt::NoButton, Qt::NoModifier);
533+}
534+
535+QPoint Cursor::pos() const
536+{
537+ if (m_mousePointer) {
538+ return m_mousePointer->mapToItem(nullptr, QPointF(0, 0)).toPoint();
539+ } else {
540+ return QPlatformCursor::pos();
541+ }
542+}
543+
544+void Cursor::updateMousePointerCursorName()
545+{
546+ if (!m_mousePointer) {
547+ return;
548+ }
549+
550+ if (m_mirCursorName.isEmpty()) {
551+ if (m_qtCursorName.isEmpty()) {
552+ m_mousePointer->setCursorName("left_ptr");
553+ } else {
554+ m_mousePointer->setCursorName(m_qtCursorName);
555+ }
556+ } else {
557+ m_mousePointer->setCursorName(m_mirCursorName);
558+ }
559+}
560
561=== added file 'src/platforms/mirserver/cursor.h'
562--- src/platforms/mirserver/cursor.h 1970-01-01 00:00:00 +0000
563+++ src/platforms/mirserver/cursor.h 2015-09-22 20:40:38 +0000
564@@ -0,0 +1,66 @@
565+/*
566+ * Copyright (C) 2015 Canonical, Ltd.
567+ *
568+ * This program is free software: you can redistribute it and/or modify it under
569+ * the terms of the GNU Lesser General Public License version 3, as published by
570+ * the Free Software Foundation.
571+ *
572+ * This program is distributed in the hope that it will be useful, but WITHOUT
573+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
574+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
575+ * Lesser General Public License for more details.
576+ *
577+ * You should have received a copy of the GNU Lesser General Public License
578+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
579+ *
580+ */
581+
582+#ifndef QTMIR_CURSOR_H
583+#define QTMIR_CURSOR_H
584+
585+#include <QMutex>
586+#include <QPointer>
587+
588+// Unity API
589+#include <unity/shell/application/MirPlatformCursor.h>
590+
591+namespace qtmir {
592+
593+class Cursor : public MirPlatformCursor
594+{
595+public:
596+ Cursor();
597+
598+ // Called form Mir input thread
599+ bool handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons,
600+ Qt::KeyboardModifiers modifiers);
601+
602+ ////
603+ // MirPlatformCursor
604+
605+ // Called from Qt's GUI thread
606+ void setMousePointer(MirMousePointerInterface *mousePointer) override;
607+
608+ ////
609+ // QPlatformCursor
610+
611+ void changeCursor(QCursor *windowCursor, QWindow *window) override;
612+
613+ void setPos(const QPoint &pos) override;
614+ QPoint pos() const override;
615+
616+private Q_SLOTS:
617+ void setMirCursorName(const QString &mirCursorName);
618+
619+private:
620+ void updateMousePointerCursorName();
621+ QMutex m_mutex;
622+ QPointer<MirMousePointerInterface> m_mousePointer;
623+ QMap<int,QString> m_shapeToCursorName;
624+ QString m_qtCursorName;
625+ QString m_mirCursorName;
626+};
627+
628+} // namespace qtmir
629+
630+#endif // QTMIR_CURSOR_H
631
632=== modified file 'src/platforms/mirserver/mirserver.cpp'
633--- src/platforms/mirserver/mirserver.cpp 2015-08-11 12:08:32 +0000
634+++ src/platforms/mirserver/mirserver.cpp 2015-09-22 20:40:38 +0000
635@@ -32,6 +32,9 @@
636 // egl
637 #include <EGL/egl.h>
638
639+// mir
640+#include <mir/graphics/cursor.h>
641+
642 namespace mo = mir::options;
643 namespace msh = mir::shell;
644 namespace ms = mir::scene;
645@@ -100,6 +103,9 @@
646
647 apply_settings();
648
649+ // We will draw our own cursor.
650+ add_init_callback([this](){ the_cursor()->hide(); });
651+
652 qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created";
653 }
654
655
656=== added file 'src/platforms/mirserver/mirsingleton.cpp'
657--- src/platforms/mirserver/mirsingleton.cpp 1970-01-01 00:00:00 +0000
658+++ src/platforms/mirserver/mirsingleton.cpp 2015-09-22 20:40:38 +0000
659@@ -0,0 +1,33 @@
660+#include "mirsingleton.h"
661+
662+qtmir::Mir *qtmir::Mir::m_instance = nullptr;
663+
664+qtmir::Mir::Mir()
665+{
666+}
667+
668+qtmir::Mir::~Mir()
669+{
670+ m_instance = nullptr;
671+}
672+
673+qtmir::Mir *qtmir::Mir::instance()
674+{
675+ if (!m_instance) {
676+ m_instance = new qtmir::Mir;
677+ }
678+ return m_instance;
679+}
680+
681+void qtmir::Mir::setCursorName(const QString &cursorName)
682+{
683+ if (m_cursorName != cursorName) {
684+ m_cursorName = cursorName;
685+ Q_EMIT cursorNameChanged(m_cursorName);
686+ }
687+}
688+
689+QString qtmir::Mir::cursorName() const
690+{
691+ return m_cursorName;
692+}
693
694=== added file 'src/platforms/mirserver/mirsingleton.h'
695--- src/platforms/mirserver/mirsingleton.h 1970-01-01 00:00:00 +0000
696+++ src/platforms/mirserver/mirsingleton.h 2015-09-22 20:40:38 +0000
697@@ -0,0 +1,46 @@
698+/*
699+ * Copyright (C) 2015 Canonical, Ltd.
700+ *
701+ * This program is free software: you can redistribute it and/or modify it under
702+ * the terms of the GNU Lesser General Public License version 3, as published by
703+ * the Free Software Foundation.
704+ *
705+ * This program is distributed in the hope that it will be useful, but WITHOUT
706+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
707+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
708+ * Lesser General Public License for more details.
709+ *
710+ * You should have received a copy of the GNU Lesser General Public License
711+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
712+ */
713+
714+#ifndef QTMIR_MIRSINGLETON_H
715+#define QTMIR_MIRSINGLETON_H
716+
717+// unity-api
718+#include <unity/shell/application/Mir.h>
719+
720+namespace qtmir {
721+
722+class Mir : public ::Mir
723+{
724+ Q_OBJECT
725+public:
726+ virtual ~Mir();
727+
728+ static Mir *instance();
729+
730+ void setCursorName(const QString &cursorName) override;
731+ QString cursorName() const override;
732+
733+private:
734+ Mir();
735+ Q_DISABLE_COPY(Mir)
736+
737+ QString m_cursorName;
738+ static qtmir::Mir *m_instance;
739+};
740+
741+} // namespace qtmir
742+
743+#endif // QTMIR_MIRSINGLETON_H
744
745=== modified file 'src/platforms/mirserver/qteventfeeder.cpp'
746--- src/platforms/mirserver/qteventfeeder.cpp 2015-08-27 16:10:20 +0000
747+++ src/platforms/mirserver/qteventfeeder.cpp 2015-09-22 20:40:38 +0000
748@@ -15,7 +15,9 @@
749 */
750
751 #include "qteventfeeder.h"
752+#include "cursor.h"
753 #include "logging.h"
754+#include "screen.h"
755
756 #include <qpa/qplatforminputcontext.h>
757 #include <qpa/qplatformintegration.h>
758@@ -366,6 +368,13 @@
759 namespace {
760
761 class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {
762+public:
763+ QtWindowSystem()
764+ {
765+ // because we're using QMetaObject::invoke with arguments of those types
766+ qRegisterMetaType<Qt::KeyboardModifiers>("Qt::KeyboardModifiers");
767+ qRegisterMetaType<Qt::MouseButton>("Qt::MouseButton");
768+ }
769
770 bool hasTargetWindow() override
771 {
772@@ -404,11 +413,11 @@
773 QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods);
774 }
775
776- void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) override
777+ void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) override
778 {
779 Q_ASSERT(!mTopLevelWindow.isNull());
780- QWindowSystemInterface::handleMouseEvent(mTopLevelWindow.data(), timestamp, point, point, // local and global point are the same
781- buttons, modifiers);
782+ auto platformCursor = static_cast<qtmir::Cursor*>(mTopLevelWindow->screen()->handle()->cursor());
783+ platformCursor->handleMouseEvent(timestamp, movement, buttons, modifiers);
784 }
785
786
787@@ -518,12 +527,10 @@
788
789 auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev));
790 auto buttons = getQtMouseButtonsfromMirPointerEvent(pev);
791-
792- auto local_point = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
793- mir_pointer_event_axis_value(pev, mir_pointer_axis_y));
794-
795- mQtWindowSystem->handleMouseEvent(timestamp, local_point,
796- buttons, modifiers);
797+ auto movement = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x),
798+ mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y));
799+
800+ mQtWindowSystem->handleMouseEvent(timestamp, movement, buttons, modifiers);
801 }
802
803 void QtEventFeeder::dispatchKey(MirInputEvent const* event)
804
805=== modified file 'src/platforms/mirserver/qteventfeeder.h'
806--- src/platforms/mirserver/qteventfeeder.h 2015-08-11 12:08:32 +0000
807+++ src/platforms/mirserver/qteventfeeder.h 2015-09-22 20:40:38 +0000
808@@ -49,7 +49,7 @@
809 virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device,
810 const QList<struct QWindowSystemInterface::TouchPoint> &points,
811 Qt::KeyboardModifiers mods = Qt::NoModifier) = 0;
812- virtual void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0;
813+ virtual void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0;
814 };
815
816 QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr);
817
818=== modified file 'src/platforms/mirserver/screen.cpp'
819--- src/platforms/mirserver/screen.cpp 2015-08-11 12:08:32 +0000
820+++ src/platforms/mirserver/screen.cpp 2015-09-22 20:40:38 +0000
821@@ -226,3 +226,9 @@
822 OrientationReadingEvent::m_type,
823 m_orientationSensor->reading()->orientation()));
824 }
825+
826+QPlatformCursor *Screen::cursor() const
827+{
828+ const QPlatformCursor *platformCursor = &m_cursor;
829+ return const_cast<QPlatformCursor *>(platformCursor);
830+}
831
832=== modified file 'src/platforms/mirserver/screen.h'
833--- src/platforms/mirserver/screen.h 2015-08-11 12:08:32 +0000
834+++ src/platforms/mirserver/screen.h 2015-09-22 20:40:38 +0000
835@@ -22,7 +22,9 @@
836 #include <QtDBus/QDBusInterface>
837 #include <qpa/qplatformscreen.h>
838
839-#include "mir/graphics/display_configuration.h"
840+#include <mir/graphics/display_configuration.h>
841+
842+#include "cursor.h"
843
844 class QOrientationSensor;
845
846@@ -40,6 +42,7 @@
847 qreal refreshRate() const override { return m_refreshRate; }
848 Qt::ScreenOrientation nativeOrientation() const override { return m_nativeOrientation; }
849 Qt::ScreenOrientation orientation() const override { return m_currentOrientation; }
850+ QPlatformCursor *cursor() const override;
851
852 void toggleSensors(const bool enable) const;
853
854@@ -68,6 +71,8 @@
855 QOrientationSensor *m_orientationSensor;
856
857 QDBusInterface *m_unityScreen;
858+
859+ qtmir::Cursor m_cursor;
860 };
861
862 #endif // SCREEN_H

Subscribers

People subscribed via source and target branches