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

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

Issue 174803002: Move root_window.* to window_event_dispatcher.* (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 6 years, 10 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 | Annotate | Revision Log
« no previous file with comments | « ui/aura/root_window.cc ('k') | ui/aura/test/aura_test_base.cc » ('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/root_window.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/event_client.h"
13 #include "ui/aura/client/focus_client.h"
14 #include "ui/aura/env.h"
15 #include "ui/aura/test/aura_test_base.h"
16 #include "ui/aura/test/event_generator.h"
17 #include "ui/aura/test/test_cursor_client.h"
18 #include "ui/aura/test/test_event_handler.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/gfx/point.h"
31 #include "ui/gfx/rect.h"
32 #include "ui/gfx/screen.h"
33 #include "ui/gfx/transform.h"
34
35 namespace aura {
36 namespace {
37
38 // A delegate that always returns a non-client component for hit tests.
39 class NonClientDelegate : public test::TestWindowDelegate {
40 public:
41 NonClientDelegate()
42 : non_client_count_(0),
43 mouse_event_count_(0),
44 mouse_event_flags_(0x0) {
45 }
46 virtual ~NonClientDelegate() {}
47
48 int non_client_count() const { return non_client_count_; }
49 gfx::Point non_client_location() const { return non_client_location_; }
50 int mouse_event_count() const { return mouse_event_count_; }
51 gfx::Point mouse_event_location() const { return mouse_event_location_; }
52 int mouse_event_flags() const { return mouse_event_flags_; }
53
54 virtual int GetNonClientComponent(const gfx::Point& location) const OVERRIDE {
55 NonClientDelegate* self = const_cast<NonClientDelegate*>(this);
56 self->non_client_count_++;
57 self->non_client_location_ = location;
58 return HTTOPLEFT;
59 }
60 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
61 mouse_event_count_++;
62 mouse_event_location_ = event->location();
63 mouse_event_flags_ = event->flags();
64 event->SetHandled();
65 }
66
67 private:
68 int non_client_count_;
69 gfx::Point non_client_location_;
70 int mouse_event_count_;
71 gfx::Point mouse_event_location_;
72 int mouse_event_flags_;
73
74 DISALLOW_COPY_AND_ASSIGN(NonClientDelegate);
75 };
76
77 // A simple event handler that consumes key events.
78 class ConsumeKeyHandler : public test::TestEventHandler {
79 public:
80 ConsumeKeyHandler() {}
81 virtual ~ConsumeKeyHandler() {}
82
83 // Overridden from ui::EventHandler:
84 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
85 test::TestEventHandler::OnKeyEvent(event);
86 event->StopPropagation();
87 }
88
89 private:
90 DISALLOW_COPY_AND_ASSIGN(ConsumeKeyHandler);
91 };
92
93 bool IsFocusedWindow(aura::Window* window) {
94 return client::GetFocusClient(window)->GetFocusedWindow() == window;
95 }
96
97 } // namespace
98
99 typedef test::AuraTestBase WindowEventDispatcherTest;
100
101 TEST_F(WindowEventDispatcherTest, OnHostMouseEvent) {
102 // Create two non-overlapping windows so we don't have to worry about which
103 // is on top.
104 scoped_ptr<NonClientDelegate> delegate1(new NonClientDelegate());
105 scoped_ptr<NonClientDelegate> delegate2(new NonClientDelegate());
106 const int kWindowWidth = 123;
107 const int kWindowHeight = 45;
108 gfx::Rect bounds1(100, 200, kWindowWidth, kWindowHeight);
109 gfx::Rect bounds2(300, 400, kWindowWidth, kWindowHeight);
110 scoped_ptr<aura::Window> window1(CreateTestWindowWithDelegate(
111 delegate1.get(), -1234, bounds1, root_window()));
112 scoped_ptr<aura::Window> window2(CreateTestWindowWithDelegate(
113 delegate2.get(), -5678, bounds2, root_window()));
114
115 // Send a mouse event to window1.
116 gfx::Point point(101, 201);
117 ui::MouseEvent event1(
118 ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON,
119 ui::EF_LEFT_MOUSE_BUTTON);
120 DispatchEventUsingWindowDispatcher(&event1);
121
122 // Event was tested for non-client area for the target window.
123 EXPECT_EQ(1, delegate1->non_client_count());
124 EXPECT_EQ(0, delegate2->non_client_count());
125 // The non-client component test was in local coordinates.
126 EXPECT_EQ(gfx::Point(1, 1), delegate1->non_client_location());
127 // Mouse event was received by target window.
128 EXPECT_EQ(1, delegate1->mouse_event_count());
129 EXPECT_EQ(0, delegate2->mouse_event_count());
130 // Event was in local coordinates.
131 EXPECT_EQ(gfx::Point(1, 1), delegate1->mouse_event_location());
132 // Non-client flag was set.
133 EXPECT_TRUE(delegate1->mouse_event_flags() & ui::EF_IS_NON_CLIENT);
134 }
135
136 TEST_F(WindowEventDispatcherTest, RepostEvent) {
137 // Test RepostEvent in RootWindow. It only works for Mouse Press.
138 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
139 gfx::Point point(10, 10);
140 ui::MouseEvent event(
141 ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON,
142 ui::EF_LEFT_MOUSE_BUTTON);
143 dispatcher()->RepostEvent(event);
144 RunAllPendingInMessageLoop();
145 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
146 }
147
148 // Check that we correctly track the state of the mouse buttons in response to
149 // button press and release events.
150 TEST_F(WindowEventDispatcherTest, MouseButtonState) {
151 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
152
153 gfx::Point location;
154 scoped_ptr<ui::MouseEvent> event;
155
156 // Press the left button.
157 event.reset(new ui::MouseEvent(
158 ui::ET_MOUSE_PRESSED,
159 location,
160 location,
161 ui::EF_LEFT_MOUSE_BUTTON,
162 ui::EF_LEFT_MOUSE_BUTTON));
163 DispatchEventUsingWindowDispatcher(event.get());
164 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
165
166 // Additionally press the right.
167 event.reset(new ui::MouseEvent(
168 ui::ET_MOUSE_PRESSED,
169 location,
170 location,
171 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON,
172 ui::EF_RIGHT_MOUSE_BUTTON));
173 DispatchEventUsingWindowDispatcher(event.get());
174 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
175
176 // Release the left button.
177 event.reset(new ui::MouseEvent(
178 ui::ET_MOUSE_RELEASED,
179 location,
180 location,
181 ui::EF_RIGHT_MOUSE_BUTTON,
182 ui::EF_LEFT_MOUSE_BUTTON));
183 DispatchEventUsingWindowDispatcher(event.get());
184 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
185
186 // Release the right button. We should ignore the Shift-is-down flag.
187 event.reset(new ui::MouseEvent(
188 ui::ET_MOUSE_RELEASED,
189 location,
190 location,
191 ui::EF_SHIFT_DOWN,
192 ui::EF_RIGHT_MOUSE_BUTTON));
193 DispatchEventUsingWindowDispatcher(event.get());
194 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
195
196 // Press the middle button.
197 event.reset(new ui::MouseEvent(
198 ui::ET_MOUSE_PRESSED,
199 location,
200 location,
201 ui::EF_MIDDLE_MOUSE_BUTTON,
202 ui::EF_MIDDLE_MOUSE_BUTTON));
203 DispatchEventUsingWindowDispatcher(event.get());
204 EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown());
205 }
206
207 TEST_F(WindowEventDispatcherTest, TranslatedEvent) {
208 scoped_ptr<Window> w1(test::CreateTestWindowWithDelegate(NULL, 1,
209 gfx::Rect(50, 50, 100, 100), root_window()));
210
211 gfx::Point origin(100, 100);
212 ui::MouseEvent root(ui::ET_MOUSE_PRESSED, origin, origin, 0, 0);
213
214 EXPECT_EQ("100,100", root.location().ToString());
215 EXPECT_EQ("100,100", root.root_location().ToString());
216
217 ui::MouseEvent translated_event(
218 root, static_cast<Window*>(root_window()), w1.get(),
219 ui::ET_MOUSE_ENTERED, root.flags());
220 EXPECT_EQ("50,50", translated_event.location().ToString());
221 EXPECT_EQ("100,100", translated_event.root_location().ToString());
222 }
223
224 namespace {
225
226 class TestEventClient : public client::EventClient {
227 public:
228 static const int kNonLockWindowId = 100;
229 static const int kLockWindowId = 200;
230
231 explicit TestEventClient(Window* root_window)
232 : root_window_(root_window),
233 lock_(false) {
234 client::SetEventClient(root_window_, this);
235 Window* lock_window =
236 test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
237 lock_window->set_id(kLockWindowId);
238 Window* non_lock_window =
239 test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
240 non_lock_window->set_id(kNonLockWindowId);
241 }
242 virtual ~TestEventClient() {
243 client::SetEventClient(root_window_, NULL);
244 }
245
246 // Starts/stops locking. Locking prevents windows other than those inside
247 // the lock container from receiving events, getting focus etc.
248 void Lock() {
249 lock_ = true;
250 }
251 void Unlock() {
252 lock_ = false;
253 }
254
255 Window* GetLockWindow() {
256 return const_cast<Window*>(
257 static_cast<const TestEventClient*>(this)->GetLockWindow());
258 }
259 const Window* GetLockWindow() const {
260 return root_window_->GetChildById(kLockWindowId);
261 }
262 Window* GetNonLockWindow() {
263 return root_window_->GetChildById(kNonLockWindowId);
264 }
265
266 private:
267 // Overridden from client::EventClient:
268 virtual bool CanProcessEventsWithinSubtree(
269 const Window* window) const OVERRIDE {
270 return lock_ ?
271 window->Contains(GetLockWindow()) || GetLockWindow()->Contains(window) :
272 true;
273 }
274
275 virtual ui::EventTarget* GetToplevelEventTarget() OVERRIDE {
276 return NULL;
277 }
278
279 Window* root_window_;
280 bool lock_;
281
282 DISALLOW_COPY_AND_ASSIGN(TestEventClient);
283 };
284
285 } // namespace
286
287 TEST_F(WindowEventDispatcherTest, CanProcessEventsWithinSubtree) {
288 TestEventClient client(root_window());
289 test::TestWindowDelegate d;
290
291 test::TestEventHandler* nonlock_ef = new test::TestEventHandler;
292 test::TestEventHandler* lock_ef = new test::TestEventHandler;
293 client.GetNonLockWindow()->SetEventFilter(nonlock_ef);
294 client.GetLockWindow()->SetEventFilter(lock_ef);
295
296 Window* w1 = test::CreateTestWindowWithBounds(gfx::Rect(10, 10, 20, 20),
297 client.GetNonLockWindow());
298 w1->set_id(1);
299 Window* w2 = test::CreateTestWindowWithBounds(gfx::Rect(30, 30, 20, 20),
300 client.GetNonLockWindow());
301 w2->set_id(2);
302 scoped_ptr<Window> w3(
303 test::CreateTestWindowWithDelegate(&d, 3, gfx::Rect(30, 30, 20, 20),
304 client.GetLockWindow()));
305
306 w1->Focus();
307 EXPECT_TRUE(IsFocusedWindow(w1));
308
309 client.Lock();
310
311 // Since we're locked, the attempt to focus w2 will be ignored.
312 w2->Focus();
313 EXPECT_TRUE(IsFocusedWindow(w1));
314 EXPECT_FALSE(IsFocusedWindow(w2));
315
316 {
317 // Attempting to send a key event to w1 (not in the lock container) should
318 // cause focus to be reset.
319 test::EventGenerator generator(root_window());
320 generator.PressKey(ui::VKEY_SPACE, 0);
321 EXPECT_EQ(NULL, client::GetFocusClient(w1)->GetFocusedWindow());
322 EXPECT_FALSE(IsFocusedWindow(w1));
323 }
324
325 {
326 // Events sent to a window not in the lock container will not be processed.
327 // i.e. never sent to the non-lock container's event filter.
328 test::EventGenerator generator(root_window(), w1);
329 generator.ClickLeftButton();
330 EXPECT_EQ(0, nonlock_ef->num_mouse_events());
331
332 // Events sent to a window in the lock container will be processed.
333 test::EventGenerator generator3(root_window(), w3.get());
334 generator3.PressLeftButton();
335 EXPECT_EQ(1, lock_ef->num_mouse_events());
336 }
337
338 // Prevent w3 from being deleted by the hierarchy since its delegate is owned
339 // by this scope.
340 w3->parent()->RemoveChild(w3.get());
341 }
342
343 TEST_F(WindowEventDispatcherTest, IgnoreUnknownKeys) {
344 test::TestEventHandler* filter = new ConsumeKeyHandler;
345 root_window()->SetEventFilter(filter); // passes ownership
346
347 ui::KeyEvent unknown_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 0, false);
348 DispatchEventUsingWindowDispatcher(&unknown_event);
349 EXPECT_FALSE(unknown_event.handled());
350 EXPECT_EQ(0, filter->num_key_events());
351
352 ui::KeyEvent known_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false);
353 DispatchEventUsingWindowDispatcher(&known_event);
354 EXPECT_TRUE(known_event.handled());
355 EXPECT_EQ(1, filter->num_key_events());
356 }
357
358 TEST_F(WindowEventDispatcherTest, NoDelegateWindowReceivesKeyEvents) {
359 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
360 w1->Show();
361 w1->Focus();
362
363 test::TestEventHandler handler;
364 w1->AddPreTargetHandler(&handler);
365 ui::KeyEvent key_press(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false);
366 DispatchEventUsingWindowDispatcher(&key_press);
367 EXPECT_TRUE(key_press.handled());
368 EXPECT_EQ(1, handler.num_key_events());
369
370 w1->RemovePreTargetHandler(&handler);
371 }
372
373 // Tests that touch-events that are beyond the bounds of the root-window do get
374 // propagated to the event filters correctly with the root as the target.
375 TEST_F(WindowEventDispatcherTest, TouchEventsOutsideBounds) {
376 test::TestEventHandler* filter = new test::TestEventHandler;
377 root_window()->SetEventFilter(filter); // passes ownership
378
379 gfx::Point position = root_window()->bounds().origin();
380 position.Offset(-10, -10);
381 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position, 0, base::TimeDelta());
382 DispatchEventUsingWindowDispatcher(&press);
383 EXPECT_EQ(1, filter->num_touch_events());
384
385 position = root_window()->bounds().origin();
386 position.Offset(root_window()->bounds().width() + 10,
387 root_window()->bounds().height() + 10);
388 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, position, 0, base::TimeDelta());
389 DispatchEventUsingWindowDispatcher(&release);
390 EXPECT_EQ(2, filter->num_touch_events());
391 }
392
393 // Tests that scroll events are dispatched correctly.
394 TEST_F(WindowEventDispatcherTest, ScrollEventDispatch) {
395 base::TimeDelta now = ui::EventTimeForNow();
396 test::TestEventHandler* filter = new test::TestEventHandler;
397 root_window()->SetEventFilter(filter);
398
399 test::TestWindowDelegate delegate;
400 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate));
401 w1->SetBounds(gfx::Rect(20, 20, 40, 40));
402
403 // A scroll event on the root-window itself is dispatched.
404 ui::ScrollEvent scroll1(ui::ET_SCROLL,
405 gfx::Point(10, 10),
406 now,
407 0,
408 0, -10,
409 0, -10,
410 2);
411 DispatchEventUsingWindowDispatcher(&scroll1);
412 EXPECT_EQ(1, filter->num_scroll_events());
413
414 // Scroll event on a window should be dispatched properly.
415 ui::ScrollEvent scroll2(ui::ET_SCROLL,
416 gfx::Point(25, 30),
417 now,
418 0,
419 -10, 0,
420 -10, 0,
421 2);
422 DispatchEventUsingWindowDispatcher(&scroll2);
423 EXPECT_EQ(2, filter->num_scroll_events());
424 }
425
426 namespace {
427
428 // FilterFilter that tracks the types of events it's seen.
429 class EventFilterRecorder : public ui::EventHandler {
430 public:
431 typedef std::vector<ui::EventType> Events;
432 typedef std::vector<gfx::Point> EventLocations;
433
434 EventFilterRecorder()
435 : wait_until_event_(ui::ET_UNKNOWN) {
436 }
437
438 const Events& events() const { return events_; }
439
440 const EventLocations& mouse_locations() const { return mouse_locations_; }
441 gfx::Point mouse_location(int i) const { return mouse_locations_[i]; }
442 const EventLocations& touch_locations() const { return touch_locations_; }
443
444 void WaitUntilReceivedEvent(ui::EventType type) {
445 wait_until_event_ = type;
446 run_loop_.reset(new base::RunLoop());
447 run_loop_->Run();
448 }
449
450 Events GetAndResetEvents() {
451 Events events = events_;
452 Reset();
453 return events;
454 }
455
456 void Reset() {
457 events_.clear();
458 mouse_locations_.clear();
459 touch_locations_.clear();
460 }
461
462 // ui::EventHandler overrides:
463 virtual void OnEvent(ui::Event* event) OVERRIDE {
464 ui::EventHandler::OnEvent(event);
465 events_.push_back(event->type());
466 if (wait_until_event_ == event->type() && run_loop_) {
467 run_loop_->Quit();
468 wait_until_event_ = ui::ET_UNKNOWN;
469 }
470 }
471
472 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
473 mouse_locations_.push_back(event->location());
474 }
475
476 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
477 touch_locations_.push_back(event->location());
478 }
479
480 private:
481 scoped_ptr<base::RunLoop> run_loop_;
482 ui::EventType wait_until_event_;
483
484 Events events_;
485 EventLocations mouse_locations_;
486 EventLocations touch_locations_;
487
488 DISALLOW_COPY_AND_ASSIGN(EventFilterRecorder);
489 };
490
491 // Converts an EventType to a string.
492 std::string EventTypeToString(ui::EventType type) {
493 switch (type) {
494 case ui::ET_TOUCH_RELEASED:
495 return "TOUCH_RELEASED";
496
497 case ui::ET_TOUCH_CANCELLED:
498 return "TOUCH_CANCELLED";
499
500 case ui::ET_TOUCH_PRESSED:
501 return "TOUCH_PRESSED";
502
503 case ui::ET_TOUCH_MOVED:
504 return "TOUCH_MOVED";
505
506 case ui::ET_MOUSE_PRESSED:
507 return "MOUSE_PRESSED";
508
509 case ui::ET_MOUSE_DRAGGED:
510 return "MOUSE_DRAGGED";
511
512 case ui::ET_MOUSE_RELEASED:
513 return "MOUSE_RELEASED";
514
515 case ui::ET_MOUSE_MOVED:
516 return "MOUSE_MOVED";
517
518 case ui::ET_MOUSE_ENTERED:
519 return "MOUSE_ENTERED";
520
521 case ui::ET_MOUSE_EXITED:
522 return "MOUSE_EXITED";
523
524 case ui::ET_GESTURE_SCROLL_BEGIN:
525 return "GESTURE_SCROLL_BEGIN";
526
527 case ui::ET_GESTURE_SCROLL_END:
528 return "GESTURE_SCROLL_END";
529
530 case ui::ET_GESTURE_SCROLL_UPDATE:
531 return "GESTURE_SCROLL_UPDATE";
532
533 case ui::ET_GESTURE_PINCH_BEGIN:
534 return "GESTURE_PINCH_BEGIN";
535
536 case ui::ET_GESTURE_PINCH_END:
537 return "GESTURE_PINCH_END";
538
539 case ui::ET_GESTURE_PINCH_UPDATE:
540 return "GESTURE_PINCH_UPDATE";
541
542 case ui::ET_GESTURE_TAP:
543 return "GESTURE_TAP";
544
545 case ui::ET_GESTURE_TAP_DOWN:
546 return "GESTURE_TAP_DOWN";
547
548 case ui::ET_GESTURE_TAP_CANCEL:
549 return "GESTURE_TAP_CANCEL";
550
551 case ui::ET_GESTURE_SHOW_PRESS:
552 return "GESTURE_SHOW_PRESS";
553
554 case ui::ET_GESTURE_BEGIN:
555 return "GESTURE_BEGIN";
556
557 case ui::ET_GESTURE_END:
558 return "GESTURE_END";
559
560 default:
561 // We should explicitly require each event type.
562 NOTREACHED();
563 break;
564 }
565 return "";
566 }
567
568 std::string EventTypesToString(const EventFilterRecorder::Events& events) {
569 std::string result;
570 for (size_t i = 0; i < events.size(); ++i) {
571 if (i != 0)
572 result += " ";
573 result += EventTypeToString(events[i]);
574 }
575 return result;
576 }
577
578 } // namespace
579
580 // Verifies a repost mouse event targets the window with capture (if there is
581 // one).
582 TEST_F(WindowEventDispatcherTest, RepostTargetsCaptureWindow) {
583 // Set capture on |window| generate a mouse event (that is reposted) and not
584 // over |window| and verify |window| gets it (|window| gets it because it has
585 // capture).
586 EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown());
587 scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), NULL));
588 window->SetBounds(gfx::Rect(20, 20, 40, 30));
589 EventFilterRecorder* recorder = new EventFilterRecorder;
590 window->SetEventFilter(recorder); // Takes ownership.
591 window->SetCapture();
592 const ui::MouseEvent press_event(
593 ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
594 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
595 dispatcher()->RepostEvent(press_event);
596 RunAllPendingInMessageLoop(); // Necessitated by RepostEvent().
597 // Mouse moves/enters may be generated. We only care about a pressed.
598 EXPECT_TRUE(EventTypesToString(recorder->events()).find("MOUSE_PRESSED") !=
599 std::string::npos) << EventTypesToString(recorder->events());
600 }
601
602 TEST_F(WindowEventDispatcherTest, MouseMovesHeld) {
603 EventFilterRecorder* filter = new EventFilterRecorder;
604 root_window()->SetEventFilter(filter); // passes ownership
605
606 test::TestWindowDelegate delegate;
607 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
608 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
609
610 ui::MouseEvent mouse_move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0),
611 gfx::Point(0, 0), 0, 0);
612 DispatchEventUsingWindowDispatcher(&mouse_move_event);
613 // Discard MOUSE_ENTER.
614 filter->Reset();
615
616 dispatcher()->HoldPointerMoves();
617
618 // Check that we don't immediately dispatch the MOUSE_DRAGGED event.
619 ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0),
620 gfx::Point(0, 0), 0, 0);
621 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
622 EXPECT_TRUE(filter->events().empty());
623
624 // Check that we do dispatch the held MOUSE_DRAGGED event before another type
625 // of event.
626 ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0),
627 gfx::Point(0, 0), 0, 0);
628 DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
629 EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
630 EventTypesToString(filter->events()));
631 filter->Reset();
632
633 // Check that we coalesce held MOUSE_DRAGGED events.
634 ui::MouseEvent mouse_dragged_event2(ui::ET_MOUSE_DRAGGED, gfx::Point(10, 10),
635 gfx::Point(10, 10), 0, 0);
636 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
637 DispatchEventUsingWindowDispatcher(&mouse_dragged_event2);
638 EXPECT_TRUE(filter->events().empty());
639 DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
640 EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
641 EventTypesToString(filter->events()));
642 filter->Reset();
643
644 // Check that on ReleasePointerMoves, held events are not dispatched
645 // immediately, but posted instead.
646 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
647 dispatcher()->ReleasePointerMoves();
648 EXPECT_TRUE(filter->events().empty());
649 RunAllPendingInMessageLoop();
650 EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(filter->events()));
651 filter->Reset();
652
653 // However if another message comes in before the dispatch of the posted
654 // event, check that the posted event is dispatched before this new event.
655 dispatcher()->HoldPointerMoves();
656 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
657 dispatcher()->ReleasePointerMoves();
658 DispatchEventUsingWindowDispatcher(&mouse_pressed_event);
659 EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED",
660 EventTypesToString(filter->events()));
661 filter->Reset();
662 RunAllPendingInMessageLoop();
663 EXPECT_TRUE(filter->events().empty());
664
665 // Check that if the other message is another MOUSE_DRAGGED, we still coalesce
666 // them.
667 dispatcher()->HoldPointerMoves();
668 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
669 dispatcher()->ReleasePointerMoves();
670 DispatchEventUsingWindowDispatcher(&mouse_dragged_event2);
671 EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(filter->events()));
672 filter->Reset();
673 RunAllPendingInMessageLoop();
674 EXPECT_TRUE(filter->events().empty());
675
676 // Check that synthetic mouse move event has a right location when issued
677 // while holding pointer moves.
678 ui::MouseEvent mouse_dragged_event3(ui::ET_MOUSE_DRAGGED, gfx::Point(28, 28),
679 gfx::Point(28, 28), 0, 0);
680 dispatcher()->HoldPointerMoves();
681 DispatchEventUsingWindowDispatcher(&mouse_dragged_event);
682 DispatchEventUsingWindowDispatcher(&mouse_dragged_event2);
683 window->SetBounds(gfx::Rect(15, 15, 80, 80));
684 DispatchEventUsingWindowDispatcher(&mouse_dragged_event3);
685 RunAllPendingInMessageLoop();
686 EXPECT_TRUE(filter->events().empty());
687 dispatcher()->ReleasePointerMoves();
688 RunAllPendingInMessageLoop();
689 EXPECT_EQ("MOUSE_MOVED", EventTypesToString(filter->events()));
690 EXPECT_EQ(gfx::Point(13, 13), filter->mouse_location(0));
691 filter->Reset();
692 }
693
694 TEST_F(WindowEventDispatcherTest, TouchMovesHeld) {
695 EventFilterRecorder* filter = new EventFilterRecorder;
696 root_window()->SetEventFilter(filter); // passes ownership
697
698 test::TestWindowDelegate delegate;
699 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
700 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
701
702 const gfx::Point touch_location(60, 60);
703 // Starting the touch and throwing out the first few events, since the system
704 // is going to generate synthetic mouse events that are not relevant to the
705 // test.
706 ui::TouchEvent touch_pressed_event(ui::ET_TOUCH_PRESSED, touch_location,
707 0, base::TimeDelta());
708 DispatchEventUsingWindowDispatcher(&touch_pressed_event);
709 filter->WaitUntilReceivedEvent(ui::ET_GESTURE_SHOW_PRESS);
710 filter->Reset();
711
712 dispatcher()->HoldPointerMoves();
713
714 // Check that we don't immediately dispatch the TOUCH_MOVED event.
715 ui::TouchEvent touch_moved_event(ui::ET_TOUCH_MOVED, touch_location,
716 0, base::TimeDelta());
717 DispatchEventUsingWindowDispatcher(&touch_moved_event);
718 EXPECT_TRUE(filter->events().empty());
719
720 // Check that on ReleasePointerMoves, held events are not dispatched
721 // immediately, but posted instead.
722 DispatchEventUsingWindowDispatcher(&touch_moved_event);
723 dispatcher()->ReleasePointerMoves();
724 EXPECT_TRUE(filter->events().empty());
725
726 RunAllPendingInMessageLoop();
727 EXPECT_EQ("TOUCH_MOVED", EventTypesToString(filter->events()));
728 filter->Reset();
729
730 // If another touch event occurs then the held touch should be dispatched
731 // immediately before it.
732 ui::TouchEvent touch_released_event(ui::ET_TOUCH_RELEASED, touch_location,
733 0, base::TimeDelta());
734 filter->Reset();
735 dispatcher()->HoldPointerMoves();
736 DispatchEventUsingWindowDispatcher(&touch_moved_event);
737 DispatchEventUsingWindowDispatcher(&touch_released_event);
738 EXPECT_EQ("TOUCH_MOVED TOUCH_RELEASED GESTURE_TAP_CANCEL GESTURE_END",
739 EventTypesToString(filter->events()));
740 filter->Reset();
741 dispatcher()->ReleasePointerMoves();
742 RunAllPendingInMessageLoop();
743 EXPECT_TRUE(filter->events().empty());
744 }
745
746 class HoldPointerOnScrollHandler : public test::TestEventHandler {
747 public:
748 HoldPointerOnScrollHandler(WindowEventDispatcher* dispatcher,
749 EventFilterRecorder* filter)
750 : dispatcher_(dispatcher),
751 filter_(filter),
752 holding_moves_(false) {
753 }
754 virtual ~HoldPointerOnScrollHandler() {}
755
756 private:
757 virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE {
758 if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
759 CHECK(!holding_moves_);
760 holding_moves_ = true;
761 dispatcher_->HoldPointerMoves();
762 filter_->Reset();
763 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) {
764 dispatcher_->ReleasePointerMoves();
765 holding_moves_ = false;
766 }
767 }
768
769 WindowEventDispatcher* dispatcher_;
770 EventFilterRecorder* filter_;
771 bool holding_moves_;
772
773 DISALLOW_COPY_AND_ASSIGN(HoldPointerOnScrollHandler);
774 };
775
776 // Tests that touch-move events don't contribute to an in-progress scroll
777 // gesture if touch-move events are being held by the dispatcher.
778 TEST_F(WindowEventDispatcherTest, TouchMovesHeldOnScroll) {
779 EventFilterRecorder* filter = new EventFilterRecorder;
780 root_window()->SetEventFilter(filter);
781 test::TestWindowDelegate delegate;
782 HoldPointerOnScrollHandler handler(dispatcher(), filter);
783 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
784 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
785 window->AddPreTargetHandler(&handler);
786
787 test::EventGenerator generator(root_window());
788 generator.GestureScrollSequence(
789 gfx::Point(60, 60), gfx::Point(10, 60),
790 base::TimeDelta::FromMilliseconds(100), 25);
791
792 // |handler| will have reset |filter| and started holding the touch-move
793 // events when scrolling started. At the end of the scroll (i.e. upon
794 // touch-release), the held touch-move event will have been dispatched first,
795 // along with the subsequent events (i.e. touch-release, scroll-end, and
796 // gesture-end).
797 const EventFilterRecorder::Events& events = filter->events();
798 EXPECT_EQ("TOUCH_MOVED TOUCH_RELEASED GESTURE_SCROLL_END GESTURE_END",
799 EventTypesToString(events));
800 ASSERT_EQ(2u, filter->touch_locations().size());
801 EXPECT_EQ(gfx::Point(-40, 10).ToString(),
802 filter->touch_locations()[0].ToString());
803 EXPECT_EQ(gfx::Point(-40, 10).ToString(),
804 filter->touch_locations()[1].ToString());
805 }
806
807 // Tests that synthetic mouse events are ignored when mouse
808 // events are disabled.
809 TEST_F(WindowEventDispatcherTest, DispatchSyntheticMouseEvents) {
810 EventFilterRecorder* filter = new EventFilterRecorder;
811 root_window()->SetEventFilter(filter); // passes ownership
812
813 test::TestWindowDelegate delegate;
814 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
815 &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window()));
816 window->Show();
817 window->SetCapture();
818
819 test::TestCursorClient cursor_client(root_window());
820
821 // Dispatch a non-synthetic mouse event when mouse events are enabled.
822 ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
823 gfx::Point(10, 10), 0, 0);
824 DispatchEventUsingWindowDispatcher(&mouse1);
825 EXPECT_FALSE(filter->events().empty());
826 filter->Reset();
827
828 // Dispatch a synthetic mouse event when mouse events are enabled.
829 ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
830 gfx::Point(10, 10), ui::EF_IS_SYNTHESIZED, 0);
831 DispatchEventUsingWindowDispatcher(&mouse2);
832 EXPECT_FALSE(filter->events().empty());
833 filter->Reset();
834
835 // Dispatch a synthetic mouse event when mouse events are disabled.
836 cursor_client.DisableMouseEvents();
837 DispatchEventUsingWindowDispatcher(&mouse2);
838 EXPECT_TRUE(filter->events().empty());
839 }
840
841 // Tests that a mouse exit is dispatched to the last known cursor location
842 // when the cursor becomes invisible.
843 TEST_F(WindowEventDispatcherTest, DispatchMouseExitWhenCursorHidden) {
844 EventFilterRecorder* filter = new EventFilterRecorder;
845 root_window()->SetEventFilter(filter); // passes ownership
846
847 test::TestWindowDelegate delegate;
848 gfx::Point window_origin(7, 18);
849 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
850 &delegate, 1234, gfx::Rect(window_origin, gfx::Size(100, 100)),
851 root_window()));
852 window->Show();
853
854 // Dispatch a mouse move event into the window.
855 gfx::Point mouse_location(gfx::Point(15, 25));
856 ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location,
857 mouse_location, 0, 0);
858 EXPECT_TRUE(filter->events().empty());
859 DispatchEventUsingWindowDispatcher(&mouse1);
860 EXPECT_FALSE(filter->events().empty());
861 filter->Reset();
862
863 // Hide the cursor and verify a mouse exit was dispatched.
864 dispatcher()->host()->OnCursorVisibilityChanged(false);
865 EXPECT_FALSE(filter->events().empty());
866 EXPECT_EQ("MOUSE_EXITED", EventTypesToString(filter->events()));
867
868 // Verify the mouse exit was dispatched at the correct location
869 // (in the correct coordinate space).
870 int translated_x = mouse_location.x() - window_origin.x();
871 int translated_y = mouse_location.y() - window_origin.y();
872 gfx::Point translated_point(translated_x, translated_y);
873 EXPECT_EQ(filter->mouse_location(0).ToString(), translated_point.ToString());
874 }
875
876 class DeletingEventFilter : public ui::EventHandler {
877 public:
878 DeletingEventFilter()
879 : delete_during_pre_handle_(false) {}
880 virtual ~DeletingEventFilter() {}
881
882 void Reset(bool delete_during_pre_handle) {
883 delete_during_pre_handle_ = delete_during_pre_handle;
884 }
885
886 private:
887 // Overridden from ui::EventHandler:
888 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
889 if (delete_during_pre_handle_)
890 delete event->target();
891 }
892
893 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
894 if (delete_during_pre_handle_)
895 delete event->target();
896 }
897
898 bool delete_during_pre_handle_;
899
900 DISALLOW_COPY_AND_ASSIGN(DeletingEventFilter);
901 };
902
903 class DeletingWindowDelegate : public test::TestWindowDelegate {
904 public:
905 DeletingWindowDelegate()
906 : window_(NULL),
907 delete_during_handle_(false),
908 got_event_(false) {}
909 virtual ~DeletingWindowDelegate() {}
910
911 void Reset(Window* window, bool delete_during_handle) {
912 window_ = window;
913 delete_during_handle_ = delete_during_handle;
914 got_event_ = false;
915 }
916 bool got_event() const { return got_event_; }
917
918 private:
919 // Overridden from WindowDelegate:
920 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
921 if (delete_during_handle_)
922 delete window_;
923 got_event_ = true;
924 }
925
926 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
927 if (delete_during_handle_)
928 delete window_;
929 got_event_ = true;
930 }
931
932 Window* window_;
933 bool delete_during_handle_;
934 bool got_event_;
935
936 DISALLOW_COPY_AND_ASSIGN(DeletingWindowDelegate);
937 };
938
939 TEST_F(WindowEventDispatcherTest, DeleteWindowDuringDispatch) {
940 // Verifies that we can delete a window during each phase of event handling.
941 // Deleting the window should not cause a crash, only prevent further
942 // processing from occurring.
943 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
944 DeletingWindowDelegate d11;
945 Window* w11 = CreateNormalWindow(11, w1.get(), &d11);
946 WindowTracker tracker;
947 DeletingEventFilter* w1_filter = new DeletingEventFilter;
948 w1->SetEventFilter(w1_filter);
949 client::GetFocusClient(w1.get())->FocusWindow(w11);
950
951 test::EventGenerator generator(root_window(), w11);
952
953 // First up, no one deletes anything.
954 tracker.Add(w11);
955 d11.Reset(w11, false);
956
957 generator.PressLeftButton();
958 EXPECT_TRUE(tracker.Contains(w11));
959 EXPECT_TRUE(d11.got_event());
960 generator.ReleaseLeftButton();
961
962 // Delegate deletes w11. This will prevent the post-handle step from applying.
963 w1_filter->Reset(false);
964 d11.Reset(w11, true);
965 generator.PressKey(ui::VKEY_A, 0);
966 EXPECT_FALSE(tracker.Contains(w11));
967 EXPECT_TRUE(d11.got_event());
968
969 // Pre-handle step deletes w11. This will prevent the delegate and the post-
970 // handle steps from applying.
971 w11 = CreateNormalWindow(11, w1.get(), &d11);
972 w1_filter->Reset(true);
973 d11.Reset(w11, false);
974 generator.PressLeftButton();
975 EXPECT_FALSE(tracker.Contains(w11));
976 EXPECT_FALSE(d11.got_event());
977 }
978
979 namespace {
980
981 // A window delegate that detaches the parent of the target's parent window when
982 // it receives a tap event.
983 class DetachesParentOnTapDelegate : public test::TestWindowDelegate {
984 public:
985 DetachesParentOnTapDelegate() {}
986 virtual ~DetachesParentOnTapDelegate() {}
987
988 private:
989 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
990 if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
991 event->SetHandled();
992 return;
993 }
994
995 if (event->type() == ui::ET_GESTURE_TAP) {
996 Window* parent = static_cast<Window*>(event->target())->parent();
997 parent->parent()->RemoveChild(parent);
998 event->SetHandled();
999 }
1000 }
1001
1002 DISALLOW_COPY_AND_ASSIGN(DetachesParentOnTapDelegate);
1003 };
1004
1005 } // namespace
1006
1007 // Tests that the gesture recognizer is reset for all child windows when a
1008 // window hides. No expectations, just checks that the test does not crash.
1009 TEST_F(WindowEventDispatcherTest,
1010 GestureRecognizerResetsTargetWhenParentHides) {
1011 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
1012 DetachesParentOnTapDelegate delegate;
1013 scoped_ptr<Window> parent(CreateNormalWindow(22, w1.get(), NULL));
1014 Window* child = CreateNormalWindow(11, parent.get(), &delegate);
1015 test::EventGenerator generator(root_window(), child);
1016 generator.GestureTapAt(gfx::Point(40, 40));
1017 }
1018
1019 namespace {
1020
1021 // A window delegate that processes nested gestures on tap.
1022 class NestedGestureDelegate : public test::TestWindowDelegate {
1023 public:
1024 NestedGestureDelegate(test::EventGenerator* generator,
1025 const gfx::Point tap_location)
1026 : generator_(generator),
1027 tap_location_(tap_location),
1028 gesture_end_count_(0) {}
1029 virtual ~NestedGestureDelegate() {}
1030
1031 int gesture_end_count() const { return gesture_end_count_; }
1032
1033 private:
1034 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
1035 switch (event->type()) {
1036 case ui::ET_GESTURE_TAP_DOWN:
1037 event->SetHandled();
1038 break;
1039 case ui::ET_GESTURE_TAP:
1040 if (generator_)
1041 generator_->GestureTapAt(tap_location_);
1042 event->SetHandled();
1043 break;
1044 case ui::ET_GESTURE_END:
1045 ++gesture_end_count_;
1046 break;
1047 default:
1048 break;
1049 }
1050 }
1051
1052 test::EventGenerator* generator_;
1053 const gfx::Point tap_location_;
1054 int gesture_end_count_;
1055 DISALLOW_COPY_AND_ASSIGN(NestedGestureDelegate);
1056 };
1057
1058 } // namespace
1059
1060 // Tests that gesture end is delivered after nested gesture processing.
1061 TEST_F(WindowEventDispatcherTest, GestureEndDeliveredAfterNestedGestures) {
1062 NestedGestureDelegate d1(NULL, gfx::Point());
1063 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &d1));
1064 w1->SetBounds(gfx::Rect(0, 0, 100, 100));
1065
1066 test::EventGenerator nested_generator(root_window(), w1.get());
1067 NestedGestureDelegate d2(&nested_generator, w1->bounds().CenterPoint());
1068 scoped_ptr<Window> w2(CreateNormalWindow(1, root_window(), &d2));
1069 w2->SetBounds(gfx::Rect(100, 0, 100, 100));
1070
1071 // Tap on w2 which triggers nested gestures for w1.
1072 test::EventGenerator generator(root_window(), w2.get());
1073 generator.GestureTapAt(w2->bounds().CenterPoint());
1074
1075 // Both windows should get their gesture end events.
1076 EXPECT_EQ(1, d1.gesture_end_count());
1077 EXPECT_EQ(1, d2.gesture_end_count());
1078 }
1079
1080 // Tests whether we can repost the Tap down gesture event.
1081 TEST_F(WindowEventDispatcherTest, RepostTapdownGestureTest) {
1082 EventFilterRecorder* filter = new EventFilterRecorder;
1083 root_window()->SetEventFilter(filter); // passes ownership
1084
1085 test::TestWindowDelegate delegate;
1086 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1087 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
1088
1089 ui::GestureEventDetails details(ui::ET_GESTURE_TAP_DOWN, 0.0f, 0.0f);
1090 gfx::Point point(10, 10);
1091 ui::GestureEvent event(
1092 ui::ET_GESTURE_TAP_DOWN,
1093 point.x(),
1094 point.y(),
1095 0,
1096 ui::EventTimeForNow(),
1097 details,
1098 0);
1099 dispatcher()->RepostEvent(event);
1100 RunAllPendingInMessageLoop();
1101 // TODO(rbyers): Currently disabled - crbug.com/170987
1102 EXPECT_FALSE(EventTypesToString(filter->events()).find("GESTURE_TAP_DOWN") !=
1103 std::string::npos);
1104 filter->Reset();
1105 }
1106
1107 // This class inherits from the EventFilterRecorder class which provides a
1108 // facility to record events. This class additionally provides a facility to
1109 // repost the ET_GESTURE_TAP_DOWN gesture to the target window and records
1110 // events after that.
1111 class RepostGestureEventRecorder : public EventFilterRecorder {
1112 public:
1113 RepostGestureEventRecorder(aura::Window* repost_source,
1114 aura::Window* repost_target)
1115 : repost_source_(repost_source),
1116 repost_target_(repost_target),
1117 reposted_(false),
1118 done_cleanup_(false) {}
1119
1120 virtual ~RepostGestureEventRecorder() {}
1121
1122 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
1123 if (reposted_ && event->type() == ui::ET_TOUCH_PRESSED) {
1124 done_cleanup_ = true;
1125 Reset();
1126 }
1127 EventFilterRecorder::OnTouchEvent(event);
1128 }
1129
1130 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
1131 EXPECT_EQ(done_cleanup_ ? repost_target_ : repost_source_, event->target());
1132 if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
1133 if (!reposted_) {
1134 EXPECT_NE(repost_target_, event->target());
1135 reposted_ = true;
1136 repost_target_->GetDispatcher()->RepostEvent(*event);
1137 // Ensure that the reposted gesture event above goes to the
1138 // repost_target_;
1139 repost_source_->GetRootWindow()->RemoveChild(repost_source_);
1140 return;
1141 }
1142 }
1143 EventFilterRecorder::OnGestureEvent(event);
1144 }
1145
1146 // Ignore mouse events as they don't fire at all times. This causes
1147 // the GestureRepostEventOrder test to fail randomly.
1148 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {}
1149
1150 private:
1151 aura::Window* repost_source_;
1152 aura::Window* repost_target_;
1153 // set to true if we reposted the ET_GESTURE_TAP_DOWN event.
1154 bool reposted_;
1155 // set true if we're done cleaning up after hiding repost_source_;
1156 bool done_cleanup_;
1157 DISALLOW_COPY_AND_ASSIGN(RepostGestureEventRecorder);
1158 };
1159
1160 // Tests whether events which are generated after the reposted gesture event
1161 // are received after that. In this case the scroll sequence events should
1162 // be received after the reposted gesture event.
1163 TEST_F(WindowEventDispatcherTest, GestureRepostEventOrder) {
1164 // Expected events at the end for the repost_target window defined below.
1165 const char kExpectedTargetEvents[] =
1166 // TODO)(rbyers): Gesture event reposting is disabled - crbug.com/279039.
1167 // "GESTURE_BEGIN GESTURE_TAP_DOWN "
1168 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
1169 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE TOUCH_MOVED "
1170 "GESTURE_SCROLL_UPDATE TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED "
1171 "GESTURE_SCROLL_END GESTURE_END";
1172 // We create two windows.
1173 // The first window (repost_source) is the one to which the initial tap
1174 // gesture is sent. It reposts this event to the second window
1175 // (repost_target).
1176 // We then generate the scroll sequence for repost_target and look for two
1177 // ET_GESTURE_TAP_DOWN events in the event list at the end.
1178 test::TestWindowDelegate delegate;
1179 scoped_ptr<aura::Window> repost_target(CreateTestWindowWithDelegate(
1180 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
1181
1182 scoped_ptr<aura::Window> repost_source(CreateTestWindowWithDelegate(
1183 &delegate, 1, gfx::Rect(0, 0, 50, 50), root_window()));
1184
1185 RepostGestureEventRecorder* repost_event_recorder =
1186 new RepostGestureEventRecorder(repost_source.get(), repost_target.get());
1187 root_window()->SetEventFilter(repost_event_recorder); // passes ownership
1188
1189 // Generate a tap down gesture for the repost_source. This will be reposted
1190 // to repost_target.
1191 test::EventGenerator repost_generator(root_window(), repost_source.get());
1192 repost_generator.GestureTapAt(gfx::Point(40, 40));
1193 RunAllPendingInMessageLoop();
1194
1195 test::EventGenerator scroll_generator(root_window(), repost_target.get());
1196 scroll_generator.GestureScrollSequence(
1197 gfx::Point(80, 80),
1198 gfx::Point(100, 100),
1199 base::TimeDelta::FromMilliseconds(100),
1200 3);
1201 RunAllPendingInMessageLoop();
1202
1203 int tap_down_count = 0;
1204 for (size_t i = 0; i < repost_event_recorder->events().size(); ++i) {
1205 if (repost_event_recorder->events()[i] == ui::ET_GESTURE_TAP_DOWN)
1206 ++tap_down_count;
1207 }
1208
1209 // We expect two tap down events. One from the repost and the other one from
1210 // the scroll sequence posted above.
1211 // TODO(rbyers): Currently disabled - crbug.com/170987
1212 EXPECT_EQ(1, tap_down_count);
1213
1214 EXPECT_EQ(kExpectedTargetEvents,
1215 EventTypesToString(repost_event_recorder->events()));
1216 }
1217
1218 class OnMouseExitDeletingEventFilter : public EventFilterRecorder {
1219 public:
1220 OnMouseExitDeletingEventFilter() : window_to_delete_(NULL) {}
1221 virtual ~OnMouseExitDeletingEventFilter() {}
1222
1223 void set_window_to_delete(Window* window_to_delete) {
1224 window_to_delete_ = window_to_delete;
1225 }
1226
1227 private:
1228 // Overridden from ui::EventHandler:
1229 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
1230 EventFilterRecorder::OnMouseEvent(event);
1231 if (window_to_delete_) {
1232 delete window_to_delete_;
1233 window_to_delete_ = NULL;
1234 }
1235 }
1236
1237 Window* window_to_delete_;
1238
1239 DISALLOW_COPY_AND_ASSIGN(OnMouseExitDeletingEventFilter);
1240 };
1241
1242 // Tests that RootWindow drops mouse-moved event that is supposed to be sent to
1243 // a child, but the child is destroyed because of the synthesized mouse-exit
1244 // event generated on the previous mouse_moved_handler_.
1245 TEST_F(WindowEventDispatcherTest, DeleteWindowDuringMouseMovedDispatch) {
1246 // Create window 1 and set its event filter. Window 1 will take ownership of
1247 // the event filter.
1248 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL));
1249 OnMouseExitDeletingEventFilter* w1_filter =
1250 new OnMouseExitDeletingEventFilter();
1251 w1->SetEventFilter(w1_filter);
1252 w1->SetBounds(gfx::Rect(20, 20, 60, 60));
1253 EXPECT_EQ(NULL, dispatcher()->mouse_moved_handler());
1254
1255 test::EventGenerator generator(root_window(), w1.get());
1256
1257 // Move mouse over window 1 to set it as the |mouse_moved_handler_| for the
1258 // root window.
1259 generator.MoveMouseTo(51, 51);
1260 EXPECT_EQ(w1.get(), dispatcher()->mouse_moved_handler());
1261
1262 // Create window 2 under the mouse cursor and stack it above window 1.
1263 Window* w2 = CreateNormalWindow(2, root_window(), NULL);
1264 w2->SetBounds(gfx::Rect(30, 30, 40, 40));
1265 root_window()->StackChildAbove(w2, w1.get());
1266
1267 // Set window 2 as the window that is to be deleted when a mouse-exited event
1268 // happens on window 1.
1269 w1_filter->set_window_to_delete(w2);
1270
1271 // Move mosue over window 2. This should generate a mouse-exited event for
1272 // window 1 resulting in deletion of window 2. The original mouse-moved event
1273 // that was targeted to window 2 should be dropped since window 2 is
1274 // destroyed. This test passes if no crash happens.
1275 generator.MoveMouseTo(52, 52);
1276 EXPECT_EQ(NULL, dispatcher()->mouse_moved_handler());
1277
1278 // Check events received by window 1.
1279 EXPECT_EQ("MOUSE_ENTERED MOUSE_MOVED MOUSE_EXITED",
1280 EventTypesToString(w1_filter->events()));
1281 }
1282
1283 namespace {
1284
1285 // Used to track if OnWindowDestroying() is invoked and if there is a valid
1286 // RootWindow at such time.
1287 class ValidRootDuringDestructionWindowObserver : public aura::WindowObserver {
1288 public:
1289 ValidRootDuringDestructionWindowObserver(bool* got_destroying,
1290 bool* has_valid_root)
1291 : got_destroying_(got_destroying),
1292 has_valid_root_(has_valid_root) {
1293 }
1294
1295 // WindowObserver:
1296 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
1297 *got_destroying_ = true;
1298 *has_valid_root_ = (window->GetRootWindow() != NULL);
1299 }
1300
1301 private:
1302 bool* got_destroying_;
1303 bool* has_valid_root_;
1304
1305 DISALLOW_COPY_AND_ASSIGN(ValidRootDuringDestructionWindowObserver);
1306 };
1307
1308 } // namespace
1309
1310 #if defined(USE_OZONE)
1311 // Creating multiple WindowTreeHostOzone instances is broken.
1312 #define MAYBE_ValidRootDuringDestruction DISABLED_ValidRootDuringDestruction
1313 #else
1314 #define MAYBE_ValidRootDuringDestruction ValidRootDuringDestruction
1315 #endif
1316
1317 // Verifies GetRootWindow() from ~Window returns a valid root.
1318 TEST_F(WindowEventDispatcherTest, MAYBE_ValidRootDuringDestruction) {
1319 bool got_destroying = false;
1320 bool has_valid_root = false;
1321 ValidRootDuringDestructionWindowObserver observer(&got_destroying,
1322 &has_valid_root);
1323 {
1324 scoped_ptr<WindowEventDispatcher> dispatcher(
1325 new WindowEventDispatcher(
1326 WindowEventDispatcher::CreateParams(gfx::Rect(0, 0, 100, 100))));
1327 dispatcher->host()->InitHost();
1328 // Owned by WindowEventDispatcher.
1329 Window* w1 = CreateNormalWindow(1, dispatcher->window(), NULL);
1330 w1->AddObserver(&observer);
1331 }
1332 EXPECT_TRUE(got_destroying);
1333 EXPECT_TRUE(has_valid_root);
1334 }
1335
1336 namespace {
1337
1338 // See description above DontResetHeldEvent for details.
1339 class DontResetHeldEventWindowDelegate : public test::TestWindowDelegate {
1340 public:
1341 explicit DontResetHeldEventWindowDelegate(aura::Window* root)
1342 : root_(root),
1343 mouse_event_count_(0) {}
1344 virtual ~DontResetHeldEventWindowDelegate() {}
1345
1346 int mouse_event_count() const { return mouse_event_count_; }
1347
1348 // TestWindowDelegate:
1349 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
1350 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 &&
1351 mouse_event_count_++ == 0) {
1352 ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED,
1353 gfx::Point(10, 10), gfx::Point(10, 10),
1354 ui::EF_SHIFT_DOWN, 0);
1355 root_->GetDispatcher()->RepostEvent(mouse_event);
1356 }
1357 }
1358
1359 private:
1360 Window* root_;
1361 int mouse_event_count_;
1362
1363 DISALLOW_COPY_AND_ASSIGN(DontResetHeldEventWindowDelegate);
1364 };
1365
1366 } // namespace
1367
1368 // Verifies RootWindow doesn't reset |RootWindow::held_repostable_event_| after
1369 // dispatching. This is done by using DontResetHeldEventWindowDelegate, which
1370 // tracks the number of events with ui::EF_SHIFT_DOWN set (all reposted events
1371 // have EF_SHIFT_DOWN). When the first event is seen RepostEvent() is used to
1372 // schedule another reposted event.
1373 TEST_F(WindowEventDispatcherTest, DontResetHeldEvent) {
1374 DontResetHeldEventWindowDelegate delegate(root_window());
1375 scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate));
1376 w1->SetBounds(gfx::Rect(0, 0, 40, 40));
1377 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED,
1378 gfx::Point(10, 10), gfx::Point(10, 10),
1379 ui::EF_SHIFT_DOWN, 0);
1380 root_window()->GetDispatcher()->RepostEvent(pressed);
1381 ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED,
1382 gfx::Point(10, 10), gfx::Point(10, 10), 0, 0);
1383 // Dispatch an event to flush event scheduled by way of RepostEvent().
1384 DispatchEventUsingWindowDispatcher(&pressed2);
1385 // Delegate should have seen reposted event (identified by way of
1386 // EF_SHIFT_DOWN). Dispatch another event to flush the second
1387 // RepostedEvent().
1388 EXPECT_EQ(1, delegate.mouse_event_count());
1389 DispatchEventUsingWindowDispatcher(&pressed2);
1390 EXPECT_EQ(2, delegate.mouse_event_count());
1391 }
1392
1393 namespace {
1394
1395 // See description above DeleteDispatcherFromHeldMouseEvent for details.
1396 class DeleteDispatcherFromHeldMouseEventDelegate
1397 : public test::TestWindowDelegate {
1398 public:
1399 explicit DeleteDispatcherFromHeldMouseEventDelegate(
1400 WindowEventDispatcher* dispatcher)
1401 : dispatcher_(dispatcher),
1402 got_mouse_event_(false),
1403 got_destroy_(false) {
1404 }
1405 virtual ~DeleteDispatcherFromHeldMouseEventDelegate() {}
1406
1407 bool got_mouse_event() const { return got_mouse_event_; }
1408 bool got_destroy() const { return got_destroy_; }
1409
1410 // TestWindowDelegate:
1411 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
1412 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0) {
1413 got_mouse_event_ = true;
1414 delete dispatcher_;
1415 }
1416 }
1417 virtual void OnWindowDestroyed() OVERRIDE {
1418 got_destroy_ = true;
1419 }
1420
1421 private:
1422 WindowEventDispatcher* dispatcher_;
1423 bool got_mouse_event_;
1424 bool got_destroy_;
1425
1426 DISALLOW_COPY_AND_ASSIGN(DeleteDispatcherFromHeldMouseEventDelegate);
1427 };
1428
1429 } // namespace
1430
1431 #if defined(USE_OZONE)
1432 // Creating multiple WindowTreeHostOzone instances is broken.
1433 #define MAYBE_DeleteDispatcherFromHeldMouseEvent DISABLED_DeleteDispatcherFromHe ldMouseEvent
1434 #else
1435 #define MAYBE_DeleteDispatcherFromHeldMouseEvent DeleteDispatcherFromHeldMouseEv ent
1436 #endif
1437
1438 // Verifies if a RootWindow is deleted from dispatching a held mouse event we
1439 // don't crash.
1440 TEST_F(WindowEventDispatcherTest, MAYBE_DeleteDispatcherFromHeldMouseEvent) {
1441 // Should be deleted by |delegate|.
1442 WindowEventDispatcher* d2 = new WindowEventDispatcher(
1443 WindowEventDispatcher::CreateParams(gfx::Rect(0, 0, 100, 100)));
1444 d2->host()->InitHost();
1445 DeleteDispatcherFromHeldMouseEventDelegate delegate(d2);
1446 // Owned by |d2|.
1447 Window* w1 = CreateNormalWindow(1, d2->window(), &delegate);
1448 w1->SetBounds(gfx::Rect(0, 0, 40, 40));
1449 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED,
1450 gfx::Point(10, 10), gfx::Point(10, 10),
1451 ui::EF_SHIFT_DOWN, 0);
1452 d2->RepostEvent(pressed);
1453 // RunAllPendingInMessageLoop() to make sure the |pressed| is run.
1454 RunAllPendingInMessageLoop();
1455 EXPECT_TRUE(delegate.got_mouse_event());
1456 EXPECT_TRUE(delegate.got_destroy());
1457 }
1458
1459 TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveTouches) {
1460 EventFilterRecorder* filter = new EventFilterRecorder;
1461 root_window()->SetEventFilter(filter); // passes ownership
1462
1463 test::TestWindowDelegate delegate;
1464 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1465 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
1466
1467 gfx::Point position1 = root_window()->bounds().origin();
1468 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position1, 0, base::TimeDelta());
1469 DispatchEventUsingWindowDispatcher(&press);
1470
1471 EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN",
1472 EventTypesToString(filter->GetAndResetEvents()));
1473
1474 window->Hide();
1475
1476 EXPECT_EQ("TOUCH_CANCELLED GESTURE_TAP_CANCEL GESTURE_END",
1477 EventTypesToString(filter->events()));
1478 }
1479
1480 TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveGestures) {
1481 EventFilterRecorder* filter = new EventFilterRecorder;
1482 root_window()->SetEventFilter(filter); // passes ownership
1483
1484 test::TestWindowDelegate delegate;
1485 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1486 &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
1487
1488 gfx::Point position1 = root_window()->bounds().origin();
1489 gfx::Point position2 = root_window()->bounds().CenterPoint();
1490 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position1, 0, base::TimeDelta());
1491 DispatchEventUsingWindowDispatcher(&press);
1492
1493 ui::TouchEvent move(ui::ET_TOUCH_MOVED, position2, 0, base::TimeDelta());
1494 DispatchEventUsingWindowDispatcher(&move);
1495
1496 ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, position1, 1, base::TimeDelta());
1497 DispatchEventUsingWindowDispatcher(&press2);
1498
1499 EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
1500 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
1501 "TOUCH_PRESSED GESTURE_BEGIN GESTURE_PINCH_BEGIN",
1502 EventTypesToString(filter->GetAndResetEvents()));
1503
1504 window->Hide();
1505
1506 EXPECT_EQ("TOUCH_CANCELLED GESTURE_PINCH_END GESTURE_END TOUCH_CANCELLED "
1507 "GESTURE_SCROLL_END GESTURE_END",
1508 EventTypesToString(filter->events()));
1509 }
1510
1511 // Places two windows side by side. Presses down on one window, and starts a
1512 // scroll. Sets capture on the other window and ensures that the "ending" events
1513 // aren't sent to the window which gained capture.
1514 TEST_F(WindowEventDispatcherTest, EndingEventDoesntRetarget) {
1515 scoped_ptr<Window> window1(CreateNormalWindow(1, root_window(), NULL));
1516 window1->SetBounds(gfx::Rect(0, 0, 40, 40));
1517
1518 scoped_ptr<Window> window2(CreateNormalWindow(2, root_window(), NULL));
1519 window2->SetBounds(gfx::Rect(40, 0, 40, 40));
1520
1521 EventFilterRecorder* filter1 = new EventFilterRecorder();
1522 window1->SetEventFilter(filter1); // passes ownership
1523 EventFilterRecorder* filter2 = new EventFilterRecorder();
1524 window2->SetEventFilter(filter2); // passes ownership
1525
1526 gfx::Point position = window1->bounds().origin();
1527 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position, 0, base::TimeDelta());
1528 DispatchEventUsingWindowDispatcher(&press);
1529
1530 gfx::Point position2 = window1->bounds().CenterPoint();
1531 ui::TouchEvent move(ui::ET_TOUCH_MOVED, position2, 0, base::TimeDelta());
1532 DispatchEventUsingWindowDispatcher(&move);
1533
1534 window2->SetCapture();
1535
1536 EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED "
1537 "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE "
1538 "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END",
1539 EventTypesToString(filter1->events()));
1540
1541 EXPECT_TRUE(filter2->events().empty());
1542 }
1543
1544 namespace {
1545
1546 // This class creates and manages a window which is destroyed as soon as
1547 // capture is lost. This is the case for the drag and drop capture window.
1548 class CaptureWindowTracker : public test::TestWindowDelegate {
1549 public:
1550 CaptureWindowTracker() {}
1551 virtual ~CaptureWindowTracker() {}
1552
1553 void CreateCaptureWindow(aura::Window* root_window) {
1554 capture_window_.reset(test::CreateTestWindowWithDelegate(
1555 this, -1234, gfx::Rect(20, 20, 20, 20), root_window));
1556 capture_window_->SetCapture();
1557 }
1558
1559 void reset() {
1560 capture_window_.reset();
1561 }
1562
1563 virtual void OnCaptureLost() OVERRIDE {
1564 capture_window_.reset();
1565 }
1566
1567 virtual void OnWindowDestroyed() OVERRIDE {
1568 TestWindowDelegate::OnWindowDestroyed();
1569 capture_window_.reset();
1570 }
1571
1572 aura::Window* capture_window() { return capture_window_.get(); }
1573
1574 private:
1575 scoped_ptr<aura::Window> capture_window_;
1576
1577 DISALLOW_COPY_AND_ASSIGN(CaptureWindowTracker);
1578 };
1579
1580 }
1581
1582 // Verifies handling loss of capture by the capture window being hidden.
1583 TEST_F(WindowEventDispatcherTest, CaptureWindowHidden) {
1584 CaptureWindowTracker capture_window_tracker;
1585 capture_window_tracker.CreateCaptureWindow(root_window());
1586 capture_window_tracker.capture_window()->Hide();
1587 EXPECT_EQ(NULL, capture_window_tracker.capture_window());
1588 }
1589
1590 // Verifies handling loss of capture by the capture window being destroyed.
1591 TEST_F(WindowEventDispatcherTest, CaptureWindowDestroyed) {
1592 CaptureWindowTracker capture_window_tracker;
1593 capture_window_tracker.CreateCaptureWindow(root_window());
1594 capture_window_tracker.reset();
1595 EXPECT_EQ(NULL, capture_window_tracker.capture_window());
1596 }
1597
1598 class ExitMessageLoopOnMousePress : public test::TestEventHandler {
1599 public:
1600 ExitMessageLoopOnMousePress() {}
1601 virtual ~ExitMessageLoopOnMousePress() {}
1602
1603 protected:
1604 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
1605 test::TestEventHandler::OnMouseEvent(event);
1606 if (event->type() == ui::ET_MOUSE_PRESSED)
1607 base::MessageLoopForUI::current()->Quit();
1608 }
1609
1610 private:
1611 DISALLOW_COPY_AND_ASSIGN(ExitMessageLoopOnMousePress);
1612 };
1613
1614 class WindowEventDispatcherTestWithMessageLoop
1615 : public WindowEventDispatcherTest {
1616 public:
1617 WindowEventDispatcherTestWithMessageLoop() {}
1618 virtual ~WindowEventDispatcherTestWithMessageLoop() {}
1619
1620 void RunTest() {
1621 // Reset any event the window may have received when bringing up the window
1622 // (e.g. mouse-move events if the mouse cursor is over the window).
1623 handler_.Reset();
1624
1625 // Start a nested message-loop, post an event to be dispatched, and then
1626 // terminate the message-loop. When the message-loop unwinds and gets back,
1627 // the reposted event should not have fired.
1628 ui::MouseEvent mouse(ui::ET_MOUSE_PRESSED, gfx::Point(10, 10),
1629 gfx::Point(10, 10), ui::EF_NONE, ui::EF_NONE);
1630 message_loop()->PostTask(FROM_HERE,
1631 base::Bind(&WindowEventDispatcher::RepostEvent,
1632 base::Unretained(dispatcher()),
1633 mouse));
1634 message_loop()->PostTask(FROM_HERE,
1635 message_loop()->QuitClosure());
1636
1637 base::MessageLoop::ScopedNestableTaskAllower allow(message_loop());
1638 base::RunLoop loop;
1639 loop.Run();
1640 EXPECT_EQ(0, handler_.num_mouse_events());
1641
1642 // Let the current message-loop run. The event-handler will terminate the
1643 // message-loop when it receives the reposted event.
1644 }
1645
1646 base::MessageLoop* message_loop() {
1647 return base::MessageLoopForUI::current();
1648 }
1649
1650 protected:
1651 virtual void SetUp() OVERRIDE {
1652 WindowEventDispatcherTest::SetUp();
1653 window_.reset(CreateNormalWindow(1, root_window(), NULL));
1654 window_->AddPreTargetHandler(&handler_);
1655 }
1656
1657 virtual void TearDown() OVERRIDE {
1658 window_.reset();
1659 WindowEventDispatcherTest::TearDown();
1660 }
1661
1662 private:
1663 scoped_ptr<Window> window_;
1664 ExitMessageLoopOnMousePress handler_;
1665
1666 DISALLOW_COPY_AND_ASSIGN(WindowEventDispatcherTestWithMessageLoop);
1667 };
1668
1669 TEST_F(WindowEventDispatcherTestWithMessageLoop, EventRepostedInNonNestedLoop) {
1670 CHECK(!message_loop()->is_running());
1671 // Perform the test in a callback, so that it runs after the message-loop
1672 // starts.
1673 message_loop()->PostTask(
1674 FROM_HERE, base::Bind(
1675 &WindowEventDispatcherTestWithMessageLoop::RunTest,
1676 base::Unretained(this)));
1677 message_loop()->Run();
1678 }
1679
1680 class WindowEventDispatcherTestInHighDPI : public WindowEventDispatcherTest {
1681 public:
1682 WindowEventDispatcherTestInHighDPI() {}
1683 virtual ~WindowEventDispatcherTestInHighDPI() {}
1684
1685 protected:
1686 virtual void SetUp() OVERRIDE {
1687 WindowEventDispatcherTest::SetUp();
1688 test_screen()->SetDeviceScaleFactor(2.f);
1689 }
1690 };
1691
1692 TEST_F(WindowEventDispatcherTestInHighDPI, EventLocationTransform) {
1693 test::TestWindowDelegate delegate;
1694 scoped_ptr<aura::Window> child(test::CreateTestWindowWithDelegate(&delegate,
1695 1234, gfx::Rect(20, 20, 100, 100), root_window()));
1696 child->Show();
1697
1698 test::TestEventHandler handler_child;
1699 test::TestEventHandler handler_root;
1700 root_window()->AddPreTargetHandler(&handler_root);
1701 child->AddPreTargetHandler(&handler_child);
1702
1703 {
1704 ui::MouseEvent move(ui::ET_MOUSE_MOVED,
1705 gfx::Point(30, 30), gfx::Point(30, 30),
1706 ui::EF_NONE, ui::EF_NONE);
1707 DispatchEventUsingWindowDispatcher(&move);
1708 EXPECT_EQ(0, handler_child.num_mouse_events());
1709 EXPECT_EQ(1, handler_root.num_mouse_events());
1710 }
1711
1712 {
1713 ui::MouseEvent move(ui::ET_MOUSE_MOVED,
1714 gfx::Point(50, 50), gfx::Point(50, 50),
1715 ui::EF_NONE, ui::EF_NONE);
1716 DispatchEventUsingWindowDispatcher(&move);
1717 // The child receives an ENTER, and a MOVED event.
1718 EXPECT_EQ(2, handler_child.num_mouse_events());
1719 // The root receives both the ENTER and the MOVED events dispatched to
1720 // |child|, as well as an EXIT event.
1721 EXPECT_EQ(3, handler_root.num_mouse_events());
1722 }
1723
1724 child->RemovePreTargetHandler(&handler_child);
1725 root_window()->RemovePreTargetHandler(&handler_root);
1726 }
1727
1728 TEST_F(WindowEventDispatcherTestInHighDPI, TouchMovesHeldOnScroll) {
1729 EventFilterRecorder* filter = new EventFilterRecorder;
1730 root_window()->SetEventFilter(filter);
1731 test::TestWindowDelegate delegate;
1732 HoldPointerOnScrollHandler handler(dispatcher(), filter);
1733 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1734 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
1735 window->AddPreTargetHandler(&handler);
1736
1737 test::EventGenerator generator(root_window());
1738 generator.GestureScrollSequence(
1739 gfx::Point(120, 120), gfx::Point(20, 120),
1740 base::TimeDelta::FromMilliseconds(100), 25);
1741
1742 // |handler| will have reset |filter| and started holding the touch-move
1743 // events when scrolling started. At the end of the scroll (i.e. upon
1744 // touch-release), the held touch-move event will have been dispatched first,
1745 // along with the subsequent events (i.e. touch-release, scroll-end, and
1746 // gesture-end).
1747 const EventFilterRecorder::Events& events = filter->events();
1748 EXPECT_EQ("TOUCH_MOVED TOUCH_RELEASED GESTURE_SCROLL_END GESTURE_END",
1749 EventTypesToString(events));
1750 ASSERT_EQ(2u, filter->touch_locations().size());
1751 EXPECT_EQ(gfx::Point(-40, 10).ToString(),
1752 filter->touch_locations()[0].ToString());
1753 EXPECT_EQ(gfx::Point(-40, 10).ToString(),
1754 filter->touch_locations()[1].ToString());
1755 }
1756
1757 class SelfDestructDelegate : public test::TestWindowDelegate {
1758 public:
1759 SelfDestructDelegate() {}
1760 virtual ~SelfDestructDelegate() {}
1761
1762 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
1763 window_.reset();
1764 }
1765
1766 void set_window(scoped_ptr<aura::Window> window) {
1767 window_ = window.Pass();
1768 }
1769 bool has_window() const { return !!window_.get(); }
1770
1771 private:
1772 scoped_ptr<aura::Window> window_;
1773 DISALLOW_COPY_AND_ASSIGN(SelfDestructDelegate);
1774 };
1775
1776 TEST_F(WindowEventDispatcherTest, SynthesizedLocatedEvent) {
1777 test::EventGenerator generator(root_window());
1778 generator.MoveMouseTo(10, 10);
1779 EXPECT_EQ("10,10",
1780 Env::GetInstance()->last_mouse_location().ToString());
1781
1782 // Synthesized event should not update the mouse location.
1783 ui::MouseEvent mouseev(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
1784 ui::EF_IS_SYNTHESIZED, 0);
1785 generator.Dispatch(&mouseev);
1786 EXPECT_EQ("10,10",
1787 Env::GetInstance()->last_mouse_location().ToString());
1788
1789 generator.MoveMouseTo(0, 0);
1790 EXPECT_EQ("0,0",
1791 Env::GetInstance()->last_mouse_location().ToString());
1792
1793 // Make sure the location gets updated when a syntheiszed enter
1794 // event destroyed the window.
1795 SelfDestructDelegate delegate;
1796 scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
1797 &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window()));
1798 delegate.set_window(window.Pass());
1799 EXPECT_TRUE(delegate.has_window());
1800
1801 generator.MoveMouseTo(100, 100);
1802 EXPECT_FALSE(delegate.has_window());
1803 EXPECT_EQ("100,100",
1804 Env::GetInstance()->last_mouse_location().ToString());
1805 }
1806
1807 } // namespace aura
OLDNEW
« no previous file with comments | « ui/aura/root_window.cc ('k') | ui/aura/test/aura_test_base.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698