Merge lp:~dandrader/qtmir/mousePointer into lp:qtmir
- mousePointer
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Lukáš Tinkl |
Approved revision: | 380 |
Merged at revision: | 388 |
Proposed branch: | lp:~dandrader/qtmir/mousePointer |
Merge into: | lp:qtmir |
Diff against target: |
897 lines (+508/-104) 19 files modified
CMakeLists.txt (+1/-1) debian/control (+2/-2) 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 (+19/-12) src/platforms/mirserver/qteventfeeder.h (+2/-1) src/platforms/mirserver/screen.cpp (+6/-0) src/platforms/mirserver/screen.h (+6/-1) tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h (+1/-1) |
To merge this branch: | bzr merge lp:~dandrader/qtmir/mousePointer |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Lukáš Tinkl (community) | Approve | ||
Gerry Boland (community) | Approve | ||
Review via email: mp+272027@code.launchpad.net |
This proposal supersedes a proposal from 2015-09-09.
Commit message
Shell draws its own cursor using the new Cursor QML element
Description of the change
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Not applicable.
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Not applicable.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
=== added file 'src/modules/
=== added file 'src/modules/
I'm beginning to wonder if most of this code needs to live in qtmir at all. Since Unity8 draws it, why does QtMir need to do this work to find the image for it?
I also don't think it's QtMir's job to know anything about cursor themes.
Why doesn't QtMir just inform the shell of:
1. the position the cursor should be located at
2. the name of the desired cursor
Then unity8 can find the themed cursor image, figure out the hotspot and draw the cursor itself.
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
=== added file 'demos/
I like your code, neat and clean as always. But if I was writing this, I would have a single MouseArea behind the surface, instead of 8. It's ok for a demo, but that's a lot for a real shell.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> === added file 'demos/
> I like your code, neat and clean as always. But if I was writing this, I would
> have a single MouseArea behind the surface, instead of 8. It's ok for a demo,
> but that's a lot for a real shell.
If I recall correctly, the main reason was because of the MouseArea.
But later on the cursor shape enumeration proved insufficient for exposing all the different shapes unity uses, forcing me to introduce the Mir.cursorName API.
So yeah, now that I've given up using MouseArea.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> > === added file 'demos/
> > I like your code, neat and clean as always. But if I was writing this, I
> would
> > have a single MouseArea behind the surface, instead of 8. It's ok for a
> demo,
> > but that's a lot for a real shell.
>
> If I recall correctly, the main reason was because of the
> MouseArea.
> assume the given shape when hovering the mouse area. So I cannot be a single
> one.
>
> But later on the cursor shape enumeration proved insufficient for exposing all
> the different shapes unity uses, forcing me to introduce the Mir.cursorName
> API.
>
> So yeah, now that I've given up using MouseArea.
> a single mouse area.
FYI: I also copy-pasted ResizeArea.qml into unity8/mousePointer
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> === added file 'src/modules/
> === added file 'src/modules/
> I'm beginning to wonder if most of this code needs to live in qtmir at all.
> Since Unity8 draws it, why does QtMir need to do this work to find the image
> for it?
>
> I also don't think it's QtMir's job to know anything about cursor themes.
>
>
> Why doesn't QtMir just inform the shell of:
> 1. the position the cursor should be located at
> 2. the name of the desired cursor
> Then unity8 can find the themed cursor image, figure out the hotspot and draw
> the cursor itself.
Following the same rationale, one might also argue: "Why does qtmir has to know about application processes and upstart at all? let unity8 figure it out. qtmir should just spit out Sessions, MirSurfaces and MirSurfaceItems".
Also, by having this in qtmir, we pretty much shield unity8 from architectural changes down the road, once we ditch the QML cursor approach in favor of a unity-system-
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
On 02/09/15 13:16, Gerry Boland wrote:
> === added file 'demos/
> I like your code, neat and clean as always. But if I was writing this, I would have a single MouseArea behind the surface, instead of 8. It's ok for a demo, but that's a lot for a real shell.
>
>
Fixed. Will do likewise in untiy8 tomorrow.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:371
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
> > === added file 'src/modules/
> > === added file 'src/modules/
> > I'm beginning to wonder if most of this code needs to live in qtmir at all.
> > Since Unity8 draws it, why does QtMir need to do this work to find the image
> > for it?
> >
> > I also don't think it's QtMir's job to know anything about cursor themes.
> >
> >
> > Why doesn't QtMir just inform the shell of:
> > 1. the position the cursor should be located at
> > 2. the name of the desired cursor
> > Then unity8 can find the themed cursor image, figure out the hotspot and
> draw
> > the cursor itself.
>
> Following the same rationale, one might also argue: "Why does qtmir has to
> know about application processes and upstart at all? let unity8 figure it out.
> qtmir should just spit out Sessions, MirSurfaces and MirSurfaceItems".
Actually that's the longer-term goal.
https:/
Zanetti wants to move such logic into Unity itself. This will make QtMir a thin wrapper of Mir functionality for Qt users, which is a much clearer purpose than what it currently has.
If somebody would like to make their own shell, then can make use of QtMir without being forced to use upstart for instance. If they want to use upstart, then they can use the Unity.Application plugin.
> Also, by having this in qtmir, we pretty much shield unity8 from architectural
> changes down the road, once we ditch the QML cursor approach in favor of a
> unity-system-
I don't think that will happen. We need the shell to manage the cursor position, in order to do fancy things like edge-push detection, slowing cursor over buttons (a11y) or moving cursor with keyboard (a11y).
My main reasons for wanting USC to draw cursor were:
1. latency, cursor will react as quickly as possible
2. hardware compositing, cursor lives in a special hardware buffer which the hardware composites on top of everything. Means moving cursor doesn't require entire screen re-renders.
Mir team have plans for both problems
1. not use the mir protobuf for input, but have unity8 open socket with event stream coming in. Should reduce latency
2. Mir adding API to allow shell to designate certain buffers/surfaces as being hardware composable. Cursor will definitely be one of those, if available.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
Ok, moved all Cursor stuff from qtmir to unity8.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:372
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
=== modified file 'debian/copyright'
can undo this.
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.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:373
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
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:/
as there's a few conflicts, and the concept of multiple qwindows does make this more complex.
+ // We will draw our own cursor.
+ add_init_
This isn't great, as the mir cursor object is still being created. Can we replace Mir's implementation with our own one? -- not a blocker on this MR, can consider this later.
++ src/platforms/
+qtmir::Mir::~Mir()
+{
+ m_instance = nullptr;
+}
You're not deleting what you potentially "new"ed. QScopedPointer helps prevent such accidents...
+++ src/platforms/
+private:
+ Mir();
maybe http://
Using this Mir singleton to save the cursorName will do fine for now, but I'm wary of it being a dumping ground for lots of little things.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:371
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
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:/
> as there's a few conflicts, and the concept of multiple qwindows does make this more complex.
Done.
>
> + // We will draw our own cursor.
> + add_init_
> This isn't great, as the mir cursor object is still being created. Can we replace Mir's implementation with our own one? -- not a blocker on this MR, can consider this later.
This will be the u-s-c cursor, and u-s-c will always have its own cursor
no matter what, I think. Don't think it's worth investigating this idea.
>
> ++ src/platforms/
> +qtmir::Mir::~Mir()
> +{
> + m_instance = nullptr;
> +}
> You're not deleting what you potentially "new"ed. QScopedPointer helps prevent such accidents...
I am. The only place that does "new Mir" is Mir::instance() and it's
done only once. This is a simple, no-nonsense, singleton implementation
that does its job AFAICT. You want the global, static, Mir::m_instance
to be a QScopedPointer? I fail to see how would that work and how it
would be better than the current code. If you really want to see a
QScopedPointer there please give me a diff as I didn't get the point.
>
> +++ src/platforms/
> +private:
> + Mir();
> maybe http://
Done.
> Using this Mir singleton to save the cursorName will do fine for now, but I'm wary of it being a dumping ground for lots of little things.
Yes, Mir.cursorName is surely not the best solution but anything better
would require way more work. This is like a stop-gap measure. Also given
the uncertainty of the current cursor approach (as we will eventually
move to u-s-c cursor) I didn't want to invest a lot of effort on
something that could evaporate in the near term.
Daniel d'Andrada (dandrader) wrote : | # |
removed the multimonitor branch as a prerequisite as it still has issues.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:376
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Lukáš Tinkl (lukas-kde) wrote : | # |
The text input cursor (ibeam) is not mapped correctly; to xterm?
Daniel d'Andrada (dandrader) wrote : | # |
Replied to inline comment
Daniel d'Andrada (dandrader) wrote : | # |
> The text input cursor (ibeam) is not mapped correctly; to xterm?
It's mapped correctly, as I commented in the inline diff.
PS: Could please refrain from using inline comments in the future (for my MPs at least). I find it a badly implemented feature in launchpad. It's disjointed from the main comments and is kinda lost in the middle of the diff (there are hotkeys to jump between diff comments, but I find it gimmicky)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:377
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Lukáš Tinkl (lukas-kde) wrote : | # |
> > The text input cursor (ibeam) is not mapped correctly; to xterm?
>
> It's mapped correctly, as I commented in the inline diff.
I see, thanks for the explanation
> PS: Could please refrain from using inline comments in the future (for my MPs
> at least). I find it a badly implemented feature in launchpad. It's disjointed
> from the main comments and is kinda lost in the middle of the diff (there are
> hotkeys to jump between diff comments, but I find it gimmicky)
Noted
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:378
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:379
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
Have tested this with silo22, it's working good. Code is good. LGTM
Lukáš Tinkl (lukas-kde) wrote : | # |
bool Cursor:
Needs changing from Qt::MouseButton -> Qt::MouseButtons as the latter is expected by methods in QWindowSystemIn
- 380. By Daniel d'Andrada
-
s/Qt::MouseButt
on/Qt:: MouseButtons
Daniel d'Andrada (dandrader) wrote : | # |
> bool Cursor:
> Qt::MouseButton buttons,...)
>
> Needs changing from Qt::MouseButton -> Qt::MouseButtons as the latter is
> expected by methods in QWindowSystemIn
> stuff like emulating middle mouse click by pressing both left and right mouse
> buttons at once.
Fixed.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:380
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2015-09-17 20:17:17 +0000 | |||
3 | +++ CMakeLists.txt 2015-10-13 20:19:37 +0000 | |||
4 | @@ -75,7 +75,7 @@ | |||
5 | 75 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) | 75 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
6 | 76 | pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED) | 76 | pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED) |
7 | 77 | pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED) | 77 | pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED) |
9 | 78 | pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=8) | 78 | pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=9) |
10 | 79 | 79 | ||
11 | 80 | include_directories(${APPLICATION_API_INCLUDE_DIRS}) | 80 | include_directories(${APPLICATION_API_INCLUDE_DIRS}) |
12 | 81 | 81 | ||
13 | 82 | 82 | ||
14 | === modified file 'debian/control' | |||
15 | --- debian/control 2015-09-25 12:11:08 +0000 | |||
16 | +++ debian/control 2015-10-13 20:19:37 +0000 | |||
17 | @@ -23,7 +23,7 @@ | |||
18 | 23 | libubuntu-app-launch2-dev, | 23 | libubuntu-app-launch2-dev, |
19 | 24 | libubuntu-application-api-dev (>= 2.1.0), | 24 | libubuntu-application-api-dev (>= 2.1.0), |
20 | 25 | libudev-dev, | 25 | libudev-dev, |
22 | 26 | libunity-api-dev (>= 7.100), | 26 | libunity-api-dev (>= 7.101), |
23 | 27 | liburl-dispatcher1-dev, | 27 | liburl-dispatcher1-dev, |
24 | 28 | libxkbcommon-dev, | 28 | libxkbcommon-dev, |
25 | 29 | libxrender-dev, | 29 | libxrender-dev, |
26 | @@ -93,7 +93,7 @@ | |||
27 | 93 | Conflicts: libqtmir, | 93 | Conflicts: libqtmir, |
28 | 94 | libunity-mir1, | 94 | libunity-mir1, |
29 | 95 | Provides: unity-application-impl, | 95 | Provides: unity-application-impl, |
31 | 96 | unity-application-impl-8, | 96 | unity-application-impl-9, |
32 | 97 | Description: Qt plugin for Unity specific Mir APIs | 97 | Description: Qt plugin for Unity specific Mir APIs |
33 | 98 | QtMir provides Qt/QML bindings for Mir features that are exposed through the | 98 | QtMir provides Qt/QML bindings for Mir features that are exposed through the |
34 | 99 | qtmir-desktop or qtmir-android QPA plugin such as Application management | 99 | qtmir-desktop or qtmir-android QPA plugin such as Application management |
35 | 100 | 100 | ||
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-10-13 20:19:37 +0000 | |||
39 | @@ -0,0 +1,128 @@ | |||
40 | 1 | import QtQuick 2.4 | ||
41 | 2 | import Unity.Application 0.1 | ||
42 | 3 | |||
43 | 4 | MouseArea { | ||
44 | 5 | id: root | ||
45 | 6 | |||
46 | 7 | // to be set from outside | ||
47 | 8 | property Item target | ||
48 | 9 | property real borderThickness | ||
49 | 10 | |||
50 | 11 | property bool leftBorder: false | ||
51 | 12 | property bool rightBorder: false | ||
52 | 13 | property bool topBorder: false | ||
53 | 14 | property bool bottomBorder: false | ||
54 | 15 | |||
55 | 16 | property bool dragging: false | ||
56 | 17 | property real startX | ||
57 | 18 | property real startY | ||
58 | 19 | property real startWidth | ||
59 | 20 | property real startHeight | ||
60 | 21 | |||
61 | 22 | hoverEnabled: true | ||
62 | 23 | |||
63 | 24 | property string cursorName: { | ||
64 | 25 | if (containsMouse || pressed) { | ||
65 | 26 | if (leftBorder && !topBorder && !bottomBorder) { | ||
66 | 27 | return "left_side"; | ||
67 | 28 | } else if (rightBorder && !topBorder && !bottomBorder) { | ||
68 | 29 | return "right_side"; | ||
69 | 30 | } else if (topBorder && !leftBorder && !rightBorder) { | ||
70 | 31 | return "top_side"; | ||
71 | 32 | } else if (bottomBorder && !leftBorder && !rightBorder) { | ||
72 | 33 | return "bottom_side"; | ||
73 | 34 | } else if (leftBorder && topBorder) { | ||
74 | 35 | return "top_left_corner"; | ||
75 | 36 | } else if (leftBorder && bottomBorder) { | ||
76 | 37 | return "bottom_left_corner"; | ||
77 | 38 | } else if (rightBorder && topBorder) { | ||
78 | 39 | return "top_right_corner"; | ||
79 | 40 | } else if (rightBorder && bottomBorder) { | ||
80 | 41 | return "bottom_right_corner"; | ||
81 | 42 | } else { | ||
82 | 43 | return ""; | ||
83 | 44 | } | ||
84 | 45 | } else { | ||
85 | 46 | return ""; | ||
86 | 47 | } | ||
87 | 48 | } | ||
88 | 49 | onCursorNameChanged: { | ||
89 | 50 | Mir.cursorName = cursorName; | ||
90 | 51 | } | ||
91 | 52 | |||
92 | 53 | function updateBorders() { | ||
93 | 54 | leftBorder = mouseX <= borderThickness; | ||
94 | 55 | rightBorder = mouseX >= width - borderThickness; | ||
95 | 56 | topBorder = mouseY <= borderThickness; | ||
96 | 57 | bottomBorder = mouseY >= height - borderThickness; | ||
97 | 58 | } | ||
98 | 59 | |||
99 | 60 | onPressedChanged: { | ||
100 | 61 | if (pressed) { | ||
101 | 62 | var pos = mapToItem(target.parent, mouseX, mouseY); | ||
102 | 63 | startX = pos.x; | ||
103 | 64 | startY = pos.y; | ||
104 | 65 | startWidth = target.width; | ||
105 | 66 | startHeight = target.height; | ||
106 | 67 | dragging = true; | ||
107 | 68 | } else { | ||
108 | 69 | dragging = false; | ||
109 | 70 | if (containsMouse) { | ||
110 | 71 | updateBorders(); | ||
111 | 72 | } | ||
112 | 73 | } | ||
113 | 74 | } | ||
114 | 75 | |||
115 | 76 | onEntered: { | ||
116 | 77 | if (!pressed) { | ||
117 | 78 | updateBorders(); | ||
118 | 79 | } | ||
119 | 80 | } | ||
120 | 81 | |||
121 | 82 | onPositionChanged: { | ||
122 | 83 | if (!pressed) { | ||
123 | 84 | updateBorders(); | ||
124 | 85 | } | ||
125 | 86 | |||
126 | 87 | if (!dragging) { | ||
127 | 88 | return; | ||
128 | 89 | } | ||
129 | 90 | |||
130 | 91 | var pos = mapToItem(target.parent, mouse.x, mouse.y); | ||
131 | 92 | |||
132 | 93 | if (leftBorder) { | ||
133 | 94 | if (startX + startWidth - pos.x > target.minWidth) { | ||
134 | 95 | target.x = pos.x; | ||
135 | 96 | target.width = startX + startWidth - target.x; | ||
136 | 97 | startX = target.x; | ||
137 | 98 | startWidth = target.width; | ||
138 | 99 | } | ||
139 | 100 | |||
140 | 101 | } else if (rightBorder) { | ||
141 | 102 | var deltaX = pos.x - startX; | ||
142 | 103 | if (startWidth + deltaX >= target.minWidth) { | ||
143 | 104 | target.width = startWidth + deltaX; | ||
144 | 105 | } else { | ||
145 | 106 | target.width = target.minWidth; | ||
146 | 107 | } | ||
147 | 108 | } | ||
148 | 109 | |||
149 | 110 | if (topBorder) { | ||
150 | 111 | if (startY + startHeight - pos.y > target.minHeight) { | ||
151 | 112 | target.y = pos.y; | ||
152 | 113 | target.height = startY + startHeight - target.y; | ||
153 | 114 | startY = target.y; | ||
154 | 115 | startHeight = target.height; | ||
155 | 116 | } | ||
156 | 117 | |||
157 | 118 | } else if (bottomBorder) { | ||
158 | 119 | var deltaY = pos.y - startY; | ||
159 | 120 | if (startHeight + deltaY >= target.minHeight) { | ||
160 | 121 | target.height = startHeight + deltaY; | ||
161 | 122 | } else { | ||
162 | 123 | target.height = target.minHeight; | ||
163 | 124 | } | ||
164 | 125 | } | ||
165 | 126 | } | ||
166 | 127 | } | ||
167 | 128 | |||
168 | 0 | 129 | ||
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-10-13 20:19:37 +0000 | |||
172 | @@ -1,4 +1,5 @@ | |||
174 | 1 | import QtQuick 2.0 | 1 | import QtQuick 2.4 |
175 | 2 | import Unity.Application 0.1 | ||
176 | 2 | 3 | ||
177 | 3 | Rectangle { | 4 | Rectangle { |
178 | 4 | id: root | 5 | id: root |
179 | @@ -21,8 +22,10 @@ | |||
180 | 21 | distanceX = pos.x; | 22 | distanceX = pos.x; |
181 | 22 | distanceY = pos.y; | 23 | distanceY = pos.y; |
182 | 23 | dragging = true; | 24 | dragging = true; |
183 | 25 | Mir.cursorName = "grabbing"; | ||
184 | 24 | } else { | 26 | } else { |
185 | 25 | dragging = false; | 27 | dragging = false; |
186 | 28 | Mir.cursorName = ""; | ||
187 | 26 | } | 29 | } |
188 | 27 | } | 30 | } |
189 | 28 | onMouseXChanged: { | 31 | onMouseXChanged: { |
190 | 29 | 32 | ||
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-10-13 20:19:37 +0000 | |||
194 | @@ -58,87 +58,10 @@ | |||
195 | 58 | } | 58 | } |
196 | 59 | ] | 59 | ] |
197 | 60 | 60 | ||
279 | 61 | 61 | ResizeArea { | |
280 | 62 | MouseArea { | 62 | anchors.fill: root |
281 | 63 | anchors.fill: parent | 63 | borderThickness: root.borderThickness |
282 | 64 | 64 | target: root | |
202 | 65 | property real startX | ||
203 | 66 | property real startY | ||
204 | 67 | property real startWidth | ||
205 | 68 | property real startHeight | ||
206 | 69 | property bool leftBorder | ||
207 | 70 | property bool rightBorder | ||
208 | 71 | property bool topBorder | ||
209 | 72 | property bool bottomBorder | ||
210 | 73 | property bool dragging | ||
211 | 74 | onPressedChanged: { | ||
212 | 75 | if (pressed) { | ||
213 | 76 | var pos = mapToItem(root.parent, mouseX, mouseY); | ||
214 | 77 | startX = pos.x; | ||
215 | 78 | startY = pos.y; | ||
216 | 79 | startWidth = width; | ||
217 | 80 | startHeight = height; | ||
218 | 81 | leftBorder = mouseX > 0 && mouseX < root.borderThickness; | ||
219 | 82 | rightBorder = mouseX > (root.width - root.borderThickness) && mouseX < root.width; | ||
220 | 83 | topBorder = mouseY > 0 && mouseY < root.borderThickness; | ||
221 | 84 | bottomBorder = mouseY > (root.height - root.borderThickness) && mouseY < root.height; | ||
222 | 85 | dragging = true; | ||
223 | 86 | } else { | ||
224 | 87 | dragging = false; | ||
225 | 88 | } | ||
226 | 89 | } | ||
227 | 90 | |||
228 | 91 | onMouseXChanged: { | ||
229 | 92 | if (!pressed || !dragging) { | ||
230 | 93 | return; | ||
231 | 94 | } | ||
232 | 95 | |||
233 | 96 | var pos = mapToItem(root.parent, mouseX, mouseY); | ||
234 | 97 | |||
235 | 98 | if (leftBorder) { | ||
236 | 99 | |||
237 | 100 | if (startX + startWidth - pos.x > root.minWidth) { | ||
238 | 101 | root.x = pos.x; | ||
239 | 102 | root.width = startX + startWidth - root.x; | ||
240 | 103 | startX = root.x; | ||
241 | 104 | startWidth = root.width; | ||
242 | 105 | } | ||
243 | 106 | |||
244 | 107 | } else if (rightBorder) { | ||
245 | 108 | var deltaX = pos.x - startX; | ||
246 | 109 | if (startWidth + deltaX >= root.minWidth) { | ||
247 | 110 | root.width = startWidth + deltaX; | ||
248 | 111 | } else { | ||
249 | 112 | root.width = root.minWidth; | ||
250 | 113 | } | ||
251 | 114 | } | ||
252 | 115 | } | ||
253 | 116 | |||
254 | 117 | onMouseYChanged: { | ||
255 | 118 | if (!pressed || !dragging) { | ||
256 | 119 | return; | ||
257 | 120 | } | ||
258 | 121 | |||
259 | 122 | var pos = mapToItem(root.parent, mouseX, mouseY); | ||
260 | 123 | |||
261 | 124 | if (topBorder) { | ||
262 | 125 | |||
263 | 126 | if (startY + startHeight - pos.y > root.minHeight) { | ||
264 | 127 | root.y = pos.y; | ||
265 | 128 | root.height = startY + startHeight - root.y; | ||
266 | 129 | startY = root.y; | ||
267 | 130 | startHeight = root.height; | ||
268 | 131 | } | ||
269 | 132 | |||
270 | 133 | } else if (bottomBorder) { | ||
271 | 134 | var deltaY = pos.y - startY; | ||
272 | 135 | if (startHeight + deltaY >= root.minHeight) { | ||
273 | 136 | root.height = startHeight + deltaY; | ||
274 | 137 | } else { | ||
275 | 138 | root.height = root.minHeight; | ||
276 | 139 | } | ||
277 | 140 | } | ||
278 | 141 | } | ||
283 | 142 | } | 65 | } |
284 | 143 | 66 | ||
285 | 144 | TitleBar { | 67 | TitleBar { |
286 | 145 | 68 | ||
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-10-13 20:19:37 +0000 | |||
290 | @@ -1,4 +1,4 @@ | |||
292 | 1 | import QtQuick 2.0 | 1 | import QtQuick 2.4 |
293 | 2 | import Unity.Application 0.1 | 2 | import Unity.Application 0.1 |
294 | 3 | 3 | ||
295 | 4 | Rectangle { | 4 | Rectangle { |
296 | @@ -88,6 +88,7 @@ | |||
297 | 88 | } | 88 | } |
298 | 89 | 89 | ||
299 | 90 | Rectangle { | 90 | Rectangle { |
300 | 91 | id: resizeButton | ||
301 | 91 | width: 90 | 92 | width: 90 |
302 | 92 | height: 40 | 93 | height: 40 |
303 | 93 | color: "blue" | 94 | color: "blue" |
304 | @@ -103,6 +104,23 @@ | |||
305 | 103 | } | 104 | } |
306 | 104 | } | 105 | } |
307 | 105 | 106 | ||
308 | 107 | Rectangle { | ||
309 | 108 | width: 40 | ||
310 | 109 | height: 40 | ||
311 | 110 | color: "green" | ||
312 | 111 | anchors { right: resizeButton.left; bottom: parent.bottom } | ||
313 | 112 | Text { | ||
314 | 113 | anchors.centerIn: parent | ||
315 | 114 | text: "⟳" | ||
316 | 115 | color: "white" | ||
317 | 116 | font.pixelSize: 35 | ||
318 | 117 | } | ||
319 | 118 | MouseArea { | ||
320 | 119 | anchors.fill: parent | ||
321 | 120 | onClicked: { root.rotation += 180; } | ||
322 | 121 | } | ||
323 | 122 | } | ||
324 | 123 | |||
325 | 106 | Component { | 124 | Component { |
326 | 107 | id: windowStretchComponent | 125 | id: windowStretchComponent |
327 | 108 | Window { | 126 | Window { |
328 | 109 | 127 | ||
329 | === modified file 'src/modules/Unity/Application/CMakeLists.txt' | |||
330 | --- src/modules/Unity/Application/CMakeLists.txt 2015-09-17 16:17:17 +0000 | |||
331 | +++ src/modules/Unity/Application/CMakeLists.txt 2015-10-13 20:19:37 +0000 | |||
332 | @@ -92,4 +92,3 @@ | |||
333 | 92 | # install | 92 | # install |
334 | 93 | add_qml_plugin(Unity.Application 0.1 Unity/Application TARGETS unityapplicationplugin) | 93 | add_qml_plugin(Unity.Application 0.1 Unity/Application TARGETS unityapplicationplugin) |
335 | 94 | install(FILES com.canonical.qtmir.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas) | 94 | install(FILES com.canonical.qtmir.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas) |
336 | 95 | |||
337 | 96 | 95 | ||
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-10-13 20:19:37 +0000 | |||
341 | @@ -27,6 +27,9 @@ | |||
342 | 27 | #include "sessionmanager.h" | 27 | #include "sessionmanager.h" |
343 | 28 | #include "ubuntukeyboardinfo.h" | 28 | #include "ubuntukeyboardinfo.h" |
344 | 29 | 29 | ||
345 | 30 | // platforms/mirserver | ||
346 | 31 | #include <mirsingleton.h> | ||
347 | 32 | |||
348 | 30 | // qtmir | 33 | // qtmir |
349 | 31 | #include "logging.h" | 34 | #include "logging.h" |
350 | 32 | 35 | ||
351 | @@ -64,6 +67,10 @@ | |||
352 | 64 | } | 67 | } |
353 | 65 | return UbuntuKeyboardInfo::instance(); | 68 | return UbuntuKeyboardInfo::instance(); |
354 | 66 | } | 69 | } |
355 | 70 | |||
356 | 71 | QObject* mirSingleton(QQmlEngine* /*engine*/, QJSEngine* /*scriptEngine*/) { | ||
357 | 72 | return qtmir::Mir::instance(); | ||
358 | 73 | } | ||
359 | 67 | } // anonymous namespace | 74 | } // anonymous namespace |
360 | 68 | 75 | ||
361 | 69 | class UnityApplicationPlugin : public QQmlExtensionPlugin { | 76 | class UnityApplicationPlugin : public QQmlExtensionPlugin { |
362 | @@ -102,7 +109,7 @@ | |||
363 | 102 | uri, 0, 1, "Session", "Session can't be instantiated from QML"); | 109 | uri, 0, 1, "Session", "Session can't be instantiated from QML"); |
364 | 103 | qmlRegisterSingletonType<qtmir::UbuntuKeyboardInfo>( | 110 | qmlRegisterSingletonType<qtmir::UbuntuKeyboardInfo>( |
365 | 104 | uri, 0, 1, "UbuntuKeyboardInfo", ubuntuKeyboardInfoSingleton); | 111 | uri, 0, 1, "UbuntuKeyboardInfo", ubuntuKeyboardInfoSingleton); |
367 | 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); |
368 | 106 | } | 113 | } |
369 | 107 | 114 | ||
370 | 108 | virtual void initializeEngine(QQmlEngine *engine, const char *uri) | 115 | virtual void initializeEngine(QQmlEngine *engine, const char *uri) |
371 | 109 | 116 | ||
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-10-13 20:19:37 +0000 | |||
375 | @@ -41,7 +41,9 @@ | |||
376 | 41 | 41 | ||
377 | 42 | set(MIRSERVER_QPA_PLUGIN_SRC | 42 | set(MIRSERVER_QPA_PLUGIN_SRC |
378 | 43 | ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp | 43 | ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
379 | 44 | cursor.cpp | ||
380 | 44 | mirwindowmanager.cpp | 45 | mirwindowmanager.cpp |
381 | 46 | mirsingleton.cpp | ||
382 | 45 | qteventfeeder.cpp | 47 | qteventfeeder.cpp |
383 | 46 | plugin.cpp | 48 | plugin.cpp |
384 | 47 | qmirserver.cpp | 49 | qmirserver.cpp |
385 | @@ -63,6 +65,8 @@ | |||
386 | 63 | ubuntutheme.cpp | 65 | ubuntutheme.cpp |
387 | 64 | clipboard.cpp | 66 | clipboard.cpp |
388 | 65 | tracepoints.c | 67 | tracepoints.c |
389 | 68 | # We need to run moc on these headers | ||
390 | 69 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h | ||
391 | 66 | ) | 70 | ) |
392 | 67 | 71 | ||
393 | 68 | add_library(qpa-mirserver SHARED | 72 | add_library(qpa-mirserver SHARED |
394 | @@ -82,7 +86,7 @@ | |||
395 | 82 | ${QT5PLATFORM_SUPPORT_LDFLAGS} | 86 | ${QT5PLATFORM_SUPPORT_LDFLAGS} |
396 | 83 | # TODO Qt5Platform support LDFLAGS dont provide actual required ldflags... | 87 | # TODO Qt5Platform support LDFLAGS dont provide actual required ldflags... |
397 | 84 | # I found these were needed...perhaps there is some way to query qmake/qconfig? | 88 | # I found these were needed...perhaps there is some way to query qmake/qconfig? |
399 | 85 | -lfreetype | 89 | -lfreetype |
400 | 86 | ${GIO_LDFLAGS} | 90 | ${GIO_LDFLAGS} |
401 | 87 | ${FONTCONFIG_LDFLAGS} | 91 | ${FONTCONFIG_LDFLAGS} |
402 | 88 | 92 | ||
403 | 89 | 93 | ||
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-10-13 20:19:37 +0000 | |||
407 | @@ -0,0 +1,152 @@ | |||
408 | 1 | /* | ||
409 | 2 | * Copyright (C) 2015 Canonical, Ltd. | ||
410 | 3 | * | ||
411 | 4 | * This program is free software: you can redistribute it and/or modify it under | ||
412 | 5 | * the terms of the GNU Lesser General Public License version 3, as published by | ||
413 | 6 | * the Free Software Foundation. | ||
414 | 7 | * | ||
415 | 8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
416 | 9 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | ||
417 | 10 | * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
418 | 11 | * Lesser General Public License for more details. | ||
419 | 12 | * | ||
420 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
421 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
422 | 15 | * | ||
423 | 16 | */ | ||
424 | 17 | |||
425 | 18 | #include "cursor.h" | ||
426 | 19 | #include "logging.h" | ||
427 | 20 | |||
428 | 21 | #include "mirsingleton.h" | ||
429 | 22 | |||
430 | 23 | // Unity API | ||
431 | 24 | #include <unity/shell/application/MirMousePointerInterface.h> | ||
432 | 25 | |||
433 | 26 | using namespace qtmir; | ||
434 | 27 | |||
435 | 28 | Cursor::Cursor() | ||
436 | 29 | { | ||
437 | 30 | m_shapeToCursorName[Qt::ArrowCursor] = "left_ptr"; | ||
438 | 31 | m_shapeToCursorName[Qt::UpArrowCursor] = "up_arrow"; | ||
439 | 32 | m_shapeToCursorName[Qt::CrossCursor] = "cross"; | ||
440 | 33 | m_shapeToCursorName[Qt::WaitCursor] = "watch"; | ||
441 | 34 | m_shapeToCursorName[Qt::IBeamCursor] = "xterm"; | ||
442 | 35 | m_shapeToCursorName[Qt::SizeVerCursor] = "size_ver"; | ||
443 | 36 | m_shapeToCursorName[Qt::SizeHorCursor] = "size_hor"; | ||
444 | 37 | m_shapeToCursorName[Qt::SizeBDiagCursor] = "size_bdiag"; | ||
445 | 38 | m_shapeToCursorName[Qt::SizeFDiagCursor] = "size_fdiag"; | ||
446 | 39 | m_shapeToCursorName[Qt::SizeAllCursor] = "size_all"; | ||
447 | 40 | m_shapeToCursorName[Qt::BlankCursor] = "blank"; | ||
448 | 41 | m_shapeToCursorName[Qt::SplitVCursor] = "split_v"; | ||
449 | 42 | m_shapeToCursorName[Qt::SplitHCursor] = "split_h"; | ||
450 | 43 | m_shapeToCursorName[Qt::PointingHandCursor] = "pointing_hand"; | ||
451 | 44 | m_shapeToCursorName[Qt::ForbiddenCursor] = "forbidden"; | ||
452 | 45 | m_shapeToCursorName[Qt::WhatsThisCursor] = "whats_this"; | ||
453 | 46 | m_shapeToCursorName[Qt::BusyCursor] = "left_ptr_watch"; | ||
454 | 47 | m_shapeToCursorName[Qt::OpenHandCursor] = "openhand"; | ||
455 | 48 | m_shapeToCursorName[Qt::ClosedHandCursor] = "closedhand"; | ||
456 | 49 | m_shapeToCursorName[Qt::DragCopyCursor] = "copy"; | ||
457 | 50 | m_shapeToCursorName[Qt::DragMoveCursor] = "move"; | ||
458 | 51 | m_shapeToCursorName[Qt::DragLinkCursor] = "link"; | ||
459 | 52 | |||
460 | 53 | connect(Mir::instance(), &Mir::cursorNameChanged, this, &Cursor::setMirCursorName); | ||
461 | 54 | } | ||
462 | 55 | |||
463 | 56 | void Cursor::changeCursor(QCursor *windowCursor, QWindow * /*window*/) | ||
464 | 57 | { | ||
465 | 58 | if (m_mousePointer.isNull()) { | ||
466 | 59 | return; | ||
467 | 60 | } | ||
468 | 61 | |||
469 | 62 | if (windowCursor) { | ||
470 | 63 | m_qtCursorName = m_shapeToCursorName.value(windowCursor->shape(), QString("left_ptr")); | ||
471 | 64 | } else { | ||
472 | 65 | m_qtCursorName.clear(); | ||
473 | 66 | } | ||
474 | 67 | |||
475 | 68 | updateMousePointerCursorName(); | ||
476 | 69 | } | ||
477 | 70 | |||
478 | 71 | void Cursor::setMirCursorName(const QString &mirCursorName) | ||
479 | 72 | { | ||
480 | 73 | m_mirCursorName = mirCursorName; | ||
481 | 74 | updateMousePointerCursorName(); | ||
482 | 75 | } | ||
483 | 76 | |||
484 | 77 | void Cursor::setMousePointer(MirMousePointerInterface *mousePointer) | ||
485 | 78 | { | ||
486 | 79 | QMutexLocker locker(&m_mutex); | ||
487 | 80 | |||
488 | 81 | if (mousePointer && !m_mousePointer.isNull()) { | ||
489 | 82 | qFatal("QPA mirserver: Only one MousePointer per screen is allowed!"); | ||
490 | 83 | } | ||
491 | 84 | |||
492 | 85 | m_mousePointer = mousePointer; | ||
493 | 86 | updateMousePointerCursorName(); | ||
494 | 87 | } | ||
495 | 88 | |||
496 | 89 | bool Cursor::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, | ||
497 | 90 | Qt::KeyboardModifiers modifiers) | ||
498 | 91 | { | ||
499 | 92 | QMutexLocker locker(&m_mutex); | ||
500 | 93 | |||
501 | 94 | if (!m_mousePointer || !m_mousePointer->isVisible()) { | ||
502 | 95 | return false; | ||
503 | 96 | } | ||
504 | 97 | |||
505 | 98 | // Must not be called directly as we're most likely not in Qt's GUI (main) thread. | ||
506 | 99 | bool ok = QMetaObject::invokeMethod(m_mousePointer, "handleMouseEvent", Qt::AutoConnection, | ||
507 | 100 | Q_ARG(ulong, timestamp), | ||
508 | 101 | Q_ARG(QPointF, movement), | ||
509 | 102 | Q_ARG(Qt::MouseButtons, buttons), | ||
510 | 103 | Q_ARG(Qt::KeyboardModifiers, modifiers)); | ||
511 | 104 | |||
512 | 105 | if (!ok) { | ||
513 | 106 | qCWarning(QTMIR_MIR_INPUT) << "Failed to invoke MousePointer::handleMouseEvent"; | ||
514 | 107 | } | ||
515 | 108 | |||
516 | 109 | return ok; | ||
517 | 110 | } | ||
518 | 111 | |||
519 | 112 | void Cursor::setPos(const QPoint &pos) | ||
520 | 113 | { | ||
521 | 114 | if (!m_mousePointer) { | ||
522 | 115 | QPlatformCursor::setPos(pos); | ||
523 | 116 | return; | ||
524 | 117 | } | ||
525 | 118 | |||
526 | 119 | QPointF movement; | ||
527 | 120 | QPointF mouseScenePos = m_mousePointer->mapToItem(nullptr, QPointF(0, 0)); | ||
528 | 121 | |||
529 | 122 | movement.setX(pos.x() - mouseScenePos.x()); | ||
530 | 123 | movement.setY(pos.y() - mouseScenePos.y()); | ||
531 | 124 | |||
532 | 125 | m_mousePointer->handleMouseEvent(0 /*timestamp*/, movement, Qt::NoButton, Qt::NoModifier); | ||
533 | 126 | } | ||
534 | 127 | |||
535 | 128 | QPoint Cursor::pos() const | ||
536 | 129 | { | ||
537 | 130 | if (m_mousePointer) { | ||
538 | 131 | return m_mousePointer->mapToItem(nullptr, QPointF(0, 0)).toPoint(); | ||
539 | 132 | } else { | ||
540 | 133 | return QPlatformCursor::pos(); | ||
541 | 134 | } | ||
542 | 135 | } | ||
543 | 136 | |||
544 | 137 | void Cursor::updateMousePointerCursorName() | ||
545 | 138 | { | ||
546 | 139 | if (!m_mousePointer) { | ||
547 | 140 | return; | ||
548 | 141 | } | ||
549 | 142 | |||
550 | 143 | if (m_mirCursorName.isEmpty()) { | ||
551 | 144 | if (m_qtCursorName.isEmpty()) { | ||
552 | 145 | m_mousePointer->setCursorName("left_ptr"); | ||
553 | 146 | } else { | ||
554 | 147 | m_mousePointer->setCursorName(m_qtCursorName); | ||
555 | 148 | } | ||
556 | 149 | } else { | ||
557 | 150 | m_mousePointer->setCursorName(m_mirCursorName); | ||
558 | 151 | } | ||
559 | 152 | } | ||
560 | 0 | 153 | ||
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-10-13 20:19:37 +0000 | |||
564 | @@ -0,0 +1,66 @@ | |||
565 | 1 | /* | ||
566 | 2 | * Copyright (C) 2015 Canonical, Ltd. | ||
567 | 3 | * | ||
568 | 4 | * This program is free software: you can redistribute it and/or modify it under | ||
569 | 5 | * the terms of the GNU Lesser General Public License version 3, as published by | ||
570 | 6 | * the Free Software Foundation. | ||
571 | 7 | * | ||
572 | 8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
573 | 9 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | ||
574 | 10 | * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
575 | 11 | * Lesser General Public License for more details. | ||
576 | 12 | * | ||
577 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
578 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
579 | 15 | * | ||
580 | 16 | */ | ||
581 | 17 | |||
582 | 18 | #ifndef QTMIR_CURSOR_H | ||
583 | 19 | #define QTMIR_CURSOR_H | ||
584 | 20 | |||
585 | 21 | #include <QMutex> | ||
586 | 22 | #include <QPointer> | ||
587 | 23 | |||
588 | 24 | // Unity API | ||
589 | 25 | #include <unity/shell/application/MirPlatformCursor.h> | ||
590 | 26 | |||
591 | 27 | namespace qtmir { | ||
592 | 28 | |||
593 | 29 | class Cursor : public MirPlatformCursor | ||
594 | 30 | { | ||
595 | 31 | public: | ||
596 | 32 | Cursor(); | ||
597 | 33 | |||
598 | 34 | // Called form Mir input thread | ||
599 | 35 | bool handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, | ||
600 | 36 | Qt::KeyboardModifiers modifiers); | ||
601 | 37 | |||
602 | 38 | //// | ||
603 | 39 | // MirPlatformCursor | ||
604 | 40 | |||
605 | 41 | // Called from Qt's GUI thread | ||
606 | 42 | void setMousePointer(MirMousePointerInterface *mousePointer) override; | ||
607 | 43 | |||
608 | 44 | //// | ||
609 | 45 | // QPlatformCursor | ||
610 | 46 | |||
611 | 47 | void changeCursor(QCursor *windowCursor, QWindow *window) override; | ||
612 | 48 | |||
613 | 49 | void setPos(const QPoint &pos) override; | ||
614 | 50 | QPoint pos() const override; | ||
615 | 51 | |||
616 | 52 | private Q_SLOTS: | ||
617 | 53 | void setMirCursorName(const QString &mirCursorName); | ||
618 | 54 | |||
619 | 55 | private: | ||
620 | 56 | void updateMousePointerCursorName(); | ||
621 | 57 | QMutex m_mutex; | ||
622 | 58 | QPointer<MirMousePointerInterface> m_mousePointer; | ||
623 | 59 | QMap<int,QString> m_shapeToCursorName; | ||
624 | 60 | QString m_qtCursorName; | ||
625 | 61 | QString m_mirCursorName; | ||
626 | 62 | }; | ||
627 | 63 | |||
628 | 64 | } // namespace qtmir | ||
629 | 65 | |||
630 | 66 | #endif // QTMIR_CURSOR_H | ||
631 | 0 | 67 | ||
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-10-13 20:19:37 +0000 | |||
635 | @@ -32,6 +32,9 @@ | |||
636 | 32 | // egl | 32 | // egl |
637 | 33 | #include <EGL/egl.h> | 33 | #include <EGL/egl.h> |
638 | 34 | 34 | ||
639 | 35 | // mir | ||
640 | 36 | #include <mir/graphics/cursor.h> | ||
641 | 37 | |||
642 | 35 | namespace mo = mir::options; | 38 | namespace mo = mir::options; |
643 | 36 | namespace msh = mir::shell; | 39 | namespace msh = mir::shell; |
644 | 37 | namespace ms = mir::scene; | 40 | namespace ms = mir::scene; |
645 | @@ -100,6 +103,9 @@ | |||
646 | 100 | 103 | ||
647 | 101 | apply_settings(); | 104 | apply_settings(); |
648 | 102 | 105 | ||
649 | 106 | // We will draw our own cursor. | ||
650 | 107 | add_init_callback([this](){ the_cursor()->hide(); }); | ||
651 | 108 | |||
652 | 103 | qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created"; | 109 | qCDebug(QTMIR_MIR_MESSAGES) << "MirServer created"; |
653 | 104 | } | 110 | } |
654 | 105 | 111 | ||
655 | 106 | 112 | ||
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-10-13 20:19:37 +0000 | |||
659 | @@ -0,0 +1,33 @@ | |||
660 | 1 | #include "mirsingleton.h" | ||
661 | 2 | |||
662 | 3 | qtmir::Mir *qtmir::Mir::m_instance = nullptr; | ||
663 | 4 | |||
664 | 5 | qtmir::Mir::Mir() | ||
665 | 6 | { | ||
666 | 7 | } | ||
667 | 8 | |||
668 | 9 | qtmir::Mir::~Mir() | ||
669 | 10 | { | ||
670 | 11 | m_instance = nullptr; | ||
671 | 12 | } | ||
672 | 13 | |||
673 | 14 | qtmir::Mir *qtmir::Mir::instance() | ||
674 | 15 | { | ||
675 | 16 | if (!m_instance) { | ||
676 | 17 | m_instance = new qtmir::Mir; | ||
677 | 18 | } | ||
678 | 19 | return m_instance; | ||
679 | 20 | } | ||
680 | 21 | |||
681 | 22 | void qtmir::Mir::setCursorName(const QString &cursorName) | ||
682 | 23 | { | ||
683 | 24 | if (m_cursorName != cursorName) { | ||
684 | 25 | m_cursorName = cursorName; | ||
685 | 26 | Q_EMIT cursorNameChanged(m_cursorName); | ||
686 | 27 | } | ||
687 | 28 | } | ||
688 | 29 | |||
689 | 30 | QString qtmir::Mir::cursorName() const | ||
690 | 31 | { | ||
691 | 32 | return m_cursorName; | ||
692 | 33 | } | ||
693 | 0 | 34 | ||
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-10-13 20:19:37 +0000 | |||
697 | @@ -0,0 +1,46 @@ | |||
698 | 1 | /* | ||
699 | 2 | * Copyright (C) 2015 Canonical, Ltd. | ||
700 | 3 | * | ||
701 | 4 | * This program is free software: you can redistribute it and/or modify it under | ||
702 | 5 | * the terms of the GNU Lesser General Public License version 3, as published by | ||
703 | 6 | * the Free Software Foundation. | ||
704 | 7 | * | ||
705 | 8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
706 | 9 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | ||
707 | 10 | * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
708 | 11 | * Lesser General Public License for more details. | ||
709 | 12 | * | ||
710 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
711 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
712 | 15 | */ | ||
713 | 16 | |||
714 | 17 | #ifndef QTMIR_MIRSINGLETON_H | ||
715 | 18 | #define QTMIR_MIRSINGLETON_H | ||
716 | 19 | |||
717 | 20 | // unity-api | ||
718 | 21 | #include <unity/shell/application/Mir.h> | ||
719 | 22 | |||
720 | 23 | namespace qtmir { | ||
721 | 24 | |||
722 | 25 | class Mir : public ::Mir | ||
723 | 26 | { | ||
724 | 27 | Q_OBJECT | ||
725 | 28 | public: | ||
726 | 29 | virtual ~Mir(); | ||
727 | 30 | |||
728 | 31 | static Mir *instance(); | ||
729 | 32 | |||
730 | 33 | void setCursorName(const QString &cursorName) override; | ||
731 | 34 | QString cursorName() const override; | ||
732 | 35 | |||
733 | 36 | private: | ||
734 | 37 | Mir(); | ||
735 | 38 | Q_DISABLE_COPY(Mir) | ||
736 | 39 | |||
737 | 40 | QString m_cursorName; | ||
738 | 41 | static qtmir::Mir *m_instance; | ||
739 | 42 | }; | ||
740 | 43 | |||
741 | 44 | } // namespace qtmir | ||
742 | 45 | |||
743 | 46 | #endif // QTMIR_MIRSINGLETON_H | ||
744 | 0 | 47 | ||
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-10-13 20:19:37 +0000 | |||
748 | @@ -15,7 +15,9 @@ | |||
749 | 15 | */ | 15 | */ |
750 | 16 | 16 | ||
751 | 17 | #include "qteventfeeder.h" | 17 | #include "qteventfeeder.h" |
752 | 18 | #include "cursor.h" | ||
753 | 18 | #include "logging.h" | 19 | #include "logging.h" |
754 | 20 | #include "screen.h" | ||
755 | 19 | 21 | ||
756 | 20 | #include <qpa/qplatforminputcontext.h> | 22 | #include <qpa/qplatforminputcontext.h> |
757 | 21 | #include <qpa/qplatformintegration.h> | 23 | #include <qpa/qplatformintegration.h> |
758 | @@ -366,6 +368,13 @@ | |||
759 | 366 | namespace { | 368 | namespace { |
760 | 367 | 369 | ||
761 | 368 | class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface { | 370 | class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface { |
762 | 371 | public: | ||
763 | 372 | QtWindowSystem() | ||
764 | 373 | { | ||
765 | 374 | // because we're using QMetaObject::invoke with arguments of those types | ||
766 | 375 | qRegisterMetaType<Qt::KeyboardModifiers>("Qt::KeyboardModifiers"); | ||
767 | 376 | qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons"); | ||
768 | 377 | } | ||
769 | 369 | 378 | ||
770 | 370 | bool hasTargetWindow() override | 379 | bool hasTargetWindow() override |
771 | 371 | { | 380 | { |
772 | @@ -404,11 +413,11 @@ | |||
773 | 404 | QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods); | 413 | QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods); |
774 | 405 | } | 414 | } |
775 | 406 | 415 | ||
777 | 407 | void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) override | 416 | void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) override |
778 | 408 | { | 417 | { |
779 | 409 | Q_ASSERT(!mTopLevelWindow.isNull()); | 418 | Q_ASSERT(!mTopLevelWindow.isNull()); |
782 | 410 | QWindowSystemInterface::handleMouseEvent(mTopLevelWindow.data(), timestamp, point, point, // local and global point are the same | 419 | auto platformCursor = static_cast<qtmir::Cursor*>(mTopLevelWindow->screen()->handle()->cursor()); |
783 | 411 | buttons, modifiers); | 420 | platformCursor->handleMouseEvent(timestamp, movement, buttons, modifiers); |
784 | 412 | } | 421 | } |
785 | 413 | 422 | ||
786 | 414 | 423 | ||
787 | @@ -488,9 +497,9 @@ | |||
788 | 488 | return static_cast<Qt::KeyboardModifiers>(qtModifiers); | 497 | return static_cast<Qt::KeyboardModifiers>(qtModifiers); |
789 | 489 | } | 498 | } |
790 | 490 | 499 | ||
792 | 491 | Qt::MouseButton getQtMouseButtonsfromMirPointerEvent(MirPointerEvent const* pev) | 500 | Qt::MouseButtons getQtMouseButtonsfromMirPointerEvent(MirPointerEvent const* pev) |
793 | 492 | { | 501 | { |
795 | 493 | int buttons = Qt::NoButton; | 502 | Qt::MouseButtons buttons = Qt::NoButton; |
796 | 494 | if (mir_pointer_event_button_state(pev, mir_pointer_button_primary)) | 503 | if (mir_pointer_event_button_state(pev, mir_pointer_button_primary)) |
797 | 495 | buttons |= Qt::LeftButton; | 504 | buttons |= Qt::LeftButton; |
798 | 496 | if (mir_pointer_event_button_state(pev, mir_pointer_button_secondary)) | 505 | if (mir_pointer_event_button_state(pev, mir_pointer_button_secondary)) |
799 | @@ -502,7 +511,7 @@ | |||
800 | 502 | if (mir_pointer_event_button_state(pev, mir_pointer_button_forward)) | 511 | if (mir_pointer_event_button_state(pev, mir_pointer_button_forward)) |
801 | 503 | buttons |= Qt::ForwardButton; | 512 | buttons |= Qt::ForwardButton; |
802 | 504 | 513 | ||
804 | 505 | return static_cast<Qt::MouseButton>(buttons); | 514 | return buttons; |
805 | 506 | } | 515 | } |
806 | 507 | } | 516 | } |
807 | 508 | 517 | ||
808 | @@ -518,12 +527,10 @@ | |||
809 | 518 | 527 | ||
810 | 519 | auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev)); | 528 | auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev)); |
811 | 520 | auto buttons = getQtMouseButtonsfromMirPointerEvent(pev); | 529 | auto buttons = getQtMouseButtonsfromMirPointerEvent(pev); |
818 | 521 | 530 | auto movement = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x), | |
819 | 522 | auto local_point = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), | 531 | mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y)); |
820 | 523 | mir_pointer_event_axis_value(pev, mir_pointer_axis_y)); | 532 | |
821 | 524 | 533 | mQtWindowSystem->handleMouseEvent(timestamp, movement, buttons, modifiers); | |
816 | 525 | mQtWindowSystem->handleMouseEvent(timestamp, local_point, | ||
817 | 526 | buttons, modifiers); | ||
822 | 527 | } | 534 | } |
823 | 528 | 535 | ||
824 | 529 | void QtEventFeeder::dispatchKey(MirInputEvent const* event) | 536 | void QtEventFeeder::dispatchKey(MirInputEvent const* event) |
825 | 530 | 537 | ||
826 | === modified file 'src/platforms/mirserver/qteventfeeder.h' | |||
827 | --- src/platforms/mirserver/qteventfeeder.h 2015-08-11 12:08:32 +0000 | |||
828 | +++ src/platforms/mirserver/qteventfeeder.h 2015-10-13 20:19:37 +0000 | |||
829 | @@ -49,7 +49,8 @@ | |||
830 | 49 | virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device, | 49 | virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device, |
831 | 50 | const QList<struct QWindowSystemInterface::TouchPoint> &points, | 50 | const QList<struct QWindowSystemInterface::TouchPoint> &points, |
832 | 51 | Qt::KeyboardModifiers mods = Qt::NoModifier) = 0; | 51 | Qt::KeyboardModifiers mods = Qt::NoModifier) = 0; |
834 | 52 | virtual void handleMouseEvent(ulong timestamp, QPointF point, Qt::MouseButton buttons, Qt::KeyboardModifiers modifiers) = 0; | 52 | virtual void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, |
835 | 53 | Qt::KeyboardModifiers modifiers) = 0; | ||
836 | 53 | }; | 54 | }; |
837 | 54 | 55 | ||
838 | 55 | QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr); | 56 | QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr); |
839 | 56 | 57 | ||
840 | === modified file 'src/platforms/mirserver/screen.cpp' | |||
841 | --- src/platforms/mirserver/screen.cpp 2015-08-11 12:08:32 +0000 | |||
842 | +++ src/platforms/mirserver/screen.cpp 2015-10-13 20:19:37 +0000 | |||
843 | @@ -226,3 +226,9 @@ | |||
844 | 226 | OrientationReadingEvent::m_type, | 226 | OrientationReadingEvent::m_type, |
845 | 227 | m_orientationSensor->reading()->orientation())); | 227 | m_orientationSensor->reading()->orientation())); |
846 | 228 | } | 228 | } |
847 | 229 | |||
848 | 230 | QPlatformCursor *Screen::cursor() const | ||
849 | 231 | { | ||
850 | 232 | const QPlatformCursor *platformCursor = &m_cursor; | ||
851 | 233 | return const_cast<QPlatformCursor *>(platformCursor); | ||
852 | 234 | } | ||
853 | 229 | 235 | ||
854 | === modified file 'src/platforms/mirserver/screen.h' | |||
855 | --- src/platforms/mirserver/screen.h 2015-08-11 12:08:32 +0000 | |||
856 | +++ src/platforms/mirserver/screen.h 2015-10-13 20:19:37 +0000 | |||
857 | @@ -22,7 +22,9 @@ | |||
858 | 22 | #include <QtDBus/QDBusInterface> | 22 | #include <QtDBus/QDBusInterface> |
859 | 23 | #include <qpa/qplatformscreen.h> | 23 | #include <qpa/qplatformscreen.h> |
860 | 24 | 24 | ||
862 | 25 | #include "mir/graphics/display_configuration.h" | 25 | #include <mir/graphics/display_configuration.h> |
863 | 26 | |||
864 | 27 | #include "cursor.h" | ||
865 | 26 | 28 | ||
866 | 27 | class QOrientationSensor; | 29 | class QOrientationSensor; |
867 | 28 | 30 | ||
868 | @@ -40,6 +42,7 @@ | |||
869 | 40 | qreal refreshRate() const override { return m_refreshRate; } | 42 | qreal refreshRate() const override { return m_refreshRate; } |
870 | 41 | Qt::ScreenOrientation nativeOrientation() const override { return m_nativeOrientation; } | 43 | Qt::ScreenOrientation nativeOrientation() const override { return m_nativeOrientation; } |
871 | 42 | Qt::ScreenOrientation orientation() const override { return m_currentOrientation; } | 44 | Qt::ScreenOrientation orientation() const override { return m_currentOrientation; } |
872 | 45 | QPlatformCursor *cursor() const override; | ||
873 | 43 | 46 | ||
874 | 44 | void toggleSensors(const bool enable) const; | 47 | void toggleSensors(const bool enable) const; |
875 | 45 | 48 | ||
876 | @@ -68,6 +71,8 @@ | |||
877 | 68 | QOrientationSensor *m_orientationSensor; | 71 | QOrientationSensor *m_orientationSensor; |
878 | 69 | 72 | ||
879 | 70 | QDBusInterface *m_unityScreen; | 73 | QDBusInterface *m_unityScreen; |
880 | 74 | |||
881 | 75 | qtmir::Cursor m_cursor; | ||
882 | 71 | }; | 76 | }; |
883 | 72 | 77 | ||
884 | 73 | #endif // SCREEN_H | 78 | #endif // SCREEN_H |
885 | 74 | 79 | ||
886 | === modified file 'tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h' | |||
887 | --- tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-04-01 15:02:36 +0000 | |||
888 | +++ tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2015-10-13 20:19:37 +0000 | |||
889 | @@ -34,7 +34,7 @@ | |||
890 | 34 | MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device, | 34 | MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device, |
891 | 35 | const QList<struct QWindowSystemInterface::TouchPoint> &points, | 35 | const QList<struct QWindowSystemInterface::TouchPoint> &points, |
892 | 36 | Qt::KeyboardModifiers mods)); | 36 | Qt::KeyboardModifiers mods)); |
894 | 37 | MOCK_METHOD4(handleMouseEvent, void(ulong, QPointF, Qt::MouseButton, Qt::KeyboardModifiers)); | 37 | MOCK_METHOD4(handleMouseEvent, void(ulong, QPointF, Qt::MouseButtons, Qt::KeyboardModifiers)); |
895 | 38 | }; | 38 | }; |
896 | 39 | 39 | ||
897 | 40 | namespace testing | 40 | namespace testing |
FAILED: Continuous integration, rev:370 jenkins. qa.ubuntu. com/job/ qtmir-ci/ 386/ jenkins. qa.ubuntu. com/job/ qtmir-wily- amd64-ci/ 119/console jenkins. qa.ubuntu. com/job/ qtmir-wily- armhf-ci/ 119/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/qtmir- ci/386/ rebuild
http://