2
* Copyright © 2016 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 2 or 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Alan Griffiths <alan@octopull.co.uk>
19
#include "test_window_manager_tools.h"
21
using namespace miral;
22
using namespace testing;
23
namespace mt = mir::test;
27
auto const display_area = Rectangle{{0, 0}, {800, 600}};
28
auto const parent_width = 400;
29
auto const parent_height = 300;
32
Rectangle const& aux_rect,
33
MirPlacementGravity aux_rect_placement_gravity,
34
MirPlacementGravity window_placement_gravity,
35
MirPlacementHints placement_hints) -> WindowSpecification
37
WindowSpecification modification;
39
modification.aux_rect() = aux_rect;
40
modification.aux_rect_placement_gravity() = aux_rect_placement_gravity;
41
modification.window_placement_gravity() = window_placement_gravity;
42
modification.placement_hints() = placement_hints;
47
struct WindowPlacementAnchorsToParent : TestWindowManagerTools
49
Size const parent_size{parent_width, parent_height};
50
Size const initial_child_size{100, 50};
55
Point parent_position;
56
WindowSpecification modification;
60
TestWindowManagerTools::SetUp();
62
basic_window_manager.add_display_for_testing(display_area);
64
mir::scene::SurfaceCreationParameters creation_parameters;
65
basic_window_manager.add_session(session);
67
EXPECT_CALL(*window_manager_policy, advise_new_window(_))
68
.WillOnce(Invoke([this](WindowInfo const& window_info){ parent = window_info.window(); }))
69
.WillOnce(Invoke([this](WindowInfo const& window_info){ child = window_info.window(); }));
71
creation_parameters.size = parent_size;
72
basic_window_manager.add_surface(session, creation_parameters, &create_surface);
74
creation_parameters.type = mir_window_type_tip;
75
creation_parameters.parent = parent;
76
creation_parameters.size = initial_child_size;
77
basic_window_manager.add_surface(session, creation_parameters, &create_surface);
79
// Clear the expectations used to capture parent & child
80
Mock::VerifyAndClearExpectations(window_manager_policy);
82
parent_position = parent.top_left();
87
// there was an IRC conversation to sort this out between myself William and Thomas.
88
// I think the resulting consensus was:
90
// 1. Mir will constrain the placement anchor of the aux_rect to the parent
91
// surface. I don't think we agreed exactly how (e.g. do we "clip" the
92
// rect? What happens if there is *no* intersection?)
94
// 2. Mir will constrain the the offset placement anchor to the parent surface.
95
// Again I don't think we agreed how. (Slide it horizontally and/or vertically
96
// the minimum amount?)
97
// - alan_g (mir-devel, Mon, 5 Sep 2016 17:21:01 +0100)
99
// What we have implemented is to constrain the result of offsetting to the parent. That
100
// seems to provide reasonable behaviour. Are there test cases that require something more?
102
TEST_F(WindowPlacementAnchorsToParent, given_rect_anchor_right_of_parent_client_is_anchored_to_parent)
104
auto const rect_size = 10;
105
Rectangle const overlapping_right{{parent_width-rect_size/2, parent_height/2}, {rect_size, rect_size}};
107
modification = placement(
109
mir_placement_gravity_northeast,
110
mir_placement_gravity_northwest,
111
MirPlacementHints(mir_placement_hints_slide_y|mir_placement_hints_resize_x));
113
auto const expected_position = parent_position + Displacement{parent_width, parent_height/2};
115
EXPECT_CALL(*window_manager_policy, advise_move_to(_, expected_position));
116
EXPECT_CALL(*window_manager_policy, advise_resize(_, _)).Times(0);
117
basic_window_manager.modify_window(basic_window_manager.info_for(child), modification);
118
ASSERT_THAT(child.top_left(), Eq(expected_position));
119
ASSERT_THAT(child.size(), Eq(initial_child_size));
122
TEST_F(WindowPlacementAnchorsToParent, given_rect_anchor_above_parent_client_is_anchored_to_parent)
124
auto const rect_size = 10;
125
Rectangle const overlapping_above{{parent_width/2, -rect_size/2}, {rect_size, rect_size}};
127
modification = placement(
129
mir_placement_gravity_northeast,
130
mir_placement_gravity_southeast,
131
mir_placement_hints_slide_x);
133
auto const expected_position = parent_position + DeltaX{parent_width/2 + rect_size}
134
- as_displacement(initial_child_size);
136
EXPECT_CALL(*window_manager_policy, advise_move_to(_, expected_position));
137
EXPECT_CALL(*window_manager_policy, advise_resize(_, _)).Times(0);
138
basic_window_manager.modify_window(basic_window_manager.info_for(child), modification);
139
ASSERT_THAT(child.top_left(), Eq(expected_position));
140
ASSERT_THAT(child.size(), Eq(initial_child_size));
143
TEST_F(WindowPlacementAnchorsToParent, given_offset_right_of_parent_client_is_anchored_to_parent)
145
auto const rect_size = 10;
146
Rectangle const mid_right{{parent_width-rect_size, parent_height/2}, {rect_size, rect_size}};
148
modification = placement(
150
mir_placement_gravity_northeast,
151
mir_placement_gravity_northwest,
152
MirPlacementHints(mir_placement_hints_slide_y|mir_placement_hints_resize_x));
154
modification.aux_rect_placement_offset() = Displacement{rect_size, 0};
156
auto const expected_position = parent_position + Displacement{parent_width, parent_height/2};
158
EXPECT_CALL(*window_manager_policy, advise_move_to(_, expected_position));
159
EXPECT_CALL(*window_manager_policy, advise_resize(_, _)).Times(0);
160
basic_window_manager.modify_window(basic_window_manager.info_for(child), modification);
161
ASSERT_THAT(child.top_left(), Eq(expected_position));
162
ASSERT_THAT(child.size(), Eq(initial_child_size));
165
TEST_F(WindowPlacementAnchorsToParent, given_offset_above_parent_client_is_anchored_to_parent)
167
auto const rect_size = 10;
168
Rectangle const mid_top{{parent_width/2, 0}, {rect_size, rect_size}};
170
modification = placement(
172
mir_placement_gravity_northeast,
173
mir_placement_gravity_southeast,
174
mir_placement_hints_slide_x);
176
modification.aux_rect_placement_offset() = Displacement{0, -rect_size};
178
auto const expected_position = parent_position + DeltaX{parent_width/2 + rect_size}
179
- as_displacement(initial_child_size);
181
EXPECT_CALL(*window_manager_policy, advise_move_to(_, expected_position));
182
EXPECT_CALL(*window_manager_policy, advise_resize(_, _)).Times(0);
183
basic_window_manager.modify_window(basic_window_manager.info_for(child), modification);
184
ASSERT_THAT(child.top_left(), Eq(expected_position));
185
ASSERT_THAT(child.size(), Eq(initial_child_size));
188
TEST_F(WindowPlacementAnchorsToParent, given_rect_and_offset_below_left_parent_client_is_anchored_to_parent)
190
auto const rect_size = 10;
191
Rectangle const below_left{{-rect_size, parent_height}, {rect_size, rect_size}};
193
modification = placement(
195
mir_placement_gravity_southwest,
196
mir_placement_gravity_northeast,
197
mir_placement_hints_resize_any);
199
modification.aux_rect_placement_offset() = Displacement{-rect_size, rect_size};
201
auto const expected_position = parent_position + DeltaY{parent_height} - as_displacement(initial_child_size).dx;
203
EXPECT_CALL(*window_manager_policy, advise_move_to(_, expected_position));
204
EXPECT_CALL(*window_manager_policy, advise_resize(_, _)).Times(0);
205
basic_window_manager.modify_window(basic_window_manager.info_for(child), modification);
206
ASSERT_THAT(child.top_left(), Eq(expected_position));
207
ASSERT_THAT(child.size(), Eq(initial_child_size));