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.
5 #include "ash/wm/system_gesture_event_filter.h"
9 #include "ash/accelerators/accelerator_controller.h"
10 #include "ash/display/display_manager.h"
11 #include "ash/shelf/shelf.h"
12 #include "ash/shelf/shelf_model.h"
13 #include "ash/shell.h"
14 #include "ash/system/tray/system_tray_delegate.h"
15 #include "ash/test/ash_test_base.h"
16 #include "ash/test/display_manager_test_api.h"
17 #include "ash/test/shell_test_api.h"
18 #include "ash/test/test_shelf_delegate.h"
19 #include "ash/wm/gestures/long_press_affordance_handler.h"
20 #include "ash/wm/window_state.h"
21 #include "ash/wm/window_util.h"
22 #include "base/time/time.h"
23 #include "base/timer/timer.h"
24 #include "ui/aura/env.h"
25 #include "ui/aura/test/test_window_delegate.h"
26 #include "ui/aura/test/test_windows.h"
27 #include "ui/aura/window_event_dispatcher.h"
28 #include "ui/base/hit_test.h"
29 #include "ui/events/event.h"
30 #include "ui/events/event_handler.h"
31 #include "ui/events/event_utils.h"
32 #include "ui/events/gestures/gesture_configuration.h"
33 #include "ui/events/test/event_generator.h"
34 #include "ui/events/test/test_event_handler.h"
35 #include "ui/gfx/screen.h"
36 #include "ui/gfx/size.h"
37 #include "ui/views/widget/widget.h"
38 #include "ui/views/widget/widget_delegate.h"
39 #include "ui/views/window/non_client_view.h"
40 #include "ui/views/window/window_button_order_provider.h"
47 class ResizableWidgetDelegate : public views::WidgetDelegateView {
49 ResizableWidgetDelegate() {}
50 virtual ~ResizableWidgetDelegate() {}
53 virtual bool CanResize() const OVERRIDE { return true; }
54 virtual bool CanMaximize() const OVERRIDE { return true; }
55 virtual bool CanMinimize() const OVERRIDE { return true; }
56 virtual void DeleteDelegate() OVERRIDE { delete this; }
58 DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate);
61 // Support class for testing windows with a maximum size.
62 class MaxSizeNCFV : public views::NonClientFrameView {
66 virtual gfx::Size GetMaximumSize() const OVERRIDE {
67 return gfx::Size(200, 200);
69 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE {
73 virtual gfx::Rect GetWindowBoundsForClientBounds(
74 const gfx::Rect& client_bounds) const OVERRIDE {
78 // This function must ask the ClientView to do a hittest. We don't do this in
79 // the parent NonClientView because that makes it more difficult to calculate
80 // hittests for regions that are partially obscured by the ClientView, e.g.
82 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
85 virtual void GetWindowMask(const gfx::Size& size,
86 gfx::Path* window_mask) OVERRIDE {}
87 virtual void ResetWindowControls() OVERRIDE {}
88 virtual void UpdateWindowIcon() OVERRIDE {}
89 virtual void UpdateWindowTitle() OVERRIDE {}
90 virtual void SizeConstraintsChanged() OVERRIDE {}
92 DISALLOW_COPY_AND_ASSIGN(MaxSizeNCFV);
95 class MaxSizeWidgetDelegate : public views::WidgetDelegateView {
97 MaxSizeWidgetDelegate() {}
98 virtual ~MaxSizeWidgetDelegate() {}
101 virtual bool CanResize() const OVERRIDE { return true; }
102 virtual bool CanMaximize() const OVERRIDE { return false; }
103 virtual void DeleteDelegate() OVERRIDE { delete this; }
104 virtual views::NonClientFrameView* CreateNonClientFrameView(
105 views::Widget* widget) OVERRIDE {
106 return new MaxSizeNCFV;
109 DISALLOW_COPY_AND_ASSIGN(MaxSizeWidgetDelegate);
114 class SystemGestureEventFilterTest : public AshTestBase {
116 SystemGestureEventFilterTest() : AshTestBase() {}
117 virtual ~SystemGestureEventFilterTest() {}
119 LongPressAffordanceHandler* GetLongPressAffordance() {
120 ShellTestApi shell_test(Shell::GetInstance());
121 return shell_test.system_gesture_event_filter()->
122 long_press_affordance_.get();
125 base::OneShotTimer<LongPressAffordanceHandler>*
126 GetLongPressAffordanceTimer() {
127 return &GetLongPressAffordance()->timer_;
130 aura::Window* GetLongPressAffordanceTarget() {
131 return GetLongPressAffordance()->tap_down_target_;
134 views::View* GetLongPressAffordanceView() {
135 return reinterpret_cast<views::View*>(
136 GetLongPressAffordance()->view_.get());
139 // Overridden from AshTestBase:
140 virtual void SetUp() OVERRIDE {
141 // TODO(jonross): TwoFingerDragDelayed() and ThreeFingerGestureStopsDrag()
142 // both use hardcoded touch points, assuming that they target empty header
143 // space. Window control order now reflects configuration files and can
144 // change. The tests should be improved to dynamically decide touch points.
145 // To address this we specify the originally expected window control
146 // positions to be consistent across tests.
147 std::vector<views::FrameButton> leading;
148 std::vector<views::FrameButton> trailing;
149 trailing.push_back(views::FRAME_BUTTON_MINIMIZE);
150 trailing.push_back(views::FRAME_BUTTON_MAXIMIZE);
151 trailing.push_back(views::FRAME_BUTTON_CLOSE);
152 views::WindowButtonOrderProvider::GetInstance()->
153 SetWindowButtonOrder(leading, trailing);
155 test::AshTestBase::SetUp();
156 // Enable brightness key.
157 test::DisplayManagerTestApi(Shell::GetInstance()->display_manager()).
158 SetFirstDisplayAsInternalDisplay();
162 DISALLOW_COPY_AND_ASSIGN(SystemGestureEventFilterTest);
165 ui::GestureEvent* CreateGesture(ui::EventType type,
171 ui::GestureEventDetails details =
172 ui::GestureEventDetails(type, delta_x, delta_y);
173 details.set_oldest_touch_id(touch_id);
174 return new ui::GestureEvent(x, y, 0,
175 base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000),
176 ui::GestureEventDetails(type, delta_x, delta_y));
179 TEST_F(SystemGestureEventFilterTest, LongPressAffordanceStateOnCaptureLoss) {
180 aura::Window* root_window = Shell::GetPrimaryRootWindow();
182 aura::test::TestWindowDelegate delegate;
183 scoped_ptr<aura::Window> window0(
184 aura::test::CreateTestWindowWithDelegate(
185 &delegate, 9, gfx::Rect(0, 0, 100, 100), root_window));
186 scoped_ptr<aura::Window> window1(
187 aura::test::CreateTestWindowWithDelegate(
188 &delegate, 10, gfx::Rect(0, 0, 100, 50), window0.get()));
189 scoped_ptr<aura::Window> window2(
190 aura::test::CreateTestWindowWithDelegate(
191 &delegate, 11, gfx::Rect(0, 50, 100, 50), window0.get()));
193 const int kTouchId = 5;
195 // Capture first window.
196 window1->SetCapture();
197 EXPECT_TRUE(window1->HasCapture());
199 // Send touch event to first window.
200 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
203 ui::EventTimeForNow());
204 ui::EventDispatchDetails details =
205 root_window->GetHost()->dispatcher()->OnEventFromSource(&press);
206 ASSERT_FALSE(details.dispatcher_destroyed);
207 EXPECT_TRUE(window1->HasCapture());
209 base::OneShotTimer<LongPressAffordanceHandler>* timer =
210 GetLongPressAffordanceTimer();
211 EXPECT_TRUE(timer->IsRunning());
212 EXPECT_EQ(window1, GetLongPressAffordanceTarget());
214 // Force timeout so that the affordance animation can start.
215 timer->user_task().Run();
217 EXPECT_TRUE(GetLongPressAffordance()->is_animating());
220 window2->SetCapture();
221 EXPECT_TRUE(window2->HasCapture());
223 EXPECT_TRUE(GetLongPressAffordance()->is_animating());
224 EXPECT_EQ(window1, GetLongPressAffordanceTarget());
226 // Animate to completion.
227 GetLongPressAffordance()->End(); // end grow animation.
228 // Force timeout to start shrink animation.
229 EXPECT_TRUE(timer->IsRunning());
230 timer->user_task().Run();
232 EXPECT_TRUE(GetLongPressAffordance()->is_animating());
233 GetLongPressAffordance()->End(); // end shrink animation.
235 // Check if state has reset.
236 EXPECT_EQ(NULL, GetLongPressAffordanceTarget());
237 EXPECT_EQ(NULL, GetLongPressAffordanceView());
240 TEST_F(SystemGestureEventFilterTest, TwoFingerDrag) {
241 gfx::Rect bounds(0, 0, 600, 600);
242 aura::Window* root_window = Shell::GetPrimaryRootWindow();
243 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
244 new ResizableWidgetDelegate, root_window, bounds);
247 const int kSteps = 15;
248 const int kTouchPoints = 2;
249 gfx::Point points[kTouchPoints] = {
250 gfx::Point(250, 250),
251 gfx::Point(350, 350),
254 ui::test::EventGenerator generator(root_window, toplevel->GetNativeWindow());
256 wm::WindowState* toplevel_state =
257 wm::GetWindowState(toplevel->GetNativeWindow());
258 // Swipe down to minimize.
259 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
260 EXPECT_TRUE(toplevel_state->IsMinimized());
263 toplevel->GetNativeWindow()->SetBounds(bounds);
265 // Swipe up to maximize.
266 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, -150);
267 EXPECT_TRUE(toplevel_state->IsMaximized());
270 toplevel->GetNativeWindow()->SetBounds(bounds);
272 // Swipe right to snap.
273 gfx::Rect normal_bounds = toplevel->GetWindowBoundsInScreen();
274 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
275 gfx::Rect right_tile_bounds = toplevel->GetWindowBoundsInScreen();
276 EXPECT_NE(normal_bounds.ToString(), right_tile_bounds.ToString());
278 // Swipe left to snap.
279 gfx::Point left_points[kTouchPoints];
280 for (int i = 0; i < kTouchPoints; ++i) {
281 left_points[i] = points[i];
282 left_points[i].Offset(right_tile_bounds.x(), right_tile_bounds.y());
284 generator.GestureMultiFingerScroll(kTouchPoints, left_points, 15, kSteps,
286 gfx::Rect left_tile_bounds = toplevel->GetWindowBoundsInScreen();
287 EXPECT_NE(normal_bounds.ToString(), left_tile_bounds.ToString());
288 EXPECT_NE(right_tile_bounds.ToString(), left_tile_bounds.ToString());
290 // Swipe right again.
291 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
292 gfx::Rect current_bounds = toplevel->GetWindowBoundsInScreen();
293 EXPECT_NE(current_bounds.ToString(), left_tile_bounds.ToString());
294 EXPECT_EQ(current_bounds.ToString(), right_tile_bounds.ToString());
297 TEST_F(SystemGestureEventFilterTest, TwoFingerDragTwoWindows) {
298 aura::Window* root_window = Shell::GetPrimaryRootWindow();
299 ui::GestureConfiguration::set_max_separation_for_gesture_touches_in_pixels(0);
300 views::Widget* first = views::Widget::CreateWindowWithContextAndBounds(
301 new ResizableWidgetDelegate, root_window, gfx::Rect(10, 0, 50, 100));
303 views::Widget* second = views::Widget::CreateWindowWithContextAndBounds(
304 new ResizableWidgetDelegate, root_window, gfx::Rect(100, 0, 100, 100));
307 // Start a two-finger drag on |first|, and then try to use another two-finger
308 // drag to move |second|. The attempt to move |second| should fail.
309 const gfx::Rect& first_bounds = first->GetWindowBoundsInScreen();
310 const gfx::Rect& second_bounds = second->GetWindowBoundsInScreen();
311 const int kSteps = 15;
312 const int kTouchPoints = 4;
313 gfx::Point points[kTouchPoints] = {
314 first_bounds.origin() + gfx::Vector2d(5, 5),
315 first_bounds.origin() + gfx::Vector2d(30, 10),
316 second_bounds.origin() + gfx::Vector2d(5, 5),
317 second_bounds.origin() + gfx::Vector2d(40, 20)
320 ui::test::EventGenerator generator(root_window);
321 // Do not drag too fast to avoid fling.
322 generator.GestureMultiFingerScroll(kTouchPoints, points,
325 EXPECT_NE(first_bounds.ToString(),
326 first->GetWindowBoundsInScreen().ToString());
327 EXPECT_EQ(second_bounds.ToString(),
328 second->GetWindowBoundsInScreen().ToString());
331 TEST_F(SystemGestureEventFilterTest, WindowsWithMaxSizeDontSnap) {
332 gfx::Rect bounds(250, 150, 100, 100);
333 aura::Window* root_window = Shell::GetPrimaryRootWindow();
334 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
335 new MaxSizeWidgetDelegate, root_window, bounds);
338 const int kSteps = 15;
339 const int kTouchPoints = 2;
340 gfx::Point points[kTouchPoints] = {
341 gfx::Point(bounds.x() + 10, bounds.y() + 30),
342 gfx::Point(bounds.x() + 30, bounds.y() + 20),
345 ui::test::EventGenerator generator(root_window, toplevel->GetNativeWindow());
347 // Swipe down to minimize.
348 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
349 wm::WindowState* toplevel_state =
350 wm::GetWindowState(toplevel->GetNativeWindow());
351 EXPECT_TRUE(toplevel_state->IsMinimized());
354 toplevel->GetNativeWindow()->SetBounds(bounds);
356 // Check that swiping up doesn't maximize.
357 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, -150);
358 EXPECT_FALSE(toplevel_state->IsMaximized());
361 toplevel->GetNativeWindow()->SetBounds(bounds);
363 // Check that swiping right doesn't snap.
364 gfx::Rect normal_bounds = toplevel->GetWindowBoundsInScreen();
365 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
366 normal_bounds.set_x(normal_bounds.x() + 150);
367 EXPECT_EQ(normal_bounds.ToString(),
368 toplevel->GetWindowBoundsInScreen().ToString());
370 toplevel->GetNativeWindow()->SetBounds(bounds);
372 // Check that swiping left doesn't snap.
373 normal_bounds = toplevel->GetWindowBoundsInScreen();
374 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, -150, 0);
375 normal_bounds.set_x(normal_bounds.x() - 150);
376 EXPECT_EQ(normal_bounds.ToString(),
377 toplevel->GetWindowBoundsInScreen().ToString());
379 toplevel->GetNativeWindow()->SetBounds(bounds);
381 // Swipe right again, make sure the window still doesn't snap.
382 normal_bounds = toplevel->GetWindowBoundsInScreen();
383 normal_bounds.set_x(normal_bounds.x() + 150);
384 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 150, 0);
385 EXPECT_EQ(normal_bounds.ToString(),
386 toplevel->GetWindowBoundsInScreen().ToString());
389 TEST_F(SystemGestureEventFilterTest, DISABLED_TwoFingerDragEdge) {
390 gfx::Rect bounds(0, 0, 200, 100);
391 aura::Window* root_window = Shell::GetPrimaryRootWindow();
392 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
393 new ResizableWidgetDelegate, root_window, bounds);
396 const int kSteps = 15;
397 const int kTouchPoints = 2;
398 gfx::Point points[kTouchPoints] = {
399 gfx::Point(30, 20), // Caption
400 gfx::Point(0, 40), // Left edge
403 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
404 GetNonClientComponent(points[0]));
405 EXPECT_EQ(HTLEFT, toplevel->GetNativeWindow()->delegate()->
406 GetNonClientComponent(points[1]));
408 ui::test::EventGenerator generator(root_window, toplevel->GetNativeWindow());
410 bounds = toplevel->GetNativeWindow()->bounds();
411 // Swipe down. Nothing should happen.
412 generator.GestureMultiFingerScroll(kTouchPoints, points, 15, kSteps, 0, 150);
413 EXPECT_EQ(bounds.ToString(),
414 toplevel->GetNativeWindow()->bounds().ToString());
417 // We do not allow resizing a window via multiple edges simultaneously. Test
418 // that the behavior is reasonable if a user attempts to resize a window via
420 TEST_F(SystemGestureEventFilterTest,
421 TwoFingerAttemptResizeLeftAndRightEdgesSimultaneously) {
422 gfx::Rect initial_bounds(0, 0, 400, 400);
423 views::Widget* toplevel =
424 views::Widget::CreateWindowWithContextAndBounds(
425 new ResizableWidgetDelegate, CurrentContext(), initial_bounds);
428 const int kSteps = 15;
429 const int kTouchPoints = 2;
430 gfx::Point points[kTouchPoints] = {
431 gfx::Point(0, 40), // Left edge
432 gfx::Point(399, 40), // Right edge
434 int delays[kTouchPoints] = {0, 120};
436 EXPECT_EQ(HTLEFT, toplevel->GetNonClientComponent(points[0]));
437 EXPECT_EQ(HTRIGHT, toplevel->GetNonClientComponent(points[1]));
439 GetEventGenerator().GestureMultiFingerScrollWithDelays(
440 kTouchPoints, points, delays, 15, kSteps, 0, 40);
442 // The window bounds should not have changed because neither of the fingers
443 // moved horizontally.
444 EXPECT_EQ(initial_bounds.ToString(),
445 toplevel->GetNativeWindow()->bounds().ToString());
448 TEST_F(SystemGestureEventFilterTest, TwoFingerDragDelayed) {
449 gfx::Rect bounds(0, 0, 200, 100);
450 aura::Window* root_window = Shell::GetPrimaryRootWindow();
451 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
452 new ResizableWidgetDelegate, root_window, bounds);
455 const int kSteps = 15;
456 const int kTouchPoints = 2;
457 gfx::Point points[kTouchPoints] = {
458 gfx::Point(30, 20), // Caption
459 gfx::Point(34, 20), // Caption
461 int delays[kTouchPoints] = {0, 120};
463 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
464 GetNonClientComponent(points[0]));
465 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
466 GetNonClientComponent(points[1]));
468 ui::test::EventGenerator generator(root_window, toplevel->GetNativeWindow());
470 bounds = toplevel->GetNativeWindow()->bounds();
471 // Swipe right and down starting with one finger.
472 // Add another finger after 120ms and continue dragging.
473 // The window should move and the drag should be determined by the center
474 // point between the fingers.
475 generator.GestureMultiFingerScrollWithDelays(
476 kTouchPoints, points, delays, 15, kSteps, 150, 150);
477 bounds += gfx::Vector2d(150 + (points[1].x() - points[0].x()) / 2, 150);
478 EXPECT_EQ(bounds.ToString(),
479 toplevel->GetNativeWindow()->bounds().ToString());
482 TEST_F(SystemGestureEventFilterTest, ThreeFingerGestureStopsDrag) {
483 gfx::Rect bounds(0, 0, 200, 100);
484 aura::Window* root_window = Shell::GetPrimaryRootWindow();
485 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
486 new ResizableWidgetDelegate, root_window, bounds);
489 const int kSteps = 10;
490 const int kTouchPoints = 3;
491 gfx::Point points[kTouchPoints] = {
492 gfx::Point(30, 20), // Caption
493 gfx::Point(34, 20), // Caption
494 gfx::Point(38, 20), // Caption
496 int delays[kTouchPoints] = {0, 0, 120};
498 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
499 GetNonClientComponent(points[0]));
500 EXPECT_EQ(HTCAPTION, toplevel->GetNativeWindow()->delegate()->
501 GetNonClientComponent(points[1]));
503 ui::test::EventGenerator generator(root_window, toplevel->GetNativeWindow());
505 bounds = toplevel->GetNativeWindow()->bounds();
506 // Swipe right and down starting with two fingers.
507 // Add third finger after 120ms and continue dragging.
508 // The window should start moving but stop when the 3rd finger touches down.
509 const int kEventSeparation = 15;
510 generator.GestureMultiFingerScrollWithDelays(
511 kTouchPoints, points, delays, kEventSeparation, kSteps, 150, 150);
512 int expected_drag = 150 / kSteps * 120 / kEventSeparation;
513 bounds += gfx::Vector2d(expected_drag, expected_drag);
514 EXPECT_EQ(bounds.ToString(),
515 toplevel->GetNativeWindow()->bounds().ToString());
518 TEST_F(SystemGestureEventFilterTest, DragLeftNearEdgeSnaps) {
519 gfx::Rect bounds(200, 150, 400, 100);
520 aura::Window* root_window = Shell::GetPrimaryRootWindow();
521 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
522 new ResizableWidgetDelegate, root_window, bounds);
525 const int kSteps = 15;
526 const int kTouchPoints = 2;
527 gfx::Point points[kTouchPoints] = {
528 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
529 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
531 aura::Window* toplevel_window = toplevel->GetNativeWindow();
532 ui::test::EventGenerator generator(root_window, toplevel_window);
534 // Check that dragging left snaps before reaching the screen edge.
535 gfx::Rect work_area =
536 Shell::GetScreen()->GetDisplayNearestWindow(root_window).work_area();
537 int drag_x = work_area.x() + 20 - points[0].x();
538 generator.GestureMultiFingerScroll(
539 kTouchPoints, points, 120, kSteps, drag_x, 0);
541 EXPECT_EQ(wm::GetDefaultLeftSnappedWindowBoundsInParent(
542 toplevel_window).ToString(),
543 toplevel_window->bounds().ToString());
546 TEST_F(SystemGestureEventFilterTest, DragRightNearEdgeSnaps) {
547 gfx::Rect bounds(200, 150, 400, 100);
548 aura::Window* root_window = Shell::GetPrimaryRootWindow();
549 views::Widget* toplevel = views::Widget::CreateWindowWithContextAndBounds(
550 new ResizableWidgetDelegate, root_window, bounds);
553 const int kSteps = 15;
554 const int kTouchPoints = 2;
555 gfx::Point points[kTouchPoints] = {
556 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
557 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
559 aura::Window* toplevel_window = toplevel->GetNativeWindow();
560 ui::test::EventGenerator generator(root_window, toplevel_window);
562 // Check that dragging right snaps before reaching the screen edge.
563 gfx::Rect work_area =
564 Shell::GetScreen()->GetDisplayNearestWindow(root_window).work_area();
565 int drag_x = work_area.right() - 20 - points[0].x();
566 generator.GestureMultiFingerScroll(
567 kTouchPoints, points, 120, kSteps, drag_x, 0);
568 EXPECT_EQ(wm::GetDefaultRightSnappedWindowBoundsInParent(
569 toplevel_window).ToString(),
570 toplevel_window->bounds().ToString());
573 // Tests that the window manager does not consume gesture events targeted to
574 // windows of type WINDOW_TYPE_CONTROL. This is important because the web
575 // contents are often (but not always) of type WINDOW_TYPE_CONTROL.
576 TEST_F(SystemGestureEventFilterTest,
577 ControlWindowGetsMultiFingerGestureEvents) {
578 scoped_ptr<aura::Window> parent(
579 CreateTestWindowInShellWithBounds(gfx::Rect(100, 100)));
581 aura::test::EventCountDelegate delegate;
582 delegate.set_window_component(HTCLIENT);
583 scoped_ptr<aura::Window> child(new aura::Window(&delegate));
584 child->SetType(ui::wm::WINDOW_TYPE_CONTROL);
585 child->Init(aura::WINDOW_LAYER_TEXTURED);
586 parent->AddChild(child.get());
587 child->SetBounds(gfx::Rect(100, 100));
590 ui::test::TestEventHandler event_handler;
591 aura::Env::GetInstance()->PrependPreTargetHandler(&event_handler);
593 GetEventGenerator().MoveMouseTo(0, 0);
594 for (int i = 1; i <= 3; ++i)
595 GetEventGenerator().PressTouchId(i);
596 for (int i = 1; i <= 3; ++i)
597 GetEventGenerator().ReleaseTouchId(i);
598 EXPECT_EQ(event_handler.num_gesture_events(),
599 delegate.GetGestureCountAndReset());
601 aura::Env::GetInstance()->RemovePreTargetHandler(&event_handler);