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

Side by Side Diff: components/mus/public/cpp/tests/window_tree_client_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
OLDNEW
(Empty)
1 // Copyright 2015 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/public/cpp/window_tree_client.h"
6
7 #include <stdint.h>
8
9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "components/mus/common/util.h"
12 #include "components/mus/public/cpp/input_event_handler.h"
13 #include "components/mus/public/cpp/lib/window_private.h"
14 #include "components/mus/public/cpp/property_type_converters.h"
15 #include "components/mus/public/cpp/tests/test_window.h"
16 #include "components/mus/public/cpp/tests/test_window_tree.h"
17 #include "components/mus/public/cpp/tests/window_tree_client_private.h"
18 #include "components/mus/public/cpp/window.h"
19 #include "components/mus/public/cpp/window_observer.h"
20 #include "components/mus/public/cpp/window_property.h"
21 #include "components/mus/public/cpp/window_tracker.h"
22 #include "components/mus/public/cpp/window_tree_client_delegate.h"
23 #include "mojo/common/common_type_converters.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "ui/events/event.h"
26 #include "ui/events/event_utils.h"
27 #include "ui/gfx/geometry/rect.h"
28
29 namespace mus {
30
31 namespace {
32
33 void DoNothingWithEventResult(mojom::EventResult result) {}
34
35 Id server_id(mus::Window* window) {
36 return WindowPrivate(window).server_id();
37 }
38
39 } // namespace
40
41 mojo::Array<uint8_t> Int32ToPropertyTransportValue(int32_t value) {
42 const std::vector<uint8_t> bytes =
43 mojo::ConvertTo<std::vector<uint8_t>>(value);
44 mojo::Array<uint8_t> transport_value;
45 transport_value.resize(bytes.size());
46 memcpy(&transport_value.front(), &(bytes.front()), bytes.size());
47 return transport_value;
48 }
49
50 class TestWindowTreeClientDelegate : public WindowTreeClientDelegate {
51 public:
52 TestWindowTreeClientDelegate() {}
53 ~TestWindowTreeClientDelegate() override {}
54
55 ui::Event* last_event_observed() { return last_event_observed_.get(); }
56
57 void Reset() { last_event_observed_.reset(); }
58
59 // WindowTreeClientDelegate:
60 void OnEmbed(Window* root) override {}
61 void OnDidDestroyClient(WindowTreeClient* client) override {}
62 void OnEventObserved(const ui::Event& event, Window* target) override {
63 last_event_observed_ = ui::Event::Clone(event);
64 }
65
66 private:
67 std::unique_ptr<ui::Event> last_event_observed_;
68
69 DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClientDelegate);
70 };
71
72 class WindowTreeSetup {
73 public:
74 WindowTreeSetup() : tree_client_(&window_tree_delegate_, nullptr, nullptr) {
75 WindowTreeClientPrivate(&tree_client_).OnEmbed(&window_tree_);
76 window_tree_.GetAndClearChangeId(nullptr);
77 }
78
79 WindowTreeClient* client() {
80 return &tree_client_;
81 }
82
83 mojom::WindowTreeClient* window_tree_client() {
84 return static_cast<mojom::WindowTreeClient*>(&tree_client_);
85 }
86
87 TestWindowTree* window_tree() { return &window_tree_; }
88
89 TestWindowTreeClientDelegate* window_tree_delegate() {
90 return &window_tree_delegate_;
91 }
92
93 Window* GetFirstRoot() {
94 return client()->GetRoots().empty() ? nullptr
95 : *client()->GetRoots().begin();
96 }
97
98 uint32_t GetEventObserverId() {
99 return WindowTreeClientPrivate(&tree_client_).event_observer_id();
100 }
101
102 private:
103 TestWindowTree window_tree_;
104 TestWindowTreeClientDelegate window_tree_delegate_;
105 WindowTreeClient tree_client_;
106
107 DISALLOW_COPY_AND_ASSIGN(WindowTreeSetup);
108 };
109
110 class TestInputEventHandler : public InputEventHandler {
111 public:
112 TestInputEventHandler()
113 : received_event_(false), should_manually_ack_(false) {}
114 ~TestInputEventHandler() override {}
115
116 void set_should_manually_ack() { should_manually_ack_ = true; }
117
118 void AckEvent() {
119 DCHECK(should_manually_ack_);
120 DCHECK(!ack_callback_.is_null());
121 ack_callback_.Run(mojom::EventResult::HANDLED);
122 ack_callback_ = base::Bind(&DoNothingWithEventResult);
123 }
124
125 void Reset() {
126 received_event_ = false;
127 ack_callback_ = base::Bind(&DoNothingWithEventResult);
128 }
129 bool received_event() const { return received_event_; }
130
131 private:
132 // InputEventHandler:
133 void OnWindowInputEvent(
134 Window* target,
135 const ui::Event& event,
136 std::unique_ptr<base::Callback<void(mojom::EventResult)>>* ack_callback)
137 override {
138 EXPECT_FALSE(received_event_)
139 << "Observer was not reset after receiving event.";
140 received_event_ = true;
141 if (should_manually_ack_) {
142 ack_callback_ = *ack_callback->get();
143 ack_callback->reset();
144 }
145 }
146
147 bool received_event_;
148 bool should_manually_ack_;
149 base::Callback<void(mojom::EventResult)> ack_callback_;
150
151 DISALLOW_COPY_AND_ASSIGN(TestInputEventHandler);
152 };
153
154 using WindowTreeClientTest = testing::Test;
155
156 // Verifies bounds are reverted if the server replied that the change failed.
157 TEST_F(WindowTreeClientTest, SetBoundsFailed) {
158 WindowTreeSetup setup;
159 Window* root = setup.GetFirstRoot();
160 ASSERT_TRUE(root);
161 const gfx::Rect original_bounds(root->bounds());
162 const gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100));
163 ASSERT_NE(new_bounds, root->bounds());
164 root->SetBounds(new_bounds);
165 uint32_t change_id;
166 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
167 setup.window_tree_client()->OnChangeCompleted(change_id, false);
168 EXPECT_EQ(original_bounds, root->bounds());
169 }
170
171 // Simulates a bounds change, and while the bounds change is in flight the
172 // server replies with a new bounds and the original bounds change fails.
173 TEST_F(WindowTreeClientTest, SetBoundsFailedWithPendingChange) {
174 WindowTreeSetup setup;
175 Window* root = setup.GetFirstRoot();
176 ASSERT_TRUE(root);
177 const gfx::Rect original_bounds(root->bounds());
178 const gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100));
179 ASSERT_NE(new_bounds, root->bounds());
180 root->SetBounds(new_bounds);
181 EXPECT_EQ(new_bounds, root->bounds());
182 uint32_t change_id;
183 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
184
185 // Simulate the server responding with a bounds change.
186 const gfx::Rect server_changed_bounds(gfx::Rect(0, 0, 101, 102));
187 setup.window_tree_client()->OnWindowBoundsChanged(
188 server_id(root), original_bounds, server_changed_bounds);
189
190 // This shouldn't trigger the bounds changing yet.
191 EXPECT_EQ(new_bounds, root->bounds());
192
193 // Tell the client the change failed, which should trigger failing to the
194 // most recent bounds from server.
195 setup.window_tree_client()->OnChangeCompleted(change_id, false);
196 EXPECT_EQ(server_changed_bounds, root->bounds());
197
198 // Simulate server changing back to original bounds. Should take immediately.
199 setup.window_tree_client()->OnWindowBoundsChanged(
200 server_id(root), server_changed_bounds, original_bounds);
201 EXPECT_EQ(original_bounds, root->bounds());
202 }
203
204 TEST_F(WindowTreeClientTest, TwoInFlightBoundsChangesBothCanceled) {
205 WindowTreeSetup setup;
206 Window* root = setup.GetFirstRoot();
207 ASSERT_TRUE(root);
208 const gfx::Rect original_bounds(root->bounds());
209 const gfx::Rect bounds1(gfx::Rect(0, 0, 100, 100));
210 const gfx::Rect bounds2(gfx::Rect(0, 0, 100, 102));
211 root->SetBounds(bounds1);
212 EXPECT_EQ(bounds1, root->bounds());
213 uint32_t change_id1;
214 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
215
216 root->SetBounds(bounds2);
217 EXPECT_EQ(bounds2, root->bounds());
218 uint32_t change_id2;
219 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
220
221 // Tell the client change 1 failed. As there is a still a change in flight
222 // nothing should happen.
223 setup.window_tree_client()->OnChangeCompleted(change_id1, false);
224 EXPECT_EQ(bounds2, root->bounds());
225
226 // And tell the client change 2 failed too. Should now fallback to original
227 // bounds.
228 setup.window_tree_client()->OnChangeCompleted(change_id2, false);
229 EXPECT_EQ(original_bounds, root->bounds());
230 }
231
232 // Verifies properties are reverted if the server replied that the change
233 // failed.
234 TEST_F(WindowTreeClientTest, SetPropertyFailed) {
235 WindowTreeSetup setup;
236 Window* root = setup.GetFirstRoot();
237 ASSERT_TRUE(root);
238 ASSERT_FALSE(root->HasSharedProperty("foo"));
239 const int32_t new_value = 11;
240 root->SetSharedProperty("foo", new_value);
241 ASSERT_TRUE(root->HasSharedProperty("foo"));
242 EXPECT_EQ(new_value, root->GetSharedProperty<int32_t>("foo"));
243 uint32_t change_id;
244 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
245 setup.window_tree_client()->OnChangeCompleted(change_id, false);
246 EXPECT_FALSE(root->HasSharedProperty("foo"));
247 }
248
249 // Simulates a property change, and while the property change is in flight the
250 // server replies with a new property and the original property change fails.
251 TEST_F(WindowTreeClientTest, SetPropertyFailedWithPendingChange) {
252 WindowTreeSetup setup;
253 Window* root = setup.GetFirstRoot();
254 ASSERT_TRUE(root);
255 const int32_t value1 = 11;
256 root->SetSharedProperty("foo", value1);
257 ASSERT_TRUE(root->HasSharedProperty("foo"));
258 EXPECT_EQ(value1, root->GetSharedProperty<int32_t>("foo"));
259 uint32_t change_id;
260 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
261
262 // Simulate the server responding with a different value.
263 const int32_t server_value = 12;
264 setup.window_tree_client()->OnWindowSharedPropertyChanged(
265 server_id(root), "foo", Int32ToPropertyTransportValue(server_value));
266
267 // This shouldn't trigger the property changing yet.
268 ASSERT_TRUE(root->HasSharedProperty("foo"));
269 EXPECT_EQ(value1, root->GetSharedProperty<int32_t>("foo"));
270
271 // Tell the client the change failed, which should trigger failing to the
272 // most recent value from server.
273 setup.window_tree_client()->OnChangeCompleted(change_id, false);
274 ASSERT_TRUE(root->HasSharedProperty("foo"));
275 EXPECT_EQ(server_value, root->GetSharedProperty<int32_t>("foo"));
276
277 // Simulate server changing back to value1. Should take immediately.
278 setup.window_tree_client()->OnWindowSharedPropertyChanged(
279 server_id(root), "foo", Int32ToPropertyTransportValue(value1));
280 ASSERT_TRUE(root->HasSharedProperty("foo"));
281 EXPECT_EQ(value1, root->GetSharedProperty<int32_t>("foo"));
282 }
283
284 // Verifies visible is reverted if the server replied that the change failed.
285 TEST_F(WindowTreeClientTest, SetVisibleFailed) {
286 WindowTreeSetup setup;
287 Window* root = setup.GetFirstRoot();
288 ASSERT_TRUE(root);
289 const bool original_visible = root->visible();
290 const bool new_visible = !original_visible;
291 ASSERT_NE(new_visible, root->visible());
292 root->SetVisible(new_visible);
293 uint32_t change_id;
294 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
295 setup.window_tree_client()->OnChangeCompleted(change_id, false);
296 EXPECT_EQ(original_visible, root->visible());
297 }
298
299 // Simulates a visible change, and while the visible change is in flight the
300 // server replies with a new visible and the original visible change fails.
301 TEST_F(WindowTreeClientTest, SetVisibleFailedWithPendingChange) {
302 WindowTreeSetup setup;
303 Window* root = setup.GetFirstRoot();
304 ASSERT_TRUE(root);
305 const bool original_visible = root->visible();
306 const bool new_visible = !original_visible;
307 ASSERT_NE(new_visible, root->visible());
308 root->SetVisible(new_visible);
309 EXPECT_EQ(new_visible, root->visible());
310 uint32_t change_id;
311 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
312
313 // Simulate the server responding with a visible change.
314 const bool server_changed_visible = !new_visible;
315 setup.window_tree_client()->OnWindowVisibilityChanged(server_id(root),
316 server_changed_visible);
317
318 // This shouldn't trigger visible changing yet.
319 EXPECT_EQ(new_visible, root->visible());
320
321 // Tell the client the change failed, which should trigger failing to the
322 // most recent visible from server.
323 setup.window_tree_client()->OnChangeCompleted(change_id, false);
324 EXPECT_EQ(server_changed_visible, root->visible());
325
326 // Simulate server changing back to original visible. Should take immediately.
327 setup.window_tree_client()->OnWindowVisibilityChanged(server_id(root),
328 original_visible);
329 EXPECT_EQ(original_visible, root->visible());
330 }
331
332 // Verifies that local opacity is not changed if the server replied that the
333 // change succeeded.
334 TEST_F(WindowTreeClientTest, SetOpacitySucceeds) {
335 WindowTreeSetup setup;
336 Window* root = setup.GetFirstRoot();
337 ASSERT_TRUE(root);
338 const float original_opacity = root->opacity();
339 const float new_opacity = 0.5f;
340 ASSERT_NE(new_opacity, original_opacity);
341 ASSERT_NE(new_opacity, root->opacity());
342 root->SetOpacity(new_opacity);
343 uint32_t change_id;
344 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
345 setup.window_tree_client()->OnChangeCompleted(change_id, true);
346 EXPECT_EQ(new_opacity, root->opacity());
347 }
348
349 // Verifies that opacity is reverted if the server replied that the change
350 // failed.
351 TEST_F(WindowTreeClientTest, SetOpacityFailed) {
352 WindowTreeSetup setup;
353 Window* root = setup.GetFirstRoot();
354 ASSERT_TRUE(root);
355 const float original_opacity = root->opacity();
356 const float new_opacity = 0.5f;
357 ASSERT_NE(new_opacity, root->opacity());
358 root->SetOpacity(new_opacity);
359 uint32_t change_id;
360 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
361 setup.window_tree_client()->OnChangeCompleted(change_id, false);
362 EXPECT_EQ(original_opacity, root->opacity());
363 }
364
365 // Simulates the server changing the opacitry while there is an opacity change
366 // in flight, causing the requested change to fail.
367 TEST_F(WindowTreeClientTest, SetOpacityFailedWithPendingChange) {
368 WindowTreeSetup setup;
369 Window* root = setup.GetFirstRoot();
370 ASSERT_TRUE(root);
371 const float original_opacity = root->opacity();
372 const float new_opacity = 0.5f;
373 ASSERT_NE(new_opacity, root->opacity());
374 root->SetOpacity(new_opacity);
375 EXPECT_EQ(new_opacity, root->opacity());
376 uint32_t change_id;
377 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
378
379 // Simulate the server responding with an opacity change.
380 const float server_changed_opacity = 0.75f;
381 setup.window_tree_client()->OnWindowOpacityChanged(
382 server_id(root), original_opacity, server_changed_opacity);
383
384 // This shouldn't trigger opacity changing yet.
385 EXPECT_EQ(new_opacity, root->opacity());
386
387 // Tell the client the change failed, which should trigger failing to the
388 // most recent opacity from server.
389 setup.window_tree_client()->OnChangeCompleted(change_id, false);
390 EXPECT_EQ(server_changed_opacity, root->opacity());
391
392 // Simulate server changing back to original opacity. Should take immediately.
393 setup.window_tree_client()->OnWindowOpacityChanged(
394 server_id(root), server_changed_opacity, original_opacity);
395 EXPECT_EQ(original_opacity, root->opacity());
396 }
397
398 // Tests that when there are multiple changes in flight, that failing changes
399 // update the revert state of subsequent changes.
400 TEST_F(WindowTreeClientTest, SetOpacityFailedWithMultiplePendingChange) {
401 WindowTreeSetup setup;
402 Window* root = setup.GetFirstRoot();
403 ASSERT_TRUE(root);
404 const float original_opacity = root->opacity();
405 const float new_opacity = 0.5f;
406 ASSERT_NE(new_opacity, root->opacity());
407 root->SetOpacity(new_opacity);
408 uint32_t change_id1;
409 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
410
411 const float second_new_opacity = 0.75f;
412 ASSERT_NE(second_new_opacity, root->opacity());
413 root->SetOpacity(second_new_opacity);
414 uint32_t change_id2;
415 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
416
417 // Canceling the first one, while there is another in flight, should not
418 // change the local opacity.
419 setup.window_tree_client()->OnChangeCompleted(change_id1, false);
420 EXPECT_EQ(second_new_opacity, root->opacity());
421
422 // The previous cancelation should have updated the revert value of the in
423 // flight change.
424 setup.window_tree_client()->OnChangeCompleted(change_id2, false);
425 EXPECT_EQ(original_opacity, root->opacity());
426 }
427
428 // Verifies |is_modal| is reverted if the server replied that the change failed.
429 TEST_F(WindowTreeClientTest, SetModalFailed) {
430 WindowTreeSetup setup;
431 Window* root = setup.GetFirstRoot();
432 ASSERT_TRUE(root);
433 EXPECT_FALSE(root->is_modal());
434 root->SetModal();
435 uint32_t change_id;
436 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
437 EXPECT_TRUE(root->is_modal());
438 setup.window_tree_client()->OnChangeCompleted(change_id, false);
439 EXPECT_FALSE(root->is_modal());
440 }
441
442 TEST_F(WindowTreeClientTest, InputEventBasic) {
443 WindowTreeSetup setup;
444 Window* root = setup.GetFirstRoot();
445 ASSERT_TRUE(root);
446
447 TestInputEventHandler event_handler;
448 root->set_input_event_handler(&event_handler);
449
450 std::unique_ptr<ui::Event> ui_event(
451 new ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
452 ui::EventTimeForNow(), ui::EF_NONE, 0));
453 setup.window_tree_client()->OnWindowInputEvent(
454 1, server_id(root), ui::Event::Clone(*ui_event.get()), 0);
455 EXPECT_TRUE(event_handler.received_event());
456 EXPECT_TRUE(setup.window_tree()->WasEventAcked(1));
457 event_handler.Reset();
458
459 event_handler.set_should_manually_ack();
460 setup.window_tree_client()->OnWindowInputEvent(
461 33, server_id(root), ui::Event::Clone(*ui_event.get()), 0);
462 EXPECT_TRUE(event_handler.received_event());
463 EXPECT_FALSE(setup.window_tree()->WasEventAcked(33));
464
465 event_handler.AckEvent();
466 EXPECT_TRUE(setup.window_tree()->WasEventAcked(33));
467 }
468
469 // Tests event observers triggered by events that did not hit a target in this
470 // window tree.
471 TEST_F(WindowTreeClientTest, OnEventObserved) {
472 WindowTreeSetup setup;
473 Window* root = setup.GetFirstRoot();
474 ASSERT_TRUE(root);
475
476 // Set up an event observer.
477 mojom::EventMatcherPtr matcher = mojom::EventMatcher::New();
478 matcher->type_matcher = mojom::EventTypeMatcher::New();
479 matcher->type_matcher->type = ui::mojom::EventType::POINTER_DOWN;
480 setup.client()->SetEventObserver(std::move(matcher));
481
482 // Simulate the server sending an observed event.
483 uint32_t event_observer_id = setup.GetEventObserverId();
484 std::unique_ptr<ui::Event> ui_event(
485 new ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
486 ui::EventTimeForNow(), ui::EF_CONTROL_DOWN, 0));
487 setup.window_tree_client()->OnEventObserved(ui::Event::Clone(*ui_event.get()),
488 event_observer_id);
489
490 // Delegate sensed the event.
491 ui::Event* last_event = setup.window_tree_delegate()->last_event_observed();
492 EXPECT_EQ(ui::ET_MOUSE_PRESSED, last_event->type());
493 EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags());
494 setup.window_tree_delegate()->Reset();
495
496 // Clear the event observer.
497 setup.client()->SetEventObserver(nullptr);
498
499 // Simulate another event from the server.
500 setup.window_tree_client()->OnEventObserved(ui::Event::Clone(*ui_event.get()),
501 event_observer_id);
502
503 // No event was sensed.
504 EXPECT_FALSE(setup.window_tree_delegate()->last_event_observed());
505 }
506
507 // Tests event observers triggered by events that hit this window tree.
508 TEST_F(WindowTreeClientTest, OnWindowInputEventWithEventObserver) {
509 WindowTreeSetup setup;
510 Window* root = setup.GetFirstRoot();
511 ASSERT_TRUE(root);
512
513 // Set up an event observer.
514 mojom::EventMatcherPtr matcher = mojom::EventMatcher::New();
515 matcher->type_matcher = mojom::EventTypeMatcher::New();
516 matcher->type_matcher->type = ui::mojom::EventType::POINTER_DOWN;
517 setup.client()->SetEventObserver(std::move(matcher));
518
519 // Simulate the server dispatching an event that also matched the observer.
520 uint32_t event_observer_id = setup.GetEventObserverId();
521 std::unique_ptr<ui::Event> ui_event(
522 new ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
523 ui::EventTimeForNow(), ui::EF_CONTROL_DOWN, 0));
524 setup.window_tree_client()->OnWindowInputEvent(
525 1, server_id(root), std::move(ui_event), event_observer_id);
526
527 // Delegate sensed the event.
528 ui::Event* last_event = setup.window_tree_delegate()->last_event_observed();
529 EXPECT_EQ(ui::ET_MOUSE_PRESSED, last_event->type());
530 EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags());
531 }
532
533 // Tests that replacing an event observer with a new one results in only new
534 // events being observed.
535 TEST_F(WindowTreeClientTest, EventObserverReplaced) {
536 WindowTreeSetup setup;
537 Window* root = setup.GetFirstRoot();
538 ASSERT_TRUE(root);
539
540 // Set up an event observer.
541 mojom::EventMatcherPtr matcher1 = mojom::EventMatcher::New();
542 matcher1->type_matcher = mojom::EventTypeMatcher::New();
543 matcher1->type_matcher->type = ui::mojom::EventType::POINTER_DOWN;
544 setup.client()->SetEventObserver(std::move(matcher1));
545 uint32_t event_observer_id1 = setup.GetEventObserverId();
546
547 // Replace it with a second observer.
548 mojom::EventMatcherPtr matcher2 = mojom::EventMatcher::New();
549 matcher2->type_matcher = mojom::EventTypeMatcher::New();
550 matcher2->type_matcher->type = ui::mojom::EventType::POINTER_UP;
551 setup.client()->SetEventObserver(std::move(matcher2));
552 uint32_t event_observer_id2 = setup.GetEventObserverId();
553
554 // Simulate the server sending an observed event that matched the old observer
555 // (e.g. that was in-flight when the observer was replaced).
556 std::unique_ptr<ui::Event> pressed_event(
557 new ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
558 ui::EventTimeForNow(), ui::EF_NONE, 0));
559 setup.window_tree_client()->OnEventObserved(std::move(pressed_event),
560 event_observer_id1);
561
562 // The event was not sensed, because it does not match the current observer.
563 EXPECT_FALSE(setup.window_tree_delegate()->last_event_observed());
564
565 // Simulate another event that matches the new observer.
566 std::unique_ptr<ui::Event> released_event(
567 new ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
568 ui::EventTimeForNow(), ui::EF_CONTROL_DOWN, 0));
569 setup.window_tree_client()->OnEventObserved(std::move(released_event),
570 event_observer_id2);
571
572 // The delegate sensed the event.
573 ui::Event* last_event = setup.window_tree_delegate()->last_event_observed();
574 EXPECT_EQ(ui::ET_MOUSE_RELEASED, last_event->type());
575 EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags());
576 }
577
578 // Verifies focus is reverted if the server replied that the change failed.
579 TEST_F(WindowTreeClientTest, SetFocusFailed) {
580 WindowTreeSetup setup;
581 Window* root = setup.GetFirstRoot();
582 ASSERT_TRUE(root);
583 root->SetVisible(true);
584 Window* child = setup.client()->NewWindow();
585 child->SetVisible(true);
586 root->AddChild(child);
587 Window* original_focus = setup.client()->GetFocusedWindow();
588 Window* new_focus = child;
589 ASSERT_NE(new_focus, original_focus);
590 new_focus->SetFocus();
591 ASSERT_TRUE(new_focus->HasFocus());
592 uint32_t change_id;
593 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
594 setup.window_tree_client()->OnChangeCompleted(change_id, false);
595 EXPECT_EQ(original_focus, setup.client()->GetFocusedWindow());
596 }
597
598 // Simulates a focus change, and while the focus change is in flight the server
599 // replies with a new focus and the original focus change fails.
600 TEST_F(WindowTreeClientTest, SetFocusFailedWithPendingChange) {
601 WindowTreeSetup setup;
602 Window* root = setup.GetFirstRoot();
603 ASSERT_TRUE(root);
604 root->SetVisible(true);
605 Window* child1 = setup.client()->NewWindow();
606 child1->SetVisible(true);
607 root->AddChild(child1);
608 Window* child2 = setup.client()->NewWindow();
609 child2->SetVisible(true);
610 root->AddChild(child2);
611 Window* original_focus = setup.client()->GetFocusedWindow();
612 Window* new_focus = child1;
613 ASSERT_NE(new_focus, original_focus);
614 new_focus->SetFocus();
615 ASSERT_TRUE(new_focus->HasFocus());
616 uint32_t change_id;
617 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
618
619 // Simulate the server responding with a focus change.
620 setup.window_tree_client()->OnWindowFocused(server_id(child2));
621
622 // This shouldn't trigger focus changing yet.
623 EXPECT_TRUE(child1->HasFocus());
624
625 // Tell the client the change failed, which should trigger failing to the
626 // most recent focus from server.
627 setup.window_tree_client()->OnChangeCompleted(change_id, false);
628 EXPECT_FALSE(child1->HasFocus());
629 EXPECT_TRUE(child2->HasFocus());
630 EXPECT_EQ(child2, setup.client()->GetFocusedWindow());
631
632 // Simulate server changing focus to child1. Should take immediately.
633 setup.window_tree_client()->OnWindowFocused(server_id(child1));
634 EXPECT_TRUE(child1->HasFocus());
635 }
636
637 TEST_F(WindowTreeClientTest, FocusOnRemovedWindowWithInFlightFocusChange) {
638 WindowTreeSetup setup;
639 Window* root = setup.GetFirstRoot();
640 ASSERT_TRUE(root);
641 root->SetVisible(true);
642 Window* child1 = setup.client()->NewWindow();
643 child1->SetVisible(true);
644 root->AddChild(child1);
645 Window* child2 = setup.client()->NewWindow();
646 child2->SetVisible(true);
647 root->AddChild(child2);
648
649 child1->SetFocus();
650 uint32_t change_id;
651 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
652
653 // Destroy child1, which should set focus to null.
654 child1->Destroy();
655 EXPECT_EQ(nullptr, setup.client()->GetFocusedWindow());
656
657 // Server changes focus to 2.
658 setup.window_tree_client()->OnWindowFocused(server_id(child2));
659 // Shouldn't take immediately.
660 EXPECT_FALSE(child2->HasFocus());
661
662 // Ack the change, focus should still be null.
663 setup.window_tree_client()->OnChangeCompleted(change_id, true);
664 EXPECT_EQ(nullptr, setup.client()->GetFocusedWindow());
665
666 // Change to 2 again, this time it should take.
667 setup.window_tree_client()->OnWindowFocused(server_id(child2));
668 EXPECT_TRUE(child2->HasFocus());
669 }
670
671 class ToggleVisibilityFromDestroyedObserver : public WindowObserver {
672 public:
673 explicit ToggleVisibilityFromDestroyedObserver(Window* window)
674 : window_(window) {
675 window_->AddObserver(this);
676 }
677
678 ToggleVisibilityFromDestroyedObserver() { EXPECT_FALSE(window_); }
679
680 // WindowObserver:
681 void OnWindowDestroyed(Window* window) override {
682 window_->SetVisible(!window->visible());
683 window_->RemoveObserver(this);
684 window_ = nullptr;
685 }
686
687 private:
688 Window* window_;
689
690 DISALLOW_COPY_AND_ASSIGN(ToggleVisibilityFromDestroyedObserver);
691 };
692
693 TEST_F(WindowTreeClientTest, ToggleVisibilityFromWindowDestroyed) {
694 WindowTreeSetup setup;
695 Window* root = setup.GetFirstRoot();
696 ASSERT_TRUE(root);
697 Window* child1 = setup.client()->NewWindow();
698 root->AddChild(child1);
699 ToggleVisibilityFromDestroyedObserver toggler(child1);
700 // Destroying the window triggers
701 // ToggleVisibilityFromDestroyedObserver::OnWindowDestroyed(), which toggles
702 // the visibility of the window. Ack the change, which should not crash or
703 // trigger DCHECKs.
704 child1->Destroy();
705 uint32_t change_id;
706 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
707 setup.window_tree_client()->OnChangeCompleted(change_id, true);
708 }
709
710 TEST_F(WindowTreeClientTest, NewTopLevelWindow) {
711 WindowTreeSetup setup;
712 Window* root1 = setup.GetFirstRoot();
713 ASSERT_TRUE(root1);
714 Window* root2 = setup.client()->NewTopLevelWindow(nullptr);
715 ASSERT_TRUE(root2);
716 EXPECT_TRUE(WindowPrivate(root2).parent_drawn());
717 ASSERT_NE(root2, root1);
718 EXPECT_NE(server_id(root2), server_id(root1));
719 EXPECT_EQ(2u, setup.client()->GetRoots().size());
720 EXPECT_TRUE(setup.client()->GetRoots().count(root1) > 0u);
721 EXPECT_TRUE(setup.client()->GetRoots().count(root2) > 0u);
722
723 // Ack the request to the windowtree to create the new window.
724 uint32_t change_id;
725 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
726 EXPECT_EQ(setup.window_tree()->window_id(), server_id(root2));
727
728 mojom::WindowDataPtr data = mojom::WindowData::New();
729 data->window_id = server_id(root2);
730 const int64_t display_id = 1;
731 setup.window_tree_client()->OnTopLevelCreated(change_id, std::move(data),
732 display_id, false);
733
734 EXPECT_FALSE(WindowPrivate(root2).parent_drawn());
735
736 // Should not be able to add a top level as a child of another window.
737 root1->AddChild(root2);
738 ASSERT_EQ(nullptr, root2->parent());
739
740 // Destroy the first root, shouldn't initiate tear down.
741 root1->Destroy();
742 root1 = nullptr;
743 EXPECT_EQ(1u, setup.client()->GetRoots().size());
744 EXPECT_TRUE(setup.client()->GetRoots().count(root2) > 0u);
745 }
746
747 TEST_F(WindowTreeClientTest, NewTopLevelWindowGetsPropertiesFromData) {
748 WindowTreeSetup setup;
749 Window* root1 = setup.GetFirstRoot();
750 ASSERT_TRUE(root1);
751 Window* root2 = setup.client()->NewTopLevelWindow(nullptr);
752 ASSERT_TRUE(root2);
753
754 EXPECT_FALSE(root2->IsDrawn());
755 EXPECT_FALSE(root2->visible());
756
757 // Ack the request to the windowtree to create the new window.
758 uint32_t change_id;
759 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
760 EXPECT_EQ(setup.window_tree()->window_id(), server_id(root2));
761
762 mojom::WindowDataPtr data = mojom::WindowData::New();
763 data->window_id = server_id(root2);
764 data->bounds.SetRect(1, 2, 3, 4);
765 data->visible = true;
766 const int64_t display_id = 1;
767 setup.window_tree_client()->OnTopLevelCreated(change_id, std::move(data),
768 display_id, true);
769
770 // Make sure all the properties took.
771 EXPECT_TRUE(root2->IsDrawn());
772 EXPECT_TRUE(root2->visible());
773 EXPECT_EQ(1, root2->display_id());
774 EXPECT_EQ(gfx::Rect(1, 2, 3, 4), root2->bounds());
775 }
776
777 TEST_F(WindowTreeClientTest, NewTopLevelWindowGetsAllChangesInFlight) {
778 WindowTreeSetup setup;
779 Window* root1 = setup.GetFirstRoot();
780 ASSERT_TRUE(root1);
781 Window* root2 = setup.client()->NewTopLevelWindow(nullptr);
782 ASSERT_TRUE(root2);
783
784 EXPECT_FALSE(root2->IsDrawn());
785 EXPECT_FALSE(root2->visible());
786
787 // Get the id of the in flight change for creating the new window.
788 uint32_t new_window_in_flight_change_id;
789 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(
790 &new_window_in_flight_change_id));
791 EXPECT_EQ(setup.window_tree()->window_id(), server_id(root2));
792
793 // Make visibility go from false->true->false. Don't ack immediately.
794 root2->SetVisible(true);
795 uint32_t vis_in_flight_change_id1;
796 ASSERT_TRUE(
797 setup.window_tree()->GetAndClearChangeId(&vis_in_flight_change_id1));
798 EXPECT_NE(new_window_in_flight_change_id, vis_in_flight_change_id1);
799 root2->SetVisible(false);
800 uint32_t vis_in_flight_change_id2;
801 ASSERT_TRUE(
802 setup.window_tree()->GetAndClearChangeId(&vis_in_flight_change_id2));
803 EXPECT_NE(vis_in_flight_change_id1, vis_in_flight_change_id2);
804
805 // Change bounds to 5, 6, 7, 8.
806 root2->SetBounds(gfx::Rect(5, 6, 7, 8));
807 uint32_t bounds_in_flight_change_id;
808 ASSERT_TRUE(
809 setup.window_tree()->GetAndClearChangeId(&bounds_in_flight_change_id));
810 EXPECT_NE(vis_in_flight_change_id2, bounds_in_flight_change_id);
811
812 root2->SetSharedProperty<std::string>("xx", "client_xx");
813 uint32_t property_in_flight_change_id;
814 ASSERT_TRUE(
815 setup.window_tree()->GetAndClearChangeId(&property_in_flight_change_id));
816 EXPECT_NE(bounds_in_flight_change_id, property_in_flight_change_id);
817
818 // Ack the new window top level window. Vis and bounds shouldn't change.
819 mojom::WindowDataPtr data = mojom::WindowData::New();
820 data->window_id = server_id(root2);
821 data->bounds.SetRect(1, 2, 3, 4);
822 data->visible = true;
823 data->properties["xx"] = mojo::Array<uint8_t>::From(std::string("server_xx"));
824 data->properties["yy"] = mojo::Array<uint8_t>::From(std::string("server_yy"));
825 const int64_t display_id = 1;
826 setup.window_tree_client()->OnTopLevelCreated(
827 new_window_in_flight_change_id, std::move(data), display_id, true);
828
829 // The only value that should take effect is the property for 'yy' as it was
830 // not in flight.
831 EXPECT_TRUE(WindowPrivate(root2).parent_drawn());
832 EXPECT_FALSE(root2->visible());
833 EXPECT_EQ(1, root2->display_id());
834 EXPECT_EQ(gfx::Rect(5, 6, 7, 8), root2->bounds());
835 EXPECT_EQ(2u, root2->shared_properties().size());
836 ASSERT_TRUE(root2->HasSharedProperty("yy"));
837 EXPECT_EQ("server_yy", root2->GetSharedProperty<std::string>("yy"));
838 ASSERT_TRUE(root2->HasSharedProperty("xx"));
839 EXPECT_EQ("client_xx", root2->GetSharedProperty<std::string>("xx"));
840
841 // Tell the client the changes failed. This should cause the values to change
842 // to that of the server.
843 setup.window_tree_client()->OnChangeCompleted(vis_in_flight_change_id1,
844 false);
845 EXPECT_FALSE(root2->visible());
846 setup.window_tree_client()->OnChangeCompleted(vis_in_flight_change_id2,
847 false);
848 EXPECT_TRUE(root2->visible());
849 setup.window_tree_client()->OnChangeCompleted(bounds_in_flight_change_id,
850 false);
851 EXPECT_EQ(gfx::Rect(1, 2, 3, 4), root2->bounds());
852 setup.window_tree_client()->OnChangeCompleted(property_in_flight_change_id,
853 false);
854 EXPECT_EQ(2u, root2->shared_properties().size());
855 ASSERT_TRUE(root2->HasSharedProperty("yy"));
856 EXPECT_EQ("server_yy", root2->GetSharedProperty<std::string>("yy"));
857 ASSERT_TRUE(root2->HasSharedProperty("xx"));
858 EXPECT_EQ("server_xx", root2->GetSharedProperty<std::string>("xx"));
859 }
860
861 // Tests that if the client has multiple unowned windows, and one of them is a
862 // transient child to another, the teardown can happen cleanly.
863 TEST_F(WindowTreeClientTest, MultipleUnOwnedWindowsDuringDestruction) {
864 std::unique_ptr<WindowTreeSetup> setup(new WindowTreeSetup());
865 Window* root1 = setup->GetFirstRoot();
866 ASSERT_TRUE(root1);
867 Window* root2 = setup->client()->NewTopLevelWindow(nullptr);
868 ASSERT_TRUE(root2);
869 root1->AddTransientWindow(root2);
870
871 WindowTracker tracker;
872 tracker.Add(root1);
873 tracker.Add(root2);
874 setup.reset();
875 EXPECT_TRUE(tracker.windows().empty());
876 }
877
878 TEST_F(WindowTreeClientTest, TopLevelWindowDestroyedBeforeCreateComplete) {
879 WindowTreeSetup setup;
880 Window* root1 = setup.GetFirstRoot();
881 ASSERT_TRUE(root1);
882 Window* root2 = setup.client()->NewTopLevelWindow(nullptr);
883 ASSERT_TRUE(root2);
884 ASSERT_EQ(2u, setup.client()->GetRoots().size());
885
886 // Get the id of the in flight change for creating the new window.
887 uint32_t change_id;
888 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id));
889 EXPECT_EQ(setup.window_tree()->window_id(), server_id(root2));
890
891 mojom::WindowDataPtr data = mojom::WindowData::New();
892 data->window_id = server_id(root2);
893
894 // Destroy the window before the server has a chance to ack the window
895 // creation.
896 root2->Destroy();
897 EXPECT_EQ(1u, setup.client()->GetRoots().size());
898
899 const int64_t display_id = 1;
900 setup.window_tree_client()->OnTopLevelCreated(change_id, std::move(data),
901 display_id, true);
902 EXPECT_EQ(1u, setup.client()->GetRoots().size());
903 }
904
905 // Tests both SetCapture and ReleaseCapture, to ensure that Window is properly
906 // updated on failures.
907 TEST_F(WindowTreeClientTest, ExplicitCapture) {
908 WindowTreeSetup setup;
909 Window* root = setup.GetFirstRoot();
910 ASSERT_TRUE(root);
911
912 root->SetCapture();
913 EXPECT_TRUE(root->HasCapture());
914 uint32_t change_id1;
915 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
916 setup.window_tree_client()->OnChangeCompleted(change_id1, false);
917 EXPECT_FALSE(root->HasCapture());
918
919 root->SetCapture();
920 EXPECT_TRUE(root->HasCapture());
921 uint32_t change_id2;
922 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
923 setup.window_tree_client()->OnChangeCompleted(change_id2, true);
924 EXPECT_TRUE(root->HasCapture());
925
926 root->ReleaseCapture();
927 EXPECT_FALSE(root->HasCapture());
928 uint32_t change_id3;
929 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id3));
930 setup.window_tree_client()->OnChangeCompleted(change_id3, false);
931 EXPECT_TRUE(root->HasCapture());
932
933 root->ReleaseCapture();
934 uint32_t change_id4;
935 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id4));
936 setup.window_tree_client()->OnChangeCompleted(change_id4, true);
937 EXPECT_FALSE(root->HasCapture());
938 }
939
940 // Tests that when capture is lost, that the window tree updates properly.
941 TEST_F(WindowTreeClientTest, LostCapture) {
942 WindowTreeSetup setup;
943 Window* root = setup.GetFirstRoot();
944 ASSERT_TRUE(root);
945
946 root->SetCapture();
947 EXPECT_TRUE(root->HasCapture());
948 uint32_t change_id1;
949 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
950 setup.window_tree_client()->OnChangeCompleted(change_id1, true);
951 EXPECT_TRUE(root->HasCapture());
952
953 // The second SetCapture should be ignored.
954 root->SetCapture();
955 uint32_t change_id2;
956 ASSERT_FALSE(setup.window_tree()->GetAndClearChangeId(&change_id2));
957
958 setup.window_tree_client()->OnLostCapture(server_id(root));
959 EXPECT_FALSE(root->HasCapture());
960 }
961
962 // Tests that when capture is lost, while there is a release capture request
963 // inflight, that the revert value of that request is updated correctly.
964 TEST_F(WindowTreeClientTest, LostCaptureDifferentInFlightChange) {
965 WindowTreeSetup setup;
966 Window* root = setup.GetFirstRoot();
967 ASSERT_TRUE(root);
968
969 root->SetCapture();
970 EXPECT_TRUE(root->HasCapture());
971 uint32_t change_id1;
972 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
973 setup.window_tree_client()->OnChangeCompleted(change_id1, true);
974 EXPECT_TRUE(root->HasCapture());
975
976 // The ReleaseCapture should be updated to the revert of the SetCapture.
977 root->ReleaseCapture();
978 uint32_t change_id2;
979 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
980
981 setup.window_tree_client()->OnLostCapture(server_id(root));
982 EXPECT_FALSE(root->HasCapture());
983
984 setup.window_tree_client()->OnChangeCompleted(change_id2, false);
985 EXPECT_FALSE(root->HasCapture());
986 }
987
988 // Tests that while two windows can inflight capture requests, that the
989 // WindowTreeClient only identifies one as having the current capture.
990 TEST_F(WindowTreeClientTest, TwoWindowsRequestCapture) {
991 WindowTreeSetup setup;
992 Window* root = setup.GetFirstRoot();
993 Window* child = setup.client()->NewWindow();
994 child->SetVisible(true);
995 root->AddChild(child);
996
997 root->SetCapture();
998 EXPECT_TRUE(root->HasCapture());
999 uint32_t change_id1;
1000 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id1));
1001
1002 child->SetCapture();
1003 EXPECT_TRUE(child->HasCapture());
1004 EXPECT_FALSE(root->HasCapture());
1005
1006 uint32_t change_id2;
1007 ASSERT_TRUE(setup.window_tree()->GetAndClearChangeId(&change_id2));
1008
1009 setup.window_tree_client()->OnChangeCompleted(change_id1, true);
1010 EXPECT_FALSE(root->HasCapture());
1011 EXPECT_TRUE(child->HasCapture());
1012
1013 setup.window_tree_client()->OnChangeCompleted(change_id2, false);
1014 EXPECT_FALSE(child->HasCapture());
1015 EXPECT_TRUE(root->HasCapture());
1016
1017 setup.window_tree_client()->OnLostCapture(server_id(root));
1018 EXPECT_FALSE(root->HasCapture());
1019 }
1020
1021 TEST_F(WindowTreeClientTest, WindowDestroyedWhileTransientChildHasCapture) {
1022 WindowTreeSetup setup;
1023 Window* root = setup.GetFirstRoot();
1024 Window* transient_parent = setup.client()->NewWindow();
1025 Window* transient_child = setup.client()->NewWindow();
1026 transient_parent->SetVisible(true);
1027 transient_child->SetVisible(true);
1028 root->AddChild(transient_parent);
1029 root->AddChild(transient_child);
1030
1031 transient_parent->AddTransientWindow(transient_child);
1032
1033 WindowTracker tracker;
1034 tracker.Add(transient_parent);
1035 tracker.Add(transient_child);
1036 // Request a capture on the transient child, then destroy the transient
1037 // parent. That will destroy both windows, and should reset the capture window
1038 // correctly.
1039 transient_child->SetCapture();
1040 transient_parent->Destroy();
1041 EXPECT_TRUE(tracker.windows().empty());
1042
1043 // Create a new Window, and attempt to place capture on that.
1044 Window* child = setup.client()->NewWindow();
1045 child->SetVisible(true);
1046 root->AddChild(child);
1047 child->SetCapture();
1048 EXPECT_TRUE(child->HasCapture());
1049 }
1050
1051 } // namespace mus
OLDNEW
« no previous file with comments | « components/mus/public/cpp/tests/window_tree_client_private.cc ('k') | components/mus/public/cpp/tests/window_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698