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
=== modified file 'src/platform/graphics/mesa/cursor.cpp'
--- src/platform/graphics/mesa/cursor.cpp 2014-01-22 10:03:11 +0000
+++ src/platform/graphics/mesa/cursor.cpp 2014-03-03 16:21:52 +0000
@@ -28,15 +28,32 @@
28#include <stdexcept>28#include <stdexcept>
29#include <vector>29#include <vector>
3030
31namespace mgm = mir::graphics::mesa;
32namespace geom = mir::geometry;
33
31namespace34namespace
32{35{
33#include "black_arrow.c"36#include "black_arrow.c"
34int const width = black_arrow.width;37int const width = black_arrow.width;
35int const height = black_arrow.height;38int const height = black_arrow.height;
36}
3739
38namespace mgm = mir::graphics::mesa;40// Transforms a relative position within the display bounds described by \a rect which is rotated with \a orientation
39namespace geom = mir::geometry;41geom::Displacement transform(geom::Rectangle const& rect, geom::Displacement const& vector, MirOrientation orientation)
42{
43 switch(orientation)
44 {
45 case mir_orientation_left:
46 return {vector.dy.as_int(), rect.size.width.as_int() -vector.dx.as_int()};
47 case mir_orientation_inverted:
48 return {rect.size.width.as_int() -vector.dx.as_int(), rect.size.height.as_int() - vector.dy.as_int()};
49 case mir_orientation_right:
50 return {rect.size.height.as_int() -vector.dy.as_int(), vector.dx.as_int()};
51 default:
52 case mir_orientation_normal:
53 return vector;
54 }
55}
56}
4057
41mgm::Cursor::GBMBOWrapper::GBMBOWrapper(gbm_device* gbm) :58mgm::Cursor::GBMBOWrapper::GBMBOWrapper(gbm_device* gbm) :
42 buffer(gbm_bo_create(59 buffer(gbm_bo_create(
@@ -103,7 +120,7 @@
103}120}
104121
105void mgm::Cursor::for_each_used_output(122void mgm::Cursor::for_each_used_output(
106 std::function<void(KMSOutput&, geom::Rectangle const&)> const& f)123 std::function<void(KMSOutput&, geom::Rectangle const&, MirOrientation orientation)> const& f)
107{124{
108 current_configuration->with_current_configuration_do(125 current_configuration->with_current_configuration_do(
109 [this,&f](KMSDisplayConfiguration const& kms_conf)126 [this,&f](KMSDisplayConfiguration const& kms_conf)
@@ -115,13 +132,7 @@
115 uint32_t const connector_id = kms_conf.get_kms_connector_id(conf_output.id);132 uint32_t const connector_id = kms_conf.get_kms_connector_id(conf_output.id);
116 auto output = output_container.get_kms_output_for(connector_id);133 auto output = output_container.get_kms_output_for(connector_id);
117134
118 // TODO: Cursor rotation support (conf_output.extents())135 f(*output, conf_output.extents(), conf_output.orientation);
119 geom::Rectangle output_rect
120 {
121 conf_output.top_left,
122 conf_output.modes[conf_output.current_mode_index].size
123 };
124 f(*output, output_rect);
125 }136 }
126 });137 });
127 });138 });
@@ -131,15 +142,15 @@
131 geometry::Point position,142 geometry::Point position,
132 ForceCursorState force_state)143 ForceCursorState force_state)
133{144{
134 for_each_used_output([&](KMSOutput& output, geom::Rectangle const& output_rect)145 for_each_used_output([&](KMSOutput& output, geom::Rectangle const& output_rect, MirOrientation orientation)
135 {146 {
136 if (output_rect.contains(position))147 if (output_rect.contains(position))
137 {148 {
138 auto dp = position - output_rect.top_left;149 auto dp = transform(output_rect, position - output_rect.top_left, orientation);
139 output.move_cursor({dp.dx.as_int(), dp.dy.as_int()});150 output.move_cursor({dp.dx.as_int(), dp.dy.as_int()});
140 if (force_state || !output.has_cursor())151 if (force_state || !output.has_cursor()) // TODO - or if orientation had changed - then set buffer..
141 {152 {
142 output.set_cursor(buffer);153 output.set_cursor(buffer);// TODO - select rotated buffer image
143 }154 }
144 }155 }
145 else156 else
146157
=== modified file 'src/platform/graphics/mesa/cursor.h'
--- src/platform/graphics/mesa/cursor.h 2014-01-22 10:03:11 +0000
+++ src/platform/graphics/mesa/cursor.h 2014-03-03 16:21:52 +0000
@@ -21,6 +21,7 @@
21#define MIR_GRAPHICS_MESA_CURSOR_H_21#define MIR_GRAPHICS_MESA_CURSOR_H_
2222
23#include "mir/graphics/cursor.h"23#include "mir/graphics/cursor.h"
24#include "mir_toolkit/common.h"
2425
25#include <gbm.h>26#include <gbm.h>
26#include <memory>27#include <memory>
@@ -73,7 +74,7 @@
7374
74private:75private:
75 enum ForceCursorState { UpdateState, ForceState };76 enum ForceCursorState { UpdateState, ForceState };
76 void for_each_used_output(std::function<void(KMSOutput&, geometry::Rectangle const&)> const& f);77 void for_each_used_output(std::function<void(KMSOutput&, geometry::Rectangle const&, MirOrientation orientation)> const& f);
77 void place_cursor_at(geometry::Point position, ForceCursorState force_state);78 void place_cursor_at(geometry::Point position, ForceCursorState force_state);
7879
79 KMSOutputContainer& output_container;80 KMSOutputContainer& output_container;
8081
=== modified file 'tests/unit-tests/graphics/mesa/test_cursor.cpp'
--- tests/unit-tests/graphics/mesa/test_cursor.cpp 2014-02-13 09:38:32 +0000
+++ tests/unit-tests/graphics/mesa/test_cursor.cpp 2014-03-03 16:21:52 +0000
@@ -22,12 +22,14 @@
22#include "src/platform/graphics/mesa/kms_display_configuration.h"22#include "src/platform/graphics/mesa/kms_display_configuration.h"
2323
24#include "mir_test_doubles/mock_gbm.h"24#include "mir_test_doubles/mock_gbm.h"
25#include "mir_test/fake_shared.h"
25#include "mock_kms_output.h"26#include "mock_kms_output.h"
2627
27#include <gtest/gtest.h>28#include <gtest/gtest.h>
28#include <gmock/gmock.h>29#include <gmock/gmock.h>
2930
30#include <unordered_map>31#include <unordered_map>
32#include <algorithm>
3133
32namespace mg = mir::graphics;34namespace mg = mir::graphics;
33namespace mgm = mir::graphics::mesa;35namespace mgm = mir::graphics::mesa;
@@ -43,7 +45,8 @@
43 StubKMSOutputContainer()45 StubKMSOutputContainer()
44 : outputs{46 : outputs{
45 {10, std::make_shared<testing::NiceMock<MockKMSOutput>>()},47 {10, std::make_shared<testing::NiceMock<MockKMSOutput>>()},
46 {11, std::make_shared<testing::NiceMock<MockKMSOutput>>()}}48 {11, std::make_shared<testing::NiceMock<MockKMSOutput>>()},
49 {12, std::make_shared<testing::NiceMock<MockKMSOutput>>()}}
47 {50 {
48 }51 }
4952
@@ -112,6 +115,26 @@
112 mir_power_mode_on,115 mir_power_mode_on,
113 mir_orientation_normal116 mir_orientation_normal
114 });117 });
118 outputs.push_back(
119 {
120 mg::DisplayConfigurationOutputId{12},
121 card_id,
122 mg::DisplayConfigurationOutputType::vga,
123 {},
124 {
125 {geom::Size{800, 200}, 59.9},
126 {geom::Size{100, 200}, 59.9},
127 },
128 0,
129 geom::Size{800, 200},
130 true,
131 true,
132 geom::Point{666, 0},
133 0,
134 mir_pixel_format_invalid,
135 mir_power_mode_on,
136 mir_orientation_right
137 });
115 }138 }
116139
117 void for_each_card(std::function<void(mg::DisplayConfigurationCard const&)> f) const override140 void for_each_card(std::function<void(mg::DisplayConfigurationCard const&)> f) const override
@@ -148,6 +171,16 @@
148 {171 {
149 }172 }
150173
174 void set_orentation_of_output(mg::DisplayConfigurationOutputId id, MirOrientation orientation)
175 {
176 auto output = std::find_if(outputs.begin(), outputs.end(),
177 [id] (mg::DisplayConfigurationOutput const& output) -> bool {return output.id == id;});
178 if (output != outputs.end())
179 {
180 output->orientation = orientation;
181 }
182 }
183
151 mg::DisplayConfigurationCardId card_id;184 mg::DisplayConfigurationCardId card_id;
152 std::vector<mg::DisplayConfigurationOutput> outputs;185 std::vector<mg::DisplayConfigurationOutput> outputs;
153};186};
@@ -167,10 +200,11 @@
167{200{
168 MesaCursorTest()201 MesaCursorTest()
169 : cursor{mock_gbm.fake_gbm.device, output_container,202 : cursor{mock_gbm.fake_gbm.device, output_container,
170 std::make_shared<StubCurrentConfiguration>()}203 mir::test::fake_shared(current_configuration)}
171 {204 {
172 }205 }
173206
207 StubCurrentConfiguration current_configuration;
174 testing::NiceMock<mtd::MockGBM> mock_gbm;208 testing::NiceMock<mtd::MockGBM> mock_gbm;
175 StubKMSOutputContainer output_container;209 StubKMSOutputContainer output_container;
176 mgm::Cursor cursor;210 mgm::Cursor cursor;
@@ -224,10 +258,12 @@
224 EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{0,0}));258 EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{0,0}));
225 EXPECT_CALL(*output_container.outputs[10], set_cursor(_));259 EXPECT_CALL(*output_container.outputs[10], set_cursor(_));
226 EXPECT_CALL(*output_container.outputs[11], clear_cursor());260 EXPECT_CALL(*output_container.outputs[11], clear_cursor());
261 EXPECT_CALL(*output_container.outputs[12], clear_cursor());
227262
228 /* No checking of existing cursor state */263 /* No checking of existing cursor state */
229 EXPECT_CALL(*output_container.outputs[10], has_cursor()).Times(0);264 EXPECT_CALL(*output_container.outputs[10], has_cursor()).Times(0);
230 EXPECT_CALL(*output_container.outputs[11], has_cursor()).Times(0);265 EXPECT_CALL(*output_container.outputs[11], has_cursor()).Times(0);
266 EXPECT_CALL(*output_container.outputs[12], has_cursor()).Times(0);
231267
232 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,268 mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container,
233 std::make_shared<StubCurrentConfiguration>()};269 std::make_shared<StubCurrentConfiguration>()};
@@ -328,12 +364,60 @@
328 output_container.verify_and_clear_expectations();364 output_container.verify_and_clear_expectations();
329}365}
330366
367TEST_F(MesaCursorTest, moves_properly_to_and_inside_left_rotated_output)
368{
369 using namespace testing;
370
371 current_configuration.conf.set_orentation_of_output(mg::DisplayConfigurationOutputId{12}, mir_orientation_left);
372
373 EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{112,100}));
374 EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{150,96}));
375
376 cursor.move_to({766, 112});
377 cursor.move_to({770, 150});
378
379 output_container.verify_and_clear_expectations();
380}
381
382
383TEST_F(MesaCursorTest, moves_properly_to_and_inside_right_rotated_output)
384{
385 using namespace testing;
386
387 current_configuration.conf.set_orentation_of_output(mg::DisplayConfigurationOutputId{12}, mir_orientation_right);
388
389
390 EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{688,100}));
391 EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{650,104}));
392
393 cursor.move_to({766, 112});
394 cursor.move_to({770, 150});
395
396 output_container.verify_and_clear_expectations();
397}
398
399TEST_F(MesaCursorTest, moves_properly_to_and_inside_inverted_output)
400{
401 using namespace testing;
402
403 current_configuration.conf.set_orentation_of_output(mg::DisplayConfigurationOutputId{12}, mir_orientation_inverted);
404
405 EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{700,88}));
406 EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{696,50}));
407
408 cursor.move_to({766, 112});
409 cursor.move_to({770, 150});
410
411 output_container.verify_and_clear_expectations();
412}
413
331TEST_F(MesaCursorTest, hides_cursor_in_all_outputs)414TEST_F(MesaCursorTest, hides_cursor_in_all_outputs)
332{415{
333 using namespace testing;416 using namespace testing;
334417
335 EXPECT_CALL(*output_container.outputs[10], clear_cursor());418 EXPECT_CALL(*output_container.outputs[10], clear_cursor());
336 EXPECT_CALL(*output_container.outputs[11], clear_cursor());419 EXPECT_CALL(*output_container.outputs[11], clear_cursor());
420 EXPECT_CALL(*output_container.outputs[12], clear_cursor());
337421
338 cursor.hide();422 cursor.hide();
339423
@@ -346,4 +430,5 @@
346430
347 EXPECT_CALL(*output_container.outputs[10], clear_cursor());431 EXPECT_CALL(*output_container.outputs[10], clear_cursor());
348 EXPECT_CALL(*output_container.outputs[11], clear_cursor());432 EXPECT_CALL(*output_container.outputs[11], clear_cursor());
433 EXPECT_CALL(*output_container.outputs[12], clear_cursor());
349}434}

Subscribers

People subscribed via source and target branches