| 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 |