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

Side by Side Diff: ui/aura/window_event_dispatcher_unittest.cc

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/aura/window_event_dispatcher.cc ('k') | ui/aura/window_layer_type.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "ui/aura/window_event_dispatcher.h"
6
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/run_loop.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/aura/client/capture_client.h"
13 #include "ui/aura/client/event_client.h"
14 #include "ui/aura/client/focus_client.h"
15 #include "ui/aura/env.h"
16 #include "ui/aura/test/aura_test_base.h"
17 #include "ui/aura/test/env_test_helper.h"
18 #include "ui/aura/test/test_cursor_client.h"
19 #include "ui/aura/test/test_screen.h"
20 #include "ui/aura/test/test_window_delegate.h"
21 #include "ui/aura/test/test_windows.h"
22 #include "ui/aura/window.h"
23 #include "ui/aura/window_tracker.h"
24 #include "ui/base/hit_test.h"
25 #include "ui/events/event.h"
26 #include "ui/events/event_handler.h"
27 #include "ui/events/event_utils.h"
28 #include "ui/events/gestures/gesture_configuration.h"
29 #include "ui/events/keycodes/keyboard_codes.h"
30 #include "ui/events/test/event_generator.h"
31 #include "ui/events/test/test_event_handler.h"
32 #include "ui/gfx/point.h"
33 #include "ui/gfx/rect.h"
34 #include "ui/gfx/screen.h"
35 #include "ui/gfx/transform.h"
36
37 namespace aura {
38 namespace {
39
40 // A delegate that always returns a non-client component for hit tests.
41 class NonClientDelegate : public test::TestWindowDelegate {
42 public:
43 NonClientDelegate()
44 : non_client_count_(0),
45 mouse_event_count_(0),
46 mouse_event_flags_(0x0) {
47 }
48 virtual ~NonClientDelegate() {}
49
50 int non_client_count() const { return non_client_count_; }
51 gfx::Point non_client_location() const { return non_client_location_; }
52 int mouse_event_count() const { return mouse_event_count_; }
53 gfx::Point mouse_event_location() const { return mouse_event_location_; }
54 int mouse_event_flags() const { return mouse_event_flags_; }
55
56 virtual int GetNonClientComponent(const gfx::Point& location) const override {
57 NonClientDelegate* self = const_cast<NonClientDelegate*>(this);
58 self->non_client_count_++;
59 self->non_client_location_ = location;
60 return HTTOPLEFT;
61 }
62 virtual void OnMouseEvent(ui::MouseEvent* event) override {
63 mouse_event_count_++;
64 mouse_event_location_ = event->location();
65 mouse_event_flags_ = event->flags();
66 event->SetHandled();
67 }
68
69 private:
70 int non_client_count_;
71 gfx::Point non_client_location_;
72 int mouse_event_count_;
73 gfx::Point mouse_event_location_;
74 int mouse_event_flags_;
75
76 DISALLOW_COPY_AND_ASSIGN(NonClientDelegate);
77 };
78
79 // A simple event handler that consumes key events.
80 class ConsumeKeyHandler : public ui::test::TestEventHandler {
81 public:
82 ConsumeKeyHandler() {}
83 virtual ~ConsumeKeyHandler() {}
84
85 // Overridden from ui::EventHandler:
86 virtual void OnKeyEvent(ui::KeyEvent* event) override {
87 ui::test::TestEventHandler::OnKeyEvent(event);
88 event->StopPropagation();
89 }
90
91 private:
92 DISALLOW_COPY_AND_ASSIGN(ConsumeKeyHandler);
93 };
94
95 bool IsFocusedWindow(aura::Window* window) {
96 return client::GetFocusClient(window)->GetFocusedWindow() == window;
97 }
98
99 } // namespace
100
101 typedef test::AuraTestBase WindowEventDispatcherTest;
102
103 TEST_F(WindowEventDispatcherTest, OnHostMouseEvent) {
104 // Create two non-overlapping windows so we don't have to worry about which
105 // is on top.
106 scoped_ptr<NonClientDelegate> delegate1(new NonClientDelegate());
107 scoped_ptr<NonClientDelegate> delegate2(new NonClientDelegate());
108 const int kWindowWidth = 123;
109 const int kWindowHeight = 45;
110 gfx::Rect bounds1(100, 200, kWindowWidth, kWindowHeight);
111 gfx::Rect bounds2(300, 400, kWindowWidth, kWindowHeight);
112 scoped_ptr<aura::Window> window1(CreateTestWindowWithDelegate(
113 delegate1.get(), -1234, bounds1, root_window()));
114 scoped_ptr<aura::Window> window2(CreateTestWindowWithDelegate(
115 delegate2.get(), -5678, bounds2, root_window()));
116
117 // Send a mouse event to window1.
118 gfx::Point point(101, 201);
119 ui::MouseEvent event1(
120 ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON,
121 ui::EF_LEFT_MOUSE_BUTTON);
122 DispatchEventUsingWindowDispatcher(&event1);
123
124 // Event was tested for non-client area for the target window.
125 EXPECT_EQ(1, delegate1->non_client_count());
126 EXPECT_EQ(0, delegate2->non_client_count());
127 // The non-client component test was in local coordinates.
128 EXPECT_EQ(gfx::Point(1, 1), delegate1->non_client_location());
129 // Mouse event was received by target window.
130 EXPECT_EQ(1, delegate1->mouse_event_count());
131 EXPECT_EQ(0, delegate2->mouse_event_count());
132 // Event was in local coordinates.
133 EXPECT_EQ(gfx::Point(1, 1), delegate1->mouse_event_location());
134 // Non-client flag was set.
135 EXPECT_TRUE(delegate1->mouse_event_flags() & ui::EF_IS_NON_CLIENT);
136 }
137
138 TEST_F(WindowEventDispatcherTest, RepostEvent) {
139 // Test RepostEvent in RootWindow. It only works for Mouse Press.
140 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
141 gfx::Point point(10, 10);
142 ui::MouseEvent event(
143 ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON,
144 ui::EF_LEFT_MOUSE_BUTTON);
145 host()->dispatcher()->RepostEvent(event);
146 RunAllPendingInMessageLoop();
147 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
148 }
149
150 // Check that we correctly track the state of the mouse buttons in response to
151 // button press and release events.
152 TEST_F(WindowEventDispatcherTest, MouseButtonState) {
153 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
154
155 gfx::Point location;
156 scoped_ptr<ui::MouseEvent> event;
157
158 // Press the left button.
159 event.reset(new ui::MouseEvent(
160 ui::ET_MOUSE_PRESSED,
161 location,
162 location,
163 ui::EF_LEFT_MOUSE_BUTTON,
164 ui::EF_LEFT_MOUSE_BUTTON));
165 DispatchEventUsingWindowDispatcher(event.get());
166 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
167
168 // Additionally press the right.
169 event.reset(new ui::MouseEvent(
170 ui::ET_MOUSE_PRESSED,
171 location,
172 location,
173 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON,
174 ui::EF_RIGHT_MOUSE_BUTTON));
175 DispatchEventUsingWindowDispatcher(event.get());
176 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
177
178 // Release the left button.
179 event.reset(new ui::MouseEvent(
180 ui::ET_MOUSE_RELEASED,
181 location,
182 location,
183 ui::EF_RIGHT_MOUSE_BUTTON,
184 ui::EF_LEFT_MOUSE_BUTTON));
185 DispatchEventUsingWindowDispatcher(event.get());
186 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
187
188 // Release the right button. We should ignore the Shift-is-down flag.
189 event.reset(new ui::MouseEvent(
190 ui::ET_MOUSE_RELEASED,
191 location,
192 location,
193 ui::EF_SHIFT_DOWN,
194 ui::EF_RIGHT_MOUSE_BUTTON));
195 DispatchEventUsingWindowDispatcher(event.get());
196 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
197
198 // Press the middle button.
199 event.reset(new ui::MouseEvent(
200 ui::ET_MOUSE_PRESSED,
201 location,
202 location,
203 ui::EF_MIDDLE_MOUSE_BUTTON,
204 ui::EF_MIDDLE_MOUSE_BUTTON));
205 DispatchEventUsingWindowDispatcher(event.get());
206 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
207 }
208
209 TEST_F(WindowEventDispatcherTest, TranslatedEvent) {
210 scoped_ptr<Window> w1(test::CreateTestWindowWithDelegate(NULL, 1,
211 gfx::Rect(50, 50, 100, 100), root_window()));
212
213 gfx::Point origin(100, 100);
214 ui::MouseEvent root(ui::ET_MOUSE_PRESSED, origin, origin, 0, 0);
215
216 EXPECT_EQ("100,100", root.location().ToString());
217 EXPECT_EQ("100,100", root.root_location().ToString());
218
219 ui::MouseEvent translated_event(
220 root, static_cast<Window*>(root_window()), w1.get(),
221 ui::ET_MOUSE_ENTERED, root.flags());
222 EXPECT_EQ("50,50", translated_event.location().ToString());
223 EXPECT_EQ("100,100", translated_event.root_location().ToString());
224 }
225
226 namespace {
227
228 class TestEventClient : public client::EventClient {
229 public:
230 static const int kNonLockWindowId = 100;
231 static const int kLockWindowId = 200;
232
233 explicit TestEventClient(Window* root_window)
234 : root_window_(root_window),
235 lock_(false) {
236 client::SetEventClient(root_window_, this);
237 Window* lock_window =
238 test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
239 lock_window->set_id(kLockWindowId);
240 Window* non_lock_window =
241 test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
242 non_lock_window->set_id(kNonLockWindowId);
243 }
244 virtual ~TestEventClient() {
245 client::SetEventClient(root_window_, NULL);
246 }
247
248 // Starts/stops locking. Locking prevents windows other than those inside
249 // the lock container from receiving events, getting focus etc.
250 void Lock() {
251 lock_ = true;
252 }
253 void Unlock() {
254 lock_ = false;
255 }
256
257 Window* GetLockWindow() {
258 return const_cast<Window*>(
259 static_cast<const TestEventClient*>(this)->GetLockWindow());
260 }
261 const Window* GetLockWindow() const {
262 return root_window_->GetChildById(kLockWindowId);
263 }
264 Window* GetNonLockWindow() {
265 return root_window_->GetChildById(kNonLockWindowId);
266 }
267
268 private:
269 // Overridden from client::EventClient:
270 virtual bool CanProcessEventsWithinSubtree(
271 const Window* window) const override {
272 return lock_ ?
273 window->Contains(GetLockWindow()) || GetLockWindow()->Contains(window) :
274 true;
275 }
276
277 virtual ui::EventTarget* GetToplevelEventTarget() override {
278 return NULL;
279 }
280
281 Window* root_window_;
282 bool lock_;
283
284 DISALLOW_COPY_AND_ASSIGN(TestEventClient);
285 };
286
287 } // namespace
288
289 TEST_F(WindowEventDispatcherTest, CanProcessEventsWithinSubtree) {
290 TestEventClient client(root_window());
291 test::TestWindowDelegate d;
292
293 ui::test::TestEventHandler nonlock_ef;
294 ui::test::TestEventHandler lock_ef;
295 client.GetNonLockWindow()->AddPreTargetHandler(&nonlock_ef);
296 client.GetLockWindow()->AddPreTargetHandler(&lock_ef);
297
298 Window* w1 = test::CreateTestWindowWithBounds(gfx::Rect(10, 10, 20, 20),
299 client.GetNonLockWindow());
300 w1->set_id(1);
301 Window* w2 = test::CreateTestWindowWithBounds(gfx::Rect(30, 30, 20, 20),
302 client.GetNonLockWindow());
303 w2->set_id(2);
304 scoped_ptr<Window> w3(
305 test::CreateTestWindowWithDelegate(&d, 3, gfx::Rect(30, 30, 20, 20),
306 client.GetLockWindow()));
307
308 w1->Focus();
309 EXPECT_TRUE(IsFocusedWindow(w1));
310
311 client.Lock();
312
313 // Since we're locked, the attempt to focus w2 will be ignored.
314 w2->Focus();
315 EXPECT_TRUE(IsFocusedWindow(w1));
316 EXPECT_FALSE(IsFocusedWindow(w2));
317
318 {
319 // Attempting to send a key event to w1 (not in the lock container) should
320 // cause focus to be reset.
321 ui::test::EventGenerator generator(root_window());
322 generator.PressKey(ui::VKEY_SPACE, 0);
323 EXPECT_EQ(NULL, client::GetFocusClient(w1)->GetFocusedWindow());
324 EXPECT_FALSE(IsFocusedWindow(w1));
325 }
326
327 {
328 // Events sent to a window not in the lock container will not be processed.
329 // i.e. never sent to the non-lock container's event filter.
330 ui::test::EventGenerator generator(root_window(), w1);
331 generator.ClickLeftButton();
332 EXPECT_EQ(0, nonlock_ef.num_mouse_events());
333
334 // Events sent to a window in the lock container will be processed.
335 ui::test::EventGenerator generator3(root_window(), w3.get());
336 generator3.PressLeftButton();
337 EXPECT_EQ(1, lock_ef.num_mouse_events());
338 }
339
340 // Prevent w3 from being deleted by the hierarchy since its delegate is owned
341 // by this scope.
342 w3->parent()->RemoveChild(w3.get());
343 }
344
345 TEST_F(WindowEventDispatcherTest, DontIgnoreUnknownKeys) {
346 ConsumeKeyHandler handler;
347 root_window()->AddPreTargetHandler(&handler);
348
349 ui::KeyEvent unknown_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, ui::EF_NONE);
350 DispatchEventUsingWindowDispatcher(&unknown_event);
351 EXPECT_TRUE(unknown_event.handled());
352 EXPECT_EQ(1, handler.num_key_events());
353
354 handler.Reset();
355 ui::KeyEvent known_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
356 DispatchEventUsingWindowDispatcher(&known_event);
357 EXPECT_TRUE(known_event.handled());
358 EXPECT_EQ(1, handler.num_key_events());
359
360 handler.Reset();
361 ui::KeyEvent ime_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN,
362 ui::EF_IME_FABRICATED_KEY);
363 DispatchEventUsingWindowDispatcher(&ime_event);
364 EXPECT_TRUE(ime_event.handled());
365 EXPECT_EQ(1, handler.num_key_events());
366
367 handler.Reset();
368 ui::KeyEvent unknown_key_with_char_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN,
369 ui::EF_NONE);
370 unknown_key_with_char_event.set_character(0x00e4 /* "ä" */);
371 DispatchEventUsingWindowDispatcher(&unknown_key_with_char_event);
372 EXPECT_TRUE(unknown_key_with_char_event.handled());
373 EXPECT_EQ(1, handler.num_key_events());
374 }
375
376 TEST_F(WindowEventDispatcherTest, NoDelegateWindowReceivesKeyEvents) {
377 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
378 w1->Show();
379 w1->Focus();
380
381 ui::test::TestEventHandler handler;
382 w1->AddPreTargetHandler(&handler);
383 ui::KeyEvent key_press(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
384 DispatchEventUsingWindowDispatcher(&key_press);
385 EXPECT_TRUE(key_press.handled());
386 EXPECT_EQ(1, handler.num_key_events());
387
388 w1->RemovePreTargetHandler(&handler);
389 }
390
391 // Tests that touch-events that are beyond the bounds of the root-window do get
392 // propagated to the event filters correctly with the root as the target.
393 TEST_F(WindowEventDispatcherTest, TouchEventsOutsideBounds) {
394 ui::test::TestEventHandler handler;
395 root_window()->AddPreTargetHandler(&handler);
396
397 gfx::Point position = root_window()->bounds().origin();
398 position.Offset(-10, -10);
399 ui::TouchEvent press(
400 ui::ET_TOUCH_PRESSED, position, 0, ui::EventTimeForNow());
401 DispatchEventUsingWindowDispatcher(&press);
402 EXPECT_EQ(1, handler.num_touch_events());
403
404 position = root_window()->bounds().origin();
405 position.Offset(root_window()->bounds().width() + 10,
406 root_window()->bounds().height() + 10);
407 ui::TouchEvent release(
408 ui::ET_TOUCH_RELEASED, position, 0, ui::EventTimeForNow());
409 DispatchEventUsingWindowDispatcher(&release);
410 EXPECT_EQ(2, handler.num_touch_events());
411 }
412
413 // Tests that scroll events are dispatched correctly.
414 TEST_F(WindowEventDispatcherTest, ScrollEventDispatch) {
415 base::TimeDelta now = ui::EventTimeForNow();
416 ui::test::TestEventHandler handler;
417 root_window()->AddPreTargetHandler(&handler);
418
419 test::TestWindowDelegate delegate;
420 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate));
421 w1->SetBounds(gfx::Rect(20, 20, 40, 40));
422
423 // A scroll event on the root-window itself is dispatched.
424 ui::ScrollEvent scroll1(ui::ET_SCROLL,
425 gfx::Point(10, 10),
426 now,
427 0,
428 0, -10,
429 0, -10,
430 2);
431 DispatchEventUsingWindowDispatcher(&scroll1);
432 EXPECT_EQ(1, handler.num_scroll_events());
433
434 // Scroll event on a window should be dispatched properly.
435 ui::ScrollEvent scroll2(ui::ET_SCROLL,
436 gfx::Point(25, 30),
437 now,
438 0,
439 -10, 0,
440 -10, 0,
441 2);
442 DispatchEventUsingWindowDispatcher(&scroll2);
443 EXPECT_EQ(2, handler.num_scroll_events());
444 root_window()->RemovePreTargetHandler(&handler);
445 }
446
447 namespace {
448
449 // FilterFilter that tracks the types of events it's seen.
450 class EventFilterRecorder : public ui::EventHandler {
451 public:
452 typedef std::vector<ui::EventType> Events;
453 typedef std::vector<gfx::Point> EventLocations;
454 typedef std::vector<int> EventFlags;
455
456 EventFilterRecorder()
457 : wait_until_event_(ui::ET_UNKNOWN) {
458 }
459
460 const Events& events() const { return events_; }
461
462 const EventLocations& mouse_locations() const { return mouse_locations_; }
463 gfx::Point mouse_location(int i) const { return mouse_locations_[i]; }
464 const EventLocations& touch_locations() const { return touch_locations_; }
465 const EventLocations& gesture_locations() const { return gesture_locations_; }
466 const EventFlags& mouse_event_flags() const { return mouse_event_flags_; }
467
468 void WaitUntilReceivedEvent(ui::EventType type) {
469 wait_until_event_ = type;
470 run_loop_.reset(new base::RunLoop());
471 run_loop_->Run();
472 }
473
474 Events GetAndResetEvents() {
475 Events events = events_;
476 Reset();
477 return events;
478 }
479
480 void Reset() {
481 events_.clear();
482 mouse_locations_.clear();
483 touch_locations_.clear();
484 gesture_locations_.clear();
485 mouse_event_flags_.clear();
486 }
487
488 // ui::EventHandler overrides:
489 virtual void OnEvent(ui::Event* event) override {
490 ui::EventHandler::OnEvent(event);
491 events_.push_back(event->type());
492 if (wait_until_event_ == event->type() && run_loop_) {
493 run_loop_->Quit();
494 wait_until_event_ = ui::ET_UNKNOWN;
495 }
496 }
497
498 virtual void OnMouseEvent(ui::MouseEvent* event) override {
499 mouse_locations_.push_back(event->location());
500 mouse_event_flags_.push_back(event->flags());
501 }
502
503 virtual void OnTouchEvent(ui::TouchEvent* event) override {
504 touch_locations_.push_back(event->location());
505 }
506
507 virtual void OnGestureEvent(ui::GestureEvent* event) override {
508 gesture_locations_.push_back(event->location());
509 }
510
511 bool HasReceivedEvent(ui::EventType type) {
512 return std::find(events_.begin(), events_.end(), type) != events_.end();
513 }
514
515 private:
516 scoped_ptr<base::RunLoop> run_loop_;
517 ui::EventType wait_until_event_;
518
519 Events events_;
520 EventLocations mouse_locations_;
521 EventLocations touch_locations_;
522 EventLocations gesture_locations_;
523 EventFlags mouse_event_flags_;
524
525 DISALLOW_COPY_AND_ASSIGN(EventFilterRecorder);
526 };
527
528 // Converts an EventType to a string.
529 std::string EventTypeToString(ui::EventType type) {
530 switch (type) {
531 case ui::ET_TOUCH_RELEASED:
532 return "TOUCH_RELEASED";
533
534 case ui::ET_TOUCH_CANCELLED:
535 return "TOUCH_CANCELLED";
536
537 case ui::ET_TOUCH_PRESSED:
538 return "TOUCH_PRESSED";
539
540 case ui::ET_TOUCH_MOVED:
541 return "TOUCH_MOVED";
542
543 case ui::ET_MOUSE_PRESSED:
544 return "MOUSE_PRESSED";
545
546 case ui::ET_MOUSE_DRAGGED:
547 return "MOUSE_DRAGGED";
548
549 case ui::ET_MOUSE_RELEASED:
550 return "MOUSE_RELEASED";
551
552 case ui::ET_MOUSE_MOVED:
553 return "MOUSE_MOVED";
554
555 case ui::ET_MOUSE_ENTERED:
556 return "MOUSE_ENTERED";
557
558 case ui::ET_MOUSE_EXITED:
559 return "MOUSE_EXITED";
560
561 case ui::ET_GESTURE_SCROLL_BEGIN:
562 return "GESTURE_SCROLL_BEGIN";
563
564 case ui::ET_GESTURE_SCROLL_END:
565 return "GESTURE_SCROLL_END";
566
567 case ui::ET_GESTURE_SCROLL_UPDATE:
568 return "GESTURE_SCROLL_UPDATE";
569
570 case ui::ET_GESTURE_PINCH_BEGIN:
571 return "GESTURE_PINCH_BEGIN";
572
573 case ui::ET_GESTURE_PINCH_END:
574 return "GESTURE_PINCH_END";
575
576 case ui::ET_GESTURE_PINCH_UPDATE:
577 return "GESTURE_PINCH_UPDATE";
578
579 case ui::ET_GESTURE_TAP:
580 return "GESTURE_TAP";
581
582 case ui::ET_GESTURE_TAP_DOWN:
583 return "GESTURE_TAP_DOWN";
584
585 case ui::ET_GESTURE_TAP_CANCEL:
586 return "GESTURE_TAP_CANCEL";
587
588 case ui::ET_GESTURE_SHOW_PRESS:
589 return "GESTURE_SHOW_PRESS";
590
591 case ui::ET_GESTURE_BEGIN:
592 return "GESTURE_BEGIN";
593
594 case ui::ET_GESTURE_END:
595 return "GESTURE_END";
596
597 default:
598 // We should explicitly require each event type.
599 NOTREACHED() << "Received unexpected event: " << type;
600 break;
601 }
602 return "";
603 }
604
605 std::string EventTypesToString(const EventFilterRecorder::Events& events) {
606 std::string result;
607 for (size_t i = 0; i < events.size(); ++i) {
608 if (i != 0)
609 result += " ";
610 result += EventTypeToString(events[i]);
611 }
612 return result;
613 }
614
615 } // namespace
616
617 #if defined(OS_WIN) && defined(ARCH_CPU_X86)
618 #define MAYBE(x) DISABLED_##x
619 #else
620 #define MAYBE(x) x
621 #endif
622
623 // Verifies a repost mouse event targets the window with capture (if there is
624 // one).
625 // Flaky on 32-bit Windows bots. http://crbug.com/388290
626 TEST_F(WindowEventDispatcherTest, MAYBE(RepostTargetsCaptureWindow)) {
627 // Set capture on |window| generate a mouse event (that is reposted) and not
628 // over |window| and verify |window| gets it (|window| gets it because it has
629 // capture).
630 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
631 EventFilterRecorder recorder;
632 scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), NULL));
633 window->SetBounds(gfx::Rect(20, 20, 40, 30));
634 window->AddPreTargetHandler(&recorder);
635 window->SetCapture();
636 const ui::MouseEvent press_event(
637 ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
638 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
639 host()->dispatcher()->RepostEvent(press_event);
640 RunAllPendingInMessageLoop(); // Necessitated by RepostEvent().
641 // Mouse moves/enters may be generated. We only care about a pressed.
642 EXPECT_TRUE(EventTypesToString(recorder.events()).find("MOUSE_PRESSED") !=
643 std::string::npos) << EventTypesToString(recorder.events());
644 }
645
646 TEST_F(WindowEventDispatcherTest, MouseMovesHeld) {
647 EventFilterRecorder recorder;
648 root_window()->AddPreTargetHandler(&recorder);
649
650 test::TestWindowDelegate delegate;
651 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
652 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
653
654 ui::MouseEvent mouse_move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
655 gfx::Point(0, 0), 0, 0);
656 DispatchEventUsingWindowDispatcher(&mouse_move_event);
657 // Discard MOUSE_ENTER.
658 recorder.Reset();
659
660 host()->dispatcher()->HoldPointerMoves();
661
662 // Check that we don't immediately dispatch the MOUSE_DRAGGED event.
663 ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0),
664 gfx::Point(0, 0), 0, 0);
665 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
666 EXPECT_TRUE(recorder.events().empty());
667
668 // Check that we do dispatch the held MOUSE_DRAGGED event before another type
669 // of event.
670 ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0),
671 gfx::Point(0, 0), 0, 0);
672 DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
673 EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
674 EventTypesToString(recorder.events()));
675 recorder.Reset();
676
677 // Check that we coalesce held MOUSE_DRAGGED events. Note that here (and
678 // elsewhere in this test) we re-define each event prior to dispatch so that
679 // it has the correct state (phase, handled, target, etc.).
680 mouse_dragged_event = ui::MouseEvent(
681 ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0), gfx::Point(0, 0), 0, 0);
682 ui::MouseEvent mouse_dragged_event2(ui::ET_MOUSE_DRAGGED, gfx::Point(10, 10),
683 gfx::Point(10, 10), 0, 0);
684 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
685 DispatchEventUsingWindowDispatcher(&mouse_dragged_event2);
686 EXPECT_TRUE(recorder.events().empty());
687 mouse_pressed_event = ui::MouseEvent(
688 ui::ET_MOUSE_PRESSED, gfx::Point(0, 0), gfx::Point(0, 0), 0, 0);
689 DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
690 EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
691 EventTypesToString(recorder.events()));
692 recorder.Reset();
693
694 // Check that on ReleasePointerMoves, held events are not dispatched
695 // immediately, but posted instead.
696 mouse_dragged_event = ui::MouseEvent(
697 ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0), gfx::Point(0, 0), 0, 0);
698 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
699 host()->dispatcher()->ReleasePointerMoves();
700 EXPECT_TRUE(recorder.events().empty());
701 RunAllPendingInMessageLoop();
702 EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(recorder.events()));
703 recorder.Reset();
704
705 // However if another message comes in before the dispatch of the posted
706 // event, check that the posted event is dispatched before this new event.
707 host()->dispatcher()->HoldPointerMoves();
708 mouse_dragged_event = ui::MouseEvent(
709 ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0), gfx::Point(0, 0), 0, 0);
710 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
711 host()->dispatcher()->ReleasePointerMoves();
712 mouse_pressed_event = ui::MouseEvent(
713 ui::ET_MOUSE_PRESSED, gfx::Point(0, 0), gfx::Point(0, 0), 0, 0);
714 DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
715 EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
716 EventTypesToString(recorder.events()));
717 recorder.Reset();
718 RunAllPendingInMessageLoop();
719 EXPECT_TRUE(recorder.events().empty());
720
721 // Check that if the other message is another MOUSE_DRAGGED, we still coalesce
722 // them.
723 host()->dispatcher()->HoldPointerMoves();
724 mouse_dragged_event = ui::MouseEvent(
725 ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0), gfx::Point(0, 0), 0, 0);
726 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
727 host()->dispatcher()->ReleasePointerMoves();
728 mouse_dragged_event2 = ui::MouseEvent(
729 ui::ET_MOUSE_DRAGGED, gfx::Point(10, 10), gfx::Point(10, 10), 0, 0);
730 DispatchEventUsingWindowDispatcher(&mouse_dragged_event2);
731 EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(recorder.events()));
732 recorder.Reset();
733 RunAllPendingInMessageLoop();
734 EXPECT_TRUE(recorder.events().empty());
735
736 // Check that synthetic mouse move event has a right location when issued
737 // while holding pointer moves.
738 mouse_dragged_event = ui::MouseEvent(
739 ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0), gfx::Point(0, 0), 0, 0);
740 mouse_dragged_event2 = ui::MouseEvent(
741 ui::ET_MOUSE_DRAGGED, gfx::Point(10, 10), gfx::Point(10, 10), 0, 0);
742 ui::MouseEvent mouse_dragged_event3(ui::ET_MOUSE_DRAGGED, gfx::Point(28, 28),
743 gfx::Point(28, 28), 0, 0);
744 host()->dispatcher()->HoldPointerMoves();
745 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
746 DispatchEventUsingWindowDispatcher(&mouse_dragged_event2);
747 window->SetBounds(gfx::Rect(15, 15, 80, 80));
748 DispatchEventUsingWindowDispatcher(&mouse_dragged_event3);
749 RunAllPendingInMessageLoop();
750 EXPECT_TRUE(recorder.events().empty());
751 host()->dispatcher()->ReleasePointerMoves();
752 RunAllPendingInMessageLoop();
753 EXPECT_EQ("MOUSE_MOVED", EventTypesToString(recorder.events()));
754 EXPECT_EQ(gfx::Point(13, 13), recorder.mouse_location(0));
755 recorder.Reset();
756 root_window()->RemovePreTargetHandler(&recorder);
757 }
758
759 TEST_F(WindowEventDispatcherTest, TouchMovesHeld) {
760 EventFilterRecorder recorder;
761 root_window()->AddPreTargetHandler(&recorder);
762
763 test::TestWindowDelegate delegate;
764 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
765 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
766
767 // Starting the touch and throwing out the first few events, since the system
768 // is going to generate synthetic mouse events that are not relevant to the
769 // test.
770 ui::TouchEvent touch_pressed_event(
771 ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, ui::EventTimeForNow());
772 DispatchEventUsingWindowDispatcher(&touch_pressed_event);
773 recorder.WaitUntilReceivedEvent(ui::ET_GESTURE_SHOW_PRESS);
774 recorder.Reset();
775
776 host()->dispatcher()->HoldPointerMoves();
777
778 // Check that we don't immediately dispatch the TOUCH_MOVED event.
779 ui::TouchEvent touch_moved_event(
780 ui::ET_TOUCH_MOVED, gfx::Point(10, 10), 0, ui::EventTimeForNow());
781 ui::TouchEvent touch_moved_event2(
782 ui::ET_TOUCH_MOVED, gfx::Point(11, 10), 0, ui::EventTimeForNow());
783 ui::TouchEvent touch_moved_event3(
784 ui::ET_TOUCH_MOVED, gfx::Point(12, 10), 0, ui::EventTimeForNow());
785
786 DispatchEventUsingWindowDispatcher(&touch_moved_event);
787 EXPECT_TRUE(recorder.events().empty());
788
789 // Check that on ReleasePointerMoves, held events are not dispatched
790 // immediately, but posted instead.
791 DispatchEventUsingWindowDispatcher(&touch_moved_event2);
792 host()->dispatcher()->ReleasePointerMoves();
793 EXPECT_TRUE(recorder.events().empty());
794
795 RunAllPendingInMessageLoop();
796 EXPECT_EQ("TOUCH_MOVED", EventTypesToString(recorder.events()));
797 recorder.Reset();
798
799 // If another touch event occurs then the held touch should be dispatched
800 // immediately before it.
801 ui::TouchEvent touch_released_event(
802 ui::ET_TOUCH_RELEASED, gfx::Point(10, 10), 0, ui::EventTimeForNow());
803 recorder.Reset();
804 host()->dispatcher()->HoldPointerMoves();
805 DispatchEventUsingWindowDispatcher(&touch_moved_event3);
806 DispatchEventUsingWindowDispatcher(&touch_released_event);
807 EXPECT_EQ("TOUCH_MOVED TOUCH_RELEASED GESTURE_TAP GESTURE_END",
808 EventTypesToString(recorder.events()));
809 recorder.Reset();
810 host()->dispatcher()->ReleasePointerMoves();
811 RunAllPendingInMessageLoop();
812 EXPECT_TRUE(recorder.events().empty());
813 }
814
815 // Verifies that a direct call to ProcessedTouchEvent() with a
816 // TOUCH_PRESSED event does not cause a crash.
817 TEST_F(WindowEventDispatcherTest, CallToProcessedTouchEvent) {
818 test::TestWindowDelegate delegate;
819 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
820 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
821
822 ui::TouchEvent touch(
823 ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1, ui::EventTimeForNow());
824 host()->dispatcher()->ProcessedTouchEvent(
825 &touch, window.get(), ui::ER_UNHANDLED);
826 }
827
828 // This event handler requests the dispatcher to start holding pointer-move
829 // events when it receives the first scroll-update gesture.
830 class HoldPointerOnScrollHandler : public ui::test::TestEventHandler {
831 public:
832 HoldPointerOnScrollHandler(WindowEventDispatcher* dispatcher,
833 EventFilterRecorder* filter)
834 : dispatcher_(dispatcher),
835 filter_(filter),
836 holding_moves_(false) {}
837 virtual ~HoldPointerOnScrollHandler() {}
838
839 private:
840 // ui::test::TestEventHandler:
841 virtual void OnGestureEvent(ui::GestureEvent* gesture) override {
842 if (!holding_moves_ && gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
843 holding_moves_ = true;
844 dispatcher_->HoldPointerMoves();
845 filter_->Reset();
846 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) {
847 dispatcher_->ReleasePointerMoves();
848 holding_moves_ = false;
849 }
850 }
851
852 WindowEventDispatcher* dispatcher_;
853 EventFilterRecorder* filter_;
854 bool holding_moves_;
855
856 DISALLOW_COPY_AND_ASSIGN(HoldPointerOnScrollHandler);
857 };
858
859 // Tests that touch-move events don't contribute to an in-progress scroll
860 // gesture if touch-move events are being held by the dispatcher.
861 TEST_F(WindowEventDispatcherTest, TouchMovesHeldOnScroll) {
862 EventFilterRecorder recorder;
863 root_window()->AddPreTargetHandler(&recorder);
864 test::TestWindowDelegate delegate;
865 HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder);
866 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
867 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
868 window->AddPreTargetHandler(&handler);
869
870 ui::test::EventGenerator generator(root_window());
871 generator.GestureScrollSequence(
872 gfx::Point(60, 60), gfx::Point(10, 60),
873 base::TimeDelta::FromMilliseconds(100), 25);
874
875 // |handler| will have reset |filter| and started holding the touch-move
876 // events when scrolling started. At the end of the scroll (i.e. upon
877 // touch-release), the held touch-move event will have been dispatched first,
878 // along with the subsequent events (i.e. touch-release, scroll-end, and
879 // gesture-end).
880 const EventFilterRecorder::Events& events = recorder.events();
881 EXPECT_EQ(
882 "TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED "
883 "GESTURE_SCROLL_END GESTURE_END",
884 EventTypesToString(events));
885 ASSERT_EQ(2u, recorder.touch_locations().size());
886 EXPECT_EQ(gfx::Point(-40, 10).ToString(),
887 recorder.touch_locations()[0].ToString());
888 EXPECT_EQ(gfx::Point(-40, 10).ToString(),
889 recorder.touch_locations()[1].ToString());
890 }
891
892 // Tests that a 'held' touch-event does contribute to gesture event when it is
893 // dispatched.
894 TEST_F(WindowEventDispatcherTest, HeldTouchMoveContributesToGesture) {
895 EventFilterRecorder recorder;
896 root_window()->AddPreTargetHandler(&recorder);
897
898 const gfx::Point location(20, 20);
899 ui::TouchEvent press(
900 ui::ET_TOUCH_PRESSED, location, 0, ui::EventTimeForNow());
901 DispatchEventUsingWindowDispatcher(&press);
902 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_TOUCH_PRESSED));
903 recorder.Reset();
904
905 host()->dispatcher()->HoldPointerMoves();
906
907 ui::TouchEvent move(ui::ET_TOUCH_MOVED,
908 location + gfx::Vector2d(100, 100),
909 0,
910 ui::EventTimeForNow());
911 DispatchEventUsingWindowDispatcher(&move);
912 EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED));
913 EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_BEGIN));
914 recorder.Reset();
915
916 host()->dispatcher()->ReleasePointerMoves();
917 EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED));
918 RunAllPendingInMessageLoop();
919 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED));
920 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_BEGIN));
921 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_UPDATE));
922
923 root_window()->RemovePreTargetHandler(&recorder);
924 }
925
926 // Tests that synthetic mouse events are ignored when mouse
927 // events are disabled.
928 TEST_F(WindowEventDispatcherTest, DispatchSyntheticMouseEvents) {
929 EventFilterRecorder recorder;
930 root_window()->AddPreTargetHandler(&recorder);
931
932 test::TestWindowDelegate delegate;
933 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
934 &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window()));
935 window->Show();
936 window->SetCapture();
937
938 test::TestCursorClient cursor_client(root_window());
939
940 // Dispatch a non-synthetic mouse event when mouse events are enabled.
941 ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
942 gfx::Point(10, 10), 0, 0);
943 DispatchEventUsingWindowDispatcher(&mouse1);
944 EXPECT_FALSE(recorder.events().empty());
945 recorder.Reset();
946
947 // Dispatch a synthetic mouse event when mouse events are enabled.
948 ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
949 gfx::Point(10, 10), ui::EF_IS_SYNTHESIZED, 0);
950 DispatchEventUsingWindowDispatcher(&mouse2);
951 EXPECT_FALSE(recorder.events().empty());
952 recorder.Reset();
953
954 // Dispatch a synthetic mouse event when mouse events are disabled.
955 cursor_client.DisableMouseEvents();
956 DispatchEventUsingWindowDispatcher(&mouse2);
957 EXPECT_TRUE(recorder.events().empty());
958 root_window()->RemovePreTargetHandler(&recorder);
959 }
960
961 // Tests that a mouse-move event is not synthesized when a mouse-button is down.
962 TEST_F(WindowEventDispatcherTest, DoNotSynthesizeWhileButtonDown) {
963 EventFilterRecorder recorder;
964 test::TestWindowDelegate delegate;
965 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
966 &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window()));
967 window->Show();
968
969 window->AddPreTargetHandler(&recorder);
970 // Dispatch a non-synthetic mouse event when mouse events are enabled.
971 ui::MouseEvent mouse1(ui::ET_MOUSE_PRESSED, gfx::Point(10, 10),
972 gfx::Point(10, 10), ui::EF_LEFT_MOUSE_BUTTON,
973 ui::EF_LEFT_MOUSE_BUTTON);
974 DispatchEventUsingWindowDispatcher(&mouse1);
975 ASSERT_EQ(1u, recorder.events().size());
976 EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.events()[0]);
977 window->RemovePreTargetHandler(&recorder);
978 recorder.Reset();
979
980 // Move |window| away from underneath the cursor.
981 root_window()->AddPreTargetHandler(&recorder);
982 window->SetBounds(gfx::Rect(30, 30, 100, 100));
983 EXPECT_TRUE(recorder.events().empty());
984 RunAllPendingInMessageLoop();
985 EXPECT_TRUE(recorder.events().empty());
986 root_window()->RemovePreTargetHandler(&recorder);
987 }
988
989 #if defined(OS_WIN) && defined(ARCH_CPU_X86)
990 #define MAYBE(x) DISABLED_##x
991 #else
992 #define MAYBE(x) x
993 #endif
994
995 // Tests synthetic mouse events generated when window bounds changes such that
996 // the cursor previously outside the window becomes inside, or vice versa.
997 // Do not synthesize events if the window ignores events or is invisible.
998 // Flaky on 32-bit Windows bots. http://crbug.com/388272
999 TEST_F(WindowEventDispatcherTest,
1000 MAYBE(SynthesizeMouseEventsOnWindowBoundsChanged)) {
1001 test::TestWindowDelegate delegate;
1002 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1003 &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window()));
1004 window->Show();
1005 window->SetCapture();
1006
1007 EventFilterRecorder recorder;
1008 window->AddPreTargetHandler(&recorder);
1009
1010 // Dispatch a non-synthetic mouse event to place cursor inside window bounds.
1011 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
1012 gfx::Point(10, 10), 0, 0);
1013 DispatchEventUsingWindowDispatcher(&mouse);
1014 EXPECT_FALSE(recorder.events().empty());
1015 recorder.Reset();
1016
1017 // Update the window bounds so that cursor is now outside the window.
1018 // This should trigger a synthetic MOVED event.
1019 gfx::Rect bounds1(20, 20, 100, 100);
1020 window->SetBounds(bounds1);
1021 RunAllPendingInMessageLoop();
1022 ASSERT_FALSE(recorder.events().empty());
1023 ASSERT_FALSE(recorder.mouse_event_flags().empty());
1024 EXPECT_EQ(ui::ET_MOUSE_MOVED, recorder.events().back());
1025 EXPECT_EQ(ui::EF_IS_SYNTHESIZED, recorder.mouse_event_flags().back());
1026 recorder.Reset();
1027
1028 // Set window to ignore events.
1029 window->set_ignore_events(true);
1030
1031 // Update the window bounds so that cursor is back inside the window.
1032 // This should not trigger a synthetic event.
1033 gfx::Rect bounds2(5, 5, 100, 100);
1034 window->SetBounds(bounds2);
1035 RunAllPendingInMessageLoop();
1036 EXPECT_TRUE(recorder.events().empty());
1037 recorder.Reset();
1038
1039 // Set window to accept events but invisible.
1040 window->set_ignore_events(false);
1041 window->Hide();
1042 recorder.Reset();
1043
1044 // Update the window bounds so that cursor is outside the window.
1045 // This should not trigger a synthetic event.
1046 window->SetBounds(bounds1);
1047 RunAllPendingInMessageLoop();
1048 EXPECT_TRUE(recorder.events().empty());
1049 }
1050
1051 // Tests that a mouse exit is dispatched to the last known cursor location
1052 // when the cursor becomes invisible.
1053 TEST_F(WindowEventDispatcherTest, DispatchMouseExitWhenCursorHidden) {
1054 EventFilterRecorder recorder;
1055 root_window()->AddPreTargetHandler(&recorder);
1056
1057 test::TestWindowDelegate delegate;
1058 gfx::Point window_origin(7, 18);
1059 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1060 &delegate, 1234, gfx::Rect(window_origin, gfx::Size(100, 100)),
1061 root_window()));
1062 window->Show();
1063
1064 // Dispatch a mouse move event into the window.
1065 gfx::Point mouse_location(gfx::Point(15, 25));
1066 ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location,
1067 mouse_location, 0, 0);
1068 EXPECT_TRUE(recorder.events().empty());
1069 DispatchEventUsingWindowDispatcher(&mouse1);
1070 EXPECT_FALSE(recorder.events().empty());
1071 recorder.Reset();
1072
1073 // Hide the cursor and verify a mouse exit was dispatched.
1074 host()->OnCursorVisibilityChanged(false);
1075 EXPECT_FALSE(recorder.events().empty());
1076 EXPECT_EQ("MOUSE_EXITED", EventTypesToString(recorder.events()));
1077
1078 // Verify the mouse exit was dispatched at the correct location
1079 // (in the correct coordinate space).
1080 int translated_x = mouse_location.x() - window_origin.x();
1081 int translated_y = mouse_location.y() - window_origin.y();
1082 gfx::Point translated_point(translated_x, translated_y);
1083 EXPECT_EQ(recorder.mouse_location(0).ToString(), translated_point.ToString());
1084 root_window()->RemovePreTargetHandler(&recorder);
1085 }
1086
1087 // Tests that a synthetic mouse exit is dispatched to the last known cursor
1088 // location after mouse events are disabled on the cursor client.
1089 TEST_F(WindowEventDispatcherTest,
1090 DispatchSyntheticMouseExitAfterMouseEventsDisabled) {
1091 EventFilterRecorder recorder;
1092 root_window()->AddPreTargetHandler(&recorder);
1093
1094 test::TestWindowDelegate delegate;
1095 gfx::Point window_origin(7, 18);
1096 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1097 &delegate, 1234, gfx::Rect(window_origin, gfx::Size(100, 100)),
1098 root_window()));
1099 window->Show();
1100
1101 // Dispatch a mouse move event into the window.
1102 gfx::Point mouse_location(gfx::Point(15, 25));
1103 ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location,
1104 mouse_location, 0, 0);
1105 EXPECT_TRUE(recorder.events().empty());
1106 DispatchEventUsingWindowDispatcher(&mouse1);
1107 EXPECT_FALSE(recorder.events().empty());
1108 recorder.Reset();
1109
1110 test::TestCursorClient cursor_client(root_window());
1111 cursor_client.DisableMouseEvents();
1112
1113 gfx::Point mouse_exit_location(gfx::Point(150, 150));
1114 ui::MouseEvent mouse2(ui::ET_MOUSE_EXITED, gfx::Point(150, 150),
1115 gfx::Point(150, 150), ui::EF_IS_SYNTHESIZED, 0);
1116 DispatchEventUsingWindowDispatcher(&mouse2);
1117
1118 EXPECT_FALSE(recorder.events().empty());
1119 // We get the mouse exited event twice in our filter. Once during the
1120 // predispatch phase and during the actual dispatch.
1121 EXPECT_EQ("MOUSE_EXITED MOUSE_EXITED", EventTypesToString(recorder.events()));
1122
1123 // Verify the mouse exit was dispatched at the correct location
1124 // (in the correct coordinate space).
1125 int translated_x = mouse_exit_location.x() - window_origin.x();
1126 int translated_y = mouse_exit_location.y() - window_origin.y();
1127 gfx::Point translated_point(translated_x, translated_y);
1128 EXPECT_EQ(recorder.mouse_location(0).ToString(), translated_point.ToString());
1129 root_window()->RemovePreTargetHandler(&recorder);
1130 }
1131
1132 class DeletingEventFilter : public ui::EventHandler {
1133 public:
1134 DeletingEventFilter()
1135 : delete_during_pre_handle_(false) {}
1136 virtual ~DeletingEventFilter() {}
1137
1138 void Reset(bool delete_during_pre_handle) {
1139 delete_during_pre_handle_ = delete_during_pre_handle;
1140 }
1141
1142 private:
1143 // Overridden from ui::EventHandler:
1144 virtual void OnKeyEvent(ui::KeyEvent* event) override {
1145 if (delete_during_pre_handle_)
1146 delete event->target();
1147 }
1148
1149 virtual void OnMouseEvent(ui::MouseEvent* event) override {
1150 if (delete_during_pre_handle_)
1151 delete event->target();
1152 }
1153
1154 bool delete_during_pre_handle_;
1155
1156 DISALLOW_COPY_AND_ASSIGN(DeletingEventFilter);
1157 };
1158
1159 class DeletingWindowDelegate : public test::TestWindowDelegate {
1160 public:
1161 DeletingWindowDelegate()
1162 : window_(NULL),
1163 delete_during_handle_(false),
1164 got_event_(false) {}
1165 virtual ~DeletingWindowDelegate() {}
1166
1167 void Reset(Window* window, bool delete_during_handle) {
1168 window_ = window;
1169 delete_during_handle_ = delete_during_handle;
1170 got_event_ = false;
1171 }
1172 bool got_event() const { return got_event_; }
1173
1174 private:
1175 // Overridden from WindowDelegate:
1176 virtual void OnKeyEvent(ui::KeyEvent* event) override {
1177 if (delete_during_handle_)
1178 delete window_;
1179 got_event_ = true;
1180 }
1181
1182 virtual void OnMouseEvent(ui::MouseEvent* event) override {
1183 if (delete_during_handle_)
1184 delete window_;
1185 got_event_ = true;
1186 }
1187
1188 Window* window_;
1189 bool delete_during_handle_;
1190 bool got_event_;
1191
1192 DISALLOW_COPY_AND_ASSIGN(DeletingWindowDelegate);
1193 };
1194
1195 TEST_F(WindowEventDispatcherTest, DeleteWindowDuringDispatch) {
1196 // Verifies that we can delete a window during each phase of event handling.
1197 // Deleting the window should not cause a crash, only prevent further
1198 // processing from occurring.
1199 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
1200 DeletingWindowDelegate d11;
1201 Window* w11 = CreateNormalWindow(11, w1.get(), &d11);
1202 WindowTracker tracker;
1203 DeletingEventFilter w1_filter;
1204 w1->AddPreTargetHandler(&w1_filter);
1205 client::GetFocusClient(w1.get())->FocusWindow(w11);
1206
1207 ui::test::EventGenerator generator(root_window(), w11);
1208
1209 // First up, no one deletes anything.
1210 tracker.Add(w11);
1211 d11.Reset(w11, false);
1212
1213 generator.PressLeftButton();
1214 EXPECT_TRUE(tracker.Contains(w11));
1215 EXPECT_TRUE(d11.got_event());
1216 generator.ReleaseLeftButton();
1217
1218 // Delegate deletes w11. This will prevent the post-handle step from applying.
1219 w1_filter.Reset(false);
1220 d11.Reset(w11, true);
1221 generator.PressKey(ui::VKEY_A, 0);
1222 EXPECT_FALSE(tracker.Contains(w11));
1223 EXPECT_TRUE(d11.got_event());
1224
1225 // Pre-handle step deletes w11. This will prevent the delegate and the post-
1226 // handle steps from applying.
1227 w11 = CreateNormalWindow(11, w1.get(), &d11);
1228 w1_filter.Reset(true);
1229 d11.Reset(w11, false);
1230 generator.PressLeftButton();
1231 EXPECT_FALSE(tracker.Contains(w11));
1232 EXPECT_FALSE(d11.got_event());
1233 }
1234
1235 namespace {
1236
1237 // A window delegate that detaches the parent of the target's parent window when
1238 // it receives a tap event.
1239 class DetachesParentOnTapDelegate : public test::TestWindowDelegate {
1240 public:
1241 DetachesParentOnTapDelegate() {}
1242 virtual ~DetachesParentOnTapDelegate() {}
1243
1244 private:
1245 virtual void OnGestureEvent(ui::GestureEvent* event) override {
1246 if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
1247 event->SetHandled();
1248 return;
1249 }
1250
1251 if (event->type() == ui::ET_GESTURE_TAP) {
1252 Window* parent = static_cast<Window*>(event->target())->parent();
1253 parent->parent()->RemoveChild(parent);
1254 event->SetHandled();
1255 }
1256 }
1257
1258 DISALLOW_COPY_AND_ASSIGN(DetachesParentOnTapDelegate);
1259 };
1260
1261 } // namespace
1262
1263 // Tests that the gesture recognizer is reset for all child windows when a
1264 // window hides. No expectations, just checks that the test does not crash.
1265 TEST_F(WindowEventDispatcherTest,
1266 GestureRecognizerResetsTargetWhenParentHides) {
1267 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
1268 DetachesParentOnTapDelegate delegate;
1269 scoped_ptr<Window> parent(CreateNormalWindow(22, w1.get(), NULL));
1270 Window* child = CreateNormalWindow(11, parent.get(), &delegate);
1271 ui::test::EventGenerator generator(root_window(), child);
1272 generator.GestureTapAt(gfx::Point(40, 40));
1273 }
1274
1275 namespace {
1276
1277 // A window delegate that processes nested gestures on tap.
1278 class NestedGestureDelegate : public test::TestWindowDelegate {
1279 public:
1280 NestedGestureDelegate(ui::test::EventGenerator* generator,
1281 const gfx::Point tap_location)
1282 : generator_(generator),
1283 tap_location_(tap_location),
1284 gesture_end_count_(0) {}
1285 virtual ~NestedGestureDelegate() {}
1286
1287 int gesture_end_count() const { return gesture_end_count_; }
1288
1289 private:
1290 virtual void OnGestureEvent(ui::GestureEvent* event) override {
1291 switch (event->type()) {
1292 case ui::ET_GESTURE_TAP_DOWN:
1293 event->SetHandled();
1294 break;
1295 case ui::ET_GESTURE_TAP:
1296 if (generator_)
1297 generator_->GestureTapAt(tap_location_);
1298 event->SetHandled();
1299 break;
1300 case ui::ET_GESTURE_END:
1301 ++gesture_end_count_;
1302 break;
1303 default:
1304 break;
1305 }
1306 }
1307
1308 ui::test::EventGenerator* generator_;
1309 const gfx::Point tap_location_;
1310 int gesture_end_count_;
1311 DISALLOW_COPY_AND_ASSIGN(NestedGestureDelegate);
1312 };
1313
1314 } // namespace
1315
1316 // Tests that gesture end is delivered after nested gesture processing.
1317 TEST_F(WindowEventDispatcherTest, GestureEndDeliveredAfterNestedGestures) {
1318 NestedGestureDelegate d1(NULL, gfx::Point());
1319 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &d1));
1320 w1->SetBounds(gfx::Rect(0, 0, 100, 100));
1321
1322 ui::test::EventGenerator nested_generator(root_window(), w1.get());
1323 NestedGestureDelegate d2(&nested_generator, w1->bounds().CenterPoint());
1324 scoped_ptr<Window> w2(CreateNormalWindow(1, root_window(), &d2));
1325 w2->SetBounds(gfx::Rect(100, 0, 100, 100));
1326
1327 // Tap on w2 which triggers nested gestures for w1.
1328 ui::test::EventGenerator generator(root_window(), w2.get());
1329 generator.GestureTapAt(w2->bounds().CenterPoint());
1330
1331 // Both windows should get their gesture end events.
1332 EXPECT_EQ(1, d1.gesture_end_count());
1333 EXPECT_EQ(1, d2.gesture_end_count());
1334 }
1335
1336 // Tests whether we can repost the Tap down gesture event.
1337 TEST_F(WindowEventDispatcherTest, RepostTapdownGestureTest) {
1338 EventFilterRecorder recorder;
1339 root_window()->AddPreTargetHandler(&recorder);
1340
1341 test::TestWindowDelegate delegate;
1342 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1343 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
1344
1345 ui::GestureEventDetails details(ui::ET_GESTURE_TAP_DOWN);
1346 gfx::Point point(10, 10);
1347 ui::GestureEvent event(point.x(),
1348 point.y(),
1349 0,
1350 ui::EventTimeForNow(),
1351 details);
1352 host()->dispatcher()->RepostEvent(event);
1353 RunAllPendingInMessageLoop();
1354 // TODO(rbyers): Currently disabled - crbug.com/170987
1355 EXPECT_FALSE(EventTypesToString(recorder.events()).find("GESTURE_TAP_DOWN") !=
1356 std::string::npos);
1357 recorder.Reset();
1358 root_window()->RemovePreTargetHandler(&recorder);
1359 }
1360
1361 // This class inherits from the EventFilterRecorder class which provides a
1362 // facility to record events. This class additionally provides a facility to
1363 // repost the ET_GESTURE_TAP_DOWN gesture to the target window and records
1364 // events after that.
1365 class RepostGestureEventRecorder : public EventFilterRecorder {
1366 public:
1367 RepostGestureEventRecorder(aura::Window* repost_source,
1368 aura::Window* repost_target)
1369 : repost_source_(repost_source),
1370 repost_target_(repost_target),
1371 reposted_(false),
1372 done_cleanup_(false) {}
1373
1374 virtual ~RepostGestureEventRecorder() {}
1375
1376 virtual void OnTouchEvent(ui::TouchEvent* event) override {
1377 if (reposted_ && event->type() == ui::ET_TOUCH_PRESSED) {
1378 done_cleanup_ = true;
1379 Reset();
1380 }
1381 EventFilterRecorder::OnTouchEvent(event);
1382 }
1383
1384 virtual void OnGestureEvent(ui::GestureEvent* event) override {
1385 EXPECT_EQ(done_cleanup_ ? repost_target_ : repost_source_, event->target());
1386 if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
1387 if (!reposted_) {
1388 EXPECT_NE(repost_target_, event->target());
1389 reposted_ = true;
1390 repost_target_->GetHost()->dispatcher()->RepostEvent(*event);
1391 // Ensure that the reposted gesture event above goes to the
1392 // repost_target_;
1393 repost_source_->GetRootWindow()->RemoveChild(repost_source_);
1394 return;
1395 }
1396 }
1397 EventFilterRecorder::OnGestureEvent(event);
1398 }
1399
1400 // Ignore mouse events as they don't fire at all times. This causes
1401 // the GestureRepostEventOrder test to fail randomly.
1402 virtual void OnMouseEvent(ui::MouseEvent* event) override {}
1403
1404 private:
1405 aura::Window* repost_source_;
1406 aura::Window* repost_target_;
1407 // set to true if we reposted the ET_GESTURE_TAP_DOWN event.
1408 bool reposted_;
1409 // set true if we're done cleaning up after hiding repost_source_;
1410 bool done_cleanup_;
1411 DISALLOW_COPY_AND_ASSIGN(RepostGestureEventRecorder);
1412 };
1413
1414 // Tests whether events which are generated after the reposted gesture event
1415 // are received after that. In this case the scroll sequence events should
1416 // be received after the reposted gesture event.
1417 TEST_F(WindowEventDispatcherTest, GestureRepostEventOrder) {
1418 // Expected events at the end for the repost_target window defined below.
1419 const char kExpectedTargetEvents[] =
1420 // TODO)(rbyers): Gesture event reposting is disabled - crbug.com/279039.
1421 // "GESTURE_BEGIN GESTURE_TAP_DOWN "
1422 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
1423 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE TOUCH_MOVED "
1424 "GESTURE_SCROLL_UPDATE TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED "
1425 "GESTURE_SCROLL_END GESTURE_END";
1426 // We create two windows.
1427 // The first window (repost_source) is the one to which the initial tap
1428 // gesture is sent. It reposts this event to the second window
1429 // (repost_target).
1430 // We then generate the scroll sequence for repost_target and look for two
1431 // ET_GESTURE_TAP_DOWN events in the event list at the end.
1432 test::TestWindowDelegate delegate;
1433 scoped_ptr<aura::Window> repost_target(CreateTestWindowWithDelegate(
1434 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
1435
1436 scoped_ptr<aura::Window> repost_source(CreateTestWindowWithDelegate(
1437 &delegate, 1, gfx::Rect(0, 0, 50, 50), root_window()));
1438
1439 RepostGestureEventRecorder repost_event_recorder(repost_source.get(),
1440 repost_target.get());
1441 root_window()->AddPreTargetHandler(&repost_event_recorder);
1442
1443 // Generate a tap down gesture for the repost_source. This will be reposted
1444 // to repost_target.
1445 ui::test::EventGenerator repost_generator(root_window(), repost_source.get());
1446 repost_generator.GestureTapAt(gfx::Point(40, 40));
1447 RunAllPendingInMessageLoop();
1448
1449 ui::test::EventGenerator scroll_generator(root_window(), repost_target.get());
1450 scroll_generator.GestureScrollSequence(
1451 gfx::Point(80, 80),
1452 gfx::Point(100, 100),
1453 base::TimeDelta::FromMilliseconds(100),
1454 3);
1455 RunAllPendingInMessageLoop();
1456
1457 int tap_down_count = 0;
1458 for (size_t i = 0; i < repost_event_recorder.events().size(); ++i) {
1459 if (repost_event_recorder.events()[i] == ui::ET_GESTURE_TAP_DOWN)
1460 ++tap_down_count;
1461 }
1462
1463 // We expect two tap down events. One from the repost and the other one from
1464 // the scroll sequence posted above.
1465 // TODO(rbyers): Currently disabled - crbug.com/170987
1466 EXPECT_EQ(1, tap_down_count);
1467
1468 EXPECT_EQ(kExpectedTargetEvents,
1469 EventTypesToString(repost_event_recorder.events()));
1470 root_window()->RemovePreTargetHandler(&repost_event_recorder);
1471 }
1472
1473 class OnMouseExitDeletingEventFilter : public EventFilterRecorder {
1474 public:
1475 OnMouseExitDeletingEventFilter() : window_to_delete_(NULL) {}
1476 virtual ~OnMouseExitDeletingEventFilter() {}
1477
1478 void set_window_to_delete(Window* window_to_delete) {
1479 window_to_delete_ = window_to_delete;
1480 }
1481
1482 private:
1483 // Overridden from ui::EventHandler:
1484 virtual void OnMouseEvent(ui::MouseEvent* event) override {
1485 EventFilterRecorder::OnMouseEvent(event);
1486 if (window_to_delete_) {
1487 delete window_to_delete_;
1488 window_to_delete_ = NULL;
1489 }
1490 }
1491
1492 Window* window_to_delete_;
1493
1494 DISALLOW_COPY_AND_ASSIGN(OnMouseExitDeletingEventFilter);
1495 };
1496
1497 // Tests that RootWindow drops mouse-moved event that is supposed to be sent to
1498 // a child, but the child is destroyed because of the synthesized mouse-exit
1499 // event generated on the previous mouse_moved_handler_.
1500 TEST_F(WindowEventDispatcherTest, DeleteWindowDuringMouseMovedDispatch) {
1501 // Create window 1 and set its event filter. Window 1 will take ownership of
1502 // the event filter.
1503 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
1504 OnMouseExitDeletingEventFilter w1_filter;
1505 w1->AddPreTargetHandler(&w1_filter);
1506 w1->SetBounds(gfx::Rect(20, 20, 60, 60));
1507 EXPECT_EQ(NULL, host()->dispatcher()->mouse_moved_handler());
1508
1509 ui::test::EventGenerator generator(root_window(), w1.get());
1510
1511 // Move mouse over window 1 to set it as the |mouse_moved_handler_| for the
1512 // root window.
1513 generator.MoveMouseTo(51, 51);
1514 EXPECT_EQ(w1.get(), host()->dispatcher()->mouse_moved_handler());
1515
1516 // Create window 2 under the mouse cursor and stack it above window 1.
1517 Window* w2 = CreateNormalWindow(2, root_window(), NULL);
1518 w2->SetBounds(gfx::Rect(30, 30, 40, 40));
1519 root_window()->StackChildAbove(w2, w1.get());
1520
1521 // Set window 2 as the window that is to be deleted when a mouse-exited event
1522 // happens on window 1.
1523 w1_filter.set_window_to_delete(w2);
1524
1525 // Move mosue over window 2. This should generate a mouse-exited event for
1526 // window 1 resulting in deletion of window 2. The original mouse-moved event
1527 // that was targeted to window 2 should be dropped since window 2 is
1528 // destroyed. This test passes if no crash happens.
1529 generator.MoveMouseTo(52, 52);
1530 EXPECT_EQ(NULL, host()->dispatcher()->mouse_moved_handler());
1531
1532 // Check events received by window 1.
1533 EXPECT_EQ("MOUSE_ENTERED MOUSE_MOVED MOUSE_EXITED",
1534 EventTypesToString(w1_filter.events()));
1535 }
1536
1537 namespace {
1538
1539 // Used to track if OnWindowDestroying() is invoked and if there is a valid
1540 // RootWindow at such time.
1541 class ValidRootDuringDestructionWindowObserver : public aura::WindowObserver {
1542 public:
1543 ValidRootDuringDestructionWindowObserver(bool* got_destroying,
1544 bool* has_valid_root)
1545 : got_destroying_(got_destroying),
1546 has_valid_root_(has_valid_root) {
1547 }
1548
1549 // WindowObserver:
1550 virtual void OnWindowDestroying(aura::Window* window) override {
1551 *got_destroying_ = true;
1552 *has_valid_root_ = (window->GetRootWindow() != NULL);
1553 }
1554
1555 private:
1556 bool* got_destroying_;
1557 bool* has_valid_root_;
1558
1559 DISALLOW_COPY_AND_ASSIGN(ValidRootDuringDestructionWindowObserver);
1560 };
1561
1562 } // namespace
1563
1564 // Verifies GetRootWindow() from ~Window returns a valid root.
1565 TEST_F(WindowEventDispatcherTest, ValidRootDuringDestruction) {
1566 bool got_destroying = false;
1567 bool has_valid_root = false;
1568 ValidRootDuringDestructionWindowObserver observer(&got_destroying,
1569 &has_valid_root);
1570 {
1571 scoped_ptr<WindowTreeHost> host(
1572 WindowTreeHost::Create(gfx::Rect(0, 0, 100, 100)));
1573 host->InitHost();
1574 // Owned by WindowEventDispatcher.
1575 Window* w1 = CreateNormalWindow(1, host->window(), NULL);
1576 w1->AddObserver(&observer);
1577 }
1578 EXPECT_TRUE(got_destroying);
1579 EXPECT_TRUE(has_valid_root);
1580 }
1581
1582 namespace {
1583
1584 // See description above DontResetHeldEvent for details.
1585 class DontResetHeldEventWindowDelegate : public test::TestWindowDelegate {
1586 public:
1587 explicit DontResetHeldEventWindowDelegate(aura::Window* root)
1588 : root_(root),
1589 mouse_event_count_(0) {}
1590 virtual ~DontResetHeldEventWindowDelegate() {}
1591
1592 int mouse_event_count() const { return mouse_event_count_; }
1593
1594 // TestWindowDelegate:
1595 virtual void OnMouseEvent(ui::MouseEvent* event) override {
1596 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 &&
1597 mouse_event_count_++ == 0) {
1598 ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED,
1599 gfx::Point(10, 10), gfx::Point(10, 10),
1600 ui::EF_SHIFT_DOWN, 0);
1601 root_->GetHost()->dispatcher()->RepostEvent(mouse_event);
1602 }
1603 }
1604
1605 private:
1606 Window* root_;
1607 int mouse_event_count_;
1608
1609 DISALLOW_COPY_AND_ASSIGN(DontResetHeldEventWindowDelegate);
1610 };
1611
1612 } // namespace
1613
1614 // Verifies RootWindow doesn't reset |RootWindow::held_repostable_event_| after
1615 // dispatching. This is done by using DontResetHeldEventWindowDelegate, which
1616 // tracks the number of events with ui::EF_SHIFT_DOWN set (all reposted events
1617 // have EF_SHIFT_DOWN). When the first event is seen RepostEvent() is used to
1618 // schedule another reposted event.
1619 TEST_F(WindowEventDispatcherTest, DontResetHeldEvent) {
1620 DontResetHeldEventWindowDelegate delegate(root_window());
1621 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate));
1622 w1->SetBounds(gfx::Rect(0, 0, 40, 40));
1623 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED,
1624 gfx::Point(10, 10), gfx::Point(10, 10),
1625 ui::EF_SHIFT_DOWN, 0);
1626 root_window()->GetHost()->dispatcher()->RepostEvent(pressed);
1627 ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED,
1628 gfx::Point(10, 10), gfx::Point(10, 10), 0, 0);
1629 // Dispatch an event to flush event scheduled by way of RepostEvent().
1630 DispatchEventUsingWindowDispatcher(&pressed2);
1631 // Delegate should have seen reposted event (identified by way of
1632 // EF_SHIFT_DOWN). Dispatch another event to flush the second
1633 // RepostedEvent().
1634 EXPECT_EQ(1, delegate.mouse_event_count());
1635 DispatchEventUsingWindowDispatcher(&pressed2);
1636 EXPECT_EQ(2, delegate.mouse_event_count());
1637 }
1638
1639 namespace {
1640
1641 // See description above DeleteHostFromHeldMouseEvent for details.
1642 class DeleteHostFromHeldMouseEventDelegate
1643 : public test::TestWindowDelegate {
1644 public:
1645 explicit DeleteHostFromHeldMouseEventDelegate(WindowTreeHost* host)
1646 : host_(host),
1647 got_mouse_event_(false),
1648 got_destroy_(false) {
1649 }
1650 virtual ~DeleteHostFromHeldMouseEventDelegate() {}
1651
1652 bool got_mouse_event() const { return got_mouse_event_; }
1653 bool got_destroy() const { return got_destroy_; }
1654
1655 // TestWindowDelegate:
1656 virtual void OnMouseEvent(ui::MouseEvent* event) override {
1657 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0) {
1658 got_mouse_event_ = true;
1659 delete host_;
1660 }
1661 }
1662 virtual void OnWindowDestroyed(Window* window) override {
1663 got_destroy_ = true;
1664 }
1665
1666 private:
1667 WindowTreeHost* host_;
1668 bool got_mouse_event_;
1669 bool got_destroy_;
1670
1671 DISALLOW_COPY_AND_ASSIGN(DeleteHostFromHeldMouseEventDelegate);
1672 };
1673
1674 } // namespace
1675
1676 // Verifies if a WindowTreeHost is deleted from dispatching a held mouse event
1677 // we don't crash.
1678 TEST_F(WindowEventDispatcherTest, DeleteHostFromHeldMouseEvent) {
1679 // Should be deleted by |delegate|.
1680 WindowTreeHost* h2 = WindowTreeHost::Create(gfx::Rect(0, 0, 100, 100));
1681 h2->InitHost();
1682 DeleteHostFromHeldMouseEventDelegate delegate(h2);
1683 // Owned by |h2|.
1684 Window* w1 = CreateNormalWindow(1, h2->window(), &delegate);
1685 w1->SetBounds(gfx::Rect(0, 0, 40, 40));
1686 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED,
1687 gfx::Point(10, 10), gfx::Point(10, 10),
1688 ui::EF_SHIFT_DOWN, 0);
1689 h2->dispatcher()->RepostEvent(pressed);
1690 // RunAllPendingInMessageLoop() to make sure the |pressed| is run.
1691 RunAllPendingInMessageLoop();
1692 EXPECT_TRUE(delegate.got_mouse_event());
1693 EXPECT_TRUE(delegate.got_destroy());
1694 }
1695
1696 TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveTouches) {
1697 EventFilterRecorder recorder;
1698 root_window()->AddPreTargetHandler(&recorder);
1699
1700 test::TestWindowDelegate delegate;
1701 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1702 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
1703
1704 gfx::Point position1 = root_window()->bounds().origin();
1705 ui::TouchEvent press(
1706 ui::ET_TOUCH_PRESSED, position1, 0, ui::EventTimeForNow());
1707 DispatchEventUsingWindowDispatcher(&press);
1708
1709 EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN",
1710 EventTypesToString(recorder.GetAndResetEvents()));
1711
1712 window->Hide();
1713
1714 EXPECT_EQ(ui::ET_TOUCH_CANCELLED, recorder.events()[0]);
1715 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_TAP_CANCEL));
1716 EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_END));
1717 EXPECT_EQ(3U, recorder.events().size());
1718 root_window()->RemovePreTargetHandler(&recorder);
1719 }
1720
1721 TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveGestures) {
1722 EventFilterRecorder recorder;
1723 root_window()->AddPreTargetHandler(&recorder);
1724
1725 test::TestWindowDelegate delegate;
1726 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1727 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
1728
1729 gfx::Point position1 = root_window()->bounds().origin();
1730 gfx::Point position2 = root_window()->bounds().CenterPoint();
1731 ui::TouchEvent press(
1732 ui::ET_TOUCH_PRESSED, position1, 0, ui::EventTimeForNow());
1733 DispatchEventUsingWindowDispatcher(&press);
1734
1735 ui::TouchEvent move(
1736 ui::ET_TOUCH_MOVED, position2, 0, ui::EventTimeForNow());
1737 DispatchEventUsingWindowDispatcher(&move);
1738
1739 ui::TouchEvent press2(
1740 ui::ET_TOUCH_PRESSED, position1, 1, ui::EventTimeForNow());
1741 DispatchEventUsingWindowDispatcher(&press2);
1742
1743 // TODO(tdresser): once the unified Gesture Recognizer has stuck, remove the
1744 // special casing here. See crbug.com/332418 for details.
1745 std::string expected =
1746 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
1747 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
1748 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_PINCH_BEGIN";
1749
1750 std::string expected_ugr =
1751 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
1752 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
1753 "TOUCH_PRESSED GESTURE_BEGIN";
1754
1755 std::string events_string = EventTypesToString(recorder.GetAndResetEvents());
1756 EXPECT_TRUE((expected == events_string) || (expected_ugr == events_string));
1757
1758 window->Hide();
1759
1760 expected =
1761 "TOUCH_CANCELLED GESTURE_PINCH_END GESTURE_END TOUCH_CANCELLED "
1762 "GESTURE_SCROLL_END GESTURE_END";
1763 expected_ugr =
1764 "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END TOUCH_CANCELLED "
1765 "GESTURE_END";
1766
1767 events_string = EventTypesToString(recorder.GetAndResetEvents());
1768 EXPECT_TRUE((expected == events_string) || (expected_ugr == events_string));
1769
1770 root_window()->RemovePreTargetHandler(&recorder);
1771 }
1772
1773 // Places two windows side by side. Presses down on one window, and starts a
1774 // scroll. Sets capture on the other window and ensures that the "ending" events
1775 // aren't sent to the window which gained capture.
1776 TEST_F(WindowEventDispatcherTest, EndingEventDoesntRetarget) {
1777 EventFilterRecorder recorder1;
1778 EventFilterRecorder recorder2;
1779 scoped_ptr<Window> window1(CreateNormalWindow(1, root_window(), NULL));
1780 window1->SetBounds(gfx::Rect(0, 0, 40, 40));
1781
1782 scoped_ptr<Window> window2(CreateNormalWindow(2, root_window(), NULL));
1783 window2->SetBounds(gfx::Rect(40, 0, 40, 40));
1784
1785 window1->AddPreTargetHandler(&recorder1);
1786 window2->AddPreTargetHandler(&recorder2);
1787
1788 gfx::Point position = window1->bounds().origin();
1789 ui::TouchEvent press(
1790 ui::ET_TOUCH_PRESSED, position, 0, ui::EventTimeForNow());
1791 DispatchEventUsingWindowDispatcher(&press);
1792
1793 gfx::Point position2 = window1->bounds().CenterPoint();
1794 ui::TouchEvent move(
1795 ui::ET_TOUCH_MOVED, position2, 0, ui::EventTimeForNow());
1796 DispatchEventUsingWindowDispatcher(&move);
1797
1798 window2->SetCapture();
1799
1800 EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
1801 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
1802 "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END",
1803 EventTypesToString(recorder1.events()));
1804
1805 EXPECT_TRUE(recorder2.events().empty());
1806 }
1807
1808 namespace {
1809
1810 // This class creates and manages a window which is destroyed as soon as
1811 // capture is lost. This is the case for the drag and drop capture window.
1812 class CaptureWindowTracker : public test::TestWindowDelegate {
1813 public:
1814 CaptureWindowTracker() {}
1815 virtual ~CaptureWindowTracker() {}
1816
1817 void CreateCaptureWindow(aura::Window* root_window) {
1818 capture_window_.reset(test::CreateTestWindowWithDelegate(
1819 this, -1234, gfx::Rect(20, 20, 20, 20), root_window));
1820 capture_window_->SetCapture();
1821 }
1822
1823 void reset() {
1824 capture_window_.reset();
1825 }
1826
1827 virtual void OnCaptureLost() override {
1828 capture_window_.reset();
1829 }
1830
1831 virtual void OnWindowDestroyed(Window* window) override {
1832 TestWindowDelegate::OnWindowDestroyed(window);
1833 capture_window_.reset();
1834 }
1835
1836 aura::Window* capture_window() { return capture_window_.get(); }
1837
1838 private:
1839 scoped_ptr<aura::Window> capture_window_;
1840
1841 DISALLOW_COPY_AND_ASSIGN(CaptureWindowTracker);
1842 };
1843
1844 }
1845
1846 // Verifies handling loss of capture by the capture window being hidden.
1847 TEST_F(WindowEventDispatcherTest, CaptureWindowHidden) {
1848 CaptureWindowTracker capture_window_tracker;
1849 capture_window_tracker.CreateCaptureWindow(root_window());
1850 capture_window_tracker.capture_window()->Hide();
1851 EXPECT_EQ(NULL, capture_window_tracker.capture_window());
1852 }
1853
1854 // Verifies handling loss of capture by the capture window being destroyed.
1855 TEST_F(WindowEventDispatcherTest, CaptureWindowDestroyed) {
1856 CaptureWindowTracker capture_window_tracker;
1857 capture_window_tracker.CreateCaptureWindow(root_window());
1858 capture_window_tracker.reset();
1859 EXPECT_EQ(NULL, capture_window_tracker.capture_window());
1860 }
1861
1862 class ExitMessageLoopOnMousePress : public ui::test::TestEventHandler {
1863 public:
1864 ExitMessageLoopOnMousePress() {}
1865 virtual ~ExitMessageLoopOnMousePress() {}
1866
1867 protected:
1868 virtual void OnMouseEvent(ui::MouseEvent* event) override {
1869 ui::test::TestEventHandler::OnMouseEvent(event);
1870 if (event->type() == ui::ET_MOUSE_PRESSED)
1871 base::MessageLoopForUI::current()->Quit();
1872 }
1873
1874 private:
1875 DISALLOW_COPY_AND_ASSIGN(ExitMessageLoopOnMousePress);
1876 };
1877
1878 class WindowEventDispatcherTestWithMessageLoop
1879 : public WindowEventDispatcherTest {
1880 public:
1881 WindowEventDispatcherTestWithMessageLoop() {}
1882 virtual ~WindowEventDispatcherTestWithMessageLoop() {}
1883
1884 void RunTest() {
1885 // Reset any event the window may have received when bringing up the window
1886 // (e.g. mouse-move events if the mouse cursor is over the window).
1887 handler_.Reset();
1888
1889 // Start a nested message-loop, post an event to be dispatched, and then
1890 // terminate the message-loop. When the message-loop unwinds and gets back,
1891 // the reposted event should not have fired.
1892 scoped_ptr<ui::MouseEvent> mouse(new ui::MouseEvent(ui::ET_MOUSE_PRESSED,
1893 gfx::Point(10, 10),
1894 gfx::Point(10, 10),
1895 ui::EF_NONE,
1896 ui::EF_NONE));
1897 message_loop()->PostTask(
1898 FROM_HERE,
1899 base::Bind(&WindowEventDispatcherTestWithMessageLoop::RepostEventHelper,
1900 host()->dispatcher(),
1901 base::Passed(&mouse)));
1902 message_loop()->PostTask(FROM_HERE, message_loop()->QuitClosure());
1903
1904 base::MessageLoop::ScopedNestableTaskAllower allow(message_loop());
1905 base::RunLoop loop;
1906 loop.Run();
1907 EXPECT_EQ(0, handler_.num_mouse_events());
1908
1909 // Let the current message-loop run. The event-handler will terminate the
1910 // message-loop when it receives the reposted event.
1911 }
1912
1913 base::MessageLoop* message_loop() {
1914 return base::MessageLoopForUI::current();
1915 }
1916
1917 protected:
1918 virtual void SetUp() override {
1919 WindowEventDispatcherTest::SetUp();
1920 window_.reset(CreateNormalWindow(1, root_window(), NULL));
1921 window_->AddPreTargetHandler(&handler_);
1922 }
1923
1924 virtual void TearDown() override {
1925 window_.reset();
1926 WindowEventDispatcherTest::TearDown();
1927 }
1928
1929 private:
1930 // Used to avoid a copying |event| when binding to a closure.
1931 static void RepostEventHelper(WindowEventDispatcher* dispatcher,
1932 scoped_ptr<ui::MouseEvent> event) {
1933 dispatcher->RepostEvent(*event);
1934 }
1935
1936 scoped_ptr<Window> window_;
1937 ExitMessageLoopOnMousePress handler_;
1938
1939 DISALLOW_COPY_AND_ASSIGN(WindowEventDispatcherTestWithMessageLoop);
1940 };
1941
1942 TEST_F(WindowEventDispatcherTestWithMessageLoop, EventRepostedInNonNestedLoop) {
1943 CHECK(!message_loop()->is_running());
1944 // Perform the test in a callback, so that it runs after the message-loop
1945 // starts.
1946 message_loop()->PostTask(
1947 FROM_HERE, base::Bind(
1948 &WindowEventDispatcherTestWithMessageLoop::RunTest,
1949 base::Unretained(this)));
1950 message_loop()->Run();
1951 }
1952
1953 class WindowEventDispatcherTestInHighDPI : public WindowEventDispatcherTest {
1954 public:
1955 WindowEventDispatcherTestInHighDPI() {}
1956 virtual ~WindowEventDispatcherTestInHighDPI() {}
1957
1958 protected:
1959 virtual void SetUp() override {
1960 WindowEventDispatcherTest::SetUp();
1961 test_screen()->SetDeviceScaleFactor(2.f);
1962 }
1963 };
1964
1965 TEST_F(WindowEventDispatcherTestInHighDPI, EventLocationTransform) {
1966 test::TestWindowDelegate delegate;
1967 scoped_ptr<aura::Window> child(test::CreateTestWindowWithDelegate(&delegate,
1968 1234, gfx::Rect(20, 20, 100, 100), root_window()));
1969 child->Show();
1970
1971 ui::test::TestEventHandler handler_child;
1972 ui::test::TestEventHandler handler_root;
1973 root_window()->AddPreTargetHandler(&handler_root);
1974 child->AddPreTargetHandler(&handler_child);
1975
1976 {
1977 ui::MouseEvent move(ui::ET_MOUSE_MOVED,
1978 gfx::Point(30, 30), gfx::Point(30, 30),
1979 ui::EF_NONE, ui::EF_NONE);
1980 DispatchEventUsingWindowDispatcher(&move);
1981 EXPECT_EQ(0, handler_child.num_mouse_events());
1982 EXPECT_EQ(1, handler_root.num_mouse_events());
1983 }
1984
1985 {
1986 ui::MouseEvent move(ui::ET_MOUSE_MOVED,
1987 gfx::Point(50, 50), gfx::Point(50, 50),
1988 ui::EF_NONE, ui::EF_NONE);
1989 DispatchEventUsingWindowDispatcher(&move);
1990 // The child receives an ENTER, and a MOVED event.
1991 EXPECT_EQ(2, handler_child.num_mouse_events());
1992 // The root receives both the ENTER and the MOVED events dispatched to
1993 // |child|, as well as an EXIT event.
1994 EXPECT_EQ(3, handler_root.num_mouse_events());
1995 }
1996
1997 child->RemovePreTargetHandler(&handler_child);
1998 root_window()->RemovePreTargetHandler(&handler_root);
1999 }
2000
2001 TEST_F(WindowEventDispatcherTestInHighDPI, TouchMovesHeldOnScroll) {
2002 EventFilterRecorder recorder;
2003 root_window()->AddPreTargetHandler(&recorder);
2004 test::TestWindowDelegate delegate;
2005 HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder);
2006 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
2007 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
2008 window->AddPreTargetHandler(&handler);
2009
2010 ui::test::EventGenerator generator(root_window());
2011 generator.GestureScrollSequence(
2012 gfx::Point(120, 120), gfx::Point(20, 120),
2013 base::TimeDelta::FromMilliseconds(100), 25);
2014
2015 // |handler| will have reset |filter| and started holding the touch-move
2016 // events when scrolling started. At the end of the scroll (i.e. upon
2017 // touch-release), the held touch-move event will have been dispatched first,
2018 // along with the subsequent events (i.e. touch-release, scroll-end, and
2019 // gesture-end).
2020 const EventFilterRecorder::Events& events = recorder.events();
2021 EXPECT_EQ(
2022 "TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED "
2023 "GESTURE_SCROLL_END GESTURE_END",
2024 EventTypesToString(events));
2025 ASSERT_EQ(2u, recorder.touch_locations().size());
2026 EXPECT_EQ(gfx::Point(-40, 10).ToString(),
2027 recorder.touch_locations()[0].ToString());
2028 EXPECT_EQ(gfx::Point(-40, 10).ToString(),
2029 recorder.touch_locations()[1].ToString());
2030 }
2031
2032 class SelfDestructDelegate : public test::TestWindowDelegate {
2033 public:
2034 SelfDestructDelegate() {}
2035 virtual ~SelfDestructDelegate() {}
2036
2037 virtual void OnMouseEvent(ui::MouseEvent* event) override {
2038 window_.reset();
2039 }
2040
2041 void set_window(scoped_ptr<aura::Window> window) {
2042 window_ = window.Pass();
2043 }
2044 bool has_window() const { return !!window_.get(); }
2045
2046 private:
2047 scoped_ptr<aura::Window> window_;
2048 DISALLOW_COPY_AND_ASSIGN(SelfDestructDelegate);
2049 };
2050
2051 TEST_F(WindowEventDispatcherTest, SynthesizedLocatedEvent) {
2052 ui::test::EventGenerator generator(root_window());
2053 generator.MoveMouseTo(10, 10);
2054 EXPECT_EQ("10,10",
2055 Env::GetInstance()->last_mouse_location().ToString());
2056
2057 // Synthesized event should not update the mouse location.
2058 ui::MouseEvent mouseev(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
2059 ui::EF_IS_SYNTHESIZED, 0);
2060 generator.Dispatch(&mouseev);
2061 EXPECT_EQ("10,10",
2062 Env::GetInstance()->last_mouse_location().ToString());
2063
2064 generator.MoveMouseTo(0, 0);
2065 EXPECT_EQ("0,0",
2066 Env::GetInstance()->last_mouse_location().ToString());
2067
2068 // Make sure the location gets updated when a syntheiszed enter
2069 // event destroyed the window.
2070 SelfDestructDelegate delegate;
2071 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
2072 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
2073 delegate.set_window(window.Pass());
2074 EXPECT_TRUE(delegate.has_window());
2075
2076 generator.MoveMouseTo(100, 100);
2077 EXPECT_FALSE(delegate.has_window());
2078 EXPECT_EQ("100,100",
2079 Env::GetInstance()->last_mouse_location().ToString());
2080 }
2081
2082 class StaticFocusClient : public client::FocusClient {
2083 public:
2084 explicit StaticFocusClient(Window* focused)
2085 : focused_(focused) {}
2086 virtual ~StaticFocusClient() {}
2087
2088 private:
2089 // client::FocusClient:
2090 virtual void AddObserver(client::FocusChangeObserver* observer) override {}
2091 virtual void RemoveObserver(client::FocusChangeObserver* observer) override {}
2092 virtual void FocusWindow(Window* window) override {}
2093 virtual void ResetFocusWithinActiveWindow(Window* window) override {}
2094 virtual Window* GetFocusedWindow() override { return focused_; }
2095
2096 Window* focused_;
2097
2098 DISALLOW_COPY_AND_ASSIGN(StaticFocusClient);
2099 };
2100
2101 // Tests that host-cancel-mode event can be dispatched to a dispatcher safely
2102 // when the focused window does not live in the dispatcher's tree.
2103 TEST_F(WindowEventDispatcherTest, HostCancelModeWithFocusedWindowOutside) {
2104 test::TestWindowDelegate delegate;
2105 scoped_ptr<Window> focused(CreateTestWindowWithDelegate(&delegate, 123,
2106 gfx::Rect(20, 30, 100, 50), NULL));
2107 StaticFocusClient focus_client(focused.get());
2108 client::SetFocusClient(root_window(), &focus_client);
2109 EXPECT_FALSE(root_window()->Contains(focused.get()));
2110 EXPECT_EQ(focused.get(),
2111 client::GetFocusClient(root_window())->GetFocusedWindow());
2112 host()->dispatcher()->DispatchCancelModeEvent();
2113 EXPECT_EQ(focused.get(),
2114 client::GetFocusClient(root_window())->GetFocusedWindow());
2115 }
2116
2117 // Dispatches a mouse-move event to |target| when it receives a mouse-move
2118 // event.
2119 class DispatchEventHandler : public ui::EventHandler {
2120 public:
2121 explicit DispatchEventHandler(Window* target)
2122 : target_(target),
2123 dispatched_(false) {}
2124 virtual ~DispatchEventHandler() {}
2125
2126 bool dispatched() const { return dispatched_; }
2127 private:
2128 // ui::EventHandler:
2129 virtual void OnMouseEvent(ui::MouseEvent* mouse) override {
2130 if (mouse->type() == ui::ET_MOUSE_MOVED) {
2131 ui::MouseEvent move(ui::ET_MOUSE_MOVED, target_->bounds().CenterPoint(),
2132 target_->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE);
2133 ui::EventDispatchDetails details =
2134 target_->GetHost()->dispatcher()->OnEventFromSource(&move);
2135 ASSERT_FALSE(details.dispatcher_destroyed);
2136 EXPECT_FALSE(details.target_destroyed);
2137 EXPECT_EQ(target_, move.target());
2138 dispatched_ = true;
2139 }
2140 ui::EventHandler::OnMouseEvent(mouse);
2141 }
2142
2143 Window* target_;
2144 bool dispatched_;
2145
2146 DISALLOW_COPY_AND_ASSIGN(DispatchEventHandler);
2147 };
2148
2149 // Moves |window| to |root_window| when it receives a mouse-move event.
2150 class MoveWindowHandler : public ui::EventHandler {
2151 public:
2152 MoveWindowHandler(Window* window, Window* root_window)
2153 : window_to_move_(window),
2154 root_window_to_move_to_(root_window) {}
2155 virtual ~MoveWindowHandler() {}
2156
2157 private:
2158 // ui::EventHandler:
2159 virtual void OnMouseEvent(ui::MouseEvent* mouse) override {
2160 if (mouse->type() == ui::ET_MOUSE_MOVED) {
2161 root_window_to_move_to_->AddChild(window_to_move_);
2162 }
2163 ui::EventHandler::OnMouseEvent(mouse);
2164 }
2165
2166 Window* window_to_move_;
2167 Window* root_window_to_move_to_;
2168
2169 DISALLOW_COPY_AND_ASSIGN(MoveWindowHandler);
2170 };
2171
2172 // Tests that nested event dispatch works correctly if the target of the older
2173 // event being dispatched is moved to a different dispatcher in response to an
2174 // event in the inner loop.
2175 TEST_F(WindowEventDispatcherTest, NestedEventDispatchTargetMoved) {
2176 scoped_ptr<WindowTreeHost> second_host(
2177 WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50)));
2178 second_host->InitHost();
2179 Window* second_root = second_host->window();
2180
2181 // Create two windows parented to |root_window()|.
2182 test::TestWindowDelegate delegate;
2183 scoped_ptr<Window> first(CreateTestWindowWithDelegate(&delegate, 123,
2184 gfx::Rect(20, 10, 10, 20), root_window()));
2185 scoped_ptr<Window> second(CreateTestWindowWithDelegate(&delegate, 234,
2186 gfx::Rect(40, 10, 50, 20), root_window()));
2187
2188 // Setup a handler on |first| so that it dispatches an event to |second| when
2189 // |first| receives an event.
2190 DispatchEventHandler dispatch_event(second.get());
2191 first->AddPreTargetHandler(&dispatch_event);
2192
2193 // Setup a handler on |second| so that it moves |first| into |second_root|
2194 // when |second| receives an event.
2195 MoveWindowHandler move_window(first.get(), second_root);
2196 second->AddPreTargetHandler(&move_window);
2197
2198 // Some sanity checks: |first| is inside |root_window()|'s tree.
2199 EXPECT_EQ(root_window(), first->GetRootWindow());
2200 // The two root windows are different.
2201 EXPECT_NE(root_window(), second_root);
2202
2203 // Dispatch an event to |first|.
2204 ui::MouseEvent move(ui::ET_MOUSE_MOVED, first->bounds().CenterPoint(),
2205 first->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE);
2206 ui::EventDispatchDetails details =
2207 host()->dispatcher()->OnEventFromSource(&move);
2208 ASSERT_FALSE(details.dispatcher_destroyed);
2209 EXPECT_TRUE(details.target_destroyed);
2210 EXPECT_EQ(first.get(), move.target());
2211 EXPECT_TRUE(dispatch_event.dispatched());
2212 EXPECT_EQ(second_root, first->GetRootWindow());
2213
2214 first->RemovePreTargetHandler(&dispatch_event);
2215 second->RemovePreTargetHandler(&move_window);
2216 }
2217
2218 class AlwaysMouseDownInputStateLookup : public InputStateLookup {
2219 public:
2220 AlwaysMouseDownInputStateLookup() {}
2221 virtual ~AlwaysMouseDownInputStateLookup() {}
2222
2223 private:
2224 // InputStateLookup:
2225 virtual bool IsMouseButtonDown() const override { return true; }
2226
2227 DISALLOW_COPY_AND_ASSIGN(AlwaysMouseDownInputStateLookup);
2228 };
2229
2230 TEST_F(WindowEventDispatcherTest,
2231 CursorVisibilityChangedWhileCaptureWindowInAnotherDispatcher) {
2232 test::EventCountDelegate delegate;
2233 scoped_ptr<Window> window(CreateTestWindowWithDelegate(&delegate, 123,
2234 gfx::Rect(20, 10, 10, 20), root_window()));
2235 window->Show();
2236
2237 scoped_ptr<WindowTreeHost> second_host(
2238 WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50)));
2239 second_host->InitHost();
2240 WindowEventDispatcher* second_dispatcher = second_host->dispatcher();
2241
2242 // Install an InputStateLookup on the Env that always claims that a
2243 // mouse-button is down.
2244 test::EnvTestHelper(Env::GetInstance()).SetInputStateLookup(
2245 scoped_ptr<InputStateLookup>(new AlwaysMouseDownInputStateLookup()));
2246
2247 window->SetCapture();
2248
2249 // Because the mouse button is down, setting the capture on |window| will set
2250 // it as the mouse-move handler for |root_window()|.
2251 EXPECT_EQ(window.get(), host()->dispatcher()->mouse_moved_handler());
2252
2253 // This does not set |window| as the mouse-move handler for the second
2254 // dispatcher.
2255 EXPECT_EQ(NULL, second_dispatcher->mouse_moved_handler());
2256
2257 // However, some capture-client updates the capture in each root-window on a
2258 // capture. Emulate that here. Because of this, the second dispatcher also has
2259 // |window| as the mouse-move handler.
2260 client::CaptureDelegate* second_capture_delegate = second_dispatcher;
2261 second_capture_delegate->UpdateCapture(NULL, window.get());
2262 EXPECT_EQ(window.get(), second_dispatcher->mouse_moved_handler());
2263
2264 // Reset the mouse-event counts for |window|.
2265 delegate.GetMouseMotionCountsAndReset();
2266
2267 // Notify both hosts that the cursor is now hidden. This should send a single
2268 // mouse-exit event to |window|.
2269 host()->OnCursorVisibilityChanged(false);
2270 second_host->OnCursorVisibilityChanged(false);
2271 EXPECT_EQ("0 0 1", delegate.GetMouseMotionCountsAndReset());
2272 }
2273
2274 TEST_F(WindowEventDispatcherTest,
2275 RedirectedEventToDifferentDispatcherLocation) {
2276 scoped_ptr<WindowTreeHost> second_host(
2277 WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50)));
2278 second_host->InitHost();
2279 client::SetCaptureClient(second_host->window(),
2280 client::GetCaptureClient(root_window()));
2281
2282 test::EventCountDelegate delegate;
2283 scoped_ptr<Window> window_first(CreateTestWindowWithDelegate(&delegate, 123,
2284 gfx::Rect(20, 10, 10, 20), root_window()));
2285 window_first->Show();
2286
2287 scoped_ptr<Window> window_second(CreateTestWindowWithDelegate(&delegate, 12,
2288 gfx::Rect(10, 10, 20, 30), second_host->window()));
2289 window_second->Show();
2290
2291 window_second->SetCapture();
2292 EXPECT_EQ(window_second.get(),
2293 client::GetCaptureWindow(root_window()));
2294
2295 // Send an event to the first host. Make sure it goes to |window_second| in
2296 // |second_host| instead (since it has capture).
2297 EventFilterRecorder recorder_first;
2298 window_first->AddPreTargetHandler(&recorder_first);
2299 EventFilterRecorder recorder_second;
2300 window_second->AddPreTargetHandler(&recorder_second);
2301 const gfx::Point event_location(25, 15);
2302 ui::MouseEvent mouse(ui::ET_MOUSE_PRESSED, event_location,
2303 event_location, ui::EF_LEFT_MOUSE_BUTTON,
2304 ui::EF_LEFT_MOUSE_BUTTON);
2305 DispatchEventUsingWindowDispatcher(&mouse);
2306 EXPECT_TRUE(recorder_first.events().empty());
2307 ASSERT_EQ(1u, recorder_second.events().size());
2308 EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder_second.events()[0]);
2309 EXPECT_EQ(event_location.ToString(),
2310 recorder_second.mouse_locations()[0].ToString());
2311 }
2312
2313 class AsyncWindowDelegate : public test::TestWindowDelegate {
2314 public:
2315 AsyncWindowDelegate(WindowEventDispatcher* dispatcher)
2316 : dispatcher_(dispatcher) {}
2317
2318 void set_window(Window* window) {
2319 window_ = window;
2320 }
2321 private:
2322 virtual void OnTouchEvent(ui::TouchEvent* event) override {
2323 // Convert touch event back to root window coordinates.
2324 event->ConvertLocationToTarget(window_, window_->GetRootWindow());
2325 dispatcher_->ProcessedTouchEvent(event, window_, ui::ER_UNHANDLED);
2326 event->StopPropagation();
2327 }
2328
2329 WindowEventDispatcher* dispatcher_;
2330 Window* window_;
2331
2332 DISALLOW_COPY_AND_ASSIGN(AsyncWindowDelegate);
2333 };
2334
2335 // Tests that gesture events dispatched through the asynchronous flow have
2336 // co-ordinates in the right co-ordinate space.
2337 TEST_F(WindowEventDispatcherTest, GestureEventCoordinates) {
2338 const float kX = 67.3f;
2339 const float kY = 97.8f;
2340
2341 const int kWindowOffset = 50;
2342 EventFilterRecorder recorder;
2343 root_window()->AddPreTargetHandler(&recorder);
2344 AsyncWindowDelegate delegate(host()->dispatcher());
2345 HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder);
2346 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
2347 &delegate,
2348 1,
2349 gfx::Rect(kWindowOffset, kWindowOffset, 100, 100),
2350 root_window()));
2351 window->AddPreTargetHandler(&handler);
2352
2353 delegate.set_window(window.get());
2354
2355 ui::TouchEvent touch_pressed_event(
2356 ui::ET_TOUCH_PRESSED, gfx::PointF(kX, kY), 0, ui::EventTimeForNow());
2357
2358 DispatchEventUsingWindowDispatcher(&touch_pressed_event);
2359
2360 ASSERT_EQ(1u, recorder.touch_locations().size());
2361 EXPECT_EQ(gfx::Point(kX - kWindowOffset, kY - kWindowOffset).ToString(),
2362 recorder.touch_locations()[0].ToString());
2363
2364 ASSERT_EQ(2u, recorder.gesture_locations().size());
2365 EXPECT_EQ(gfx::Point(kX - kWindowOffset, kY - kWindowOffset).ToString(),
2366 recorder.gesture_locations()[0].ToString());
2367 }
2368
2369 } // namespace aura
OLDNEW
« no previous file with comments | « ui/aura/window_event_dispatcher.cc ('k') | ui/aura/window_layer_type.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698