Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: components/mus/ws/window_tree_unittest.cc

Issue 2119963002: Move mus to //services/ui (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/mus/ws/window_tree_host_factory.cc ('k') | content/browser/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/mus/ws/window_tree.h"
6
7 #include <stdint.h>
8
9 #include <string>
10 #include <vector>
11
12 #include "base/macros.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "components/mus/common/types.h"
16 #include "components/mus/common/util.h"
17 #include "components/mus/public/interfaces/window_tree.mojom.h"
18 #include "components/mus/surfaces/surfaces_state.h"
19 #include "components/mus/ws/default_access_policy.h"
20 #include "components/mus/ws/display_binding.h"
21 #include "components/mus/ws/ids.h"
22 #include "components/mus/ws/platform_display.h"
23 #include "components/mus/ws/platform_display_factory.h"
24 #include "components/mus/ws/platform_display_init_params.h"
25 #include "components/mus/ws/server_window.h"
26 #include "components/mus/ws/server_window_surface_manager_test_api.h"
27 #include "components/mus/ws/test_change_tracker.h"
28 #include "components/mus/ws/test_server_window_delegate.h"
29 #include "components/mus/ws/test_utils.h"
30 #include "components/mus/ws/window_manager_access_policy.h"
31 #include "components/mus/ws/window_manager_display_root.h"
32 #include "components/mus/ws/window_server.h"
33 #include "components/mus/ws/window_server_delegate.h"
34 #include "components/mus/ws/window_tree_binding.h"
35 #include "services/shell/public/interfaces/connector.mojom.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37 #include "ui/events/event.h"
38 #include "ui/events/event_utils.h"
39 #include "ui/gfx/geometry/rect.h"
40
41 namespace mus {
42 namespace ws {
43 namespace test {
44 namespace {
45
46 std::string WindowIdToString(const WindowId& id) {
47 return base::StringPrintf("%d,%d", id.client_id, id.window_id);
48 }
49
50 ClientWindowId BuildClientWindowId(WindowTree* tree,
51 ClientSpecificId window_id) {
52 return ClientWindowId(WindowIdToTransportId(WindowId(tree->id(), window_id)));
53 }
54
55 // -----------------------------------------------------------------------------
56
57 ui::PointerEvent CreatePointerDownEvent(int x, int y) {
58 return ui::PointerEvent(ui::TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(x, y),
59 1, ui::EventTimeForNow()));
60 }
61
62 ui::PointerEvent CreatePointerUpEvent(int x, int y) {
63 return ui::PointerEvent(ui::TouchEvent(
64 ui::ET_TOUCH_RELEASED, gfx::Point(x, y), 1, ui::EventTimeForNow()));
65 }
66
67 ui::PointerEvent CreateMouseMoveEvent(int x, int y) {
68 return ui::PointerEvent(
69 ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(x, y), gfx::Point(x, y),
70 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE));
71 }
72
73 ui::PointerEvent CreateMouseDownEvent(int x, int y) {
74 return ui::PointerEvent(
75 ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(x, y), gfx::Point(x, y),
76 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
77 ui::EF_LEFT_MOUSE_BUTTON));
78 }
79
80 ui::PointerEvent CreateMouseUpEvent(int x, int y) {
81 return ui::PointerEvent(
82 ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(x, y), gfx::Point(x, y),
83 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
84 ui::EF_LEFT_MOUSE_BUTTON));
85 }
86
87 ServerWindow* GetCaptureWindow(Display* display) {
88 return display->GetActiveWindowManagerDisplayRoot()
89 ->window_manager_state()
90 ->capture_window();
91 }
92
93 mojom::EventMatcherPtr CreateEventMatcher(ui::mojom::EventType type) {
94 mojom::EventMatcherPtr matcher = mojom::EventMatcher::New();
95 matcher->type_matcher = mojom::EventTypeMatcher::New();
96 matcher->type_matcher->type = type;
97 return matcher;
98 }
99
100 } // namespace
101
102 // -----------------------------------------------------------------------------
103
104 class WindowTreeTest : public testing::Test {
105 public:
106 WindowTreeTest() {}
107 ~WindowTreeTest() override {}
108
109 mus::mojom::Cursor cursor_id() {
110 return static_cast<mus::mojom::Cursor>(
111 window_event_targeting_helper_.cursor_id());
112 }
113 Display* display() { return window_event_targeting_helper_.display(); }
114 TestWindowTreeBinding* last_binding() {
115 return window_event_targeting_helper_.last_binding();
116 }
117 TestWindowTreeClient* last_window_tree_client() {
118 return window_event_targeting_helper_.last_window_tree_client();
119 }
120 TestWindowTreeClient* wm_client() {
121 return window_event_targeting_helper_.wm_client();
122 }
123 WindowServer* window_server() {
124 return window_event_targeting_helper_.window_server();
125 }
126 WindowTree* wm_tree() {
127 return window_event_targeting_helper_.window_server()->GetTreeWithId(1);
128 }
129
130 void DispatchEventWithoutAck(const ui::Event& event) {
131 DisplayTestApi(display()).OnEvent(event);
132 }
133
134 void set_window_manager_internal(WindowTree* tree,
135 mojom::WindowManager* wm_internal) {
136 WindowTreeTestApi(tree).set_window_manager_internal(wm_internal);
137 }
138
139 void AckPreviousEvent() {
140 WindowManagerStateTestApi test_api(
141 display()->GetActiveWindowManagerDisplayRoot()->window_manager_state());
142 while (test_api.tree_awaiting_input_ack()) {
143 test_api.tree_awaiting_input_ack()->OnWindowInputEventAck(
144 0, mojom::EventResult::HANDLED);
145 }
146 }
147
148 void DispatchEventAndAckImmediately(const ui::Event& event) {
149 DispatchEventWithoutAck(event);
150 AckPreviousEvent();
151 }
152
153 // Creates a new window from wm_tree() and embeds a new client in it.
154 void SetupEventTargeting(TestWindowTreeClient** out_client,
155 WindowTree** window_tree,
156 ServerWindow** window);
157
158 // Creates a new tree as the specified user. This does what creation via
159 // a WindowTreeFactory does.
160 WindowTree* CreateNewTree(const UserId& user_id,
161 TestWindowTreeBinding** binding) {
162 WindowTree* tree =
163 new WindowTree(window_server(), user_id, nullptr,
164 base::WrapUnique(new DefaultAccessPolicy));
165 *binding = new TestWindowTreeBinding(tree);
166 window_server()->AddTree(base::WrapUnique(tree), base::WrapUnique(*binding),
167 nullptr);
168 return tree;
169 }
170
171 protected:
172 WindowEventTargetingHelper window_event_targeting_helper_;
173
174 private:
175 DISALLOW_COPY_AND_ASSIGN(WindowTreeTest);
176 };
177
178 // Creates a new window in wm_tree(), adds it to the root, embeds a
179 // new client in the window and creates a child of said window. |window| is
180 // set to the child of |window_tree| that is created.
181 void WindowTreeTest::SetupEventTargeting(TestWindowTreeClient** out_client,
182 WindowTree** window_tree,
183 ServerWindow** window) {
184 ServerWindow* embed_window = window_event_targeting_helper_.CreatePrimaryTree(
185 gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 50, 50));
186 window_event_targeting_helper_.CreateSecondaryTree(
187 embed_window, gfx::Rect(20, 20, 20, 20), out_client, window_tree, window);
188 }
189
190 // Verifies focus correctly changes on pointer events.
191 TEST_F(WindowTreeTest, FocusOnPointer) {
192 const ClientWindowId embed_window_id = BuildClientWindowId(wm_tree(), 1);
193 EXPECT_TRUE(
194 wm_tree()->NewWindow(embed_window_id, ServerWindow::Properties()));
195 ServerWindow* embed_window = wm_tree()->GetWindowByClientId(embed_window_id);
196 ASSERT_TRUE(embed_window);
197 EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id, true));
198 ASSERT_TRUE(FirstRoot(wm_tree()));
199 const ClientWindowId wm_root_id = FirstRootId(wm_tree());
200 EXPECT_TRUE(wm_tree()->AddWindow(wm_root_id, embed_window_id));
201 display()->root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
202 mojom::WindowTreeClientPtr client;
203 mojom::WindowTreeClientRequest client_request = GetProxy(&client);
204 wm_client()->Bind(std::move(client_request));
205 const uint32_t embed_flags = 0;
206 wm_tree()->Embed(embed_window_id, std::move(client), embed_flags);
207 WindowTree* tree1 = window_server()->GetTreeWithRoot(embed_window);
208 ASSERT_TRUE(tree1 != nullptr);
209 ASSERT_NE(tree1, wm_tree());
210
211 embed_window->SetBounds(gfx::Rect(0, 0, 50, 50));
212
213 const ClientWindowId child1_id(BuildClientWindowId(tree1, 1));
214 EXPECT_TRUE(tree1->NewWindow(child1_id, ServerWindow::Properties()));
215 EXPECT_TRUE(tree1->AddWindow(ClientWindowIdForWindow(tree1, embed_window),
216 child1_id));
217 ServerWindow* child1 = tree1->GetWindowByClientId(child1_id);
218 ASSERT_TRUE(child1);
219 child1->SetVisible(true);
220 child1->SetBounds(gfx::Rect(20, 20, 20, 20));
221 EnableHitTest(child1);
222
223 TestWindowTreeClient* tree1_client = last_window_tree_client();
224 tree1_client->tracker()->changes()->clear();
225 wm_client()->tracker()->changes()->clear();
226
227 // Focus should not go to |child1| yet, since the parent still doesn't allow
228 // active children.
229 DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
230 Display* display1 = tree1->GetDisplay(embed_window);
231 EXPECT_EQ(nullptr, display1->GetFocusedWindow());
232 DispatchEventAndAckImmediately(CreatePointerUpEvent(21, 22));
233 tree1_client->tracker()->changes()->clear();
234 wm_client()->tracker()->changes()->clear();
235
236 display1->AddActivationParent(embed_window);
237
238 // Focus should go to child1. This result in notifying both the window
239 // manager and client client being notified.
240 DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
241 EXPECT_EQ(child1, display1->GetFocusedWindow());
242 ASSERT_GE(wm_client()->tracker()->changes()->size(), 1u);
243 EXPECT_EQ("Focused id=2,1",
244 ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
245 ASSERT_GE(tree1_client->tracker()->changes()->size(), 1u);
246 EXPECT_EQ("Focused id=2,1",
247 ChangesToDescription1(*tree1_client->tracker()->changes())[0]);
248
249 DispatchEventAndAckImmediately(CreatePointerUpEvent(21, 22));
250 wm_client()->tracker()->changes()->clear();
251 tree1_client->tracker()->changes()->clear();
252
253 // Press outside of the embedded window. Note that root cannot be focused
254 // (because it cannot be activated). So the focus would not move in this case.
255 DispatchEventAndAckImmediately(CreatePointerDownEvent(61, 22));
256 EXPECT_EQ(child1, display()->GetFocusedWindow());
257
258 DispatchEventAndAckImmediately(CreatePointerUpEvent(21, 22));
259 wm_client()->tracker()->changes()->clear();
260 tree1_client->tracker()->changes()->clear();
261
262 // Press in the same location. Should not get a focus change event (only input
263 // event).
264 DispatchEventAndAckImmediately(CreatePointerDownEvent(61, 22));
265 EXPECT_EQ(child1, display()->GetFocusedWindow());
266 ASSERT_EQ(wm_client()->tracker()->changes()->size(), 1u)
267 << SingleChangeToDescription(*wm_client()->tracker()->changes());
268 EXPECT_EQ("InputEvent window=0,3 event_action=16",
269 ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
270 EXPECT_TRUE(tree1_client->tracker()->changes()->empty());
271 }
272
273 TEST_F(WindowTreeTest, BasicInputEventTarget) {
274 TestWindowTreeClient* embed_client = nullptr;
275 WindowTree* tree = nullptr;
276 ServerWindow* window = nullptr;
277 EXPECT_NO_FATAL_FAILURE(
278 SetupEventTargeting(&embed_client, &tree, &window));
279
280 // Send an event to |v1|. |embed_client| should get the event, not
281 // |wm_client|, since |v1| lives inside an embedded window.
282 DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
283 ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
284 EXPECT_EQ("Focused id=2,1",
285 ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
286 ASSERT_EQ(2u, embed_client->tracker()->changes()->size());
287 EXPECT_EQ("Focused id=2,1",
288 ChangesToDescription1(*embed_client->tracker()->changes())[0]);
289 EXPECT_EQ("InputEvent window=2,1 event_action=16",
290 ChangesToDescription1(*embed_client->tracker()->changes())[1]);
291 }
292
293 // Tests that a client can observe events outside its bounds.
294 TEST_F(WindowTreeTest, SetEventObserver) {
295 // Create an embedded client.
296 TestWindowTreeClient* client = nullptr;
297 WindowTree* tree = nullptr;
298 ServerWindow* window = nullptr;
299 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&client, &tree, &window));
300
301 // Create an event outside the bounds of the client.
302 ui::PointerEvent pointer_down = CreatePointerDownEvent(5, 5);
303
304 // Events are not observed before setting an observer.
305 DispatchEventAndAckImmediately(pointer_down);
306 ASSERT_EQ(0u, client->tracker()->changes()->size());
307
308 // Create an observer for pointer-down events.
309 WindowTreeTestApi(tree).SetEventObserver(
310 CreateEventMatcher(ui::mojom::EventType::POINTER_DOWN), 111u);
311
312 // Pointer-down events are sent to the client.
313 DispatchEventAndAckImmediately(pointer_down);
314 ASSERT_EQ(1u, client->tracker()->changes()->size());
315 EXPECT_EQ("EventObserved event_action=16 event_observer_id=111",
316 ChangesToDescription1(*client->tracker()->changes())[0]);
317 client->tracker()->changes()->clear();
318
319 // Clearing the observer stops sending events to the client.
320 WindowTreeTestApi(tree).SetEventObserver(nullptr, 0u);
321 DispatchEventAndAckImmediately(pointer_down);
322 ASSERT_EQ(0u, client->tracker()->changes()->size());
323 }
324
325 // Tests that a client using an event observer does not receive events that
326 // don't match the EventMatcher spec.
327 TEST_F(WindowTreeTest, SetEventObserverNonMatching) {
328 // Create an embedded client.
329 TestWindowTreeClient* client = nullptr;
330 WindowTree* tree = nullptr;
331 ServerWindow* window = nullptr;
332 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&client, &tree, &window));
333
334 // Create an observer for pointer-down events.
335 WindowTreeTestApi(tree).SetEventObserver(
336 CreateEventMatcher(ui::mojom::EventType::POINTER_DOWN), 111u);
337
338 // Pointer-up events are not sent to the client, since they don't match.
339 DispatchEventAndAckImmediately(CreatePointerUpEvent(5, 5));
340 ASSERT_EQ(0u, client->tracker()->changes()->size());
341 }
342
343 // Tests that an event that both hits a client window and matches an event
344 // observer is sent only once to the client.
345 TEST_F(WindowTreeTest, SetEventObserverSendsOnce) {
346 // Create an embedded client.
347 TestWindowTreeClient* client = nullptr;
348 WindowTree* tree = nullptr;
349 ServerWindow* window = nullptr;
350 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&client, &tree, &window));
351
352 // Create an observer for pointer-up events (which do not cause focus
353 // changes).
354 WindowTreeTestApi(tree).SetEventObserver(
355 CreateEventMatcher(ui::mojom::EventType::POINTER_UP), 111u);
356
357 // Create an event inside the bounds of the client.
358 ui::PointerEvent pointer_up = CreatePointerUpEvent(25, 25);
359
360 // The event is dispatched once, with a flag set that it matched the event
361 // observer.
362 DispatchEventAndAckImmediately(pointer_up);
363 ASSERT_EQ(1u, client->tracker()->changes()->size());
364 EXPECT_EQ("InputEvent window=2,1 event_action=18 event_observer_id=111",
365 SingleChangeToDescription(*client->tracker()->changes()));
366 }
367
368 // Tests that events generated by user A are not observed by event observers for
369 // user B.
370 TEST_F(WindowTreeTest, SetEventObserverWrongUser) {
371 // Embed a window tree belonging to a different user.
372 TestWindowTreeBinding* other_binding;
373 WindowTree* other_tree = CreateNewTree("other_user", &other_binding);
374 other_binding->client()->tracker()->changes()->clear();
375
376 // Set event observers on both the wm tree and the other user's tree.
377 WindowTreeTestApi(wm_tree()).SetEventObserver(
378 CreateEventMatcher(ui::mojom::EventType::POINTER_UP), 111u);
379 WindowTreeTestApi(other_tree)
380 .SetEventObserver(CreateEventMatcher(ui::mojom::EventType::POINTER_UP),
381 222u);
382
383 // An event is observed by the wm tree, but not by the other user's tree.
384 DispatchEventAndAckImmediately(CreatePointerUpEvent(5, 5));
385 ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
386 EXPECT_EQ("InputEvent window=0,3 event_action=18 event_observer_id=111",
387 SingleChangeToDescription(*wm_client()->tracker()->changes()));
388 ASSERT_EQ(0u, other_binding->client()->tracker()->changes()->size());
389 }
390
391 // Tests that an event observer cannot observe keystrokes.
392 TEST_F(WindowTreeTest, SetEventObserverKeyEventsDisallowed) {
393 WindowTreeTestApi(wm_tree()).SetEventObserver(
394 CreateEventMatcher(ui::mojom::EventType::KEY_PRESSED), 111u);
395 ui::KeyEvent key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
396 DispatchEventAndAckImmediately(key_pressed);
397 EXPECT_EQ(0u, wm_client()->tracker()->changes()->size());
398
399 WindowTreeTestApi(wm_tree()).SetEventObserver(
400 CreateEventMatcher(ui::mojom::EventType::KEY_RELEASED), 222u);
401 ui::KeyEvent key_released(ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_NONE);
402 DispatchEventAndAckImmediately(key_released);
403 EXPECT_EQ(0u, wm_client()->tracker()->changes()->size());
404 }
405
406 TEST_F(WindowTreeTest, CursorChangesWhenMouseOverWindowAndWindowSetsCursor) {
407 TestWindowTreeClient* embed_client = nullptr;
408 WindowTree* tree = nullptr;
409 ServerWindow* window = nullptr;
410 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
411
412 // Like in BasicInputEventTarget, we send a pointer down event to be
413 // dispatched. This is only to place the mouse cursor over that window though.
414 DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
415
416 window->SetPredefinedCursor(mojom::Cursor::IBEAM);
417
418 // Because the cursor is over the window when SetCursor was called, we should
419 // have immediately changed the cursor.
420 EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
421 }
422
423 TEST_F(WindowTreeTest, CursorChangesWhenEnteringWindowWithDifferentCursor) {
424 TestWindowTreeClient* embed_client = nullptr;
425 WindowTree* tree = nullptr;
426 ServerWindow* window = nullptr;
427 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
428
429 // Let's create a pointer event outside the window and then move the pointer
430 // inside.
431 DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
432 window->SetPredefinedCursor(mojom::Cursor::IBEAM);
433 EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
434
435 DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
436 EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
437 }
438
439 TEST_F(WindowTreeTest, TouchesDontChangeCursor) {
440 TestWindowTreeClient* embed_client = nullptr;
441 WindowTree* tree = nullptr;
442 ServerWindow* window = nullptr;
443 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
444
445 // Let's create a pointer event outside the window and then move the pointer
446 // inside.
447 DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
448 window->SetPredefinedCursor(mojom::Cursor::IBEAM);
449 EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
450
451 // With a touch event, we shouldn't update the cursor.
452 DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
453 EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
454 }
455
456 TEST_F(WindowTreeTest, DragOutsideWindow) {
457 TestWindowTreeClient* embed_client = nullptr;
458 WindowTree* tree = nullptr;
459 ServerWindow* window = nullptr;
460 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
461
462 // Start with the cursor outside the window. Setting the cursor shouldn't
463 // change the cursor.
464 DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
465 window->SetPredefinedCursor(mojom::Cursor::IBEAM);
466 EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
467
468 // Move the pointer to the inside of the window
469 DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
470 EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
471
472 // Start the drag.
473 DispatchEventAndAckImmediately(CreateMouseDownEvent(21, 22));
474 EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
475
476 // Move the cursor (mouse is still down) outside the window.
477 DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
478 EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
479
480 // Release the cursor. We should now adapt the cursor of the window
481 // underneath the pointer.
482 DispatchEventAndAckImmediately(CreateMouseUpEvent(5, 5));
483 EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
484 }
485
486 TEST_F(WindowTreeTest, ChangingWindowBoundsChangesCursor) {
487 TestWindowTreeClient* embed_client = nullptr;
488 WindowTree* tree = nullptr;
489 ServerWindow* window = nullptr;
490 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
491
492 // Put the cursor just outside the bounds of the window.
493 DispatchEventAndAckImmediately(CreateMouseMoveEvent(41, 41));
494 window->SetPredefinedCursor(mojom::Cursor::IBEAM);
495 EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
496
497 // Expand the bounds of the window so they now include where the cursor now
498 // is.
499 window->SetBounds(gfx::Rect(20, 20, 25, 25));
500 EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
501
502 // Contract the bounds again.
503 window->SetBounds(gfx::Rect(20, 20, 20, 20));
504 EXPECT_EQ(mojom::Cursor::CURSOR_NULL, cursor_id());
505 }
506
507 TEST_F(WindowTreeTest, WindowReorderingChangesCursor) {
508 TestWindowTreeClient* embed_client = nullptr;
509 WindowTree* tree = nullptr;
510 ServerWindow* window1 = nullptr;
511 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window1));
512
513 // Create a second window right over the first.
514 const ClientWindowId embed_window_id(FirstRootId(tree));
515 const ClientWindowId child2_id(BuildClientWindowId(tree, 2));
516 EXPECT_TRUE(tree->NewWindow(child2_id, ServerWindow::Properties()));
517 ServerWindow* child2 = tree->GetWindowByClientId(child2_id);
518 ASSERT_TRUE(child2);
519 EXPECT_TRUE(tree->AddWindow(embed_window_id, child2_id));
520 child2->SetVisible(true);
521 child2->SetBounds(gfx::Rect(20, 20, 20, 20));
522 EnableHitTest(child2);
523
524 // Give each window a different cursor.
525 window1->SetPredefinedCursor(mojom::Cursor::IBEAM);
526 child2->SetPredefinedCursor(mojom::Cursor::HAND);
527
528 // We expect window2 to be over window1 now.
529 DispatchEventAndAckImmediately(CreateMouseMoveEvent(22, 22));
530 EXPECT_EQ(mojom::Cursor::HAND, cursor_id());
531
532 // But when we put window2 at the bottom, we should adapt window1's cursor.
533 child2->parent()->StackChildAtBottom(child2);
534 EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
535 }
536
537 TEST_F(WindowTreeTest, EventAck) {
538 const ClientWindowId embed_window_id = BuildClientWindowId(wm_tree(), 1);
539 EXPECT_TRUE(
540 wm_tree()->NewWindow(embed_window_id, ServerWindow::Properties()));
541 EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id, true));
542 ASSERT_TRUE(FirstRoot(wm_tree()));
543 EXPECT_TRUE(wm_tree()->AddWindow(FirstRootId(wm_tree()), embed_window_id));
544 display()->root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
545
546 wm_client()->tracker()->changes()->clear();
547 DispatchEventWithoutAck(CreateMouseMoveEvent(21, 22));
548 ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
549 EXPECT_EQ("InputEvent window=0,3 event_action=17",
550 ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
551 wm_client()->tracker()->changes()->clear();
552
553 // Send another event. This event shouldn't reach the client.
554 DispatchEventWithoutAck(CreateMouseMoveEvent(21, 22));
555 ASSERT_EQ(0u, wm_client()->tracker()->changes()->size());
556
557 // Ack the first event. That should trigger the dispatch of the second event.
558 AckPreviousEvent();
559 ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
560 EXPECT_EQ("InputEvent window=0,3 event_action=17",
561 ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
562 }
563
564 // Establish client, call NewTopLevelWindow(), make sure get id, and make
565 // sure client paused.
566 TEST_F(WindowTreeTest, NewTopLevelWindow) {
567 TestWindowManager wm_internal;
568 set_window_manager_internal(wm_tree(), &wm_internal);
569
570 TestWindowTreeBinding* child_binding;
571 WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
572 child_binding->client()->tracker()->changes()->clear();
573 child_binding->client()->set_record_on_change_completed(true);
574
575 // Create a new top level window.
576 mojo::Map<mojo::String, mojo::Array<uint8_t>> properties;
577 const uint32_t initial_change_id = 17;
578 // Explicitly use an id that does not contain the client id.
579 const ClientWindowId embed_window_id2_in_child(45 << 16 | 27);
580 static_cast<mojom::WindowTree*>(child_tree)
581 ->NewTopLevelWindow(initial_change_id, embed_window_id2_in_child.id,
582 std::move(properties));
583
584 // The binding should be paused until the wm acks the change.
585 uint32_t wm_change_id = 0u;
586 ASSERT_TRUE(wm_internal.did_call_create_top_level_window(&wm_change_id));
587 EXPECT_TRUE(child_binding->is_paused());
588
589 // Create the window for |embed_window_id2_in_child|.
590 const ClientWindowId embed_window_id2 = BuildClientWindowId(wm_tree(), 2);
591 EXPECT_TRUE(
592 wm_tree()->NewWindow(embed_window_id2, ServerWindow::Properties()));
593 EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id2, true));
594 EXPECT_TRUE(wm_tree()->AddWindow(FirstRootId(wm_tree()), embed_window_id2));
595
596 // Ack the change, which should resume the binding.
597 child_binding->client()->tracker()->changes()->clear();
598 static_cast<mojom::WindowManagerClient*>(wm_tree())
599 ->OnWmCreatedTopLevelWindow(wm_change_id, embed_window_id2.id);
600 EXPECT_FALSE(child_binding->is_paused());
601 EXPECT_EQ("TopLevelCreated id=17 window_id=" +
602 WindowIdToString(
603 WindowIdFromTransportId(embed_window_id2_in_child.id)) +
604 " drawn=true",
605 SingleChangeToDescription(
606 *child_binding->client()->tracker()->changes()));
607 child_binding->client()->tracker()->changes()->clear();
608
609 // Change the visibility of the window from the owner and make sure the
610 // client sees the right id.
611 ServerWindow* embed_window = wm_tree()->GetWindowByClientId(embed_window_id2);
612 ASSERT_TRUE(embed_window);
613 EXPECT_TRUE(embed_window->visible());
614 ASSERT_TRUE(wm_tree()->SetWindowVisibility(
615 ClientWindowIdForWindow(wm_tree(), embed_window), false));
616 EXPECT_FALSE(embed_window->visible());
617 EXPECT_EQ("VisibilityChanged window=" +
618 WindowIdToString(
619 WindowIdFromTransportId(embed_window_id2_in_child.id)) +
620 " visible=false",
621 SingleChangeToDescription(
622 *child_binding->client()->tracker()->changes()));
623
624 // Set the visibility from the child using the client assigned id.
625 ASSERT_TRUE(child_tree->SetWindowVisibility(embed_window_id2_in_child, true));
626 EXPECT_TRUE(embed_window->visible());
627 }
628
629 // Tests that only the capture window can release capture.
630 TEST_F(WindowTreeTest, ExplicitSetCapture) {
631 TestWindowTreeClient* embed_client = nullptr;
632 WindowTree* tree = nullptr;
633 ServerWindow* window = nullptr;
634 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
635 const ServerWindow* root_window = *tree->roots().begin();
636 tree->AddWindow(FirstRootId(tree), ClientWindowIdForWindow(tree, window));
637 window->SetBounds(gfx::Rect(0, 0, 100, 100));
638 ASSERT_TRUE(tree->GetDisplay(window));
639
640 // Set capture.
641 mojom::WindowTree* mojom_window_tree = static_cast<mojom::WindowTree*>(tree);
642 uint32_t change_id = 42;
643 mojom_window_tree->SetCapture(change_id, WindowIdToTransportId(window->id()));
644 Display* display = tree->GetDisplay(window);
645 EXPECT_EQ(window, GetCaptureWindow(display));
646
647 // Only the capture window should be able to release capture
648 mojom_window_tree->ReleaseCapture(++change_id,
649 WindowIdToTransportId(root_window->id()));
650 EXPECT_EQ(window, GetCaptureWindow(display));
651 mojom_window_tree->ReleaseCapture(++change_id,
652 WindowIdToTransportId(window->id()));
653 EXPECT_EQ(nullptr, GetCaptureWindow(display));
654 }
655
656 // Tests that while a client is interacting with input, that capture is not
657 // allowed for invisible windows.
658 TEST_F(WindowTreeTest, CaptureWindowMustBeVisible) {
659 TestWindowTreeClient* embed_client = nullptr;
660 WindowTree* tree = nullptr;
661 ServerWindow* window = nullptr;
662 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
663 tree->AddWindow(FirstRootId(tree), ClientWindowIdForWindow(tree, window));
664 window->SetBounds(gfx::Rect(0, 0, 100, 100));
665 ASSERT_TRUE(tree->GetDisplay(window));
666
667 DispatchEventWithoutAck(CreatePointerDownEvent(10, 10));
668 window->SetVisible(false);
669 EXPECT_FALSE(tree->SetCapture(ClientWindowIdForWindow(tree, window)));
670 EXPECT_NE(window, GetCaptureWindow(tree->GetDisplay(window)));
671 }
672
673 // Tests that showing a modal window releases the capture if the capture is on a
674 // descendant of the modal parent.
675 TEST_F(WindowTreeTest, ShowModalWindowWithDescendantCapture) {
676 TestWindowTreeClient* embed_client = nullptr;
677 WindowTree* tree = nullptr;
678 ServerWindow* w1 = nullptr;
679 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
680
681 w1->SetBounds(gfx::Rect(10, 10, 30, 30));
682 const ServerWindow* root_window = *tree->roots().begin();
683 ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
684 ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
685 Display* display = tree->GetDisplay(w1);
686
687 // Create |w11| as a child of |w1| and make it visible.
688 ClientWindowId w11_id = BuildClientWindowId(tree, 11);
689 ASSERT_TRUE(tree->NewWindow(w11_id, ServerWindow::Properties()));
690 ServerWindow* w11 = tree->GetWindowByClientId(w11_id);
691 w11->SetBounds(gfx::Rect(10, 10, 10, 10));
692 ASSERT_TRUE(tree->AddWindow(w1_id, w11_id));
693 ASSERT_TRUE(tree->SetWindowVisibility(w11_id, true));
694
695 // Create |w2| as a child of |root_window| and modal to |w1| and leave it
696 // hidden.
697 ClientWindowId w2_id = BuildClientWindowId(tree, 2);
698 ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
699 ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
700 w2->SetBounds(gfx::Rect(50, 10, 10, 10));
701 ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
702 ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
703 ASSERT_TRUE(tree->SetModal(w2_id));
704
705 // Set capture to |w11|.
706 DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
707 ASSERT_TRUE(tree->SetCapture(w11_id));
708 EXPECT_EQ(w11, GetCaptureWindow(display));
709 AckPreviousEvent();
710
711 // Make |w2| visible. This should release capture as capture is set to a
712 // descendant of the modal parent.
713 ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
714 EXPECT_EQ(nullptr, GetCaptureWindow(display));
715 }
716
717 // Tests that setting a visible window as modal releases the capture if the
718 // capture is on a descendant of the modal parent.
719 TEST_F(WindowTreeTest, VisibleWindowToModalWithDescendantCapture) {
720 TestWindowTreeClient* embed_client = nullptr;
721 WindowTree* tree = nullptr;
722 ServerWindow* w1 = nullptr;
723 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
724
725 w1->SetBounds(gfx::Rect(10, 10, 30, 30));
726 const ServerWindow* root_window = *tree->roots().begin();
727 ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
728 ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
729 Display* display = tree->GetDisplay(w1);
730
731 // Create |w11| as a child of |w1| and make it visible.
732 ClientWindowId w11_id = BuildClientWindowId(tree, 11);
733 ASSERT_TRUE(tree->NewWindow(w11_id, ServerWindow::Properties()));
734 ServerWindow* w11 = tree->GetWindowByClientId(w11_id);
735 w11->SetBounds(gfx::Rect(10, 10, 10, 10));
736 ASSERT_TRUE(tree->AddWindow(w1_id, w11_id));
737 ASSERT_TRUE(tree->SetWindowVisibility(w11_id, true));
738
739 // Create |w2| as a child of |root_window| and make it visible.
740 ClientWindowId w2_id = BuildClientWindowId(tree, 2);
741 ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
742 ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
743 w2->SetBounds(gfx::Rect(50, 10, 10, 10));
744 ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
745 ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
746
747 // Set capture to |w11|.
748 DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
749 ASSERT_TRUE(tree->SetCapture(w11_id));
750 EXPECT_EQ(w11, GetCaptureWindow(display));
751 AckPreviousEvent();
752
753 // Set |w2| modal to |w1|. This should release the capture as the capture is
754 // set to a descendant of the modal parent.
755 ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
756 ASSERT_TRUE(tree->SetModal(w2_id));
757 EXPECT_EQ(nullptr, GetCaptureWindow(display));
758 }
759
760 // Tests that showing a modal window does not change capture if the capture is
761 // not on a descendant of the modal parent.
762 TEST_F(WindowTreeTest, ShowModalWindowWithNonDescendantCapture) {
763 TestWindowTreeClient* embed_client = nullptr;
764 WindowTree* tree = nullptr;
765 ServerWindow* w1 = nullptr;
766 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
767
768 w1->SetBounds(gfx::Rect(10, 10, 30, 30));
769 const ServerWindow* root_window = *tree->roots().begin();
770 ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
771 ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
772 Display* display = tree->GetDisplay(w1);
773
774 // Create |w2| as a child of |root_window| and modal to |w1| and leave it
775 // hidden..
776 ClientWindowId w2_id = BuildClientWindowId(tree, 2);
777 ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
778 ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
779 w2->SetBounds(gfx::Rect(50, 10, 10, 10));
780 ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
781 ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
782 ASSERT_TRUE(tree->SetModal(w2_id));
783
784 // Create |w3| as a child of |root_window| and make it visible.
785 ClientWindowId w3_id = BuildClientWindowId(tree, 3);
786 ASSERT_TRUE(tree->NewWindow(w3_id, ServerWindow::Properties()));
787 ServerWindow* w3 = tree->GetWindowByClientId(w3_id);
788 w3->SetBounds(gfx::Rect(70, 10, 10, 10));
789 ASSERT_TRUE(tree->AddWindow(root_window_id, w3_id));
790 ASSERT_TRUE(tree->SetWindowVisibility(w3_id, true));
791
792 // Set capture to |w3|.
793 DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
794 ASSERT_TRUE(tree->SetCapture(w3_id));
795 EXPECT_EQ(w3, GetCaptureWindow(display));
796 AckPreviousEvent();
797
798 // Make |w2| visible. This should not change the capture as the capture is not
799 // set to a descendant of the modal parent.
800 ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
801 EXPECT_EQ(w3, GetCaptureWindow(display));
802 }
803
804 // Tests that setting a visible window as modal does not change the capture if
805 // the capture is not set to a descendant of the modal parent.
806 TEST_F(WindowTreeTest, VisibleWindowToModalWithNonDescendantCapture) {
807 TestWindowTreeClient* embed_client = nullptr;
808 WindowTree* tree = nullptr;
809 ServerWindow* w1 = nullptr;
810 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
811
812 w1->SetBounds(gfx::Rect(10, 10, 30, 30));
813 const ServerWindow* root_window = *tree->roots().begin();
814 ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
815 ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
816 Display* display = tree->GetDisplay(w1);
817
818 // Create |w2| and |w3| as children of |root_window| and make them visible.
819 ClientWindowId w2_id = BuildClientWindowId(tree, 2);
820 ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
821 ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
822 w2->SetBounds(gfx::Rect(50, 10, 10, 10));
823 ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
824 ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
825
826 ClientWindowId w3_id = BuildClientWindowId(tree, 3);
827 ASSERT_TRUE(tree->NewWindow(w3_id, ServerWindow::Properties()));
828 ServerWindow* w3 = tree->GetWindowByClientId(w3_id);
829 w3->SetBounds(gfx::Rect(70, 10, 10, 10));
830 ASSERT_TRUE(tree->AddWindow(root_window_id, w3_id));
831 ASSERT_TRUE(tree->SetWindowVisibility(w3_id, true));
832
833 // Set capture to |w3|.
834 DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
835 ASSERT_TRUE(tree->SetCapture(w3_id));
836 EXPECT_EQ(w3, GetCaptureWindow(display));
837 AckPreviousEvent();
838
839 // Set |w2| modal to |w1|. This should not release the capture as the capture
840 // is not set to a descendant of the modal parent.
841 ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
842 ASSERT_TRUE(tree->SetModal(w2_id));
843 EXPECT_EQ(w3, GetCaptureWindow(display));
844 }
845
846 // Tests that showing a system modal window releases the capture.
847 TEST_F(WindowTreeTest, ShowSystemModalWindowWithCapture) {
848 TestWindowTreeClient* embed_client = nullptr;
849 WindowTree* tree = nullptr;
850 ServerWindow* w1 = nullptr;
851 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
852
853 w1->SetBounds(gfx::Rect(10, 10, 10, 10));
854 const ServerWindow* root_window = *tree->roots().begin();
855 ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
856 ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
857 Display* display = tree->GetDisplay(w1);
858
859 // Create a system modal window |w2| as a child of |root_window| and leave it
860 // hidden.
861 ClientWindowId w2_id = BuildClientWindowId(tree, 2);
862 ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
863 ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
864 w2->SetBounds(gfx::Rect(30, 10, 10, 10));
865 ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
866 ASSERT_TRUE(tree->SetModal(w2_id));
867
868 // Set capture to |w1|.
869 DispatchEventWithoutAck(CreatePointerDownEvent(15, 15));
870 ASSERT_TRUE(tree->SetCapture(w1_id));
871 EXPECT_EQ(w1, GetCaptureWindow(display));
872 AckPreviousEvent();
873
874 // Make |w2| visible. This should release capture as it is system modal
875 // window.
876 ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
877 EXPECT_EQ(nullptr, GetCaptureWindow(display));
878 }
879
880 // Tests that setting a visible window as modal to system releases the capture.
881 TEST_F(WindowTreeTest, VisibleWindowToSystemModalWithCapture) {
882 TestWindowTreeClient* embed_client = nullptr;
883 WindowTree* tree = nullptr;
884 ServerWindow* w1 = nullptr;
885 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
886
887 w1->SetBounds(gfx::Rect(10, 10, 10, 10));
888 const ServerWindow* root_window = *tree->roots().begin();
889 ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
890 ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
891 Display* display = tree->GetDisplay(w1);
892
893 // Create |w2| as a child of |root_window| and make it visible.
894 ClientWindowId w2_id = BuildClientWindowId(tree, 2);
895 ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
896 ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
897 w2->SetBounds(gfx::Rect(30, 10, 10, 10));
898 ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
899 ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
900
901 // Set capture to |w1|.
902 DispatchEventWithoutAck(CreatePointerDownEvent(15, 15));
903 ASSERT_TRUE(tree->SetCapture(w1_id));
904 EXPECT_EQ(w1, GetCaptureWindow(display));
905 AckPreviousEvent();
906
907 // Make |w2| modal to system. This should release capture.
908 ASSERT_TRUE(tree->SetModal(w2_id));
909 EXPECT_EQ(nullptr, GetCaptureWindow(display));
910 }
911
912 // Tests that moving the capture window to a modal parent releases the capture
913 // as capture cannot be blocked by a modal window.
914 TEST_F(WindowTreeTest, MoveCaptureWindowToModalParent) {
915 TestWindowTreeClient* embed_client = nullptr;
916 WindowTree* tree = nullptr;
917 ServerWindow* w1 = nullptr;
918 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &w1));
919
920 w1->SetBounds(gfx::Rect(10, 10, 30, 30));
921 const ServerWindow* root_window = *tree->roots().begin();
922 ClientWindowId root_window_id = ClientWindowIdForWindow(tree, root_window);
923 ClientWindowId w1_id = ClientWindowIdForWindow(tree, w1);
924 Display* display = tree->GetDisplay(w1);
925
926 // Create |w2| and |w3| as children of |root_window| and make them visible.
927 ClientWindowId w2_id = BuildClientWindowId(tree, 2);
928 ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
929 ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
930 w2->SetBounds(gfx::Rect(50, 10, 10, 10));
931 ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
932 ASSERT_TRUE(tree->SetWindowVisibility(w2_id, true));
933
934 ClientWindowId w3_id = BuildClientWindowId(tree, 3);
935 ASSERT_TRUE(tree->NewWindow(w3_id, ServerWindow::Properties()));
936 ServerWindow* w3 = tree->GetWindowByClientId(w3_id);
937 w3->SetBounds(gfx::Rect(70, 10, 10, 10));
938 ASSERT_TRUE(tree->AddWindow(root_window_id, w3_id));
939 ASSERT_TRUE(tree->SetWindowVisibility(w3_id, true));
940
941 // Set |w2| modal to |w1|.
942 ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
943 ASSERT_TRUE(tree->SetModal(w2_id));
944
945 // Set capture to |w3|.
946 DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
947 ASSERT_TRUE(tree->SetCapture(w3_id));
948 EXPECT_EQ(w3, GetCaptureWindow(display));
949 AckPreviousEvent();
950
951 // Make |w3| child of |w1|. This should release capture as |w3| is now blocked
952 // by a modal window.
953 ASSERT_TRUE(tree->AddWindow(w1_id, w3_id));
954 EXPECT_EQ(nullptr, GetCaptureWindow(display));
955 }
956
957 // Tests that opacity can be set on a known window.
958 TEST_F(WindowTreeTest, SetOpacity) {
959 TestWindowTreeClient* embed_client = nullptr;
960 WindowTree* tree = nullptr;
961 ServerWindow* window = nullptr;
962 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
963
964 const float new_opacity = 0.5f;
965 EXPECT_NE(new_opacity, window->opacity());
966 ASSERT_TRUE(tree->SetWindowOpacity(ClientWindowIdForWindow(tree, window),
967 new_opacity));
968 EXPECT_EQ(new_opacity, window->opacity());
969
970 // Re-applying the same opacity will succeed.
971 EXPECT_TRUE(tree->SetWindowOpacity(ClientWindowIdForWindow(tree, window),
972 new_opacity));
973 }
974
975 // Tests that opacity requests for unknown windows are rejected.
976 TEST_F(WindowTreeTest, SetOpacityFailsOnUnknownWindow) {
977 TestWindowTreeClient* embed_client = nullptr;
978 WindowTree* tree = nullptr;
979 ServerWindow* window = nullptr;
980 EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
981
982 TestServerWindowDelegate delegate;
983 WindowId window_id(42, 1337);
984 ServerWindow unknown_window(&delegate, window_id);
985 const float new_opacity = 0.5f;
986 ASSERT_NE(new_opacity, unknown_window.opacity());
987
988 EXPECT_FALSE(tree->SetWindowOpacity(
989 ClientWindowId(WindowIdToTransportId(window_id)), new_opacity));
990 EXPECT_NE(new_opacity, unknown_window.opacity());
991 }
992
993 TEST_F(WindowTreeTest, SetCaptureTargetsRightConnection) {
994 ServerWindow* window = window_event_targeting_helper_.CreatePrimaryTree(
995 gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 50, 50));
996 WindowTree* owning_tree =
997 window_server()->GetTreeWithId(window->id().client_id);
998 WindowTree* embed_tree = window_server()->GetTreeWithRoot(window);
999 ASSERT_NE(owning_tree, embed_tree);
1000 ASSERT_TRUE(
1001 owning_tree->SetCapture(ClientWindowIdForWindow(owning_tree, window)));
1002 DispatchEventWithoutAck(CreateMouseMoveEvent(21, 22));
1003 WindowManagerStateTestApi wm_state_test_api(
1004 display()->GetActiveWindowManagerDisplayRoot()->window_manager_state());
1005 EXPECT_EQ(owning_tree, wm_state_test_api.tree_awaiting_input_ack());
1006 AckPreviousEvent();
1007
1008 // Set capture from the embedded client and make sure it gets the event.
1009 ASSERT_TRUE(
1010 embed_tree->SetCapture(ClientWindowIdForWindow(embed_tree, window)));
1011 DispatchEventWithoutAck(CreateMouseMoveEvent(22, 23));
1012 EXPECT_EQ(embed_tree, wm_state_test_api.tree_awaiting_input_ack());
1013 }
1014
1015 } // namespace test
1016 } // namespace ws
1017 } // namespace mus
OLDNEW
« no previous file with comments | « components/mus/ws/window_tree_host_factory.cc ('k') | content/browser/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698