OLD | NEW |
| (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/ws/event_dispatcher.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 | |
10 #include <queue> | |
11 | |
12 #include "base/macros.h" | |
13 #include "base/memory/weak_ptr.h" | |
14 #include "components/mus/common/event_matcher_util.h" | |
15 #include "components/mus/ws/accelerator.h" | |
16 #include "components/mus/ws/event_dispatcher_delegate.h" | |
17 #include "components/mus/ws/server_window.h" | |
18 #include "components/mus/ws/server_window_surface_manager_test_api.h" | |
19 #include "components/mus/ws/test_server_window_delegate.h" | |
20 #include "components/mus/ws/test_utils.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 #include "ui/events/event.h" | |
23 | |
24 namespace mus { | |
25 namespace ws { | |
26 namespace test { | |
27 namespace { | |
28 | |
29 // Client ids used to indicate the client area and non-client area. | |
30 const ClientSpecificId kClientAreaId = 11; | |
31 const ClientSpecificId kNonclientAreaId = 111; | |
32 | |
33 // Identifies a generated event. | |
34 struct DispatchedEventDetails { | |
35 DispatchedEventDetails() | |
36 : window(nullptr), client_id(kInvalidClientId), accelerator(nullptr) {} | |
37 | |
38 bool IsNonclientArea() const { return client_id == kNonclientAreaId; } | |
39 bool IsClientArea() const { return client_id == kClientAreaId; } | |
40 | |
41 ServerWindow* window; | |
42 ClientSpecificId client_id; | |
43 std::unique_ptr<ui::Event> event; | |
44 Accelerator* accelerator; | |
45 }; | |
46 | |
47 class TestEventDispatcherDelegate : public EventDispatcherDelegate { | |
48 public: | |
49 // Delegate interface used by this class to release capture on event | |
50 // dispatcher. | |
51 class Delegate { | |
52 public: | |
53 virtual void ReleaseCapture() = 0; | |
54 }; | |
55 | |
56 explicit TestEventDispatcherDelegate(Delegate* delegate) | |
57 : delegate_(delegate), | |
58 focused_window_(nullptr), | |
59 lost_capture_window_(nullptr), | |
60 last_accelerator_(0) {} | |
61 ~TestEventDispatcherDelegate() override {} | |
62 | |
63 ui::Event* last_event_target_not_found() { | |
64 return last_event_target_not_found_.get(); | |
65 } | |
66 | |
67 uint32_t GetAndClearLastAccelerator() { | |
68 uint32_t return_value = last_accelerator_; | |
69 last_accelerator_ = 0; | |
70 return return_value; | |
71 } | |
72 | |
73 void set_root(ServerWindow* root) { root_ = root; } | |
74 | |
75 // Returns the last dispatched event, or null if there are no more. | |
76 std::unique_ptr<DispatchedEventDetails> | |
77 GetAndAdvanceDispatchedEventDetails() { | |
78 if (dispatched_event_queue_.empty()) | |
79 return nullptr; | |
80 | |
81 std::unique_ptr<DispatchedEventDetails> details = | |
82 std::move(dispatched_event_queue_.front()); | |
83 dispatched_event_queue_.pop(); | |
84 return details; | |
85 } | |
86 | |
87 ServerWindow* GetAndClearLastFocusedWindow() { | |
88 ServerWindow* result = focused_window_; | |
89 focused_window_ = nullptr; | |
90 return result; | |
91 } | |
92 | |
93 bool has_queued_events() const { return !dispatched_event_queue_.empty(); } | |
94 ServerWindow* lost_capture_window() { return lost_capture_window_; } | |
95 | |
96 // EventDispatcherDelegate: | |
97 void SetFocusedWindowFromEventDispatcher(ServerWindow* window) override { | |
98 focused_window_ = window; | |
99 } | |
100 | |
101 private: | |
102 // EventDispatcherDelegate: | |
103 void OnAccelerator(uint32_t accelerator, const ui::Event& event) override { | |
104 EXPECT_EQ(0u, last_accelerator_); | |
105 last_accelerator_ = accelerator; | |
106 } | |
107 ServerWindow* GetFocusedWindowForEventDispatcher() override { | |
108 return focused_window_; | |
109 } | |
110 void SetNativeCapture(ServerWindow* window) override {} | |
111 void ReleaseNativeCapture() override { | |
112 if (delegate_) | |
113 delegate_->ReleaseCapture(); | |
114 } | |
115 void OnServerWindowCaptureLost(ServerWindow* window) override { | |
116 lost_capture_window_ = window; | |
117 } | |
118 void OnMouseCursorLocationChanged(const gfx::Point& point) override {} | |
119 void DispatchInputEventToWindow(ServerWindow* target, | |
120 ClientSpecificId client_id, | |
121 const ui::Event& event, | |
122 Accelerator* accelerator) override { | |
123 std::unique_ptr<DispatchedEventDetails> details(new DispatchedEventDetails); | |
124 details->window = target; | |
125 details->client_id = client_id; | |
126 details->event = ui::Event::Clone(event); | |
127 details->accelerator = accelerator; | |
128 dispatched_event_queue_.push(std::move(details)); | |
129 } | |
130 ClientSpecificId GetEventTargetClientId(const ServerWindow* window, | |
131 bool in_nonclient_area) override { | |
132 return in_nonclient_area ? kNonclientAreaId : kClientAreaId; | |
133 } | |
134 ServerWindow* GetRootWindowContaining(const gfx::Point& location) override { | |
135 return root_; | |
136 } | |
137 void OnEventTargetNotFound(const ui::Event& event) override { | |
138 last_event_target_not_found_ = ui::Event::Clone(event); | |
139 } | |
140 | |
141 Delegate* delegate_; | |
142 ServerWindow* focused_window_; | |
143 ServerWindow* lost_capture_window_; | |
144 uint32_t last_accelerator_; | |
145 std::queue<std::unique_ptr<DispatchedEventDetails>> dispatched_event_queue_; | |
146 ServerWindow* root_ = nullptr; | |
147 std::unique_ptr<ui::Event> last_event_target_not_found_; | |
148 | |
149 DISALLOW_COPY_AND_ASSIGN(TestEventDispatcherDelegate); | |
150 }; | |
151 | |
152 // Used by RunMouseEventTests(). Can identify up to two generated events. The | |
153 // first ServerWindow and two points identify the first event, the second | |
154 // ServerWindow and points identify the second event. If only one event is | |
155 // generated set the second window to null. | |
156 struct MouseEventTest { | |
157 ui::MouseEvent input_event; | |
158 ServerWindow* expected_target_window1; | |
159 gfx::Point expected_root_location1; | |
160 gfx::Point expected_location1; | |
161 ServerWindow* expected_target_window2; | |
162 gfx::Point expected_root_location2; | |
163 gfx::Point expected_location2; | |
164 }; | |
165 | |
166 // Verifies |details| matches the supplied ServerWindow and points. | |
167 void ExpectDispatchedEventDetailsMatches(const DispatchedEventDetails* details, | |
168 ServerWindow* target, | |
169 const gfx::Point& root_location, | |
170 const gfx::Point& location) { | |
171 if (!target) { | |
172 ASSERT_FALSE(details); | |
173 return; | |
174 } | |
175 | |
176 ASSERT_EQ(target, details->window); | |
177 ASSERT_TRUE(details->event); | |
178 ASSERT_TRUE(details->event->IsLocatedEvent()); | |
179 ASSERT_TRUE(details->IsClientArea()); | |
180 ASSERT_EQ(root_location, details->event->AsLocatedEvent()->root_location()); | |
181 ASSERT_EQ(location, details->event->AsLocatedEvent()->location()); | |
182 } | |
183 | |
184 void RunMouseEventTests(EventDispatcher* dispatcher, | |
185 TestEventDispatcherDelegate* dispatcher_delegate, | |
186 MouseEventTest* tests, | |
187 size_t test_count) { | |
188 for (size_t i = 0; i < test_count; ++i) { | |
189 const MouseEventTest& test = tests[i]; | |
190 ASSERT_FALSE(dispatcher_delegate->has_queued_events()) | |
191 << " unexpected queued events before running " << i; | |
192 if (test.input_event.IsMouseWheelEvent()) | |
193 dispatcher->ProcessEvent(test.input_event); | |
194 else | |
195 dispatcher->ProcessEvent(ui::PointerEvent(test.input_event)); | |
196 | |
197 std::unique_ptr<DispatchedEventDetails> details = | |
198 dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
199 ASSERT_NO_FATAL_FAILURE(ExpectDispatchedEventDetailsMatches( | |
200 details.get(), test.expected_target_window1, | |
201 test.expected_root_location1, test.expected_location1)) | |
202 << " details don't match " << i; | |
203 details = dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
204 ASSERT_NO_FATAL_FAILURE(ExpectDispatchedEventDetailsMatches( | |
205 details.get(), test.expected_target_window2, | |
206 test.expected_root_location2, test.expected_location2)) | |
207 << " details2 don't match " << i; | |
208 ASSERT_FALSE(dispatcher_delegate->has_queued_events()) | |
209 << " unexpected queued events after running " << i; | |
210 } | |
211 } | |
212 | |
213 } // namespace | |
214 | |
215 // Test fixture for EventDispatcher with friend access to verify the internal | |
216 // state. Setup creates a TestServerWindowDelegate, a visible root ServerWindow, | |
217 // a TestEventDispatcher and the EventDispatcher for testing. | |
218 class EventDispatcherTest : public testing::Test, | |
219 public TestEventDispatcherDelegate::Delegate { | |
220 public: | |
221 EventDispatcherTest() {} | |
222 ~EventDispatcherTest() override {} | |
223 | |
224 ServerWindow* root_window() { return root_window_.get(); } | |
225 TestEventDispatcherDelegate* test_event_dispatcher_delegate() { | |
226 return test_event_dispatcher_delegate_.get(); | |
227 } | |
228 EventDispatcher* event_dispatcher() { return event_dispatcher_.get(); } | |
229 | |
230 bool AreAnyPointersDown() const; | |
231 // Deletes everything created during SetUp() | |
232 void ClearSetup(); | |
233 std::unique_ptr<ServerWindow> CreateChildWindowWithParent( | |
234 const WindowId& id, | |
235 ServerWindow* parent); | |
236 // Creates a window which is a child of |root_window_|. | |
237 std::unique_ptr<ServerWindow> CreateChildWindow(const WindowId& id); | |
238 bool IsMouseButtonDown() const; | |
239 bool IsWindowPointerTarget(const ServerWindow* window) const; | |
240 int NumberPointerTargetsForWindow(ServerWindow* window) const; | |
241 ServerWindow* GetActiveSystemModalWindow() const; | |
242 | |
243 protected: | |
244 // testing::Test: | |
245 void SetUp() override; | |
246 | |
247 private: | |
248 // TestEventDispatcherDelegate::Delegate: | |
249 void ReleaseCapture() override { | |
250 event_dispatcher_->SetCaptureWindow(nullptr, kInvalidClientId); | |
251 } | |
252 | |
253 std::unique_ptr<TestServerWindowDelegate> window_delegate_; | |
254 std::unique_ptr<ServerWindow> root_window_; | |
255 std::unique_ptr<TestEventDispatcherDelegate> test_event_dispatcher_delegate_; | |
256 std::unique_ptr<EventDispatcher> event_dispatcher_; | |
257 | |
258 DISALLOW_COPY_AND_ASSIGN(EventDispatcherTest); | |
259 }; | |
260 | |
261 bool EventDispatcherTest::AreAnyPointersDown() const { | |
262 return EventDispatcherTestApi(event_dispatcher_.get()).AreAnyPointersDown(); | |
263 } | |
264 | |
265 void EventDispatcherTest::ClearSetup() { | |
266 window_delegate_.reset(); | |
267 root_window_.reset(); | |
268 test_event_dispatcher_delegate_.reset(); | |
269 event_dispatcher_.reset(); | |
270 } | |
271 | |
272 std::unique_ptr<ServerWindow> EventDispatcherTest::CreateChildWindowWithParent( | |
273 const WindowId& id, | |
274 ServerWindow* parent) { | |
275 std::unique_ptr<ServerWindow> child( | |
276 new ServerWindow(window_delegate_.get(), id)); | |
277 parent->Add(child.get()); | |
278 child->SetVisible(true); | |
279 EnableHitTest(child.get()); | |
280 return child; | |
281 } | |
282 | |
283 std::unique_ptr<ServerWindow> EventDispatcherTest::CreateChildWindow( | |
284 const WindowId& id) { | |
285 return CreateChildWindowWithParent(id, root_window_.get()); | |
286 } | |
287 | |
288 bool EventDispatcherTest::IsMouseButtonDown() const { | |
289 return EventDispatcherTestApi(event_dispatcher_.get()).is_mouse_button_down(); | |
290 } | |
291 | |
292 bool EventDispatcherTest::IsWindowPointerTarget( | |
293 const ServerWindow* window) const { | |
294 return EventDispatcherTestApi(event_dispatcher_.get()) | |
295 .IsWindowPointerTarget(window); | |
296 } | |
297 | |
298 int EventDispatcherTest::NumberPointerTargetsForWindow( | |
299 ServerWindow* window) const { | |
300 return EventDispatcherTestApi(event_dispatcher_.get()) | |
301 .NumberPointerTargetsForWindow(window); | |
302 } | |
303 | |
304 ServerWindow* EventDispatcherTest::GetActiveSystemModalWindow() const { | |
305 ModalWindowController* mwc = | |
306 EventDispatcherTestApi(event_dispatcher_.get()).modal_window_controller(); | |
307 return ModalWindowControllerTestApi(mwc).GetActiveSystemModalWindow(); | |
308 } | |
309 | |
310 void EventDispatcherTest::SetUp() { | |
311 testing::Test::SetUp(); | |
312 | |
313 window_delegate_.reset(new TestServerWindowDelegate()); | |
314 root_window_.reset(new ServerWindow(window_delegate_.get(), WindowId(1, 2))); | |
315 window_delegate_->set_root_window(root_window_.get()); | |
316 root_window_->SetVisible(true); | |
317 | |
318 test_event_dispatcher_delegate_.reset(new TestEventDispatcherDelegate(this)); | |
319 event_dispatcher_.reset( | |
320 new EventDispatcher(test_event_dispatcher_delegate_.get())); | |
321 test_event_dispatcher_delegate_->set_root(root_window_.get()); | |
322 } | |
323 | |
324 TEST_F(EventDispatcherTest, ProcessEvent) { | |
325 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
326 | |
327 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
328 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
329 | |
330 // Send event that is over child. | |
331 const ui::PointerEvent ui_event(ui::MouseEvent( | |
332 ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), gfx::Point(20, 25), | |
333 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
334 event_dispatcher()->ProcessEvent(ui_event); | |
335 | |
336 std::unique_ptr<DispatchedEventDetails> details = | |
337 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
338 ASSERT_TRUE(details); | |
339 ASSERT_EQ(child.get(), details->window); | |
340 | |
341 ASSERT_TRUE(details->event); | |
342 ASSERT_TRUE(details->event->IsPointerEvent()); | |
343 | |
344 ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); | |
345 EXPECT_EQ(gfx::Point(20, 25), dispatched_event->root_location()); | |
346 EXPECT_EQ(gfx::Point(10, 15), dispatched_event->location()); | |
347 } | |
348 | |
349 TEST_F(EventDispatcherTest, ProcessEventNoTarget) { | |
350 // Send event without a target. | |
351 ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE); | |
352 event_dispatcher()->ProcessEvent(key); | |
353 | |
354 // Event wasn't dispatched to a target. | |
355 std::unique_ptr<DispatchedEventDetails> details = | |
356 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
357 EXPECT_FALSE(details); | |
358 | |
359 // Delegate was informed that there wasn't a target. | |
360 ui::Event* event_out = | |
361 test_event_dispatcher_delegate()->last_event_target_not_found(); | |
362 ASSERT_TRUE(event_out); | |
363 EXPECT_TRUE(event_out->IsKeyEvent()); | |
364 EXPECT_EQ(ui::VKEY_A, event_out->AsKeyEvent()->key_code()); | |
365 } | |
366 | |
367 TEST_F(EventDispatcherTest, AcceleratorBasic) { | |
368 ClearSetup(); | |
369 TestEventDispatcherDelegate event_dispatcher_delegate(nullptr); | |
370 EventDispatcher dispatcher(&event_dispatcher_delegate); | |
371 | |
372 uint32_t accelerator_1 = 1; | |
373 mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher( | |
374 ui::mojom::KeyboardCode::W, ui::mojom::kEventFlagControlDown); | |
375 EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_1, std::move(matcher))); | |
376 | |
377 uint32_t accelerator_2 = 2; | |
378 matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::N, | |
379 ui::mojom::kEventFlagNone); | |
380 EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, std::move(matcher))); | |
381 | |
382 // Attempting to add a new accelerator with the same id should fail. | |
383 matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::T, | |
384 ui::mojom::kEventFlagNone); | |
385 EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_2, std::move(matcher))); | |
386 | |
387 // Adding the accelerator with the same id should succeed once the existing | |
388 // accelerator is removed. | |
389 dispatcher.RemoveAccelerator(accelerator_2); | |
390 matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::T, | |
391 ui::mojom::kEventFlagNone); | |
392 EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_2, std::move(matcher))); | |
393 | |
394 // Attempting to add an accelerator with the same matcher should fail. | |
395 uint32_t accelerator_3 = 3; | |
396 matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::T, | |
397 ui::mojom::kEventFlagNone); | |
398 EXPECT_FALSE(dispatcher.AddAccelerator(accelerator_3, std::move(matcher))); | |
399 | |
400 matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::T, | |
401 ui::mojom::kEventFlagControlDown); | |
402 EXPECT_TRUE(dispatcher.AddAccelerator(accelerator_3, std::move(matcher))); | |
403 } | |
404 | |
405 TEST_F(EventDispatcherTest, EventMatching) { | |
406 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
407 test_event_dispatcher_delegate(); | |
408 EventDispatcher* dispatcher = event_dispatcher(); | |
409 | |
410 mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher( | |
411 ui::mojom::KeyboardCode::W, ui::mojom::kEventFlagControlDown); | |
412 uint32_t accelerator_1 = 1; | |
413 dispatcher->AddAccelerator(accelerator_1, std::move(matcher)); | |
414 | |
415 ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN); | |
416 dispatcher->ProcessEvent(key); | |
417 EXPECT_EQ(accelerator_1, | |
418 event_dispatcher_delegate->GetAndClearLastAccelerator()); | |
419 | |
420 // EF_NUM_LOCK_ON should be ignored since CreateKeyMatcher defaults to | |
421 // ignoring. | |
422 key = ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_W, | |
423 ui::EF_CONTROL_DOWN | ui::EF_NUM_LOCK_ON); | |
424 dispatcher->ProcessEvent(key); | |
425 EXPECT_EQ(accelerator_1, | |
426 event_dispatcher_delegate->GetAndClearLastAccelerator()); | |
427 | |
428 key = ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_NONE); | |
429 dispatcher->ProcessEvent(key); | |
430 EXPECT_EQ(0u, event_dispatcher_delegate->GetAndClearLastAccelerator()); | |
431 | |
432 uint32_t accelerator_2 = 2; | |
433 matcher = mus::CreateKeyMatcher(ui::mojom::KeyboardCode::W, | |
434 ui::mojom::kEventFlagNone); | |
435 dispatcher->AddAccelerator(accelerator_2, std::move(matcher)); | |
436 dispatcher->ProcessEvent(key); | |
437 EXPECT_EQ(accelerator_2, | |
438 event_dispatcher_delegate->GetAndClearLastAccelerator()); | |
439 | |
440 dispatcher->RemoveAccelerator(accelerator_2); | |
441 dispatcher->ProcessEvent(key); | |
442 EXPECT_EQ(0u, event_dispatcher_delegate->GetAndClearLastAccelerator()); | |
443 } | |
444 | |
445 // Tests that a post-target accelerator is not triggered by ProcessEvent. | |
446 TEST_F(EventDispatcherTest, PostTargetAccelerator) { | |
447 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
448 test_event_dispatcher_delegate(); | |
449 EventDispatcher* dispatcher = event_dispatcher(); | |
450 | |
451 mojom::EventMatcherPtr matcher = mus::CreateKeyMatcher( | |
452 ui::mojom::KeyboardCode::W, ui::mojom::kEventFlagControlDown); | |
453 matcher->accelerator_phase = ui::mojom::AcceleratorPhase::POST_TARGET; | |
454 uint32_t accelerator_1 = 1; | |
455 dispatcher->AddAccelerator(accelerator_1, std::move(matcher)); | |
456 | |
457 ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN); | |
458 // The post-target accelerator should be fired if there is no focused window. | |
459 dispatcher->ProcessEvent(key); | |
460 EXPECT_EQ(accelerator_1, | |
461 event_dispatcher_delegate->GetAndClearLastAccelerator()); | |
462 std::unique_ptr<DispatchedEventDetails> details = | |
463 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
464 EXPECT_FALSE(details); | |
465 | |
466 // Set focused window for EventDispatcher dispatches key events. | |
467 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
468 event_dispatcher_delegate->SetFocusedWindowFromEventDispatcher(child.get()); | |
469 | |
470 // With a focused window the event should be dispatched. | |
471 dispatcher->ProcessEvent(key); | |
472 EXPECT_EQ(0u, event_dispatcher_delegate->GetAndClearLastAccelerator()); | |
473 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
474 EXPECT_TRUE(details); | |
475 EXPECT_TRUE(details->accelerator); | |
476 | |
477 base::WeakPtr<Accelerator> accelerator_weak_ptr = | |
478 details->accelerator->GetWeakPtr(); | |
479 dispatcher->RemoveAccelerator(accelerator_1); | |
480 EXPECT_FALSE(accelerator_weak_ptr); | |
481 | |
482 // Post deletion there should be no accelerator | |
483 dispatcher->ProcessEvent(key); | |
484 EXPECT_EQ(0u, event_dispatcher_delegate->GetAndClearLastAccelerator()); | |
485 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
486 EXPECT_TRUE(details); | |
487 EXPECT_FALSE(details->accelerator); | |
488 } | |
489 | |
490 TEST_F(EventDispatcherTest, Capture) { | |
491 ServerWindow* root = root_window(); | |
492 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
493 | |
494 root->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
495 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
496 | |
497 MouseEventTest tests[] = { | |
498 // Send a mouse down event over child. | |
499 {ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), | |
500 gfx::Point(20, 25), base::TimeTicks(), | |
501 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON), | |
502 child.get(), gfx::Point(20, 25), gfx::Point(10, 15), nullptr, | |
503 gfx::Point(), gfx::Point()}, | |
504 | |
505 // Capture should be activated. Let's send a mouse move outside the bounds | |
506 // of the child. | |
507 {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50), | |
508 gfx::Point(50, 50), base::TimeTicks(), | |
509 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON), | |
510 child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr, | |
511 gfx::Point(), gfx::Point()}, | |
512 // Release the mouse and verify that the mouse up event goes to the child. | |
513 {ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(50, 50), | |
514 gfx::Point(50, 50), base::TimeTicks(), | |
515 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON), | |
516 child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr, | |
517 gfx::Point(), gfx::Point()}, | |
518 | |
519 // A mouse move at (50, 50) should now go to the root window. As the | |
520 // move crosses between |child| and |root| |child| gets an exit, and | |
521 // |root| the move. | |
522 {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50), | |
523 gfx::Point(50, 50), base::TimeTicks(), | |
524 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON), | |
525 child.get(), gfx::Point(50, 50), gfx::Point(40, 40), root, | |
526 gfx::Point(50, 50), gfx::Point(50, 50)}, | |
527 | |
528 }; | |
529 RunMouseEventTests(event_dispatcher(), test_event_dispatcher_delegate(), | |
530 tests, arraysize(tests)); | |
531 } | |
532 | |
533 TEST_F(EventDispatcherTest, CaptureMultipleMouseButtons) { | |
534 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
535 | |
536 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
537 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
538 | |
539 MouseEventTest tests[] = { | |
540 // Send a mouse down event over child with a left mouse button | |
541 {ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), | |
542 gfx::Point(20, 25), base::TimeTicks(), | |
543 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON), | |
544 child.get(), gfx::Point(20, 25), gfx::Point(10, 15), nullptr, | |
545 gfx::Point(), gfx::Point()}, | |
546 | |
547 // Capture should be activated. Let's send a mouse move outside the bounds | |
548 // of the child and press the right mouse button too. | |
549 {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50), | |
550 gfx::Point(50, 50), base::TimeTicks(), | |
551 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, 0), | |
552 child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr, | |
553 gfx::Point(), gfx::Point()}, | |
554 | |
555 // Release the left mouse button and verify that the mouse up event goes | |
556 // to the child. | |
557 {ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(50, 50), | |
558 gfx::Point(50, 50), base::TimeTicks(), | |
559 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, | |
560 ui::EF_RIGHT_MOUSE_BUTTON), | |
561 child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr, | |
562 gfx::Point(), gfx::Point()}, | |
563 | |
564 // A mouse move at (50, 50) should still go to the child. | |
565 {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50), | |
566 gfx::Point(50, 50), base::TimeTicks(), | |
567 ui::EF_LEFT_MOUSE_BUTTON, 0), | |
568 child.get(), gfx::Point(50, 50), gfx::Point(40, 40), nullptr, | |
569 gfx::Point(), gfx::Point()}, | |
570 | |
571 }; | |
572 RunMouseEventTests(event_dispatcher(), test_event_dispatcher_delegate(), | |
573 tests, arraysize(tests)); | |
574 } | |
575 | |
576 TEST_F(EventDispatcherTest, ClientAreaGoesToOwner) { | |
577 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
578 | |
579 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
580 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
581 | |
582 child->SetClientArea(gfx::Insets(5, 5, 5, 5), std::vector<gfx::Rect>()); | |
583 | |
584 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
585 test_event_dispatcher_delegate(); | |
586 EventDispatcher* dispatcher = event_dispatcher(); | |
587 | |
588 // Start move loop by sending mouse event over non-client area. | |
589 const ui::PointerEvent press_event(ui::MouseEvent( | |
590 ui::ET_MOUSE_PRESSED, gfx::Point(12, 12), gfx::Point(12, 12), | |
591 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
592 dispatcher->ProcessEvent(press_event); | |
593 | |
594 // Events should target child and be in the non-client area. | |
595 std::unique_ptr<DispatchedEventDetails> details = | |
596 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
597 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
598 ASSERT_TRUE(details); | |
599 ASSERT_EQ(child.get(), details->window); | |
600 EXPECT_TRUE(details->IsNonclientArea()); | |
601 | |
602 // Move the mouse 5,6 pixels and target is the same. | |
603 const ui::PointerEvent move_event( | |
604 ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(17, 18), gfx::Point(17, 18), | |
605 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, 0)); | |
606 dispatcher->ProcessEvent(move_event); | |
607 | |
608 // Still same target. | |
609 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
610 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
611 ASSERT_EQ(child.get(), details->window); | |
612 EXPECT_TRUE(details->IsNonclientArea()); | |
613 | |
614 // Release the mouse. | |
615 const ui::PointerEvent release_event(ui::MouseEvent( | |
616 ui::ET_MOUSE_RELEASED, gfx::Point(17, 18), gfx::Point(17, 18), | |
617 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
618 dispatcher->ProcessEvent(release_event); | |
619 | |
620 // The event should not have been dispatched to the delegate. | |
621 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
622 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
623 ASSERT_EQ(child.get(), details->window); | |
624 EXPECT_TRUE(details->IsNonclientArea()); | |
625 | |
626 // Press in the client area and verify target/client area. The non-client area | |
627 // should get an exit first. | |
628 const ui::PointerEvent press_event2(ui::MouseEvent( | |
629 ui::ET_MOUSE_PRESSED, gfx::Point(21, 22), gfx::Point(21, 22), | |
630 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
631 dispatcher->ProcessEvent(press_event2); | |
632 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
633 EXPECT_TRUE(event_dispatcher_delegate->has_queued_events()); | |
634 ASSERT_EQ(child.get(), details->window); | |
635 EXPECT_TRUE(details->IsNonclientArea()); | |
636 EXPECT_EQ(ui::ET_POINTER_EXITED, details->event->type()); | |
637 | |
638 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
639 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
640 ASSERT_EQ(child.get(), details->window); | |
641 EXPECT_TRUE(details->IsClientArea()); | |
642 EXPECT_EQ(ui::ET_POINTER_DOWN, details->event->type()); | |
643 } | |
644 | |
645 TEST_F(EventDispatcherTest, AdditionalClientArea) { | |
646 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
647 | |
648 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
649 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
650 | |
651 std::vector<gfx::Rect> additional_client_areas; | |
652 additional_client_areas.push_back(gfx::Rect(18, 0, 2, 2)); | |
653 child->SetClientArea(gfx::Insets(5, 5, 5, 5), additional_client_areas); | |
654 | |
655 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
656 test_event_dispatcher_delegate(); | |
657 // Press in the additional client area, it should go to the child. | |
658 const ui::PointerEvent press_event(ui::MouseEvent( | |
659 ui::ET_MOUSE_PRESSED, gfx::Point(28, 11), gfx::Point(28, 11), | |
660 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
661 event_dispatcher()->ProcessEvent(press_event); | |
662 | |
663 // Events should target child and be in the client area. | |
664 std::unique_ptr<DispatchedEventDetails> details = | |
665 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
666 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
667 ASSERT_EQ(child.get(), details->window); | |
668 EXPECT_TRUE(details->IsClientArea()); | |
669 } | |
670 | |
671 TEST_F(EventDispatcherTest, HitTestMask) { | |
672 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
673 | |
674 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
675 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
676 child->SetHitTestMask(gfx::Rect(2, 2, 16, 16)); | |
677 | |
678 // Move in the masked area. | |
679 const ui::PointerEvent move1(ui::MouseEvent( | |
680 ui::ET_MOUSE_MOVED, gfx::Point(11, 11), gfx::Point(11, 11), | |
681 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, 0)); | |
682 event_dispatcher()->ProcessEvent(move1); | |
683 | |
684 // Event went through the child window and hit the root. | |
685 std::unique_ptr<DispatchedEventDetails> details1 = | |
686 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
687 EXPECT_EQ(root_window(), details1->window); | |
688 EXPECT_TRUE(details1->IsClientArea()); | |
689 | |
690 child->ClearHitTestMask(); | |
691 | |
692 // Move right in the same part of the window. | |
693 const ui::PointerEvent move2(ui::MouseEvent( | |
694 ui::ET_MOUSE_MOVED, gfx::Point(11, 12), gfx::Point(11, 12), | |
695 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, 0)); | |
696 event_dispatcher()->ProcessEvent(move2); | |
697 | |
698 // Mouse exits the root. | |
699 std::unique_ptr<DispatchedEventDetails> details2 = | |
700 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
701 EXPECT_EQ(ui::ET_POINTER_EXITED, details2->event->type()); | |
702 | |
703 // Mouse hits the child. | |
704 std::unique_ptr<DispatchedEventDetails> details3 = | |
705 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
706 EXPECT_EQ(child.get(), details3->window); | |
707 EXPECT_TRUE(details3->IsClientArea()); | |
708 } | |
709 | |
710 TEST_F(EventDispatcherTest, DontFocusOnSecondDown) { | |
711 std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3)); | |
712 std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4)); | |
713 | |
714 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
715 child1->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
716 child2->SetBounds(gfx::Rect(50, 51, 11, 12)); | |
717 | |
718 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
719 test_event_dispatcher_delegate(); | |
720 EventDispatcher* dispatcher = event_dispatcher(); | |
721 | |
722 // Press on child1. First press event should change focus. | |
723 const ui::PointerEvent press_event(ui::MouseEvent( | |
724 ui::ET_MOUSE_PRESSED, gfx::Point(12, 12), gfx::Point(12, 12), | |
725 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
726 dispatcher->ProcessEvent(press_event); | |
727 std::unique_ptr<DispatchedEventDetails> details = | |
728 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
729 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
730 EXPECT_EQ(child1.get(), details->window); | |
731 EXPECT_EQ(child1.get(), | |
732 event_dispatcher_delegate->GetAndClearLastFocusedWindow()); | |
733 | |
734 // Press (with a different pointer id) on child2. Event should go to child2, | |
735 // but focus should not change. | |
736 const ui::PointerEvent touch_event(ui::TouchEvent( | |
737 ui::ET_TOUCH_PRESSED, gfx::Point(53, 54), 2, base::TimeTicks())); | |
738 dispatcher->ProcessEvent(touch_event); | |
739 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
740 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
741 EXPECT_EQ(child2.get(), details->window); | |
742 EXPECT_EQ(nullptr, event_dispatcher_delegate->GetAndClearLastFocusedWindow()); | |
743 } | |
744 | |
745 TEST_F(EventDispatcherTest, TwoPointersActive) { | |
746 std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3)); | |
747 std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4)); | |
748 | |
749 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
750 child1->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
751 child2->SetBounds(gfx::Rect(50, 51, 11, 12)); | |
752 | |
753 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
754 test_event_dispatcher_delegate(); | |
755 EventDispatcher* dispatcher = event_dispatcher(); | |
756 | |
757 // Press on child1. | |
758 const ui::PointerEvent touch_event1(ui::TouchEvent( | |
759 ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks())); | |
760 dispatcher->ProcessEvent(touch_event1); | |
761 std::unique_ptr<DispatchedEventDetails> details = | |
762 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
763 EXPECT_EQ(child1.get(), details->window); | |
764 | |
765 // Drag over child2, child1 should get the drag. | |
766 const ui::PointerEvent drag_event1(ui::TouchEvent( | |
767 ui::ET_TOUCH_MOVED, gfx::Point(53, 54), 1, base::TimeTicks())); | |
768 dispatcher->ProcessEvent(drag_event1); | |
769 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
770 EXPECT_EQ(child1.get(), details->window); | |
771 | |
772 // Press on child2 with a different touch id. | |
773 const ui::PointerEvent touch_event2(ui::TouchEvent( | |
774 ui::ET_TOUCH_PRESSED, gfx::Point(54, 55), 2, base::TimeTicks())); | |
775 dispatcher->ProcessEvent(touch_event2); | |
776 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
777 EXPECT_EQ(child2.get(), details->window); | |
778 | |
779 // Drag over child1 with id 2, child2 should continue to get the drag. | |
780 const ui::PointerEvent drag_event2(ui::TouchEvent( | |
781 ui::ET_TOUCH_MOVED, gfx::Point(13, 14), 2, base::TimeTicks())); | |
782 dispatcher->ProcessEvent(drag_event2); | |
783 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
784 EXPECT_EQ(child2.get(), details->window); | |
785 | |
786 // Drag again with id 1, child1 should continue to get it. | |
787 dispatcher->ProcessEvent(drag_event1); | |
788 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
789 EXPECT_EQ(child1.get(), details->window); | |
790 | |
791 // Release touch id 1, and click on 2. 2 should get it. | |
792 const ui::PointerEvent touch_release(ui::TouchEvent( | |
793 ui::ET_TOUCH_RELEASED, gfx::Point(54, 55), 1, base::TimeTicks())); | |
794 dispatcher->ProcessEvent(touch_release); | |
795 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
796 EXPECT_EQ(child1.get(), details->window); | |
797 const ui::PointerEvent touch_event3(ui::TouchEvent( | |
798 ui::ET_TOUCH_PRESSED, gfx::Point(54, 55), 2, base::TimeTicks())); | |
799 dispatcher->ProcessEvent(touch_event3); | |
800 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
801 EXPECT_EQ(child2.get(), details->window); | |
802 } | |
803 | |
804 TEST_F(EventDispatcherTest, DestroyWindowWhileGettingEvents) { | |
805 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
806 | |
807 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
808 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
809 | |
810 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
811 test_event_dispatcher_delegate(); | |
812 EventDispatcher* dispatcher = event_dispatcher(); | |
813 | |
814 // Press on child. | |
815 const ui::PointerEvent touch_event1(ui::TouchEvent( | |
816 ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks())); | |
817 dispatcher->ProcessEvent(touch_event1); | |
818 std::unique_ptr<DispatchedEventDetails> details = | |
819 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
820 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
821 EXPECT_EQ(child.get(), details->window); | |
822 | |
823 // Delete child, and continue the drag. Event should not be dispatched. | |
824 child.reset(); | |
825 | |
826 const ui::PointerEvent drag_event1(ui::TouchEvent( | |
827 ui::ET_TOUCH_MOVED, gfx::Point(53, 54), 1, base::TimeTicks())); | |
828 dispatcher->ProcessEvent(drag_event1); | |
829 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
830 EXPECT_EQ(nullptr, details.get()); | |
831 } | |
832 | |
833 TEST_F(EventDispatcherTest, MouseInExtendedHitTestRegion) { | |
834 ServerWindow* root = root_window(); | |
835 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
836 | |
837 root->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
838 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
839 | |
840 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
841 test_event_dispatcher_delegate(); | |
842 EventDispatcher* dispatcher = event_dispatcher(); | |
843 | |
844 // Send event that is not over child. | |
845 const ui::PointerEvent ui_event(ui::MouseEvent( | |
846 ui::ET_MOUSE_PRESSED, gfx::Point(8, 9), gfx::Point(8, 9), | |
847 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
848 dispatcher->ProcessEvent(ui_event); | |
849 std::unique_ptr<DispatchedEventDetails> details = | |
850 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
851 ASSERT_EQ(root, details->window); | |
852 | |
853 // Release the mouse. | |
854 const ui::PointerEvent release_event(ui::MouseEvent( | |
855 ui::ET_MOUSE_RELEASED, gfx::Point(8, 9), gfx::Point(8, 9), | |
856 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
857 dispatcher->ProcessEvent(release_event); | |
858 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
859 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
860 ASSERT_EQ(root, details->window); | |
861 EXPECT_TRUE(details->IsClientArea()); | |
862 | |
863 // Change the extended hit test region and send event in extended hit test | |
864 // region. Should result in exit for root, followed by press for child. | |
865 child->set_extended_hit_test_region(gfx::Insets(5, 5, 5, 5)); | |
866 dispatcher->ProcessEvent(ui_event); | |
867 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
868 EXPECT_EQ(root, details->window); | |
869 EXPECT_EQ(ui::ET_POINTER_EXITED, details->event->type()); | |
870 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
871 ASSERT_TRUE(details); | |
872 | |
873 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
874 EXPECT_TRUE(details->IsNonclientArea()); | |
875 ASSERT_EQ(child.get(), details->window); | |
876 EXPECT_EQ(ui::ET_POINTER_DOWN, details->event->type()); | |
877 ASSERT_TRUE(details->event.get()); | |
878 ASSERT_TRUE(details->event->IsPointerEvent()); | |
879 EXPECT_EQ(gfx::Point(-2, -1), details->event->AsPointerEvent()->location()); | |
880 } | |
881 | |
882 TEST_F(EventDispatcherTest, WheelWhileDown) { | |
883 std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3)); | |
884 std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4)); | |
885 | |
886 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
887 child1->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
888 child2->SetBounds(gfx::Rect(50, 51, 11, 12)); | |
889 | |
890 MouseEventTest tests[] = { | |
891 // Send a mouse down event over child1. | |
892 {ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(15, 15), | |
893 gfx::Point(15, 15), base::TimeTicks(), | |
894 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON), | |
895 child1.get(), gfx::Point(15, 15), gfx::Point(5, 5), nullptr, | |
896 gfx::Point(), gfx::Point()}, | |
897 // Send mouse wheel over child2, should go to child1 as it has capture. | |
898 {ui::MouseWheelEvent(gfx::Vector2d(1, 0), gfx::Point(53, 54), | |
899 gfx::Point(53, 54), base::TimeTicks(), ui::EF_NONE, | |
900 ui::EF_NONE), | |
901 child1.get(), gfx::Point(53, 54), gfx::Point(43, 44), nullptr, | |
902 gfx::Point(), gfx::Point()}, | |
903 }; | |
904 RunMouseEventTests(event_dispatcher(), test_event_dispatcher_delegate(), | |
905 tests, arraysize(tests)); | |
906 } | |
907 | |
908 // Tests that when explicit capture has been set that all events go to the | |
909 // designated window, and that when capture is cleared, events find the | |
910 // appropriate target window. | |
911 TEST_F(EventDispatcherTest, SetExplicitCapture) { | |
912 ServerWindow* root = root_window(); | |
913 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
914 | |
915 root->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
916 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
917 | |
918 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
919 test_event_dispatcher_delegate(); | |
920 EventDispatcher* dispatcher = event_dispatcher(); | |
921 | |
922 { | |
923 // Send all pointer events to the child. | |
924 dispatcher->SetCaptureWindow(child.get(), kClientAreaId); | |
925 | |
926 // The mouse press should go to the child even though its outside its | |
927 // bounds. | |
928 const ui::PointerEvent left_press_event(ui::MouseEvent( | |
929 ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), gfx::Point(5, 5), | |
930 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
931 dispatcher->ProcessEvent(left_press_event); | |
932 | |
933 // Events should target child. | |
934 std::unique_ptr<DispatchedEventDetails> details = | |
935 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
936 | |
937 ASSERT_TRUE(details); | |
938 ASSERT_EQ(child.get(), details->window); | |
939 EXPECT_TRUE(details->IsClientArea()); | |
940 EXPECT_TRUE(IsMouseButtonDown()); | |
941 | |
942 // The mouse down state should update while capture is set. | |
943 const ui::PointerEvent right_press_event(ui::MouseEvent( | |
944 ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), gfx::Point(5, 5), | |
945 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, | |
946 ui::EF_RIGHT_MOUSE_BUTTON)); | |
947 dispatcher->ProcessEvent(right_press_event); | |
948 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
949 EXPECT_TRUE(IsMouseButtonDown()); | |
950 | |
951 // One button released should not clear mouse down | |
952 const ui::PointerEvent left_release_event(ui::MouseEvent( | |
953 ui::ET_MOUSE_RELEASED, gfx::Point(5, 5), gfx::Point(5, 5), | |
954 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, | |
955 ui::EF_LEFT_MOUSE_BUTTON)); | |
956 dispatcher->ProcessEvent(left_release_event); | |
957 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
958 EXPECT_TRUE(IsMouseButtonDown()); | |
959 | |
960 // Touch Event while mouse is down should not affect state. | |
961 const ui::PointerEvent touch_event(ui::TouchEvent( | |
962 ui::ET_TOUCH_PRESSED, gfx::Point(15, 15), 2, base::TimeTicks())); | |
963 dispatcher->ProcessEvent(touch_event); | |
964 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
965 EXPECT_TRUE(IsMouseButtonDown()); | |
966 | |
967 // Move event should not affect down | |
968 const ui::PointerEvent move_event( | |
969 ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(15, 5), gfx::Point(15, 5), | |
970 base::TimeTicks(), ui::EF_RIGHT_MOUSE_BUTTON, | |
971 ui::EF_RIGHT_MOUSE_BUTTON)); | |
972 dispatcher->ProcessEvent(move_event); | |
973 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
974 EXPECT_TRUE(IsMouseButtonDown()); | |
975 | |
976 // All mouse buttons up should clear mouse down. | |
977 const ui::PointerEvent right_release_event( | |
978 ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(5, 5), | |
979 gfx::Point(5, 5), base::TimeTicks(), | |
980 ui::EF_RIGHT_MOUSE_BUTTON, ui::EF_RIGHT_MOUSE_BUTTON)); | |
981 dispatcher->ProcessEvent(right_release_event); | |
982 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
983 EXPECT_FALSE(IsMouseButtonDown()); | |
984 } | |
985 | |
986 { | |
987 // Releasing capture and sending the same event will go to the root. | |
988 dispatcher->SetCaptureWindow(nullptr, kClientAreaId); | |
989 const ui::PointerEvent press_event(ui::MouseEvent( | |
990 ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), gfx::Point(5, 5), | |
991 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
992 dispatcher->ProcessEvent(press_event); | |
993 | |
994 // Events should target the root. | |
995 std::unique_ptr<DispatchedEventDetails> details = | |
996 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
997 | |
998 ASSERT_TRUE(details); | |
999 ASSERT_EQ(root, details->window); | |
1000 } | |
1001 } | |
1002 | |
1003 // This test verifies that explicit capture overrides and resets implicit | |
1004 // capture. | |
1005 TEST_F(EventDispatcherTest, ExplicitCaptureOverridesImplicitCapture) { | |
1006 ServerWindow* root = root_window(); | |
1007 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
1008 | |
1009 root->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1010 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
1011 | |
1012 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
1013 test_event_dispatcher_delegate(); | |
1014 EventDispatcher* dispatcher = event_dispatcher(); | |
1015 | |
1016 // Run some implicit capture tests. | |
1017 MouseEventTest tests[] = { | |
1018 // Send a mouse down event over child with a left mouse button | |
1019 {ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), | |
1020 gfx::Point(20, 25), base::TimeTicks(), | |
1021 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON), | |
1022 child.get(), gfx::Point(20, 25), gfx::Point(10, 15)}, | |
1023 // Capture should be activated. Let's send a mouse move outside the bounds | |
1024 // of the child and press the right mouse button too. | |
1025 {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50), | |
1026 gfx::Point(50, 50), base::TimeTicks(), | |
1027 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, 0), | |
1028 child.get(), gfx::Point(50, 50), gfx::Point(40, 40)}, | |
1029 // Release the left mouse button and verify that the mouse up event goes | |
1030 // to the child. | |
1031 {ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(50, 50), | |
1032 gfx::Point(50, 50), base::TimeTicks(), | |
1033 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, | |
1034 ui::EF_RIGHT_MOUSE_BUTTON), | |
1035 child.get(), gfx::Point(50, 50), gfx::Point(40, 40)}, | |
1036 // A mouse move at (50, 50) should still go to the child. | |
1037 {ui::MouseEvent(ui::ET_MOUSE_MOVED, gfx::Point(50, 50), | |
1038 gfx::Point(50, 50), base::TimeTicks(), | |
1039 ui::EF_LEFT_MOUSE_BUTTON, 0), | |
1040 child.get(), gfx::Point(50, 50), gfx::Point(40, 40)}, | |
1041 | |
1042 }; | |
1043 RunMouseEventTests(dispatcher, event_dispatcher_delegate, tests, | |
1044 arraysize(tests)); | |
1045 | |
1046 // Add a second pointer target to the child. | |
1047 { | |
1048 const ui::PointerEvent touch_event(ui::TouchEvent( | |
1049 ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks())); | |
1050 dispatcher->ProcessEvent(touch_event); | |
1051 } | |
1052 | |
1053 std::unique_ptr<DispatchedEventDetails> details = | |
1054 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
1055 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
1056 EXPECT_EQ(child.get(), details->window); | |
1057 | |
1058 // Verify that no window has explicit capture and hence we did indeed do | |
1059 // implicit capture. | |
1060 ASSERT_EQ(nullptr, dispatcher->capture_window()); | |
1061 | |
1062 // Give the root window explicit capture and verify input events over the | |
1063 // child go to the root instead. | |
1064 dispatcher->SetCaptureWindow(root, kNonclientAreaId); | |
1065 | |
1066 // The implicit target should receive a cancel event for each pointer target. | |
1067 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
1068 ASSERT_TRUE(details); | |
1069 EXPECT_TRUE(event_dispatcher_delegate->has_queued_events()); | |
1070 EXPECT_EQ(child.get(), details->window); | |
1071 EXPECT_EQ(ui::ET_POINTER_CANCELLED, details->event->type()); | |
1072 | |
1073 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
1074 ASSERT_TRUE(details); | |
1075 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
1076 EXPECT_EQ(child.get(), details->window); | |
1077 EXPECT_EQ(ui::ET_POINTER_EXITED, details->event->type()); | |
1078 | |
1079 const ui::PointerEvent press_event(ui::MouseEvent( | |
1080 ui::ET_MOUSE_PRESSED, gfx::Point(15, 15), gfx::Point(15, 15), | |
1081 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1082 dispatcher->ProcessEvent(press_event); | |
1083 | |
1084 // Events should target the root. | |
1085 details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
1086 ASSERT_TRUE(details); | |
1087 ASSERT_EQ(root, details->window); | |
1088 ASSERT_TRUE(details->IsNonclientArea()); | |
1089 } | |
1090 | |
1091 // Tests that setting capture does delete active pointer targets for the capture | |
1092 // window. | |
1093 TEST_F(EventDispatcherTest, CaptureUpdatesActivePointerTargets) { | |
1094 ServerWindow* root = root_window(); | |
1095 root->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1096 | |
1097 EventDispatcher* dispatcher = event_dispatcher(); | |
1098 { | |
1099 const ui::PointerEvent press_event(ui::MouseEvent( | |
1100 ui::ET_MOUSE_PRESSED, gfx::Point(5, 5), gfx::Point(5, 5), | |
1101 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1102 dispatcher->ProcessEvent(press_event); | |
1103 | |
1104 std::unique_ptr<DispatchedEventDetails> details = | |
1105 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1106 ASSERT_TRUE(details); | |
1107 ASSERT_EQ(root, details->window); | |
1108 } | |
1109 { | |
1110 const ui::PointerEvent touch_event(ui::TouchEvent( | |
1111 ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks())); | |
1112 dispatcher->ProcessEvent(touch_event); | |
1113 } | |
1114 | |
1115 ASSERT_TRUE(AreAnyPointersDown()); | |
1116 ASSERT_TRUE(IsWindowPointerTarget(root)); | |
1117 EXPECT_EQ(2, NumberPointerTargetsForWindow(root)); | |
1118 | |
1119 // Setting the capture should clear the implicit pointers for the specified | |
1120 // window. | |
1121 dispatcher->SetCaptureWindow(root, kNonclientAreaId); | |
1122 EXPECT_FALSE(AreAnyPointersDown()); | |
1123 EXPECT_FALSE(IsWindowPointerTarget(root)); | |
1124 } | |
1125 | |
1126 // Tests that when explicit capture is changed, that the previous window with | |
1127 // capture is no longer being observed. | |
1128 TEST_F(EventDispatcherTest, UpdatingCaptureStopsObservingPreviousCapture) { | |
1129 std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3)); | |
1130 std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4)); | |
1131 | |
1132 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1133 child1->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
1134 child2->SetBounds(gfx::Rect(50, 51, 11, 12)); | |
1135 | |
1136 EventDispatcher* dispatcher = event_dispatcher(); | |
1137 ASSERT_FALSE(AreAnyPointersDown()); | |
1138 ASSERT_FALSE(IsWindowPointerTarget(child1.get())); | |
1139 ASSERT_FALSE(IsWindowPointerTarget(child2.get())); | |
1140 dispatcher->SetCaptureWindow(child1.get(), kClientAreaId); | |
1141 dispatcher->SetCaptureWindow(child2.get(), kClientAreaId); | |
1142 EXPECT_EQ(child1.get(), | |
1143 test_event_dispatcher_delegate()->lost_capture_window()); | |
1144 | |
1145 // If observing does not stop during the capture update this crashes. | |
1146 child1->AddObserver(dispatcher); | |
1147 } | |
1148 | |
1149 // Tests that destroying a window with explicit capture clears the capture | |
1150 // state. | |
1151 TEST_F(EventDispatcherTest, DestroyingCaptureWindowRemovesExplicitCapture) { | |
1152 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
1153 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
1154 | |
1155 EventDispatcher* dispatcher = event_dispatcher(); | |
1156 dispatcher->SetCaptureWindow(child.get(), kClientAreaId); | |
1157 EXPECT_EQ(child.get(), dispatcher->capture_window()); | |
1158 | |
1159 ServerWindow* lost_capture_window = child.get(); | |
1160 child.reset(); | |
1161 EXPECT_EQ(nullptr, dispatcher->capture_window()); | |
1162 EXPECT_EQ(lost_capture_window, | |
1163 test_event_dispatcher_delegate()->lost_capture_window()); | |
1164 } | |
1165 | |
1166 // Tests that when |client_id| is set for a window performing capture, that this | |
1167 // preference is used regardless of whether an event targets the client region. | |
1168 TEST_F(EventDispatcherTest, CaptureInNonClientAreaOverridesActualPoint) { | |
1169 ServerWindow* root = root_window(); | |
1170 root->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1171 | |
1172 root->SetClientArea(gfx::Insets(5, 5, 5, 5), std::vector<gfx::Rect>()); | |
1173 EventDispatcher* dispatcher = event_dispatcher(); | |
1174 dispatcher->SetCaptureWindow(root, kNonclientAreaId); | |
1175 | |
1176 TestEventDispatcherDelegate* event_dispatcher_delegate = | |
1177 test_event_dispatcher_delegate(); | |
1178 // Press in the client area, it should be marked as non client. | |
1179 const ui::PointerEvent press_event(ui::MouseEvent( | |
1180 ui::ET_MOUSE_PRESSED, gfx::Point(6, 6), gfx::Point(6, 6), | |
1181 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1182 event_dispatcher()->ProcessEvent(press_event); | |
1183 | |
1184 // Events should target child and be in the client area. | |
1185 std::unique_ptr<DispatchedEventDetails> details = | |
1186 event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails(); | |
1187 EXPECT_FALSE(event_dispatcher_delegate->has_queued_events()); | |
1188 ASSERT_EQ(root, details->window); | |
1189 EXPECT_TRUE(details->IsNonclientArea()); | |
1190 } | |
1191 | |
1192 TEST_F(EventDispatcherTest, ProcessPointerEvents) { | |
1193 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
1194 | |
1195 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1196 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
1197 | |
1198 { | |
1199 const ui::PointerEvent pointer_event(ui::MouseEvent( | |
1200 ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), gfx::Point(20, 25), | |
1201 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1202 event_dispatcher()->ProcessEvent(pointer_event); | |
1203 | |
1204 std::unique_ptr<DispatchedEventDetails> details = | |
1205 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1206 ASSERT_TRUE(details); | |
1207 ASSERT_EQ(child.get(), details->window); | |
1208 | |
1209 ASSERT_TRUE(details->event); | |
1210 ASSERT_TRUE(details->event->IsPointerEvent()); | |
1211 | |
1212 ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); | |
1213 EXPECT_EQ(gfx::Point(20, 25), dispatched_event->root_location()); | |
1214 EXPECT_EQ(gfx::Point(10, 15), dispatched_event->location()); | |
1215 } | |
1216 | |
1217 { | |
1218 const int touch_id = 3; | |
1219 const ui::PointerEvent pointer_event( | |
1220 ui::TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(25, 20), touch_id, | |
1221 base::TimeTicks())); | |
1222 event_dispatcher()->ProcessEvent(pointer_event); | |
1223 | |
1224 std::unique_ptr<DispatchedEventDetails> details = | |
1225 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1226 ASSERT_TRUE(details); | |
1227 ASSERT_EQ(child.get(), details->window); | |
1228 | |
1229 ASSERT_TRUE(details->event); | |
1230 ASSERT_TRUE(details->event->IsPointerEvent()); | |
1231 | |
1232 ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); | |
1233 EXPECT_EQ(gfx::Point(25, 20), dispatched_event->root_location()); | |
1234 EXPECT_EQ(gfx::Point(15, 10), dispatched_event->location()); | |
1235 EXPECT_EQ(touch_id, dispatched_event->pointer_id()); | |
1236 } | |
1237 } | |
1238 | |
1239 TEST_F(EventDispatcherTest, ResetClearsPointerDown) { | |
1240 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
1241 | |
1242 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1243 child->SetBounds(gfx::Rect(10, 10, 20, 20)); | |
1244 | |
1245 // Send event that is over child. | |
1246 const ui::PointerEvent ui_event(ui::MouseEvent( | |
1247 ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), gfx::Point(20, 25), | |
1248 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1249 event_dispatcher()->ProcessEvent(ui_event); | |
1250 | |
1251 std::unique_ptr<DispatchedEventDetails> details = | |
1252 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1253 ASSERT_TRUE(details); | |
1254 ASSERT_EQ(child.get(), details->window); | |
1255 | |
1256 EXPECT_TRUE(AreAnyPointersDown()); | |
1257 | |
1258 event_dispatcher()->Reset(); | |
1259 EXPECT_FALSE(test_event_dispatcher_delegate()->has_queued_events()); | |
1260 EXPECT_FALSE(AreAnyPointersDown()); | |
1261 } | |
1262 | |
1263 TEST_F(EventDispatcherTest, ResetClearsCapture) { | |
1264 ServerWindow* root = root_window(); | |
1265 root->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1266 | |
1267 root->SetClientArea(gfx::Insets(5, 5, 5, 5), std::vector<gfx::Rect>()); | |
1268 EventDispatcher* dispatcher = event_dispatcher(); | |
1269 dispatcher->SetCaptureWindow(root, kNonclientAreaId); | |
1270 | |
1271 event_dispatcher()->Reset(); | |
1272 EXPECT_FALSE(test_event_dispatcher_delegate()->has_queued_events()); | |
1273 EXPECT_EQ(nullptr, event_dispatcher()->capture_window()); | |
1274 } | |
1275 | |
1276 // Tests that events on a modal parent target the modal child. | |
1277 TEST_F(EventDispatcherTest, ModalWindowEventOnModalParent) { | |
1278 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1279 std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5)); | |
1280 | |
1281 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1282 w1->SetBounds(gfx::Rect(10, 10, 30, 30)); | |
1283 w2->SetBounds(gfx::Rect(50, 10, 10, 10)); | |
1284 | |
1285 w1->AddTransientWindow(w2.get()); | |
1286 w2->SetModal(); | |
1287 | |
1288 // Send event that is over |w1|. | |
1289 const ui::PointerEvent mouse_pressed(ui::MouseEvent( | |
1290 ui::ET_MOUSE_PRESSED, gfx::Point(15, 15), gfx::Point(15, 15), | |
1291 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1292 event_dispatcher()->ProcessEvent(mouse_pressed); | |
1293 | |
1294 std::unique_ptr<DispatchedEventDetails> details = | |
1295 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1296 ASSERT_TRUE(details); | |
1297 EXPECT_EQ(w2.get(), details->window); | |
1298 EXPECT_TRUE(details->IsNonclientArea()); | |
1299 | |
1300 ASSERT_TRUE(details->event); | |
1301 ASSERT_TRUE(details->event->IsPointerEvent()); | |
1302 | |
1303 ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); | |
1304 EXPECT_EQ(gfx::Point(15, 15), dispatched_event->root_location()); | |
1305 EXPECT_EQ(gfx::Point(-35, 5), dispatched_event->location()); | |
1306 } | |
1307 | |
1308 // Tests that events on a modal child target the modal child itself. | |
1309 TEST_F(EventDispatcherTest, ModalWindowEventOnModalChild) { | |
1310 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1311 std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5)); | |
1312 | |
1313 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1314 w1->SetBounds(gfx::Rect(10, 10, 30, 30)); | |
1315 w2->SetBounds(gfx::Rect(50, 10, 10, 10)); | |
1316 | |
1317 w1->AddTransientWindow(w2.get()); | |
1318 w2->SetModal(); | |
1319 | |
1320 // Send event that is over |w2|. | |
1321 const ui::PointerEvent mouse_pressed(ui::MouseEvent( | |
1322 ui::ET_MOUSE_PRESSED, gfx::Point(55, 15), gfx::Point(55, 15), | |
1323 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1324 event_dispatcher()->ProcessEvent(mouse_pressed); | |
1325 | |
1326 std::unique_ptr<DispatchedEventDetails> details = | |
1327 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1328 ASSERT_TRUE(details); | |
1329 EXPECT_EQ(w2.get(), details->window); | |
1330 EXPECT_TRUE(details->IsClientArea()); | |
1331 | |
1332 ASSERT_TRUE(details->event); | |
1333 ASSERT_TRUE(details->event->IsPointerEvent()); | |
1334 | |
1335 ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); | |
1336 EXPECT_EQ(gfx::Point(55, 15), dispatched_event->root_location()); | |
1337 EXPECT_EQ(gfx::Point(5, 5), dispatched_event->location()); | |
1338 } | |
1339 | |
1340 // Tests that events on an unrelated window are not affected by the modal | |
1341 // window. | |
1342 TEST_F(EventDispatcherTest, ModalWindowEventOnUnrelatedWindow) { | |
1343 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1344 std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5)); | |
1345 std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 6)); | |
1346 | |
1347 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1348 w1->SetBounds(gfx::Rect(10, 10, 30, 30)); | |
1349 w2->SetBounds(gfx::Rect(50, 10, 10, 10)); | |
1350 w3->SetBounds(gfx::Rect(70, 10, 10, 10)); | |
1351 | |
1352 w1->AddTransientWindow(w2.get()); | |
1353 w2->SetModal(); | |
1354 | |
1355 // Send event that is over |w3|. | |
1356 const ui::PointerEvent mouse_pressed(ui::MouseEvent( | |
1357 ui::ET_MOUSE_PRESSED, gfx::Point(75, 15), gfx::Point(75, 15), | |
1358 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1359 event_dispatcher()->ProcessEvent(mouse_pressed); | |
1360 | |
1361 std::unique_ptr<DispatchedEventDetails> details = | |
1362 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1363 ASSERT_TRUE(details); | |
1364 EXPECT_EQ(w3.get(), details->window); | |
1365 EXPECT_TRUE(details->IsClientArea()); | |
1366 | |
1367 ASSERT_TRUE(details->event); | |
1368 ASSERT_TRUE(details->event->IsPointerEvent()); | |
1369 | |
1370 ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); | |
1371 EXPECT_EQ(gfx::Point(75, 15), dispatched_event->root_location()); | |
1372 EXPECT_EQ(gfx::Point(5, 5), dispatched_event->location()); | |
1373 } | |
1374 | |
1375 // Tests that events events on a descendant of a modal parent target the modal | |
1376 // child. | |
1377 TEST_F(EventDispatcherTest, ModalWindowEventOnDescendantOfModalParent) { | |
1378 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1379 std::unique_ptr<ServerWindow> w11 = | |
1380 CreateChildWindowWithParent(WindowId(1, 4), w1.get()); | |
1381 std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5)); | |
1382 | |
1383 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1384 w1->SetBounds(gfx::Rect(10, 10, 30, 30)); | |
1385 w11->SetBounds(gfx::Rect(10, 10, 10, 10)); | |
1386 w2->SetBounds(gfx::Rect(50, 10, 10, 10)); | |
1387 | |
1388 w1->AddTransientWindow(w2.get()); | |
1389 w2->SetModal(); | |
1390 | |
1391 // Send event that is over |w11|. | |
1392 const ui::PointerEvent mouse_pressed(ui::MouseEvent( | |
1393 ui::ET_MOUSE_PRESSED, gfx::Point(25, 25), gfx::Point(25, 25), | |
1394 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1395 event_dispatcher()->ProcessEvent(mouse_pressed); | |
1396 | |
1397 std::unique_ptr<DispatchedEventDetails> details = | |
1398 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1399 ASSERT_TRUE(details); | |
1400 EXPECT_EQ(w2.get(), details->window); | |
1401 EXPECT_TRUE(details->IsNonclientArea()); | |
1402 | |
1403 ASSERT_TRUE(details->event); | |
1404 ASSERT_TRUE(details->event->IsPointerEvent()); | |
1405 | |
1406 ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); | |
1407 EXPECT_EQ(gfx::Point(25, 25), dispatched_event->root_location()); | |
1408 EXPECT_EQ(gfx::Point(-25, 15), dispatched_event->location()); | |
1409 } | |
1410 | |
1411 // Tests that events on a system modal window target the modal window itself. | |
1412 TEST_F(EventDispatcherTest, ModalWindowEventOnSystemModal) { | |
1413 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1414 | |
1415 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1416 w1->SetBounds(gfx::Rect(10, 10, 30, 30)); | |
1417 w1->SetModal(); | |
1418 | |
1419 // Send event that is over |w1|. | |
1420 const ui::PointerEvent mouse_pressed(ui::MouseEvent( | |
1421 ui::ET_MOUSE_PRESSED, gfx::Point(15, 15), gfx::Point(15, 15), | |
1422 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1423 event_dispatcher()->ProcessEvent(mouse_pressed); | |
1424 | |
1425 std::unique_ptr<DispatchedEventDetails> details = | |
1426 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1427 ASSERT_TRUE(details); | |
1428 EXPECT_EQ(w1.get(), details->window); | |
1429 EXPECT_TRUE(details->IsClientArea()); | |
1430 | |
1431 ASSERT_TRUE(details->event); | |
1432 ASSERT_TRUE(details->event->IsPointerEvent()); | |
1433 | |
1434 ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); | |
1435 EXPECT_EQ(gfx::Point(15, 15), dispatched_event->root_location()); | |
1436 EXPECT_EQ(gfx::Point(5, 5), dispatched_event->location()); | |
1437 } | |
1438 | |
1439 // Tests that events outside of system modal window target the modal window. | |
1440 TEST_F(EventDispatcherTest, ModalWindowEventOutsideSystemModal) { | |
1441 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1442 | |
1443 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1444 w1->SetBounds(gfx::Rect(10, 10, 30, 30)); | |
1445 w1->SetModal(); | |
1446 event_dispatcher()->AddSystemModalWindow(w1.get()); | |
1447 | |
1448 // Send event that is over |w1|. | |
1449 const ui::PointerEvent mouse_pressed(ui::MouseEvent( | |
1450 ui::ET_MOUSE_PRESSED, gfx::Point(45, 15), gfx::Point(45, 15), | |
1451 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1452 event_dispatcher()->ProcessEvent(mouse_pressed); | |
1453 | |
1454 std::unique_ptr<DispatchedEventDetails> details = | |
1455 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1456 ASSERT_TRUE(details); | |
1457 EXPECT_EQ(w1.get(), details->window); | |
1458 EXPECT_TRUE(details->IsNonclientArea()); | |
1459 | |
1460 ASSERT_TRUE(details->event); | |
1461 ASSERT_TRUE(details->event->IsPointerEvent()); | |
1462 | |
1463 ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); | |
1464 EXPECT_EQ(gfx::Point(45, 15), dispatched_event->root_location()); | |
1465 EXPECT_EQ(gfx::Point(35, 5), dispatched_event->location()); | |
1466 } | |
1467 | |
1468 // Tests that setting capture to a descendant of a modal parent fails. | |
1469 TEST_F(EventDispatcherTest, ModalWindowSetCaptureDescendantOfModalParent) { | |
1470 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1471 std::unique_ptr<ServerWindow> w11 = | |
1472 CreateChildWindowWithParent(WindowId(1, 4), w1.get()); | |
1473 std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5)); | |
1474 | |
1475 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1476 w1->SetBounds(gfx::Rect(10, 10, 30, 30)); | |
1477 w11->SetBounds(gfx::Rect(10, 10, 10, 10)); | |
1478 w2->SetBounds(gfx::Rect(50, 10, 10, 10)); | |
1479 | |
1480 w1->AddTransientWindow(w2.get()); | |
1481 w2->SetModal(); | |
1482 | |
1483 EXPECT_FALSE(event_dispatcher()->SetCaptureWindow(w11.get(), kClientAreaId)); | |
1484 EXPECT_EQ(nullptr, event_dispatcher()->capture_window()); | |
1485 } | |
1486 | |
1487 // Tests that setting capture to a window unrelated to a modal parent works. | |
1488 TEST_F(EventDispatcherTest, ModalWindowSetCaptureUnrelatedWindow) { | |
1489 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1490 std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4)); | |
1491 std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 5)); | |
1492 | |
1493 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1494 w1->SetBounds(gfx::Rect(10, 10, 30, 30)); | |
1495 w2->SetBounds(gfx::Rect(50, 10, 10, 10)); | |
1496 w3->SetBounds(gfx::Rect(70, 10, 10, 10)); | |
1497 | |
1498 w1->AddTransientWindow(w2.get()); | |
1499 w2->SetModal(); | |
1500 | |
1501 EXPECT_TRUE(event_dispatcher()->SetCaptureWindow(w3.get(), kClientAreaId)); | |
1502 EXPECT_EQ(w3.get(), event_dispatcher()->capture_window()); | |
1503 } | |
1504 | |
1505 // Tests that setting capture fails when there is a system modal window. | |
1506 TEST_F(EventDispatcherTest, ModalWindowSystemSetCapture) { | |
1507 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1508 std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4)); | |
1509 | |
1510 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1511 w1->SetBounds(gfx::Rect(10, 10, 30, 30)); | |
1512 w2->SetBounds(gfx::Rect(50, 10, 10, 10)); | |
1513 | |
1514 event_dispatcher()->AddSystemModalWindow(w2.get()); | |
1515 | |
1516 EXPECT_FALSE(event_dispatcher()->SetCaptureWindow(w1.get(), kClientAreaId)); | |
1517 EXPECT_EQ(nullptr, event_dispatcher()->capture_window()); | |
1518 } | |
1519 | |
1520 // Tests having multiple system modal windows. | |
1521 TEST_F(EventDispatcherTest, ModalWindowMultipleSystemModals) { | |
1522 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1523 std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4)); | |
1524 std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 5)); | |
1525 | |
1526 w2->SetVisible(false); | |
1527 | |
1528 // In the beginning, there should be no active system modal window. | |
1529 EXPECT_EQ(nullptr, GetActiveSystemModalWindow()); | |
1530 | |
1531 // Add a visible system modal window. It should become the active one. | |
1532 event_dispatcher()->AddSystemModalWindow(w1.get()); | |
1533 EXPECT_EQ(w1.get(), GetActiveSystemModalWindow()); | |
1534 | |
1535 // Add an invisible system modal window. It should not change the active one. | |
1536 event_dispatcher()->AddSystemModalWindow(w2.get()); | |
1537 EXPECT_EQ(w1.get(), GetActiveSystemModalWindow()); | |
1538 | |
1539 // Add another visible system modal window. It should become the active one. | |
1540 event_dispatcher()->AddSystemModalWindow(w3.get()); | |
1541 EXPECT_EQ(w3.get(), GetActiveSystemModalWindow()); | |
1542 | |
1543 // Make an existing system modal window visible. It should become the active | |
1544 // one. | |
1545 w2->SetVisible(true); | |
1546 EXPECT_EQ(w2.get(), GetActiveSystemModalWindow()); | |
1547 | |
1548 // Remove the active system modal window. Next one should become active. | |
1549 w2.reset(); | |
1550 EXPECT_EQ(w3.get(), GetActiveSystemModalWindow()); | |
1551 | |
1552 // Remove an inactive system modal window. It should not change the active | |
1553 // one. | |
1554 w1.reset(); | |
1555 EXPECT_EQ(w3.get(), GetActiveSystemModalWindow()); | |
1556 | |
1557 // Remove the last remaining system modal window. There should be no active | |
1558 // one anymore. | |
1559 w3.reset(); | |
1560 EXPECT_EQ(nullptr, GetActiveSystemModalWindow()); | |
1561 } | |
1562 | |
1563 TEST_F(EventDispatcherTest, CaptureNotResetOnParentChange) { | |
1564 std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3)); | |
1565 DisableHitTest(w1.get()); | |
1566 std::unique_ptr<ServerWindow> w11 = | |
1567 CreateChildWindowWithParent(WindowId(1, 4), w1.get()); | |
1568 std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5)); | |
1569 DisableHitTest(w2.get()); | |
1570 | |
1571 root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1572 w1->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1573 w11->SetBounds(gfx::Rect(10, 10, 10, 10)); | |
1574 w2->SetBounds(gfx::Rect(0, 0, 100, 100)); | |
1575 | |
1576 // Send event that is over |w11|. | |
1577 const ui::PointerEvent mouse_pressed(ui::MouseEvent( | |
1578 ui::ET_MOUSE_PRESSED, gfx::Point(15, 15), gfx::Point(15, 15), | |
1579 base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); | |
1580 event_dispatcher()->ProcessEvent(mouse_pressed); | |
1581 event_dispatcher()->SetCaptureWindow(w11.get(), kClientAreaId); | |
1582 | |
1583 std::unique_ptr<DispatchedEventDetails> details = | |
1584 test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); | |
1585 ASSERT_TRUE(details); | |
1586 EXPECT_EQ(w11.get(), details->window); | |
1587 EXPECT_TRUE(details->IsClientArea()); | |
1588 | |
1589 // Move |w11| to |w2| and verify the mouse is still down, and |w11| has | |
1590 // capture. | |
1591 w2->Add(w11.get()); | |
1592 EXPECT_TRUE(IsMouseButtonDown()); | |
1593 EXPECT_EQ(w11.get(), | |
1594 EventDispatcherTestApi(event_dispatcher()).capture_window()); | |
1595 } | |
1596 | |
1597 TEST_F(EventDispatcherTest, ChangeCaptureFromClientToNonclient) { | |
1598 std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); | |
1599 event_dispatcher()->SetCaptureWindow(child.get(), kNonclientAreaId); | |
1600 EXPECT_EQ(kNonclientAreaId, | |
1601 event_dispatcher()->capture_window_client_id()); | |
1602 EXPECT_EQ(nullptr, test_event_dispatcher_delegate()->lost_capture_window()); | |
1603 event_dispatcher()->SetCaptureWindow(child.get(), kClientAreaId); | |
1604 // Changing capture from client to non-client should notify the delegate. | |
1605 // The delegate can decide if it really wants to forward the event or not. | |
1606 EXPECT_EQ(child.get(), | |
1607 test_event_dispatcher_delegate()->lost_capture_window()); | |
1608 EXPECT_EQ(child.get(), event_dispatcher()->capture_window()); | |
1609 EXPECT_EQ(kClientAreaId, event_dispatcher()->capture_window_client_id()); | |
1610 } | |
1611 | |
1612 } // namespace test | |
1613 } // namespace ws | |
1614 } // namespace mus | |
OLD | NEW |