Mir

Merge lp:~andreas-pokorny/mir/cursor-position-on-rotated-output into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Approved by: Kevin DuBois
Approved revision: no longer in the source branch.
Merged at revision: 1446
Proposed branch: lp:~andreas-pokorny/mir/cursor-position-on-rotated-output
Merge into: lp:mir
Diff against target: 270 lines (+115/-18)
3 files modified
src/platform/graphics/mesa/cursor.cpp (+26/-15)
src/platform/graphics/mesa/cursor.h (+2/-1)
tests/unit-tests/graphics/mesa/test_cursor.cpp (+87/-2)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/cursor-position-on-rotated-output
Reviewer Review Type Date Requested Status
Alan Griffiths Approve
Daniel van Vugt Approve
PS Jenkins bot (community) continuous-integration Approve
Robert Carr (community) Approve
Review via email: mp+209076@code.launchpad.net

Commit message

This change updates the cursor position according to the orientation of the output.

Still outstanding is a rotation of the cursor image itself.

Description of the change

Uses the rotated rectangle for bounds checking in mesa cursor and transforms the position offset that falls within the rectangle according to the orientation. This still does not provide a rotated cursor image.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

LGTM.

The MesaCursor tests might look a little nicer if the constants in: 13 +
214 + EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{112,100}));
215 + EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{150,96}));
216 +
217 + cursor.move_to({766, 112});
218 + cursor.move_to({770, 150});

et al were written symbolically (i.e. in terms of output width and cursor movement vectors)

Whitespace at 239

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Nice. Works for me. :)

This function:
21 +geom::Displacement transform(geom::Rectangle const& rect, geom::Displacement const& vector, MirOrientation orientation)
appears complicated but I think it needs to be.

P.S. I lobbied for the wrapped int types to be pure ints a while back. That would eliminate all the "as_int()" calls. But I was out-voted.

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

P.S. About rotating the cursor image -- Just rotating the image won't be enough. You would have to rotate it around the hotspot. Even right now while you can't change the hotspot (bug 1189775), simply rotating the image we load would put the cursor in the wrong place.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

25 + case mir_orientation_left:
26 + return {vector.dy.as_int(), rect.size.width.as_int() -vector.dx.as_int()};
27 + case mir_orientation_inverted:
28 + return {rect.size.width.as_int() -vector.dx.as_int(), rect.size.height.as_int() - vector.dy.as_int()};
29 + case mir_orientation_right:
30 + return {rect.size.height.as_int() -vector.dy.as_int(), vector.dx.as_int()};

Maybe it is time we added enough matrix algebra to our geometry component to write:

   return geom::rotate(geom::degrees(90)) * vector;

etc. And stopped writing as_int() all over the domain code.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/platform/graphics/mesa/cursor.cpp'
2--- src/platform/graphics/mesa/cursor.cpp 2014-01-22 10:03:11 +0000
3+++ src/platform/graphics/mesa/cursor.cpp 2014-03-03 16:21:52 +0000
4@@ -28,15 +28,32 @@
5 #include <stdexcept>
6 #include <vector>
7
8+namespace mgm = mir::graphics::mesa;
9+namespace geom = mir::geometry;
10+
11 namespace
12 {
13 #include "black_arrow.c"
14 int const width = black_arrow.width;
15 int const height = black_arrow.height;
16-}
17
18-namespace mgm = mir::graphics::mesa;
19-namespace geom = mir::geometry;
20+// Transforms a relative position within the display bounds described by \a rect which is rotated with \a orientation
21+geom::Displacement transform(geom::Rectangle const& rect, geom::Displacement const& vector, MirOrientation orientation)
22+{
23+ switch(orientation)
24+ {
25+ case mir_orientation_left:
26+ return {vector.dy.as_int(), rect.size.width.as_int() -vector.dx.as_int()};
27+ case mir_orientation_inverted:
28+ return {rect.size.width.as_int() -vector.dx.as_int(), rect.size.height.as_int() - vector.dy.as_int()};
29+ case mir_orientation_right:
30+ return {rect.size.height.as_int() -vector.dy.as_int(), vector.dx.as_int()};
31+ default:
32+ case mir_orientation_normal:
33+ return vector;
34+ }
35+}
36+}
37
38 mgm::Cursor::GBMBOWrapper::GBMBOWrapper(gbm_device* gbm) :
39 buffer(gbm_bo_create(
40@@ -103,7 +120,7 @@
41 }
42
43 void mgm::Cursor::for_each_used_output(
44- std::function<void(KMSOutput&, geom::Rectangle const&)> const& f)
45+ std::function<void(KMSOutput&, geom::Rectangle const&, MirOrientation orientation)> const& f)
46 {
47 current_configuration->with_current_configuration_do(
48 [this,&f](KMSDisplayConfiguration const& kms_conf)
49@@ -115,13 +132,7 @@
50 uint32_t const connector_id = kms_conf.get_kms_connector_id(conf_output.id);
51 auto output = output_container.get_kms_output_for(connector_id);
52
53- // TODO: Cursor rotation support (conf_output.extents())
54- geom::Rectangle output_rect
55- {
56- conf_output.top_left,
57- conf_output.modes[conf_output.current_mode_index].size
58- };
59- f(*output, output_rect);
60+ f(*output, conf_output.extents(), conf_output.orientation);
61 }
62 });
63 });
64@@ -131,15 +142,15 @@
65 geometry::Point position,
66 ForceCursorState force_state)
67 {
68- for_each_used_output([&](KMSOutput& output, geom::Rectangle const& output_rect)
69+ for_each_used_output([&](KMSOutput& output, geom::Rectangle const& output_rect, MirOrientation orientation)
70 {
71 if (output_rect.contains(position))
72 {
73- auto dp = position - output_rect.top_left;
74+ auto dp = transform(output_rect, position - output_rect.top_left, orientation);
75 output.move_cursor({dp.dx.as_int(), dp.dy.as_int()});
76- if (force_state || !output.has_cursor())
77+ if (force_state || !output.has_cursor()) // TODO - or if orientation had changed - then set buffer..
78 {
79- output.set_cursor(buffer);
80+ output.set_cursor(buffer);// TODO - select rotated buffer image
81 }
82 }
83 else
84
85=== modified file 'src/platform/graphics/mesa/cursor.h'
86--- src/platform/graphics/mesa/cursor.h 2014-01-22 10:03:11 +0000
87+++ src/platform/graphics/mesa/cursor.h 2014-03-03 16:21:52 +0000
88@@ -21,6 +21,7 @@
89 #define MIR_GRAPHICS_MESA_CURSOR_H_
90
91 #include "mir/graphics/cursor.h"
92+#include "mir_toolkit/common.h"
93
94 #include <gbm.h>
95 #include <memory>
96@@ -73,7 +74,7 @@
97
98 private:
99 enum ForceCursorState { UpdateState, ForceState };
100- void for_each_used_output(std::function<void(KMSOutput&, geometry::Rectangle const&)> const& f);
101+ void for_each_used_output(std::function<void(KMSOutput&, geometry::Rectangle const&, MirOrientation orientation)> const& f);
102 void place_cursor_at(geometry::Point position, ForceCursorState force_state);
103
104 KMSOutputContainer& output_container;
105
106=== modified file 'tests/unit-tests/graphics/mesa/test_cursor.cpp'
107--- tests/unit-tests/graphics/mesa/test_cursor.cpp 2014-02-13 09:38:32 +0000
108+++ tests/unit-tests/graphics/mesa/test_cursor.cpp 2014-03-03 16:21:52 +0000
109@@ -22,12 +22,14 @@
110 #include "src/platform/graphics/mesa/kms_display_configuration.h"
111
112 #include "mir_test_doubles/mock_gbm.h"
113+#include "mir_test/fake_shared.h"
114 #include "mock_kms_output.h"
115
116 #include <gtest/gtest.h>
117 #include <gmock/gmock.h>
118
119 #include <unordered_map>
120+#include <algorithm>
121
122 namespace mg = mir::graphics;
123 namespace mgm = mir::graphics::mesa;
124@@ -43,7 +45,8 @@
125 StubKMSOutputContainer()
126 : outputs{
127 {10, std::make_shared<testing::NiceMock<MockKMSOutput>>()},
128- {11, std::make_shared<testing::NiceMock<MockKMSOutput>>()}}
129+ {11, std::make_shared<testing::NiceMock<MockKMSOutput>>()},
130+ {12, std::make_shared<testing::NiceMock<MockKMSOutput>>()}}
131 {
132 }
133
134@@ -112,6 +115,26 @@
135 mir_power_mode_on,
136 mir_orientation_normal
137 });
138+ outputs.push_back(
139+ {
140+ mg::DisplayConfigurationOutputId{12},
141+ card_id,
142+ mg::DisplayConfigurationOutputType::vga,
143+ {},
144+ {
145+ {geom::Size{800, 200}, 59.9},
146+ {geom::Size{100, 200}, 59.9},
147+ },
148+ 0,
149+ geom::Size{800, 200},
150+ true,
151+ true,
152+ geom::Point{666, 0},
153+ 0,
154+ mir_pixel_format_invalid,
155+ mir_power_mode_on,
156+ mir_orientation_right
157+ });
158 }
159
160 void for_each_card(std::function<void(mg::DisplayConfigurationCard const&)> f) const override
161@@ -148,6 +171,16 @@
162 {
163 }
164
165+ void set_orentation_of_output(mg::DisplayConfigurationOutputId id, MirOrientation orientation)
166+ {
167+ auto output = std::find_if(outputs.begin(), outputs.end(),
168+ [id] (mg::DisplayConfigurationOutput const& output) -> bool {return output.id == id;});
169+ if (output != outputs.end())
170+ {
171+ output->orientation = orientation;
172+ }
173+ }
174+
175 mg::DisplayConfigurationCardId card_id;
176 std::vector<mg::DisplayConfigurationOutput> outputs;
177 };
178@@ -167,10 +200,11 @@
179 {
180 MesaCursorTest()
181 : cursor{mock_gbm.fake_gbm.device, output_container,
182- std::make_shared<StubCurrentConfiguration>()}
183+ mir::test::fake_shared(current_configuration)}
184 {
185 }
186
187+ StubCurrentConfiguration current_configuration;
188 testing::NiceMock<mtd::MockGBM> mock_gbm;
189 StubKMSOutputContainer output_container;
190 mgm::Cursor cursor;
191@@ -224,10 +258,12 @@
192 EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{0,0}));
193 EXPECT_CALL(*output_container.outputs[10], set_cursor(_));
194 EXPECT_CALL(*output_container.outputs[11], clear_cursor());
195+ EXPECT_CALL(*output_container.outputs[12], clear_cursor());
196
197 /* No checking of existing cursor state */
198 EXPECT_CALL(*output_container.outputs[10], has_cursor()).Times(0);
199 EXPECT_CALL(*output_container.outputs[11], has_cursor()).Times(0);
200+ EXPECT_CALL(*output_container.outputs[12], has_cursor()).Times(0);
201
202 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,
203 std::make_shared<StubCurrentConfiguration>()};
204@@ -328,12 +364,60 @@
205 output_container.verify_and_clear_expectations();
206 }
207
208+TEST_F(MesaCursorTest, moves_properly_to_and_inside_left_rotated_output)
209+{
210+ using namespace testing;
211+
212+ current_configuration.conf.set_orentation_of_output(mg::DisplayConfigurationOutputId{12}, mir_orientation_left);
213+
214+ EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{112,100}));
215+ EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{150,96}));
216+
217+ cursor.move_to({766, 112});
218+ cursor.move_to({770, 150});
219+
220+ output_container.verify_and_clear_expectations();
221+}
222+
223+
224+TEST_F(MesaCursorTest, moves_properly_to_and_inside_right_rotated_output)
225+{
226+ using namespace testing;
227+
228+ current_configuration.conf.set_orentation_of_output(mg::DisplayConfigurationOutputId{12}, mir_orientation_right);
229+
230+
231+ EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{688,100}));
232+ EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{650,104}));
233+
234+ cursor.move_to({766, 112});
235+ cursor.move_to({770, 150});
236+
237+ output_container.verify_and_clear_expectations();
238+}
239+
240+TEST_F(MesaCursorTest, moves_properly_to_and_inside_inverted_output)
241+{
242+ using namespace testing;
243+
244+ current_configuration.conf.set_orentation_of_output(mg::DisplayConfigurationOutputId{12}, mir_orientation_inverted);
245+
246+ EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{700,88}));
247+ EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{696,50}));
248+
249+ cursor.move_to({766, 112});
250+ cursor.move_to({770, 150});
251+
252+ output_container.verify_and_clear_expectations();
253+}
254+
255 TEST_F(MesaCursorTest, hides_cursor_in_all_outputs)
256 {
257 using namespace testing;
258
259 EXPECT_CALL(*output_container.outputs[10], clear_cursor());
260 EXPECT_CALL(*output_container.outputs[11], clear_cursor());
261+ EXPECT_CALL(*output_container.outputs[12], clear_cursor());
262
263 cursor.hide();
264
265@@ -346,4 +430,5 @@
266
267 EXPECT_CALL(*output_container.outputs[10], clear_cursor());
268 EXPECT_CALL(*output_container.outputs[11], clear_cursor());
269+ EXPECT_CALL(*output_container.outputs[12], clear_cursor());
270 }

Subscribers

People subscribed via source and target branches