diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/ui/aura | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) | |
download | qtwebengine-chromium-ab0a50979b9eb4dfa3320eff7e187e41efedf7a9.tar.gz |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/ui/aura')
88 files changed, 7667 insertions, 8395 deletions
diff --git a/chromium/ui/aura/BUILD.gn b/chromium/ui/aura/BUILD.gn new file mode 100644 index 00000000000..5f177e979a9 --- /dev/null +++ b/chromium/ui/aura/BUILD.gn @@ -0,0 +1,303 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import ("//build/config/ui.gni") + +component("aura") { + sources = [ + "client/aura_constants.cc", + "client/aura_constants.h", + "client/capture_client.cc", + "client/capture_client.h", + "client/capture_delegate.h", + "client/cursor_client.cc", + "client/cursor_client.h", + "client/cursor_client_observer.h", + "client/cursor_client_observer.cc", + "client/default_capture_client.cc", + "client/default_capture_client.h", + "client/event_client.cc", + "client/event_client.h", + "client/focus_change_observer.cc", + "client/focus_change_observer.h", + "client/focus_client.cc", + "client/focus_client.h", + "client/screen_position_client.cc", + "client/screen_position_client.h", + "client/visibility_client.cc", + "client/visibility_client.h", + "client/window_stacking_client.cc", + "client/window_stacking_client.h", + "client/window_tree_client.cc", + "client/window_tree_client.h", + "env.cc", + "env.h", + "env_observer.h", + "input_state_lookup.cc", + "input_state_lookup.h", + "input_state_lookup_win.cc", + "input_state_lookup_win.h", + "layout_manager.cc", + "layout_manager.h", + "remote_window_tree_host_win.cc", + "remote_window_tree_host_win.h", + "scoped_window_targeter.cc", + "scoped_window_targeter.h", + "window.cc", + "window.h", + "window_event_dispatcher.cc", + "window_event_dispatcher.h", + "window_delegate.h", + "window_layer_type.h", + "window_observer.h", + "window_targeter.cc", + "window_targeter.h", + "window_tracker.cc", + "window_tracker.h", + "window_tree_host.cc", + "window_tree_host.h", + "window_tree_host_mac.mm", + "window_tree_host_mac.h", + "window_tree_host_observer.h", + "window_tree_host_win.cc", + "window_tree_host_win.h", + "window_tree_host_x11.cc", + "window_tree_host_x11.h", + "../wm/public/activation_change_observer.h", + "../wm/public/activation_change_observer.cc", + "../wm/public/activation_client.cc", + "../wm/public/activation_client.h", + "../wm/public/activation_delegate.cc", + "../wm/public/activation_delegate.h", + "../wm/public/animation_host.cc", + "../wm/public/animation_host.h", + "../wm/public/dispatcher_client.cc", + "../wm/public/dispatcher_client.h", + "../wm/public/drag_drop_client.cc", + "../wm/public/drag_drop_client.h", + "../wm/public/drag_drop_delegate.cc", + "../wm/public/drag_drop_delegate.h", + "../wm/public/scoped_tooltip_disabler.cc", + "../wm/public/scoped_tooltip_disabler.h", + "../wm/public/tooltip_client.cc", + "../wm/public/tooltip_client.h", + "../wm/public/transient_window_client.cc", + "../wm/public/transient_window_client.h", + "../wm/public/window_move_client.cc", + "../wm/public/window_move_client.h", + ] + + defines = [ + "AURA_IMPLEMENTATION", + ] + + deps = [ + "//base", + "//base:i18n", + "//base/third_party/dynamic_annotations", + "//skia", + "//ui/base", + "//ui/compositor", + "//ui/events", + "//ui/events/platform", + "//ui/gfx", + "//ui/gfx/geometry", + ] + + if (use_x11) { + configs += [ + "//build/config/linux:x11", + "//build/config/linux:xrandr", + ] + deps += [ + "//ui/events/platform/x11", + ] + } + + if (is_win) { + sources -= [ + "input_state_lookup.cc", + ] + + deps += [ + "//ui/metro_viewer", + "//ipc", + ] + } + + if (use_ozone) { + sources += [ + "window_tree_host_ozone.cc", + "window_tree_host_ozone.h", + ] + + # TODO(GYP) enable when these targets exist. + #deps += [ + # "//ui/events/ozone", + # "//ui/ozone", + #] + } +} + +source_set("aura_test_support") { + sources = [ + "test/aura_test_base.cc", + "test/aura_test_base.h", + "test/aura_test_helper.cc", + "test/aura_test_helper.h", + "test/aura_test_utils.cc", + "test/aura_test_utils.h", + "test/env_test_helper.h", + "test/event_generator.cc", + "test/event_generator.h", + "test/test_cursor_client.cc", + "test/test_cursor_client.h", + "test/test_focus_client.cc", + "test/test_focus_client.h", + "test/test_screen.cc", + "test/test_screen.h", + "test/test_window_tree_client.cc", + "test/test_window_tree_client.h", + "test/test_windows.cc", + "test/test_windows.h", + "test/test_window_delegate.cc", + "test/test_window_delegate.h", + "test/ui_controls_factory_aura.h", + "test/window_test_api.cc", + "test/window_test_api.h", + ] + + deps = [ + ":aura", + "//skia", + "//testing/gtest", + "//ui/base", + "//ui/base:ui_base_test_support", + "//ui/compositor:test_support", + "//ui/events", + "//ui/events:events_base", + "//ui/events:events_test_support", + "//ui/gfx", + "//ui/gfx/geometry", + ] + + if (is_win) { + cflags = [ + "/wd4267", # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + ] + } + + if (use_aura) { + if (is_win) { + sources += [ + "test/ui_controls_factory_aurawin.cc", + ] + } + + if (use_x11) { + sources += [ + "test/ui_controls_factory_aurax11.cc", + ] + } + } +} + +#TODO(GYP): Enable this when everything it depends links. +#executable("aura_demo") { +# sources = [ +# "demo/demo_main.cc", +# ] +# +# deps = [ +# ":aura", +# ":aura_test_support", +# "//base", +# "//base:i18n", +# "//skia", +# "//third_party/icu", +# "//ui/base", +# "//ui/compositor", +# "//ui/compositor:test_support", +# "//ui/events", +# "//ui/gfx", +# "//ui/gfx/geometry", +# ] +# +# if (use_x11) { +# deps += [ +# "//ui/gfx/x", +# ] +# } +#} + +#TODO(GYP): Enable this when everything it depends links. +#executable("aura_bench") { +# sources = [ +# "bench/bench_main.cc", +# ] +# +# deps = [ +# ":aura", +# ":aura_test_support", +# "//base", +# "//base:i18n", +# "//cc", +# "//skia", +# "//third_party/icu", +# "//ui/base", +# "//ui/compositor", +# "//ui/compositor:test_support", +# "//ui/events", +# "//ui/gfx", +# "//ui/gfx/geometry", +# ] +# +# if (use_x11) { +# deps += [ +# "//ui/gfx/x", +# ] +# } +#} + +#TODO(GYP): Enable this when everything it depends links. +#test("aura_unittests") { +# sources = [ +# "gestures/gesture_recognizer_unittest.cc", +# "test/run_all_unittests.cc", +# "window_event_dispatcher_unittest.cc", +# "window_targeter_unittest.cc", +# "window_unittest.cc", +# ] +# +# deps = [ +# ":aura", +# ":aura_test_support", +# "//base/test:test_support", +# "//skia", +# "//testing/gtest", +# "//ui/base", +# "//ui/base:ui_base_test_support", +# "//ui/compositor", +# "//ui/compositor:test_support", +# "//ui/events", +# "//ui/events:events_base", +# "//ui/events:gesture_detection", +# "//ui/gfx", +# "//ui/gfx/geometry", +# "//ui/gl", +# ] +# +# if (is_linux) { +# deps += [ +# #"<(DEPTH)/third_party/mesa/mesa.gyp:osmesa", +# ] +# } +# +# if (is_linux) { # && use_allocator != "none") { +# deps += [ +# # See http://crbug.com/162998#c4 for why this is needed. +# "//base/allocator", +# ] +# } +#} diff --git a/chromium/ui/aura/DEPS b/chromium/ui/aura/DEPS index c2522180289..f8d111d6eab 100644 --- a/chromium/ui/aura/DEPS +++ b/chromium/ui/aura/DEPS @@ -1,6 +1,4 @@ include_rules = [ - "+grit/ui_resources.h", - "+grit/ui_strings.h", "+skia/ext", "+third_party/skia", "+ui/base", @@ -10,5 +8,6 @@ include_rules = [ "+ui/metro_viewer", # TODO(beng): investigate moving remote_root_window_host # to ui/metro_viewer. "+ui/ozone", + "+ui/wm/public", ] diff --git a/chromium/ui/aura/aura.gyp b/chromium/ui/aura/aura.gyp index 68164d4321a..56ef7987b44 100644 --- a/chromium/ui/aura/aura.gyp +++ b/chromium/ui/aura/aura.gyp @@ -14,28 +14,19 @@ '../../base/base.gyp:base', '../../base/base.gyp:base_i18n', '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - '../../cc/cc.gyp:cc', - '../../gpu/gpu.gyp:gpu', '../../skia/skia.gyp:skia', + '../base/ui_base.gyp:ui_base', '../compositor/compositor.gyp:compositor', '../events/events.gyp:events', '../events/events.gyp:events_base', + '../events/platform/events_platform.gyp:events_platform', '../gfx/gfx.gyp:gfx', - '../resources/ui_resources.gyp:ui_resources', - '../ui.gyp:ui', + '../gfx/gfx.gyp:gfx_geometry', ], 'defines': [ 'AURA_IMPLEMENTATION', ], 'sources': [ - 'client/activation_change_observer.h', - 'client/activation_change_observer.cc', - 'client/activation_client.cc', - 'client/activation_client.h', - 'client/activation_delegate.cc', - 'client/activation_delegate.h', - 'client/animation_host.cc', - 'client/animation_host.h', 'client/aura_constants.cc', 'client/aura_constants.h', 'client/capture_client.cc', @@ -45,16 +36,8 @@ 'client/cursor_client.h', 'client/cursor_client_observer.h', 'client/cursor_client_observer.cc', - 'client/default_activation_client.cc', - 'client/default_activation_client.h', 'client/default_capture_client.cc', 'client/default_capture_client.h', - 'client/dispatcher_client.cc', - 'client/dispatcher_client.h', - 'client/drag_drop_client.cc', - 'client/drag_drop_client.h', - 'client/drag_drop_delegate.cc', - 'client/drag_drop_delegate.h', 'client/event_client.cc', 'client/event_client.h', 'client/focus_change_observer.cc', @@ -63,22 +46,12 @@ 'client/focus_client.h', 'client/screen_position_client.cc', 'client/screen_position_client.h', - 'client/tooltip_client.cc', - 'client/tooltip_client.h', - 'client/user_action_client.cc', - 'client/user_action_client.h', 'client/visibility_client.cc', 'client/visibility_client.h', - 'client/window_move_client.cc', - 'client/window_move_client.h', 'client/window_stacking_client.cc', 'client/window_stacking_client.h', 'client/window_tree_client.cc', 'client/window_tree_client.h', - 'client/window_types.h', - 'device_list_updater_aurax11.cc', - 'device_list_updater_aurax11.h', - 'dispatcher_win.cc', 'env.cc', 'env.h', 'env_observer.h', @@ -88,40 +61,64 @@ 'input_state_lookup_win.h', 'layout_manager.cc', 'layout_manager.h', - 'remote_root_window_host_win.cc', - 'remote_root_window_host_win.h', - 'root_window_host_ozone.cc', - 'root_window_host_ozone.h', - 'root_window_host_win.cc', - 'root_window_host_win.h', - 'root_window_host_x11.cc', - 'root_window_host_x11.h', - 'root_window_transformer.h', - 'root_window.cc', - 'root_window.h', + 'remote_window_tree_host_win.cc', + 'remote_window_tree_host_win.h', + 'scoped_window_targeter.cc', + 'scoped_window_targeter.h', 'window.cc', 'window.h', - 'window_targeter.cc', - 'window_targeter.h', + 'window_event_dispatcher.cc', + 'window_event_dispatcher.h', 'window_delegate.h', 'window_layer_type.h', + 'window_observer.cc', 'window_observer.h', + 'window_targeter.cc', + 'window_targeter.h', 'window_tracker.cc', 'window_tracker.h', 'window_tree_host.cc', 'window_tree_host.h', - 'window_tree_host_delegate.h', + 'window_tree_host_mac.mm', + 'window_tree_host_mac.h', + 'window_tree_host_observer.h', + 'window_tree_host_ozone.cc', + 'window_tree_host_ozone.h', + 'window_tree_host_win.cc', + 'window_tree_host_win.h', + 'window_tree_host_x11.cc', + 'window_tree_host_x11.h', + '../wm/public/activation_change_observer.h', + '../wm/public/activation_change_observer.cc', + '../wm/public/activation_client.cc', + '../wm/public/activation_client.h', + '../wm/public/activation_delegate.cc', + '../wm/public/activation_delegate.h', + '../wm/public/animation_host.cc', + '../wm/public/animation_host.h', + '../wm/public/dispatcher_client.cc', + '../wm/public/dispatcher_client.h', + '../wm/public/drag_drop_client.cc', + '../wm/public/drag_drop_client.h', + '../wm/public/drag_drop_delegate.cc', + '../wm/public/drag_drop_delegate.h', + '../wm/public/scoped_tooltip_disabler.cc', + '../wm/public/scoped_tooltip_disabler.h', + '../wm/public/tooltip_client.cc', + '../wm/public/tooltip_client.h', + '../wm/public/transient_window_client.cc', + '../wm/public/transient_window_client.h', + '../wm/public/window_move_client.cc', + '../wm/public/window_move_client.h', ], 'conditions': [ ['use_x11==1', { - 'link_settings': { - 'libraries': [ - '-lX11', - '-lXi', - '-lXfixes', - '-lXrandr', - ], - }, + 'dependencies': [ + '../../build/linux/system.gyp:x11', + '../../build/linux/system.gyp:xrandr', + '../../build/linux/system.gyp:xi', + '../events/platform/x11/x11_events_platform.gyp:x11_events_platform', + ], }], ['OS=="win"', { 'dependencies': [ @@ -134,6 +131,7 @@ }], ['use_ozone==1', { 'dependencies': [ + '../events/ozone/events_ozone.gyp:events_ozone', '../ozone/ozone.gyp:ozone', ], }], @@ -145,13 +143,14 @@ 'dependencies': [ '../../skia/skia.gyp:skia', '../../testing/gtest.gyp:gtest', + '../base/ui_base.gyp:ui_base', + '../base/ui_base.gyp:ui_base_test_support', '../compositor/compositor.gyp:compositor_test_support', '../events/events.gyp:events', '../events/events.gyp:events_base', '../events/events.gyp:events_test_support', '../gfx/gfx.gyp:gfx', - '../ui.gyp:ui', - '../ui_unittests.gyp:ui_test_support', + '../gfx/gfx.gyp:gfx_geometry', 'aura', ], 'include_dirs': [ @@ -162,13 +161,13 @@ 'test/aura_test_base.h', 'test/aura_test_helper.cc', 'test/aura_test_helper.h', + 'test/aura_test_utils.cc', + 'test/aura_test_utils.h', 'test/env_test_helper.h', 'test/event_generator.cc', 'test/event_generator.h', 'test/test_cursor_client.cc', 'test/test_cursor_client.h', - 'test/test_event_handler.cc', - 'test/test_event_handler.h', 'test/test_focus_client.cc', 'test/test_focus_client.h', 'test/test_screen.cc', @@ -197,12 +196,12 @@ '../../skia/skia.gyp:skia', '../../third_party/icu/icu.gyp:icui18n', '../../third_party/icu/icu.gyp:icuuc', + '../base/ui_base.gyp:ui_base', '../compositor/compositor.gyp:compositor', '../compositor/compositor.gyp:compositor_test_support', '../events/events.gyp:events', '../gfx/gfx.gyp:gfx', - '../resources/ui_resources.gyp:ui_resources', - '../ui.gyp:ui', + '../gfx/gfx.gyp:gfx_geometry', 'aura', 'aura_test_support', ], @@ -212,6 +211,13 @@ 'sources': [ 'demo/demo_main.cc', ], + 'conditions': [ + ['use_x11==1', { + 'dependencies': [ + '../gfx/x/gfx_x11.gyp:gfx_x11', + ], + }], + ] }, { 'target_name': 'aura_bench', @@ -219,15 +225,17 @@ 'dependencies': [ '../../base/base.gyp:base', '../../base/base.gyp:base_i18n', + '../../cc/cc.gyp:cc', + '../../gpu/gpu.gyp:gles2_implementation', '../../skia/skia.gyp:skia', '../../third_party/icu/icu.gyp:icui18n', '../../third_party/icu/icu.gyp:icuuc', + '../base/ui_base.gyp:ui_base', '../compositor/compositor.gyp:compositor', '../compositor/compositor.gyp:compositor_test_support', '../events/events.gyp:events', '../gfx/gfx.gyp:gfx', - '../resources/ui_resources.gyp:ui_resources', - '../ui.gyp:ui', + '../gfx/gfx.gyp:gfx_geometry', 'aura', 'aura_test_support', ], @@ -237,24 +245,31 @@ 'sources': [ 'bench/bench_main.cc', ], + 'conditions': [ + ['use_x11==1', { + 'dependencies': [ + '../gfx/x/gfx_x11.gyp:gfx_x11', + ], + }], + ] }, { 'target_name': 'aura_unittests', 'type': 'executable', 'dependencies': [ '../../base/base.gyp:test_support_base', - '../../chrome/chrome_resources.gyp:packed_resources', '../../skia/skia.gyp:skia', '../../testing/gtest.gyp:gtest', + '../base/ui_base.gyp:ui_base', + '../base/ui_base.gyp:ui_base_test_support', '../compositor/compositor.gyp:compositor', '../compositor/compositor.gyp:compositor_test_support', '../events/events.gyp:events', '../events/events.gyp:events_base', + '../events/events.gyp:gesture_detection', '../gfx/gfx.gyp:gfx', + '../gfx/gfx.gyp:gfx_geometry', '../gl/gl.gyp:gl', - '../resources/ui_resources.gyp:ui_resources', - '../ui.gyp:ui', - '../ui_unittests.gyp:ui_test_support', 'aura_test_support', 'aura', ], @@ -263,11 +278,8 @@ ], 'sources': [ 'gestures/gesture_recognizer_unittest.cc', - 'root_window_host_x11_unittest.cc', - 'root_window_unittest.cc', + 'window_event_dispatcher_unittest.cc', 'test/run_all_unittests.cc', - 'test/test_suite.cc', - 'test/test_suite.h', 'window_targeter_unittest.cc', 'window_unittest.cc', ], @@ -278,7 +290,7 @@ '<(DEPTH)/third_party/mesa/mesa.gyp:osmesa', ], }], - ['OS=="linux" and linux_use_tcmalloc==1', { + ['OS=="linux" and use_allocator!="none"', { 'dependencies': [ # See http://crbug.com/162998#c4 for why this is needed. '../../base/allocator/allocator.gyp:allocator', diff --git a/chromium/ui/aura/aura_export.h b/chromium/ui/aura/aura_export.h index 9db662bbf7e..1093040a0c1 100644 --- a/chromium/ui/aura/aura_export.h +++ b/chromium/ui/aura/aura_export.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_AURA_AURA_EXPORT_H -#define UI_AURA_AURA_EXPORT_H +#ifndef UI_AURA_AURA_EXPORT_H_ +#define UI_AURA_AURA_EXPORT_H_ // Defines AURA_EXPORT so that functionality implemented by the aura module // can be exported to consumers. @@ -29,4 +29,4 @@ #define AURA_EXPORT #endif -#endif // UI_AURA_AURA_EXPORT_H +#endif // UI_AURA_AURA_EXPORT_H_ diff --git a/chromium/ui/aura/bench/DEPS b/chromium/ui/aura/bench/DEPS index 70bd71ca290..7fa58f955ec 100644 --- a/chromium/ui/aura/bench/DEPS +++ b/chromium/ui/aura/bench/DEPS @@ -1,5 +1,7 @@ include_rules = [ "+cc", + "-cc/surfaces", "+gpu/command_buffer/client/gles2_interface.h", "+third_party/khronos", + "+ui/gl/gl_surface.h", # To initialize GL bindings. ] diff --git a/chromium/ui/aura/bench/bench_main.cc b/chromium/ui/aura/bench/bench_main.cc index 3f6717c80ce..b5dd3e75d3d 100644 --- a/chromium/ui/aura/bench/bench_main.cc +++ b/chromium/ui/aura/bench/bench_main.cc @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#if defined(USE_X11) +#include <X11/Xlib.h> +#endif + #include "base/at_exit.h" #include "base/bind.h" #include "base/command_line.h" @@ -16,35 +20,31 @@ #include "third_party/skia/include/core/SkXfermode.h" #include "ui/aura/client/default_capture_client.h" #include "ui/aura/env.h" -#include "ui/aura/root_window.h" #include "ui/aura/test/test_focus_client.h" #include "ui/aura/test/test_screen.h" #include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" #include "ui/base/hit_test.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_base_paths.h" #include "ui/compositor/compositor.h" #include "ui/compositor/compositor_observer.h" #include "ui/compositor/debug_utils.h" #include "ui/compositor/layer.h" -#include "ui/compositor/test/context_factories_for_test.h" +#include "ui/compositor/test/in_process_context_factory.h" #include "ui/gfx/canvas.h" #include "ui/gfx/rect.h" #include "ui/gfx/skia_util.h" +#include "ui/gfx/x/x11_connection.h" +#include "ui/gl/gl_surface.h" + #ifndef GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES 1 #endif #include "third_party/khronos/GLES2/gl2ext.h" -#if defined(USE_X11) -#include "base/message_loop/message_pump_x11.h" -#endif - using base::TimeTicks; using ui::Compositor; using ui::Layer; using ui::LayerDelegate; -using blink::WebGraphicsContext3D; namespace { @@ -123,11 +123,6 @@ class BenchCompositorObserver : public ui::CompositorObserver { virtual void OnCompositingLockStateChanged( Compositor* compositor) OVERRIDE {} - virtual void OnUpdateVSyncParameters(ui::Compositor* compositor, - base::TimeTicks timebase, - base::TimeDelta interval) OVERRIDE { - } - virtual void Draw() {} int frames() const { return frames_; } @@ -140,46 +135,27 @@ class BenchCompositorObserver : public ui::CompositorObserver { DISALLOW_COPY_AND_ASSIGN(BenchCompositorObserver); }; -class WebGLTexture : public ui::Texture { - public: - WebGLTexture(gpu::gles2::GLES2Interface* gl, const gfx::Size& size) - : ui::Texture(false, size, 1.0f), - gl_(gl), - texture_id_(0u) { - gl->GenTextures(1, &texture_id_); - gl->BindTexture(GL_TEXTURE_2D, texture_id_); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), - 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - - virtual unsigned int PrepareTexture() OVERRIDE { - return texture_id_; - } - - private: - virtual ~WebGLTexture() { - gl_->DeleteTextures(1, &texture_id_); - } - - gpu::gles2::GLES2Interface* gl_; - GLuint texture_id_; - - DISALLOW_COPY_AND_ASSIGN(WebGLTexture); -}; +void ReturnMailbox(scoped_refptr<cc::ContextProvider> context_provider, + GLuint texture, + GLuint sync_point, + bool is_lost) { + gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); + gl->WaitSyncPointCHROMIUM(sync_point); + gl->DeleteTextures(1, &texture); + gl->ShallowFlushCHROMIUM(); +} // A benchmark that adds a texture layer that is updated every frame. class WebGLBench : public BenchCompositorObserver { public: - WebGLBench(Layer* parent, Compositor* compositor, int max_frames) + WebGLBench(ui::ContextFactory* context_factory, + Layer* parent, + Compositor* compositor, + int max_frames) : BenchCompositorObserver(max_frames), parent_(parent), webgl_(ui::LAYER_TEXTURED), compositor_(compositor), - texture_(), fbo_(0), do_draw_(true) { CommandLine* command_line = CommandLine::ForCurrentProcess(); @@ -204,26 +180,49 @@ class WebGLBench : public BenchCompositorObserver { webgl_.SetBounds(bounds); parent_->Add(&webgl_); - context_provider_ = - ui::ContextFactory::GetInstance()->SharedMainThreadContextProvider(); + context_provider_ = context_factory->SharedMainThreadContextProvider(); gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); - texture_ = new WebGLTexture(gl, bounds.size()); + GLuint texture = 0; + gl->GenTextures(1, &texture); + gl->BindTexture(GL_TEXTURE_2D, texture); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl->TexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + width, + height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + NULL); + gpu::Mailbox mailbox; + gl->GenMailboxCHROMIUM(mailbox.name); + gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); + gl->GenFramebuffers(1, &fbo_); - compositor->AddObserver(this); - webgl_.SetExternalTexture(texture_.get()); gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); gl->FramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, texture_->PrepareTexture(), 0); + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); gl->ClearColor(0.f, 1.f, 0.f, 1.f); gl->Clear(GL_COLOR_BUFFER_BIT); gl->Flush(); + + GLuint sync_point = gl->InsertSyncPointCHROMIUM(); + webgl_.SetTextureMailbox( + cc::TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point), + cc::SingleReleaseCallback::Create( + base::Bind(ReturnMailbox, context_provider_, texture)), + bounds.size()); + compositor->AddObserver(this); } virtual ~WebGLBench() { - context_provider_->ContextGL()->DeleteFramebuffers(1, &fbo_); webgl_.SetShowPaintedContent(); - texture_ = NULL; + gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); + gl->DeleteFramebuffers(1, &fbo_); compositor_->RemoveObserver(this); } @@ -234,7 +233,6 @@ class WebGLBench : public BenchCompositorObserver { gl->Clear(GL_COLOR_BUFFER_BIT); gl->Flush(); } - webgl_.SetExternalTexture(texture_.get()); webgl_.SchedulePaint(gfx::Rect(webgl_.bounds().size())); compositor_->ScheduleDraw(); } @@ -244,7 +242,6 @@ class WebGLBench : public BenchCompositorObserver { Layer webgl_; Compositor* compositor_; scoped_refptr<cc::ContextProvider> context_provider_; - scoped_refptr<WebGLTexture> texture_; // The FBO that is used to render to the texture. unsigned int fbo_; @@ -293,33 +290,40 @@ int main(int argc, char** argv) { base::AtExitManager exit_manager; +#if defined(USE_X11) + // This demo uses InProcessContextFactory which uses X on a separate Gpu + // thread. + gfx::InitializeThreadedX11(); +#endif + + gfx::GLSurface::InitializeOneOff(); + // The ContextFactory must exist before any Compositors are created. - bool allow_test_contexts = false; - ui::InitializeContextFactoryForTests(allow_test_contexts); + scoped_ptr<ui::InProcessContextFactory> context_factory( + new ui::InProcessContextFactory()); - ui::RegisterPathProvider(); base::i18n::InitializeICU(); - ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL); - base::MessageLoop message_loop(base::MessageLoop::TYPE_UI); - aura::Env::CreateInstance(); + base::MessageLoopForUI message_loop; + aura::Env::CreateInstance(true); + aura::Env::GetInstance()->set_context_factory(context_factory.get()); scoped_ptr<aura::TestScreen> test_screen( aura::TestScreen::CreateFullscreen()); gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen.get()); - scoped_ptr<aura::RootWindow> root_window( - test_screen->CreateRootWindowForPrimaryDisplay()); + scoped_ptr<aura::WindowTreeHost> host( + test_screen->CreateHostForPrimaryDisplay()); aura::client::SetCaptureClient( - root_window->window(), - new aura::client::DefaultCaptureClient(root_window->window())); + host->window(), + new aura::client::DefaultCaptureClient(host->window())); scoped_ptr<aura::client::FocusClient> focus_client( new aura::test::TestFocusClient); - aura::client::SetFocusClient(root_window->window(), focus_client.get()); + aura::client::SetFocusClient(host->window(), focus_client.get()); // add layers ColoredLayer background(SK_ColorRED); - background.SetBounds(root_window->window()->bounds()); - root_window->window()->layer()->Add(&background); + background.SetBounds(host->window()->bounds()); + host->window()->layer()->Add(&background); ColoredLayer window(SK_ColorBLUE); window.SetBounds(gfx::Rect(background.bounds().size())); @@ -344,22 +348,23 @@ int main(int argc, char** argv) { if (command_line->HasSwitch("bench-software-scroll")) { bench.reset(new SoftwareScrollBench(&page_background, - root_window->compositor(), + host->compositor(), frames)); } else { - bench.reset(new WebGLBench(&page_background, - root_window->compositor(), + bench.reset(new WebGLBench(context_factory.get(), + &page_background, + host->compositor(), frames)); } #ifndef NDEBUG - ui::PrintLayerHierarchy(root_window->window()->layer(), gfx::Point(100, 100)); + ui::PrintLayerHierarchy(host->window()->layer(), gfx::Point(100, 100)); #endif - root_window->host()->Show(); + host->Show(); base::MessageLoopForUI::current()->Run(); focus_client.reset(); - root_window.reset(); + host.reset(); return 0; } diff --git a/chromium/ui/aura/client/activation_change_observer.cc b/chromium/ui/aura/client/activation_change_observer.cc deleted file mode 100644 index db9f332cfae..00000000000 --- a/chromium/ui/aura/client/activation_change_observer.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/activation_change_observer.h" - -#include "ui/aura/window.h" -#include "ui/aura/window_property.h" - -DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ActivationChangeObserver*) - -namespace aura { -namespace client { - -DEFINE_LOCAL_WINDOW_PROPERTY_KEY( - ActivationChangeObserver*, kActivationChangeObserverKey, NULL); - -void SetActivationChangeObserver( - Window* window, - ActivationChangeObserver* observer) { - window->SetProperty(kActivationChangeObserverKey, observer); -} - -ActivationChangeObserver* GetActivationChangeObserver(Window* window) { - return window ? window->GetProperty(kActivationChangeObserverKey) : NULL; -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/activation_change_observer.h b/chromium/ui/aura/client/activation_change_observer.h deleted file mode 100644 index 2f247db04b3..00000000000 --- a/chromium/ui/aura/client/activation_change_observer.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_ACTIVATION_CHANGE_OBSERVER_H_ -#define UI_AURA_CLIENT_ACTIVATION_CHANGE_OBSERVER_H_ - -#include "ui/aura/aura_export.h" - -namespace aura { -class Window; - -namespace client { - -class AURA_EXPORT ActivationChangeObserver { - public: - // Called when |active| gains focus, or there is no active window - // (|active| is NULL in this case.) |old_active| refers to the - // previous active window or NULL if there was no previously active - // window. - virtual void OnWindowActivated(Window* gained_active, - Window* lost_active) = 0; - - // Called when during window activation the currently active window is - // selected for activation. This can happen when a window requested for - // activation cannot be activated because a system modal window is active. - virtual void OnAttemptToReactivateWindow(aura::Window* request_active, - aura::Window* actual_active) {} - - protected: - virtual ~ActivationChangeObserver() {} -}; - -// Gets/Sets the ActivationChangeObserver for a specific window. This observer -// is notified after the ActivationClient notifies all registered observers. -AURA_EXPORT void SetActivationChangeObserver( - Window* window, - ActivationChangeObserver* observer); -AURA_EXPORT ActivationChangeObserver* GetActivationChangeObserver( - Window* window); - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_ACTIVATION_CHANGE_OBSERVER_H_ diff --git a/chromium/ui/aura/client/activation_client.cc b/chromium/ui/aura/client/activation_client.cc deleted file mode 100644 index b4633aec5ab..00000000000 --- a/chromium/ui/aura/client/activation_client.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/activation_client.h" - -#include "ui/aura/root_window.h" -#include "ui/aura/window_property.h" - -DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, aura::Window*) -DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ActivationClient*) - -namespace aura { -namespace client { - -DEFINE_WINDOW_PROPERTY_KEY( - ActivationClient*, kRootWindowActivationClientKey, NULL); -DEFINE_WINDOW_PROPERTY_KEY(bool, kHideOnDeactivate, false); - -void SetActivationClient(Window* root_window, ActivationClient* client) { - root_window->SetProperty(kRootWindowActivationClientKey, client); -} - -ActivationClient* GetActivationClient(Window* root_window) { - return root_window ? - root_window->GetProperty(kRootWindowActivationClientKey) : NULL; -} - -void SetHideOnDeactivate(Window* window, bool hide_on_deactivate) { - window->SetProperty(kHideOnDeactivate, hide_on_deactivate); -} - -bool GetHideOnDeactivate(Window* window) { - return window->GetProperty(kHideOnDeactivate); -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/activation_client.h b/chromium/ui/aura/client/activation_client.h deleted file mode 100644 index 054829ec2aa..00000000000 --- a/chromium/ui/aura/client/activation_client.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_ACTIVATION_CLIENT_H_ -#define UI_AURA_CLIENT_ACTIVATION_CLIENT_H_ - -#include "ui/aura/aura_export.h" - -namespace ui { -class Event; -} - -namespace aura { -class Window; - -namespace client { -class ActivationChangeObserver; - -// An interface implemented by an object that manages window activation. -class AURA_EXPORT ActivationClient { - public: - // Adds/Removes ActivationChangeObservers. - virtual void AddObserver(ActivationChangeObserver* observer) = 0; - virtual void RemoveObserver(ActivationChangeObserver* observer) = 0; - - // Activates |window|. If |window| is NULL, nothing happens. - virtual void ActivateWindow(Window* window) = 0; - - // Deactivates |window|. What (if anything) is activated next is up to the - // client. If |window| is NULL, nothing happens. - virtual void DeactivateWindow(Window* window) = 0; - - // Retrieves the active window, or NULL if there is none. - virtual Window* GetActiveWindow() = 0; - - // Retrieves the activatable window for |window|, or NULL if there is none. - // Note that this is often but not always the toplevel window (see - // GetToplevelWindow() below), as the toplevel window may not be activatable - // (for example it may be blocked by a modal transient, or some other - // condition). - virtual Window* GetActivatableWindow(Window* window) = 0; - - // Retrieves the toplevel window for |window|, or NULL if there is none. - virtual Window* GetToplevelWindow(Window* window) = 0; - - // Invoked prior to |window| getting focus as a result of the |event|. |event| - // may be NULL. Returning false blocks |window| from getting focus. - virtual bool OnWillFocusWindow(Window* window, const ui::Event* event) = 0; - - // Returns true if |window| can be activated, false otherwise. If |window| has - // a modal child it can not be activated. - virtual bool CanActivateWindow(Window* window) const = 0; - - protected: - virtual ~ActivationClient() {} -}; - -// Sets/Gets the activation client on the root Window. -AURA_EXPORT void SetActivationClient(Window* root_window, - ActivationClient* client); -AURA_EXPORT ActivationClient* GetActivationClient(Window* root_window); - -// Some types of transient window are only visible when active. -// The transient parents of these windows may have visual appearance properties -// that differ from transient parents that can be deactivated. -// The presence of this property implies these traits. -// TODO(beng): currently the UI framework (views) implements the actual -// close-on-deactivate component of this feature but it should be -// possible to implement in the aura client. -AURA_EXPORT void SetHideOnDeactivate(Window* window, bool hide_on_deactivate); -AURA_EXPORT bool GetHideOnDeactivate(Window* window); - -} // namespace clients -} // namespace aura - -#endif // UI_AURA_CLIENT_ACTIVATION_CLIENT_H_ diff --git a/chromium/ui/aura/client/activation_delegate.cc b/chromium/ui/aura/client/activation_delegate.cc deleted file mode 100644 index 51b22b00a61..00000000000 --- a/chromium/ui/aura/client/activation_delegate.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/activation_delegate.h" - -#include "ui/aura/window.h" -#include "ui/aura/window_property.h" - -DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ActivationDelegate*) - -namespace aura { -namespace client { - -DEFINE_LOCAL_WINDOW_PROPERTY_KEY( - ActivationDelegate*, kActivationDelegateKey, NULL); - -void SetActivationDelegate(Window* window, ActivationDelegate* delegate) { - window->SetProperty(kActivationDelegateKey, delegate); -} - -ActivationDelegate* GetActivationDelegate(Window* window) { - return window->GetProperty(kActivationDelegateKey); -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/activation_delegate.h b/chromium/ui/aura/client/activation_delegate.h deleted file mode 100644 index 0ce86388f52..00000000000 --- a/chromium/ui/aura/client/activation_delegate.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_ACTIVATION_DELEGATE_H_ -#define UI_AURA_CLIENT_ACTIVATION_DELEGATE_H_ - -#include "ui/aura/aura_export.h" - -namespace ui { -class Event; -} - -namespace aura { -class Window; -namespace client { - -// An interface implemented by an object that configures and responds to changes -// to a window's activation state. -class AURA_EXPORT ActivationDelegate { - public: - // Returns true if the window should be activated. - virtual bool ShouldActivate() const = 0; - - protected: - virtual ~ActivationDelegate() {} -}; - -// Sets/Gets the ActivationDelegate on the Window. No ownership changes. -AURA_EXPORT void SetActivationDelegate(Window* window, - ActivationDelegate* delegate); -AURA_EXPORT ActivationDelegate* GetActivationDelegate(Window* window); - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_ACTIVATION_DELEGATE_H_ diff --git a/chromium/ui/aura/client/animation_host.cc b/chromium/ui/aura/client/animation_host.cc deleted file mode 100644 index 5df22babc62..00000000000 --- a/chromium/ui/aura/client/animation_host.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/animation_host.h" - -#include "base/compiler_specific.h" -#include "ui/aura/aura_export.h" - -#include "ui/aura/env.h" -#include "ui/aura/root_window.h" -#include "ui/aura/window_property.h" - -DECLARE_WINDOW_PROPERTY_TYPE(aura::client::AnimationHost*) - -namespace aura { -namespace client { - -DEFINE_WINDOW_PROPERTY_KEY(AnimationHost*, kRootWindowAnimationHostKey, NULL); - -void SetAnimationHost(Window* window, AnimationHost* animation_host) { - DCHECK(window); - window->SetProperty(kRootWindowAnimationHostKey, animation_host); -} - -AnimationHost* GetAnimationHost(Window* window) { - DCHECK(window); - return window->GetProperty(kRootWindowAnimationHostKey); -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/animation_host.h b/chromium/ui/aura/client/animation_host.h deleted file mode 100644 index c433b6d63dc..00000000000 --- a/chromium/ui/aura/client/animation_host.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_ANIMATION_HOST_H_ -#define UI_AURA_CLIENT_ANIMATION_HOST_H_ - -#include "base/compiler_specific.h" -#include "ui/aura/aura_export.h" - -namespace gfx { -class Vector2d; -} - -namespace aura { -class Window; -namespace client { - -// Interface for top level window host of animation. Communicates additional -// bounds required for animation as well as animation completion for deferring -// window closes on hide. -class AURA_EXPORT AnimationHost { - public: - // Ensure the host window is at least this large so that transitions have - // sufficient space. - // The |top_left_delta| parameter contains the offset to be subtracted from - // the window bounds for the top left corner. - // The |bottom_right_delta| parameter contains the offset to be added to the - // window bounds for the bottom right. - virtual void SetHostTransitionOffsets( - const gfx::Vector2d& top_left_delta, - const gfx::Vector2d& bottom_right_delta) = 0; - - // Called after the window has faded out on a hide. - virtual void OnWindowHidingAnimationCompleted() = 0; - - protected: - virtual ~AnimationHost() {} -}; - -AURA_EXPORT void SetAnimationHost(Window* window, - AnimationHost* animation_host); -AURA_EXPORT AnimationHost* GetAnimationHost(Window* window); - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_ANIMATION_HOST_H_ diff --git a/chromium/ui/aura/client/capture_client.cc b/chromium/ui/aura/client/capture_client.cc index cbcabd7393f..6d78c88d155 100644 --- a/chromium/ui/aura/client/capture_client.cc +++ b/chromium/ui/aura/client/capture_client.cc @@ -4,7 +4,7 @@ #include "ui/aura/client/capture_client.h" -#include "ui/aura/root_window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_property.h" DECLARE_WINDOW_PROPERTY_TYPE(aura::client::CaptureClient*) diff --git a/chromium/ui/aura/client/cursor_client.h b/chromium/ui/aura/client/cursor_client.h index 99d9b6a1a1c..fc48e036107 100644 --- a/chromium/ui/aura/client/cursor_client.h +++ b/chromium/ui/aura/client/cursor_client.h @@ -14,6 +14,10 @@ namespace gfx { class Display; } +namespace ui { +class KeyEvent; +} + namespace aura { class Window; namespace client { @@ -35,12 +39,6 @@ class AURA_EXPORT CursorClient { // invisible. virtual void HideCursor() = 0; - // Sets the scale of the mouse cursor icon. - virtual void SetScale(float scale) = 0; - - // Gets the current scale of the mouse cursor icon. - virtual float GetScale() const = 0; - // Sets the type of the mouse cursor icon. virtual void SetCursorSet(ui::CursorSetType cursor_set) = 0; @@ -80,6 +78,9 @@ class AURA_EXPORT CursorClient { virtual void AddObserver(CursorClientObserver* observer) = 0; virtual void RemoveObserver(CursorClientObserver* observer) = 0; + // Returns true if the mouse cursor should be hidden on |event|. + virtual bool ShouldHideCursorOnKeyEvent(const ui::KeyEvent& event) const = 0; + protected: virtual ~CursorClient() {} }; diff --git a/chromium/ui/aura/client/default_activation_client.cc b/chromium/ui/aura/client/default_activation_client.cc deleted file mode 100644 index ccb660b81f4..00000000000 --- a/chromium/ui/aura/client/default_activation_client.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/default_activation_client.h" - -#include "ui/aura/client/activation_change_observer.h" -#include "ui/aura/client/activation_delegate.h" -#include "ui/aura/window.h" - -namespace aura { -namespace client { - -//////////////////////////////////////////////////////////////////////////////// -// DefaultActivationClient, public: - -DefaultActivationClient::DefaultActivationClient(Window* root_window) - : last_active_(NULL) { - client::SetActivationClient(root_window, this); -} - -DefaultActivationClient::~DefaultActivationClient() { - for (unsigned int i = 0; i < active_windows_.size(); ++i) { - active_windows_[i]->RemoveObserver(this); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// DefaultActivationClient, client::ActivationClient implementation: - -void DefaultActivationClient::AddObserver( - client::ActivationChangeObserver* observer) { - observers_.AddObserver(observer); -} - -void DefaultActivationClient::RemoveObserver( - client::ActivationChangeObserver* observer) { - observers_.RemoveObserver(observer); -} - -void DefaultActivationClient::ActivateWindow(Window* window) { - Window* last_active = GetActiveWindow(); - if (last_active == window) - return; - - last_active_ = last_active; - RemoveActiveWindow(window); - active_windows_.push_back(window); - window->parent()->StackChildAtTop(window); - window->AddObserver(this); - - FOR_EACH_OBSERVER(client::ActivationChangeObserver, - observers_, - OnWindowActivated(window, last_active)); - - aura::client::ActivationChangeObserver* observer = - aura::client::GetActivationChangeObserver(last_active); - if (observer) - observer->OnWindowActivated(window, last_active); - observer = aura::client::GetActivationChangeObserver(window); - if (observer) - observer->OnWindowActivated(window, last_active); -} - -void DefaultActivationClient::DeactivateWindow(Window* window) { - aura::client::ActivationChangeObserver* observer = - aura::client::GetActivationChangeObserver(window); - if (observer) - observer->OnWindowActivated(NULL, window); - if (last_active_) - ActivateWindow(last_active_); -} - -Window* DefaultActivationClient::GetActiveWindow() { - if (active_windows_.empty()) - return NULL; - return active_windows_.back(); -} - -Window* DefaultActivationClient::GetActivatableWindow(Window* window) { - return NULL; -} - -Window* DefaultActivationClient::GetToplevelWindow(Window* window) { - return NULL; -} - -bool DefaultActivationClient::OnWillFocusWindow(Window* window, - const ui::Event* event) { - return true; -} - -bool DefaultActivationClient::CanActivateWindow(Window* window) const { - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// DefaultActivationClient, WindowObserver implementation: - -void DefaultActivationClient::OnWindowDestroyed(Window* window) { - if (window == last_active_) - last_active_ = NULL; - - if (window == GetActiveWindow()) { - active_windows_.pop_back(); - Window* next_active = GetActiveWindow(); - if (next_active && aura::client::GetActivationChangeObserver(next_active)) { - aura::client::GetActivationChangeObserver(next_active)->OnWindowActivated( - next_active, NULL); - } - return; - } - - RemoveActiveWindow(window); -} - -void DefaultActivationClient::RemoveActiveWindow(Window* window) { - for (unsigned int i = 0; i < active_windows_.size(); ++i) { - if (active_windows_[i] == window) { - active_windows_.erase(active_windows_.begin() + i); - window->RemoveObserver(this); - return; - } - } -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/default_activation_client.h b/chromium/ui/aura/client/default_activation_client.h deleted file mode 100644 index 842ee909d62..00000000000 --- a/chromium/ui/aura/client/default_activation_client.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_DEFAULT_ACTIVATION_CLIENT_H_ -#define UI_AURA_CLIENT_DEFAULT_ACTIVATION_CLIENT_H_ - -#include <vector> - -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/observer_list.h" -#include "ui/aura/aura_export.h" -#include "ui/aura/client/activation_client.h" -#include "ui/aura/window_observer.h" - -namespace aura { -namespace client { -class ActivationChangeObserver; -} - -namespace client { - -// Simple ActivationClient implementation for use by tests and other targets -// that just need basic behavior (e.g. activate windows whenever requested, -// restack windows at the top when they're activated, etc.). -class AURA_EXPORT DefaultActivationClient : public client::ActivationClient, - public WindowObserver { - public: - explicit DefaultActivationClient(Window* root_window); - virtual ~DefaultActivationClient(); - - // Overridden from client::ActivationClient: - virtual void AddObserver(client::ActivationChangeObserver* observer) OVERRIDE; - virtual void RemoveObserver( - client::ActivationChangeObserver* observer) OVERRIDE; - virtual void ActivateWindow(Window* window) OVERRIDE; - virtual void DeactivateWindow(Window* window) OVERRIDE; - virtual Window* GetActiveWindow() OVERRIDE; - virtual Window* GetActivatableWindow(Window* window) OVERRIDE; - virtual Window* GetToplevelWindow(Window* window) OVERRIDE; - virtual bool OnWillFocusWindow(Window* window, - const ui::Event* event) OVERRIDE; - virtual bool CanActivateWindow(Window* window) const OVERRIDE; - - // Overridden from WindowObserver: - virtual void OnWindowDestroyed(Window* window) OVERRIDE; - - private: - void RemoveActiveWindow(Window* window); - - // This class explicitly does NOT store the active window in a window property - // to make sure that ActivationChangeObserver is not treated as part of the - // aura API. Assumptions to that end will cause tests that use this client to - // fail. - std::vector<Window*> active_windows_; - - // The window which was active before the currently active one. - Window* last_active_; - - ObserverList<client::ActivationChangeObserver> observers_; - - DISALLOW_COPY_AND_ASSIGN(DefaultActivationClient); -}; - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_DEFAULT_ACTIVATION_CLIENT_H_ diff --git a/chromium/ui/aura/client/default_capture_client.cc b/chromium/ui/aura/client/default_capture_client.cc index df6a1b09745..69632d8a5be 100644 --- a/chromium/ui/aura/client/default_capture_client.cc +++ b/chromium/ui/aura/client/default_capture_client.cc @@ -4,8 +4,9 @@ #include "ui/aura/client/default_capture_client.h" -#include "ui/aura/root_window.h" #include "ui/aura/window.h" +#include "ui/aura/window_event_dispatcher.h" +#include "ui/aura/window_tree_host.h" namespace aura { namespace client { @@ -31,7 +32,7 @@ void DefaultCaptureClient::SetCapture(Window* window) { Window* old_capture_window = capture_window_; capture_window_ = window; - CaptureDelegate* capture_delegate = root_window_->GetDispatcher(); + CaptureDelegate* capture_delegate = root_window_->GetHost()->dispatcher(); if (capture_window_) capture_delegate->SetNativeCapture(); else diff --git a/chromium/ui/aura/client/dispatcher_client.cc b/chromium/ui/aura/client/dispatcher_client.cc deleted file mode 100644 index a9e1a7d4cd5..00000000000 --- a/chromium/ui/aura/client/dispatcher_client.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/dispatcher_client.h" - -#include "ui/aura/root_window.h" -#include "ui/aura/window_property.h" - -DECLARE_WINDOW_PROPERTY_TYPE(aura::client::DispatcherClient*); - -namespace aura { -namespace client { - -DEFINE_LOCAL_WINDOW_PROPERTY_KEY(DispatcherClient*, kDispatcherClientKey, NULL); - -void SetDispatcherClient(Window* root_window, DispatcherClient* client) { - DCHECK_EQ(root_window->GetRootWindow(), root_window); - root_window->SetProperty(kDispatcherClientKey, client); -} - -DispatcherClient* GetDispatcherClient(Window* root_window) { - if (root_window) - DCHECK_EQ(root_window->GetRootWindow(), root_window); - return root_window ? root_window->GetProperty(kDispatcherClientKey) : NULL; -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/dispatcher_client.h b/chromium/ui/aura/client/dispatcher_client.h deleted file mode 100644 index f2d1ff8bcb3..00000000000 --- a/chromium/ui/aura/client/dispatcher_client.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_DISPATCHER_CLIENT_H_ -#define UI_AURA_CLIENT_DISPATCHER_CLIENT_H_ - -#include "base/message_loop/message_loop.h" -#include "ui/aura/aura_export.h" -#include "ui/aura/window.h" - -namespace aura { -class Window; -namespace client { - -// An interface implemented by an object which handles nested dispatchers. -class AURA_EXPORT DispatcherClient { - public: - virtual void RunWithDispatcher(base::MessageLoop::Dispatcher* dispatcher, - aura::Window* associated_window, - bool nestable_tasks_allowed) = 0; -}; - -AURA_EXPORT void SetDispatcherClient(Window* root_window, - DispatcherClient* client); -AURA_EXPORT DispatcherClient* GetDispatcherClient(Window* root_window); - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_DISPATCHER_CLIENT_H_ diff --git a/chromium/ui/aura/client/drag_drop_client.cc b/chromium/ui/aura/client/drag_drop_client.cc deleted file mode 100644 index abf5879e578..00000000000 --- a/chromium/ui/aura/client/drag_drop_client.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/drag_drop_client.h" - -#include "ui/aura/root_window.h" -#include "ui/aura/window_property.h" - -DECLARE_WINDOW_PROPERTY_TYPE(aura::client::DragDropClient*) - -namespace aura { -namespace client { - -DEFINE_LOCAL_WINDOW_PROPERTY_KEY( - DragDropClient*, kRootWindowDragDropClientKey, NULL); - -void SetDragDropClient(Window* root_window, DragDropClient* client) { - DCHECK_EQ(root_window->GetRootWindow(), root_window); - root_window->SetProperty(kRootWindowDragDropClientKey, client); -} - -DragDropClient* GetDragDropClient(Window* root_window) { - if (root_window) - DCHECK_EQ(root_window->GetRootWindow(), root_window); - return root_window ? - root_window->GetProperty(kRootWindowDragDropClientKey) : NULL; -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/drag_drop_client.h b/chromium/ui/aura/client/drag_drop_client.h deleted file mode 100644 index 7277d6b3839..00000000000 --- a/chromium/ui/aura/client/drag_drop_client.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_DRAG_DROP_CLIENT_H_ -#define UI_AURA_CLIENT_DRAG_DROP_CLIENT_H_ - -#include "ui/aura/aura_export.h" -#include "ui/base/dragdrop/drag_drop_types.h" -#include "ui/gfx/native_widget_types.h" - -namespace gfx { -class Point; -} - -namespace ui { -class LocatedEvent; -class OSExchangeData; -} - -namespace aura { -class Window; -namespace client { - -// An interface implemented by an object that controls a drag and drop session. -class AURA_EXPORT DragDropClient { - public: - virtual ~DragDropClient() {} - - // Initiates a drag and drop session. Returns the drag operation that was - // applied at the end of the drag drop session. |root_location| is in the - // root Window's coordinate system. - virtual int StartDragAndDrop(const ui::OSExchangeData& data, - aura::Window* root_window, - aura::Window* source_window, - const gfx::Point& root_location, - int operation, - ui::DragDropTypes::DragEventSource source) = 0; - - // Called when mouse is dragged during a drag and drop. - virtual void DragUpdate(aura::Window* target, - const ui::LocatedEvent& event) = 0; - - // Called when mouse is released during a drag and drop. - virtual void Drop(aura::Window* target, - const ui::LocatedEvent& event) = 0; - - // Called when a drag and drop session is cancelled. - virtual void DragCancel() = 0; - - // Returns true if a drag and drop session is in progress. - virtual bool IsDragDropInProgress() = 0; -}; - -AURA_EXPORT void SetDragDropClient(Window* root_window, - DragDropClient* client); -AURA_EXPORT DragDropClient* GetDragDropClient(Window* root_window); - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_DRAG_DROP_CLIENT_H_ diff --git a/chromium/ui/aura/client/drag_drop_delegate.cc b/chromium/ui/aura/client/drag_drop_delegate.cc deleted file mode 100644 index 92d986be8da..00000000000 --- a/chromium/ui/aura/client/drag_drop_delegate.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/drag_drop_delegate.h" - -#include "ui/aura/window.h" -#include "ui/aura/window_property.h" - -DECLARE_WINDOW_PROPERTY_TYPE(aura::client::DragDropDelegate*) - -namespace aura { -namespace client { - -DEFINE_LOCAL_WINDOW_PROPERTY_KEY( - DragDropDelegate*, kDragDropDelegateKey, NULL); - -void SetDragDropDelegate(Window* window, DragDropDelegate* delegate) { - window->SetProperty(kDragDropDelegateKey, delegate); -} - -DragDropDelegate* GetDragDropDelegate(Window* window) { - return window->GetProperty(kDragDropDelegateKey); -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/drag_drop_delegate.h b/chromium/ui/aura/client/drag_drop_delegate.h deleted file mode 100644 index dde7f32ec73..00000000000 --- a/chromium/ui/aura/client/drag_drop_delegate.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_DRAG_DROP_DELEGATE_H_ -#define UI_AURA_CLIENT_DRAG_DROP_DELEGATE_H_ - -#include "ui/aura/aura_export.h" - -namespace ui { -class DropTargetEvent; -} - -namespace aura { -class Window; -namespace client { - -// Delegate interface for drag and drop actions on aura::Window. -class AURA_EXPORT DragDropDelegate { - public: - // OnDragEntered is invoked when the mouse enters this window during a drag & - // drop session. This is immediately followed by an invocation of - // OnDragUpdated, and eventually one of OnDragExited or OnPerformDrop. - virtual void OnDragEntered(const ui::DropTargetEvent& event) = 0; - - // Invoked during a drag and drop session while the mouse is over the window. - // This should return a bitmask of the DragDropTypes::DragOperation supported - // based on the location of the event. Return 0 to indicate the drop should - // not be accepted. - virtual int OnDragUpdated(const ui::DropTargetEvent& event) = 0; - - // Invoked during a drag and drop session when the mouse exits the window, or - // when the drag session was canceled and the mouse was over the window. - virtual void OnDragExited() = 0; - - // Invoked during a drag and drop session when OnDragUpdated returns a valid - // operation and the user release the mouse. - virtual int OnPerformDrop(const ui::DropTargetEvent& event) = 0; - - protected: - virtual ~DragDropDelegate() {} -}; - -AURA_EXPORT void SetDragDropDelegate(Window* window, - DragDropDelegate* delegate); -AURA_EXPORT DragDropDelegate* GetDragDropDelegate(Window* window); - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_DRAG_DROP_DELEGATE_H_ diff --git a/chromium/ui/aura/client/event_client.cc b/chromium/ui/aura/client/event_client.cc index c6699741b3c..d6da07e4245 100644 --- a/chromium/ui/aura/client/event_client.cc +++ b/chromium/ui/aura/client/event_client.cc @@ -4,7 +4,7 @@ #include "ui/aura/client/event_client.h" -#include "ui/aura/root_window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_property.h" DECLARE_WINDOW_PROPERTY_TYPE(aura::client::EventClient*) diff --git a/chromium/ui/aura/client/focus_client.cc b/chromium/ui/aura/client/focus_client.cc index 0769b0dfac0..1f24a802cbc 100644 --- a/chromium/ui/aura/client/focus_client.cc +++ b/chromium/ui/aura/client/focus_client.cc @@ -4,7 +4,7 @@ #include "ui/aura/client/focus_client.h" -#include "ui/aura/root_window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_property.h" DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, aura::Window*) diff --git a/chromium/ui/aura/client/screen_position_client.cc b/chromium/ui/aura/client/screen_position_client.cc index 1fb75217bcb..8601005e4ea 100644 --- a/chromium/ui/aura/client/screen_position_client.cc +++ b/chromium/ui/aura/client/screen_position_client.cc @@ -4,7 +4,7 @@ #include "ui/aura/client/screen_position_client.h" -#include "ui/aura/root_window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_property.h" DECLARE_WINDOW_PROPERTY_TYPE(aura::client::ScreenPositionClient*) diff --git a/chromium/ui/aura/client/tooltip_client.cc b/chromium/ui/aura/client/tooltip_client.cc deleted file mode 100644 index f018f262812..00000000000 --- a/chromium/ui/aura/client/tooltip_client.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/tooltip_client.h" - -#include "ui/aura/root_window.h" -#include "ui/aura/window_property.h" - -DECLARE_WINDOW_PROPERTY_TYPE(aura::client::TooltipClient*) -DECLARE_WINDOW_PROPERTY_TYPE(base::string16*) - -namespace aura { -namespace client { - -DEFINE_LOCAL_WINDOW_PROPERTY_KEY( - TooltipClient*, kRootWindowTooltipClientKey, NULL); -DEFINE_LOCAL_WINDOW_PROPERTY_KEY(base::string16*, kTooltipTextKey, NULL); - -void SetTooltipClient(Window* root_window, TooltipClient* client) { - DCHECK_EQ(root_window->GetRootWindow(), root_window); - root_window->SetProperty(kRootWindowTooltipClientKey, client); -} - -TooltipClient* GetTooltipClient(Window* root_window) { - if (root_window) - DCHECK_EQ(root_window->GetRootWindow(), root_window); - return root_window ? - root_window->GetProperty(kRootWindowTooltipClientKey) : NULL; -} - -void SetTooltipText(Window* window, base::string16* tooltip_text) { - window->SetProperty(kTooltipTextKey, tooltip_text); -} - -const base::string16 GetTooltipText(Window* window) { - base::string16* string_ptr = window->GetProperty(kTooltipTextKey); - return string_ptr ? *string_ptr : base::string16(); -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/tooltip_client.h b/chromium/ui/aura/client/tooltip_client.h deleted file mode 100644 index c280b8a8b75..00000000000 --- a/chromium/ui/aura/client/tooltip_client.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_TOOLTIP_CLIENT_H_ -#define UI_AURA_CLIENT_TOOLTIP_CLIENT_H_ - -#include "ui/aura/aura_export.h" -#include "ui/gfx/font.h" - -namespace aura { -class Window; -namespace client { - -class AURA_EXPORT TooltipClient { - public: - // Informs the shell tooltip manager of change in tooltip for window |target|. - virtual void UpdateTooltip(Window* target) = 0; - - // Sets the time after which the tooltip is hidden for Window |target|. If - // |timeout_in_ms| is <= 0, the tooltip is shown indefinitely. - virtual void SetTooltipShownTimeout(Window* target, int timeout_in_ms) = 0; - - // Enables/Disables tooltips. - virtual void SetTooltipsEnabled(bool enable) = 0; -}; - -AURA_EXPORT void SetTooltipClient(Window* root_window, - TooltipClient* client); -AURA_EXPORT TooltipClient* GetTooltipClient(Window* root_window); - -AURA_EXPORT void SetTooltipText(Window* window, base::string16* tooltip_text); -AURA_EXPORT const base::string16 GetTooltipText(Window* window); - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_TOOLTIP_CLIENT_H_ diff --git a/chromium/ui/aura/client/user_action_client.cc b/chromium/ui/aura/client/user_action_client.cc deleted file mode 100644 index 3dab666660c..00000000000 --- a/chromium/ui/aura/client/user_action_client.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/user_action_client.h" - -#include "ui/aura/root_window.h" -#include "ui/aura/window_property.h" - -namespace aura { -namespace client { - -DEFINE_WINDOW_PROPERTY_KEY(UserActionClient*, - kRootWindowUserActionClientKey, - NULL); - -void SetUserActionClient(Window* root_window, UserActionClient* client) { - DCHECK_EQ(root_window->GetRootWindow(), root_window); - root_window->SetProperty(kRootWindowUserActionClientKey, client); -} - -UserActionClient* GetUserActionClient(Window* root_window) { - if (root_window) - DCHECK_EQ(root_window->GetRootWindow(), root_window); - return root_window ? - root_window->GetProperty(kRootWindowUserActionClientKey) : NULL; -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/user_action_client.h b/chromium/ui/aura/client/user_action_client.h deleted file mode 100644 index 738a8d5fba1..00000000000 --- a/chromium/ui/aura/client/user_action_client.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_USER_ACTION_CLIENT_H_ -#define UI_AURA_CLIENT_USER_ACTION_CLIENT_H_ - -#include "ui/aura/aura_export.h" - -namespace aura { -class Window; -namespace client { - -// An interface for handling a user action that isn't handled by the standard -// event path. -class AURA_EXPORT UserActionClient { - public: - enum Command { - BACK = 0, - FORWARD, - }; - - // Returns true if the command was handled and false otherwise. - virtual bool OnUserAction(Command command) = 0; - - virtual ~UserActionClient() {} -}; - -// Sets/gets the client for handling user action on the specified root window. -AURA_EXPORT void SetUserActionClient(Window* root_window, - UserActionClient* client); -AURA_EXPORT UserActionClient* GetUserActionClient(Window* root_window); - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_USER_ACTION_CLIENT_H_ diff --git a/chromium/ui/aura/client/visibility_client.cc b/chromium/ui/aura/client/visibility_client.cc index 5fc7beed7c1..853c034951f 100644 --- a/chromium/ui/aura/client/visibility_client.cc +++ b/chromium/ui/aura/client/visibility_client.cc @@ -4,7 +4,7 @@ #include "ui/aura/client/visibility_client.h" -#include "ui/aura/root_window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_property.h" DECLARE_WINDOW_PROPERTY_TYPE(aura::client::VisibilityClient*) diff --git a/chromium/ui/aura/client/window_move_client.cc b/chromium/ui/aura/client/window_move_client.cc deleted file mode 100644 index c65452db607..00000000000 --- a/chromium/ui/aura/client/window_move_client.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/client/window_move_client.h" - -#include "ui/aura/window.h" -#include "ui/aura/window_property.h" - -DECLARE_WINDOW_PROPERTY_TYPE(aura::client::WindowMoveClient*) - -namespace aura { -namespace client { - -// A property key to store a client that handles window moves. -DEFINE_LOCAL_WINDOW_PROPERTY_KEY( - WindowMoveClient*, kWindowMoveClientKey, NULL); - -void SetWindowMoveClient(Window* window, WindowMoveClient* client) { - window->SetProperty(kWindowMoveClientKey, client); -} - -WindowMoveClient* GetWindowMoveClient(Window* window) { - return window->GetProperty(kWindowMoveClientKey); -} - -} // namespace client -} // namespace aura diff --git a/chromium/ui/aura/client/window_move_client.h b/chromium/ui/aura/client/window_move_client.h deleted file mode 100644 index 15e4245757b..00000000000 --- a/chromium/ui/aura/client/window_move_client.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_CLIENT_WINDOW_MOVE_CLIENT_H_ -#define UI_AURA_CLIENT_WINDOW_MOVE_CLIENT_H_ - -#include "ui/aura/aura_export.h" -#include "ui/gfx/vector2d.h" - -namespace gfx { -class Point; -} - -namespace aura { -class Window; -namespace client { - -enum WindowMoveResult { - MOVE_SUCCESSFUL, // Moving window was successful. - MOVE_CANCELED // Moving window was canceled. -}; - -enum WindowMoveSource { - WINDOW_MOVE_SOURCE_MOUSE, - WINDOW_MOVE_SOURCE_TOUCH, -}; - -// An interface implemented by an object that manages programatically keyed -// window moving. -class AURA_EXPORT WindowMoveClient { - public: - // Starts a nested message loop for moving the window. |drag_offset| is the - // offset from the window origin to the cursor when the drag was started. - // Returns MOVE_SUCCESSFUL if the move has completed successfully, or - // MOVE_CANCELED otherwise. - virtual WindowMoveResult RunMoveLoop(Window* window, - const gfx::Vector2d& drag_offset, - WindowMoveSource source) = 0; - - // Ends a previously started move loop. - virtual void EndMoveLoop() = 0; - - protected: - virtual ~WindowMoveClient() {} -}; - -// Sets/Gets the activation client for the specified window. -AURA_EXPORT void SetWindowMoveClient(Window* window, - WindowMoveClient* client); -AURA_EXPORT WindowMoveClient* GetWindowMoveClient(Window* window); - -} // namespace client -} // namespace aura - -#endif // UI_AURA_CLIENT_WINDOW_MOVE_CLIENT_H_ diff --git a/chromium/ui/aura/client/window_stacking_client.cc b/chromium/ui/aura/client/window_stacking_client.cc index 81da8d1ea6f..8f909766d64 100644 --- a/chromium/ui/aura/client/window_stacking_client.cc +++ b/chromium/ui/aura/client/window_stacking_client.cc @@ -14,11 +14,10 @@ WindowStackingClient* instance = NULL; } // namespace void SetWindowStackingClient(WindowStackingClient* client) { - delete instance; instance = client; } -AURA_EXPORT WindowStackingClient* GetWindowStackingClient() { +WindowStackingClient* GetWindowStackingClient() { return instance; } diff --git a/chromium/ui/aura/client/window_stacking_client.h b/chromium/ui/aura/client/window_stacking_client.h index 35772ed71c4..848260397cb 100644 --- a/chromium/ui/aura/client/window_stacking_client.h +++ b/chromium/ui/aura/client/window_stacking_client.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_AURA_CLIENT_WINDOW_STACKING_DELEGATE_H_ -#define UI_AURA_CLIENT_WINDOW_STACKING_DELEGATE_H_ +#ifndef UI_AURA_CLIENT_WINDOW_STACKING_CLIENT_H_ +#define UI_AURA_CLIENT_WINDOW_STACKING_CLIENT_H_ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" @@ -15,20 +15,25 @@ namespace client { class AURA_EXPORT WindowStackingClient { public: - virtual ~WindowStackingClient() {} - // Invoked from the various Window stacking functions. Allows the // WindowStackingClient to alter the source, target and/or direction to stack. - virtual void AdjustStacking(Window** child, + // Returns true if stacking should continue; false if the stacking should not + // happen. + virtual bool AdjustStacking(Window** child, Window** target, Window::StackDirection* direction) = 0; + + protected: + virtual ~WindowStackingClient() {} }; -// Sets/gets the WindowStackingClient. The setter takes ownership of |client|. +// Sets/gets the WindowStackingClient. This does *not* take ownership of +// |client|. It is assumed the caller will invoke SetWindowStackingClient(NULL) +// before deleting |client|. AURA_EXPORT void SetWindowStackingClient(WindowStackingClient* client); AURA_EXPORT WindowStackingClient* GetWindowStackingClient(); } // namespace client } // namespace aura -#endif // UI_AURA_CLIENT_WINDOW_STACKING_DELEGATE_H_ +#endif // UI_AURA_CLIENT_WINDOW_STACKING_CLIENT_H_ diff --git a/chromium/ui/aura/client/window_tree_client.cc b/chromium/ui/aura/client/window_tree_client.cc index de1ece561d0..1b263c3e756 100644 --- a/chromium/ui/aura/client/window_tree_client.cc +++ b/chromium/ui/aura/client/window_tree_client.cc @@ -5,7 +5,7 @@ #include "ui/aura/client/window_tree_client.h" #include "ui/aura/env.h" -#include "ui/aura/root_window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_property.h" DECLARE_WINDOW_PROPERTY_TYPE(aura::client::WindowTreeClient*) diff --git a/chromium/ui/aura/client/window_types.h b/chromium/ui/aura/client/window_types.h deleted file mode 100644 index f0a7b777a8f..00000000000 --- a/chromium/ui/aura/client/window_types.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_WINDOW_TYPES_H_ -#define UI_AURA_WINDOW_TYPES_H_ - -namespace aura { -namespace client { - -// This isn't a property because it can't change after the window has been -// initialized. It's in client because the Aura Client application derives -// meaning from these values, not Aura itself. -enum WindowType { - WINDOW_TYPE_UNKNOWN = 0, - - // Regular windows that should be laid out by the client. - WINDOW_TYPE_NORMAL, - - // Miscellaneous windows that should not be laid out by the shell. - WINDOW_TYPE_POPUP, - - // A window intended as a control. Not laid out by the shell. - WINDOW_TYPE_CONTROL, - - // Always on top windows aligned to bottom right of screen. - WINDOW_TYPE_PANEL, - - WINDOW_TYPE_MENU, - WINDOW_TYPE_TOOLTIP, -}; - -} // namespace client -} // namespace aura - -#endif // UI_AURA_WINDOW_TYPES_H_ diff --git a/chromium/ui/aura/demo/DEPS b/chromium/ui/aura/demo/DEPS new file mode 100644 index 00000000000..07d824381a5 --- /dev/null +++ b/chromium/ui/aura/demo/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+ui/gl/gl_surface.h", # To initialize GL bindings. +] diff --git a/chromium/ui/aura/demo/demo_main.cc b/chromium/ui/aura/demo/demo_main.cc index 4dfd347577b..f531cd31c2e 100644 --- a/chromium/ui/aura/demo/demo_main.cc +++ b/chromium/ui/aura/demo/demo_main.cc @@ -11,21 +11,24 @@ #include "ui/aura/client/default_capture_client.h" #include "ui/aura/client/window_tree_client.h" #include "ui/aura/env.h" -#include "ui/aura/root_window.h" #include "ui/aura/test/test_focus_client.h" #include "ui/aura/test/test_screen.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" +#include "ui/aura/window_tree_host.h" #include "ui/base/hit_test.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_base_paths.h" -#include "ui/compositor/test/context_factories_for_test.h" +#include "ui/compositor/test/in_process_context_factory.h" #include "ui/events/event.h" #include "ui/gfx/canvas.h" #include "ui/gfx/rect.h" +#include "ui/gl/gl_surface.h" #if defined(USE_X11) -#include "base/message_loop/message_pump_x11.h" +#include "ui/gfx/x/x11_connection.h" +#endif + +#if defined(OS_WIN) +#include "ui/gfx/win/dpi.h" #endif namespace { @@ -63,13 +66,11 @@ class DemoWindowDelegate : public aura::WindowDelegate { canvas->DrawColor(color_, SkXfermode::kSrc_Mode); } virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {} - virtual void OnWindowDestroying() OVERRIDE {} - virtual void OnWindowDestroyed() OVERRIDE {} + virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {} + virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {} virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {} virtual bool HasHitTestMask() const OVERRIDE { return false; } virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {} - virtual void DidRecreateLayer(ui::Layer* old_layer, - ui::Layer* new_layer) OVERRIDE {} private: SkColor color_; @@ -107,51 +108,63 @@ class DemoWindowTreeClient : public aura::client::WindowTreeClient { }; int DemoMain() { - // Create the message-loop here before creating the root window. - base::MessageLoop message_loop(base::MessageLoop::TYPE_UI); +#if defined(USE_X11) + // This demo uses InProcessContextFactory which uses X on a separate Gpu + // thread. + gfx::InitializeThreadedX11(); +#endif + + gfx::GLSurface::InitializeOneOff(); + +#if defined(OS_WIN) + gfx::InitDeviceScaleFactor(1.0f); +#endif // The ContextFactory must exist before any Compositors are created. - bool allow_test_contexts = false; - ui::InitializeContextFactoryForTests(allow_test_contexts); + scoped_ptr<ui::InProcessContextFactory> context_factory( + new ui::InProcessContextFactory()); + + // Create the message-loop here before creating the root window. + base::MessageLoopForUI message_loop; - aura::Env::CreateInstance(); - scoped_ptr<aura::TestScreen> test_screen(aura::TestScreen::Create()); + aura::Env::CreateInstance(true); + aura::Env::GetInstance()->set_context_factory(context_factory.get()); + scoped_ptr<aura::TestScreen> test_screen( + aura::TestScreen::Create(gfx::Size())); gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen.get()); - scoped_ptr<aura::RootWindow> root_window( - test_screen->CreateRootWindowForPrimaryDisplay()); - scoped_ptr<DemoWindowTreeClient> window_tree_client(new DemoWindowTreeClient( - root_window->window())); + scoped_ptr<aura::WindowTreeHost> host( + test_screen->CreateHostForPrimaryDisplay()); + scoped_ptr<DemoWindowTreeClient> window_tree_client( + new DemoWindowTreeClient(host->window())); aura::test::TestFocusClient focus_client; - aura::client::SetFocusClient(root_window->window(), &focus_client); + aura::client::SetFocusClient(host->window(), &focus_client); // Create a hierarchy of test windows. DemoWindowDelegate window_delegate1(SK_ColorBLUE); aura::Window window1(&window_delegate1); window1.set_id(1); - window1.Init(ui::LAYER_TEXTURED); + window1.Init(aura::WINDOW_LAYER_TEXTURED); window1.SetBounds(gfx::Rect(100, 100, 400, 400)); window1.Show(); - aura::client::ParentWindowWithContext( - &window1, root_window->window(), gfx::Rect()); + aura::client::ParentWindowWithContext(&window1, host->window(), gfx::Rect()); DemoWindowDelegate window_delegate2(SK_ColorRED); aura::Window window2(&window_delegate2); window2.set_id(2); - window2.Init(ui::LAYER_TEXTURED); + window2.Init(aura::WINDOW_LAYER_TEXTURED); window2.SetBounds(gfx::Rect(200, 200, 350, 350)); window2.Show(); - aura::client::ParentWindowWithContext( - &window2, root_window->window(), gfx::Rect()); + aura::client::ParentWindowWithContext(&window2, host->window(), gfx::Rect()); DemoWindowDelegate window_delegate3(SK_ColorGREEN); aura::Window window3(&window_delegate3); window3.set_id(3); - window3.Init(ui::LAYER_TEXTURED); + window3.Init(aura::WINDOW_LAYER_TEXTURED); window3.SetBounds(gfx::Rect(10, 10, 50, 50)); window3.Show(); window2.AddChild(&window3); - root_window->host()->Show(); + host->Show(); base::MessageLoopForUI::current()->Run(); return 0; @@ -165,9 +178,7 @@ int main(int argc, char** argv) { // The exit manager is in charge of calling the dtors of singleton objects. base::AtExitManager exit_manager; - ui::RegisterPathProvider(); base::i18n::InitializeICU(); - ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL); return DemoMain(); } diff --git a/chromium/ui/aura/device_list_updater_aurax11.cc b/chromium/ui/aura/device_list_updater_aurax11.cc deleted file mode 100644 index 8240cb495c3..00000000000 --- a/chromium/ui/aura/device_list_updater_aurax11.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/device_list_updater_aurax11.h" - -#include <X11/extensions/XInput2.h> - -#include "ui/events/event_utils.h" - -namespace aura { - -DeviceListUpdaterAuraX11::DeviceListUpdaterAuraX11() {} - -DeviceListUpdaterAuraX11::~DeviceListUpdaterAuraX11() {} - -base::EventStatus DeviceListUpdaterAuraX11::WillProcessEvent( - const base::NativeEvent& event) { - // XI_HierarchyChanged events are special. There is no window associated with - // these events. So process them directly from here. - if (event->type == GenericEvent && - event->xgeneric.evtype == XI_HierarchyChanged) { - ui::UpdateDeviceList(); - } - - return base::EVENT_CONTINUE; -} - -void DeviceListUpdaterAuraX11::DidProcessEvent(const base::NativeEvent& event) { -} - -} // namespace aura diff --git a/chromium/ui/aura/device_list_updater_aurax11.h b/chromium/ui/aura/device_list_updater_aurax11.h deleted file mode 100644 index cb8c884fe85..00000000000 --- a/chromium/ui/aura/device_list_updater_aurax11.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_DEVICE_LIST_UPDATER_AURAX11_H_ -#define UI_AURA_DEVICE_LIST_UPDATER_AURAX11_H_ - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/message_loop/message_pump_observer.h" - -namespace aura { - -// Filters out global XInput notifications and updates the DeviceList. -class DeviceListUpdaterAuraX11 : public base::MessagePumpObserver { - public: - DeviceListUpdaterAuraX11(); - virtual ~DeviceListUpdaterAuraX11(); - - // Overridden from base::MessagePumpObserver: - virtual base::EventStatus WillProcessEvent( - const base::NativeEvent& event) OVERRIDE; - virtual void DidProcessEvent( - const base::NativeEvent& event) OVERRIDE; - - private: - DISALLOW_COPY_AND_ASSIGN(DeviceListUpdaterAuraX11); -}; - -} // namespace aura - -#endif // UI_AURA_DEVICE_LIST_UPDATER_AURAX11_H_ diff --git a/chromium/ui/aura/dispatcher_win.cc b/chromium/ui/aura/dispatcher_win.cc deleted file mode 100644 index 7160dc7771d..00000000000 --- a/chromium/ui/aura/dispatcher_win.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/message_loop/message_loop.h" - -namespace aura { - -class DispatcherWin : public base::MessageLoop::Dispatcher { - public: - DispatcherWin() {} - virtual ~DispatcherWin() {} - - // Overridden from MessageLoop::Dispatcher: - virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; - - private: - DISALLOW_COPY_AND_ASSIGN(DispatcherWin); -}; - -bool DispatcherWin::Dispatch(const base::NativeEvent& msg) { - TranslateMessage(&msg); - DispatchMessage(&msg); - return true; -} - -base::MessageLoop::Dispatcher* CreateDispatcher() { - return new DispatcherWin; -} - -} // namespace aura diff --git a/chromium/ui/aura/env.cc b/chromium/ui/aura/env.cc index 0982d91ad26..71a43c9c5ae 100644 --- a/chromium/ui/aura/env.cc +++ b/chromium/ui/aura/env.cc @@ -4,62 +4,47 @@ #include "ui/aura/env.h" -#include "base/command_line.h" +#include "base/lazy_instance.h" +#include "base/threading/thread_local.h" #include "ui/aura/env_observer.h" #include "ui/aura/input_state_lookup.h" -#include "ui/aura/window.h" -#include "ui/compositor/compositor.h" -#include "ui/compositor/compositor_switches.h" #include "ui/events/event_target_iterator.h" +#include "ui/events/platform/platform_event_source.h" -#if defined(USE_X11) -#include "base/message_loop/message_pump_x11.h" +#if defined(USE_OZONE) +#include "ui/ozone/ozone_platform.h" #endif namespace aura { -// static -Env* Env::instance_ = NULL; - -//////////////////////////////////////////////////////////////////////////////// -// Env, public: - -Env::Env() - : mouse_button_flags_(0), - is_touch_down_(false), - input_state_lookup_(InputStateLookup::Create().Pass()) { -} +namespace { -Env::~Env() { -#if defined(USE_X11) - base::MessagePumpX11::Current()->RemoveObserver( - &device_list_updater_aurax11_); -#endif +// Env is thread local so that aura may be used on multiple threads. +base::LazyInstance<base::ThreadLocalPointer<Env> >::Leaky lazy_tls_ptr = + LAZY_INSTANCE_INITIALIZER; - FOR_EACH_OBSERVER(EnvObserver, observers_, OnWillDestroyEnv()); +} // namespace - ui::Compositor::Terminate(); -} +//////////////////////////////////////////////////////////////////////////////// +// Env, public: -//static -void Env::CreateInstance() { - if (!instance_) { - instance_ = new Env; - instance_->Init(); - } +// static +void Env::CreateInstance(bool create_event_source) { + if (!lazy_tls_ptr.Pointer()->Get()) + (new Env())->Init(create_event_source); } // static Env* Env::GetInstance() { - DCHECK(instance_) << "Env::CreateInstance must be called before getting " - "the instance of Env."; - return instance_; + Env* env = lazy_tls_ptr.Pointer()->Get(); + DCHECK(env) << "Env::CreateInstance must be called before getting the " + "instance of Env."; + return env; } // static void Env::DeleteInstance() { - delete instance_; - instance_ = NULL; + delete lazy_tls_ptr.Pointer()->Get(); } void Env::AddObserver(EnvObserver* observer) { @@ -75,47 +60,44 @@ bool Env::IsMouseButtonDown() const { mouse_button_flags_ != 0; } -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \ - !defined(USE_GTK_MESSAGE_PUMP) -base::MessageLoop::Dispatcher* Env::GetDispatcher() { -#if defined(USE_X11) - return base::MessagePumpX11::Current(); -#else - return dispatcher_.get(); -#endif -} -#endif +//////////////////////////////////////////////////////////////////////////////// +// Env, private: -void Env::RootWindowActivated(RootWindow* root_window) { - FOR_EACH_OBSERVER(EnvObserver, observers_, - OnRootWindowActivated(root_window)); +Env::Env() + : mouse_button_flags_(0), + is_touch_down_(false), + input_state_lookup_(InputStateLookup::Create().Pass()), + context_factory_(NULL) { + DCHECK(lazy_tls_ptr.Pointer()->Get() == NULL); + lazy_tls_ptr.Pointer()->Set(this); } -//////////////////////////////////////////////////////////////////////////////// -// Env, private: +Env::~Env() { + FOR_EACH_OBSERVER(EnvObserver, observers_, OnWillDestroyEnv()); + DCHECK_EQ(this, lazy_tls_ptr.Pointer()->Get()); + lazy_tls_ptr.Pointer()->Set(NULL); +} -void Env::Init() { -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(USE_X11) && \ - !defined(USE_OZONE) - dispatcher_.reset(CreateDispatcher()); -#endif -#if defined(USE_X11) - // We can't do this with a root window listener because XI_HierarchyChanged - // messages don't have a target window. - base::MessagePumpX11::Current()->AddObserver( - &device_list_updater_aurax11_); +void Env::Init(bool create_event_source) { +#if defined(USE_OZONE) + // The ozone platform can provide its own event source. So initialize the + // platform before creating the default event source. + ui::OzonePlatform::InitializeForUI(); #endif - ui::Compositor::Initialize(); + if (create_event_source && !ui::PlatformEventSource::GetInstance()) + event_source_ = ui::PlatformEventSource::CreateDefault(); } void Env::NotifyWindowInitialized(Window* window) { FOR_EACH_OBSERVER(EnvObserver, observers_, OnWindowInitialized(window)); } -void Env::NotifyRootWindowInitialized(RootWindow* root_window) { - FOR_EACH_OBSERVER(EnvObserver, - observers_, - OnRootWindowInitialized(root_window)); +void Env::NotifyHostInitialized(WindowTreeHost* host) { + FOR_EACH_OBSERVER(EnvObserver, observers_, OnHostInitialized(host)); +} + +void Env::NotifyHostActivated(WindowTreeHost* host) { + FOR_EACH_OBSERVER(EnvObserver, observers_, OnHostActivated(host)); } //////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/ui/aura/env.h b/chromium/ui/aura/env.h index e326781264f..a4f67668482 100644 --- a/chromium/ui/aura/env.h +++ b/chromium/ui/aura/env.h @@ -6,17 +6,17 @@ #define UI_AURA_ENV_H_ #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/observer_list.h" +#include "base/supports_user_data.h" #include "ui/aura/aura_export.h" #include "ui/events/event_handler.h" #include "ui/events/event_target.h" #include "ui/gfx/point.h" -#if defined(USE_X11) -#include "ui/aura/device_list_updater_aurax11.h" -#endif - +namespace ui { +class ContextFactory; +class PlatformEventSource; +} namespace aura { namespace test { @@ -25,28 +25,24 @@ class EnvTestHelper; class EnvObserver; class InputStateLookup; -class RootWindow; class Window; - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(USE_X11) -// Creates a platform-specific native event dispatcher. -base::MessageLoop::Dispatcher* CreateDispatcher(); -#endif +class WindowTreeHost; // A singleton object that tracks general state within Aura. -// TODO(beng): manage RootWindows. -class AURA_EXPORT Env : public ui::EventTarget { +class AURA_EXPORT Env : public ui::EventTarget, public base::SupportsUserData { public: - Env(); - virtual ~Env(); - - static void CreateInstance(); + // Creates the single Env instance (if it hasn't been created yet). If + // |create_event_source| is true a PlatformEventSource is created. + // TODO(sky): nuke |create_event_source|. Only necessary while mojo's + // nativeviewportservice lives in the same process as the viewmanager. + static void CreateInstance(bool create_event_source); static Env* GetInstance(); static void DeleteInstance(); void AddObserver(EnvObserver* observer); void RemoveObserver(EnvObserver* observer); + const int mouse_button_flags() const { return mouse_button_flags_; } void set_mouse_button_flags(int mouse_button_flags) { mouse_button_flags_ = mouse_button_flags; } @@ -65,29 +61,30 @@ class AURA_EXPORT Env : public ui::EventTarget { bool is_touch_down() const { return is_touch_down_; } void set_touch_down(bool value) { is_touch_down_ = value; } - // Returns the native event dispatcher. The result should only be passed to - // base::RunLoop(dispatcher), or used to dispatch an event by - // |Dispatch(const NativeEvent&)| on it. It must never be stored. -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \ - !defined(USE_GTK_MESSAGE_PUMP) - base::MessageLoop::Dispatcher* GetDispatcher(); -#endif - - // Invoked by RootWindow when its host is activated. - void RootWindowActivated(RootWindow* root_window); + void set_context_factory(ui::ContextFactory* context_factory) { + context_factory_ = context_factory; + } + ui::ContextFactory* context_factory() { return context_factory_; } private: friend class test::EnvTestHelper; friend class Window; - friend class RootWindow; + friend class WindowTreeHost; + + Env(); + virtual ~Env(); - void Init(); + // See description of CreateInstance() for deatils of |create_event_source|. + void Init(bool create_event_source); // Called by the Window when it is initialized. Notifies observers. void NotifyWindowInitialized(Window* window); - // Called by the RootWindow when it is initialized. Notifies observers. - void NotifyRootWindowInitialized(RootWindow* root_window); + // Called by the WindowTreeHost when it is initialized. Notifies observers. + void NotifyHostInitialized(WindowTreeHost* host); + + // Invoked by WindowTreeHost when it is activated. Notifies observers. + void NotifyHostActivated(WindowTreeHost* host); // Overridden from ui::EventTarget: virtual bool CanAcceptEvent(const ui::Event& event) OVERRIDE; @@ -96,21 +93,16 @@ class AURA_EXPORT Env : public ui::EventTarget { virtual ui::EventTargeter* GetEventTargeter() OVERRIDE; ObserverList<EnvObserver> observers_; -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(USE_X11) - scoped_ptr<base::MessageLoop::Dispatcher> dispatcher_; -#endif - static Env* instance_; int mouse_button_flags_; // Location of last mouse event, in screen coordinates. gfx::Point last_mouse_location_; bool is_touch_down_; -#if defined(USE_X11) - DeviceListUpdaterAuraX11 device_list_updater_aurax11_; -#endif - scoped_ptr<InputStateLookup> input_state_lookup_; + scoped_ptr<ui::PlatformEventSource> event_source_; + + ui::ContextFactory* context_factory_; DISALLOW_COPY_AND_ASSIGN(Env); }; diff --git a/chromium/ui/aura/env_observer.h b/chromium/ui/aura/env_observer.h index b624f91b6ec..51a69466b32 100644 --- a/chromium/ui/aura/env_observer.h +++ b/chromium/ui/aura/env_observer.h @@ -9,19 +9,19 @@ namespace aura { -class RootWindow; class Window; +class WindowTreeHost; class AURA_EXPORT EnvObserver { public: // Called when |window| has been initialized. virtual void OnWindowInitialized(Window* window) = 0; - // Called when |root_window| has been initialized. - virtual void OnRootWindowInitialized(RootWindow* root_window) {}; + // Called when a WindowTreeHost is initialized. + virtual void OnHostInitialized(WindowTreeHost* host) {}; - // Called when a RootWindow's host is activated. - virtual void OnRootWindowActivated(RootWindow* root_window) {} + // Called when a WindowTreeHost is activated. + virtual void OnHostActivated(WindowTreeHost* host) {} // Called right before Env is destroyed. virtual void OnWillDestroyEnv() {} diff --git a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc index 3a18d1fffc4..596cb1f40cb 100644 --- a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc +++ b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc @@ -9,12 +9,12 @@ #include "base/timer/timer.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/env.h" -#include "ui/aura/root_window.h" #include "ui/aura/test/aura_test_base.h" #include "ui/aura/test/event_generator.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/base/hit_test.h" #include "ui/base/ui_base_switches.h" #include "ui/events/event.h" @@ -93,15 +93,11 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { scroll_velocity_y_(0), velocity_x_(0), velocity_y_(0), - scroll_x_ordinal_(0), - scroll_y_ordinal_(0), - scroll_velocity_x_ordinal_(0), - scroll_velocity_y_ordinal_(0), - velocity_x_ordinal_(0), - velocity_y_ordinal_(0), + scroll_x_hint_(0), + scroll_y_hint_(0), tap_count_(0), - wait_until_event_(ui::ET_UNKNOWN) { - } + flags_(0), + wait_until_event_(ui::ET_UNKNOWN) {} virtual ~GestureEventConsumeDelegate() {} @@ -129,6 +125,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { scroll_begin_position_.SetPoint(0, 0); tap_location_.SetPoint(0, 0); + gesture_end_location_.SetPoint(0, 0); scroll_x_ = 0; scroll_y_ = 0; @@ -136,13 +133,12 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { scroll_velocity_y_ = 0; velocity_x_ = 0; velocity_y_ = 0; - scroll_x_ordinal_ = 0; - scroll_y_ordinal_ = 0; - scroll_velocity_x_ordinal_ = 0; - scroll_velocity_y_ordinal_ = 0; - velocity_x_ordinal_ = 0; - velocity_y_ordinal_ = 0; + scroll_x_hint_ = 0; + scroll_y_hint_ = 0; tap_count_ = 0; + scale_ = 0; + flags_ = 0; + latency_info_.Clear(); } const std::vector<ui::EventType>& events() const { return events_; }; @@ -168,40 +164,43 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { bool swipe_up() const { return swipe_up_; } bool swipe_down() const { return swipe_down_; } - const gfx::Point scroll_begin_position() const { + const gfx::Point& scroll_begin_position() const { return scroll_begin_position_; } - const gfx::Point tap_location() const { + const gfx::Point& tap_location() const { return tap_location_; } + const gfx::Point& gesture_end_location() const { + return gesture_end_location_; + } + float scroll_x() const { return scroll_x_; } float scroll_y() const { return scroll_y_; } float scroll_velocity_x() const { return scroll_velocity_x_; } float scroll_velocity_y() const { return scroll_velocity_y_; } float velocity_x() const { return velocity_x_; } float velocity_y() const { return velocity_y_; } - float scroll_x_ordinal() const { return scroll_x_ordinal_; } - float scroll_y_ordinal() const { return scroll_y_ordinal_; } - float scroll_velocity_x_ordinal() const { return scroll_velocity_x_ordinal_; } - float scroll_velocity_y_ordinal() const { return scroll_velocity_y_ordinal_; } - float velocity_x_ordinal() const { return velocity_x_ordinal_; } - float velocity_y_ordinal() const { return velocity_y_ordinal_; } - int touch_id() const { return touch_id_; } + float scroll_x_hint() const { return scroll_x_hint_; } + float scroll_y_hint() const { return scroll_y_hint_; } + float scale() const { return scale_; } const gfx::Rect& bounding_box() const { return bounding_box_; } int tap_count() const { return tap_count_; } + int flags() const { return flags_; } + const ui::LatencyInfo& latency_info() const { return latency_info_; } void WaitUntilReceivedGesture(ui::EventType type) { wait_until_event_ = type; - run_loop_.reset(new base::RunLoop( - Env::GetInstance()->GetDispatcher())); + run_loop_.reset(new base::RunLoop()); run_loop_->Run(); } virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE { events_.push_back(gesture->type()); bounding_box_ = gesture->details().bounding_box(); + flags_ = gesture->flags(); + latency_info_ = *gesture->latency(); switch (gesture->type()) { case ui::ET_GESTURE_TAP: tap_location_ = gesture->location(); @@ -219,21 +218,18 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { break; case ui::ET_GESTURE_END: end_ = true; + gesture_end_location_ = gesture->location(); break; case ui::ET_GESTURE_SCROLL_BEGIN: scroll_begin_ = true; scroll_begin_position_ = gesture->location(); + scroll_x_hint_ = gesture->details().scroll_x_hint(); + scroll_y_hint_ = gesture->details().scroll_y_hint(); break; case ui::ET_GESTURE_SCROLL_UPDATE: scroll_update_ = true; scroll_x_ += gesture->details().scroll_x(); scroll_y_ += gesture->details().scroll_y(); - scroll_velocity_x_ = gesture->details().velocity_x(); - scroll_velocity_y_ = gesture->details().velocity_y(); - scroll_x_ordinal_ += gesture->details().scroll_x_ordinal(); - scroll_y_ordinal_ += gesture->details().scroll_y_ordinal(); - scroll_velocity_x_ordinal_ = gesture->details().velocity_x_ordinal(); - scroll_velocity_y_ordinal_ = gesture->details().velocity_y_ordinal(); break; case ui::ET_GESTURE_SCROLL_END: EXPECT_TRUE(velocity_x_ == 0 && velocity_y_ == 0); @@ -244,13 +240,13 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { break; case ui::ET_GESTURE_PINCH_UPDATE: pinch_update_ = true; + scale_ = gesture->details().scale(); break; case ui::ET_GESTURE_PINCH_END: pinch_end_ = true; break; case ui::ET_GESTURE_LONG_PRESS: long_press_ = true; - touch_id_ = gesture->details().touch_id(); break; case ui::ET_GESTURE_LONG_TAP: long_tap_ = true; @@ -262,8 +258,6 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { fling_ = true; velocity_x_ = gesture->details().velocity_x(); velocity_y_ = gesture->details().velocity_y(); - velocity_x_ordinal_ = gesture->details().velocity_x_ordinal(); - velocity_y_ordinal_ = gesture->details().velocity_y_ordinal(); break; case ui::ET_GESTURE_TWO_FINGER_TAP: two_finger_tap_ = true; @@ -271,12 +265,15 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { case ui::ET_GESTURE_SHOW_PRESS: show_press_ = true; break; - case ui::ET_GESTURE_MULTIFINGER_SWIPE: + case ui::ET_GESTURE_SWIPE: swipe_left_ = gesture->details().swipe_left(); swipe_right_ = gesture->details().swipe_right(); swipe_up_ = gesture->details().swipe_up(); swipe_down_ = gesture->details().swipe_down(); break; + case ui::ET_SCROLL_FLING_CANCEL: + // Only used in unified gesture detection. + break; default: NOTREACHED(); } @@ -314,6 +311,7 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { gfx::Point scroll_begin_position_; gfx::Point tap_location_; + gfx::Point gesture_end_location_; float scroll_x_; float scroll_y_; @@ -321,15 +319,13 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { float scroll_velocity_y_; float velocity_x_; float velocity_y_; - float scroll_x_ordinal_; - float scroll_y_ordinal_; - float scroll_velocity_x_ordinal_; - float scroll_velocity_y_ordinal_; - float velocity_x_ordinal_; - float velocity_y_ordinal_; - int touch_id_; + float scroll_x_hint_; + float scroll_y_hint_; + float scale_; gfx::Rect bounding_box_; int tap_count_; + int flags_; + ui::LatencyInfo latency_info_; ui::EventType wait_until_event_; @@ -338,9 +334,9 @@ class GestureEventConsumeDelegate : public TestWindowDelegate { class QueueTouchEventDelegate : public GestureEventConsumeDelegate { public: - explicit QueueTouchEventDelegate(RootWindow* root_window) + explicit QueueTouchEventDelegate(WindowEventDispatcher* dispatcher) : window_(NULL), - root_window_(root_window), + dispatcher_(dispatcher), queue_events_(true) { } virtual ~QueueTouchEventDelegate() { @@ -371,14 +367,14 @@ class QueueTouchEventDelegate : public GestureEventConsumeDelegate { private: void ReceivedAckImpl(bool prevent_defaulted) { scoped_ptr<ui::TouchEvent> event(queue_.front()); - root_window_->ProcessedTouchEvent(event.get(), window_, + dispatcher_->ProcessedTouchEvent(event.get(), window_, prevent_defaulted ? ui::ER_HANDLED : ui::ER_UNHANDLED); queue_.pop(); } std::queue<ui::TouchEvent*> queue_; Window* window_; - RootWindow* root_window_; + WindowEventDispatcher* dispatcher_; bool queue_events_; DISALLOW_COPY_AND_ASSIGN(QueueTouchEventDelegate); @@ -543,7 +539,9 @@ class TimedEvents { int simulated_now_; public: - TimedEvents() : simulated_now_(0) { + // Use a non-zero start time to pass DCHECKs which ensure events have had a + // time assigned. + TimedEvents() : simulated_now_(1) { } base::TimeDelta Now() { @@ -561,9 +559,9 @@ class TimedEvents { return base::TimeDelta::FromMilliseconds(simulated_now_ + time_in_millis); } - void SendScrollEvents(RootWindow* root_window, - int x_start, - int y_start, + void SendScrollEvents(ui::EventProcessor* dispatcher, + float x_start, + float y_start, int dx, int dy, int touch_id, @@ -576,24 +574,26 @@ class TimedEvents { for (int i = 0; i < num_steps; i++) { x += dx; y += dy; - ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(x, y), + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::PointF(x, y), touch_id, base::TimeDelta::FromMilliseconds(simulated_now_)); - root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move); + ASSERT_FALSE(details.dispatcher_destroyed); simulated_now_ += time_step; } } - void SendScrollEvent(RootWindow* root_window, - int x, - int y, + void SendScrollEvent(ui::EventProcessor* dispatcher, + float x, + float y, int touch_id, GestureEventConsumeDelegate* delegate) { delegate->Reset(); - ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(x, y), + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::PointF(x, y), touch_id, base::TimeDelta::FromMilliseconds(simulated_now_)); - root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&move); + ASSERT_FALSE(details.dispatcher_destroyed); simulated_now_++; } }; @@ -601,8 +601,9 @@ class TimedEvents { // An event handler to keep track of events. class TestEventHandler : public ui::EventHandler { public: - TestEventHandler() : touch_released_count_(0), touch_pressed_count_(0), - touch_moved_count_(0), touch_stationary_count_(0), + TestEventHandler() : touch_released_count_(0), + touch_pressed_count_(0), + touch_moved_count_(0), touch_cancelled_count_(0) { } @@ -619,9 +620,6 @@ class TestEventHandler : public ui::EventHandler { case ui::ET_TOUCH_MOVED: touch_moved_count_++; break; - case ui::ET_TOUCH_STATIONARY: - touch_stationary_count_++; - break; case ui::ET_TOUCH_CANCELLED: touch_cancelled_count_++; break; @@ -634,21 +632,18 @@ class TestEventHandler : public ui::EventHandler { touch_released_count_ = 0; touch_pressed_count_ = 0; touch_moved_count_ = 0; - touch_stationary_count_ = 0; touch_cancelled_count_ = 0; } int touch_released_count() const { return touch_released_count_; } int touch_pressed_count() const { return touch_pressed_count_; } int touch_moved_count() const { return touch_moved_count_; } - int touch_stationary_count() const { return touch_stationary_count_; } int touch_cancelled_count() const { return touch_cancelled_count_; } private: int touch_released_count_; int touch_pressed_count_; int touch_moved_count_; - int touch_stationary_count_; int touch_cancelled_count_; DISALLOW_COPY_AND_ASSIGN(TestEventHandler); @@ -679,21 +674,34 @@ class RemoveOnTouchCancelHandler : public TestEventHandler { } // namespace -class GestureRecognizerTest : public AuraTestBase { +class GestureRecognizerTest : public AuraTestBase, + public ::testing::WithParamInterface<bool> { public: GestureRecognizerTest() {} + bool UsingUnifiedGR() { + return GetParam(); + } + virtual void SetUp() OVERRIDE { - CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableScrollPrediction); + // TODO(tdresser): Once unified GR has landed, only run these tests once. + CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kUnifiedGestureDetector, + UsingUnifiedGR() ? switches::kUnifiedGestureDetectorEnabled + : switches::kUnifiedGestureDetectorDisabled); + AuraTestBase::SetUp(); + ui::GestureConfiguration::set_min_touch_down_duration_in_seconds_for_click( + 0.001); + ui::GestureConfiguration::set_show_press_delay_in_ms(2); + ui::GestureConfiguration::set_long_press_time_in_seconds(0.003); } DISALLOW_COPY_AND_ASSIGN(GestureRecognizerTest); }; // Check that appropriate touch events generate tap gesture events. -TEST_F(GestureRecognizerTest, GestureEventTap) { +TEST_P(GestureRecognizerTest, GestureEventTap) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -707,7 +715,7 @@ TEST_F(GestureRecognizerTest, GestureEventTap) { delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->show_press()); EXPECT_TRUE(delegate->tap_down()); @@ -729,7 +737,7 @@ TEST_F(GestureRecognizerTest, GestureEventTap) { ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -744,7 +752,12 @@ TEST_F(GestureRecognizerTest, GestureEventTap) { // Check that appropriate touch events generate tap gesture events // when information about the touch radii are provided. -TEST_F(GestureRecognizerTest, GestureEventTapRegion) { +TEST_P(GestureRecognizerTest, GestureEventTapRegion) { + // TODO(tdresser): enable this test with unified GR once we resolve the + // bounding box differences. See crbug.com/366641. + if (UsingUnifiedGR()) + return; + scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -762,7 +775,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { kTouchId, tes.Now()); press.set_radius_x(5); press.set_radius_y(12); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -780,7 +793,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { release.set_radius_x(5); release.set_radius_y(12); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -805,7 +818,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { kTouchId, tes.Now()); press.set_radius_x(8); press.set_radius_y(14); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -821,7 +834,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { release.set_radius_x(20); release.set_radius_y(13); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -846,7 +859,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { kTouchId, tes.Now()); press.set_radius_x(6); press.set_radius_y(10); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -862,7 +875,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { kTouchId, tes.LeapForward(50)); move.set_radius_x(8); move.set_radius_y(12); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + DispatchEventUsingWindowDispatcher(&move); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -878,7 +891,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { release.set_radius_x(4); release.set_radius_y(8); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -903,7 +916,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { kTouchId, tes.Now()); press.set_radius_x(7); press.set_radius_y(10); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -918,7 +931,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { kTouchId, tes.LeapForward(50)); move.set_radius_x(13); move.set_radius_y(12); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + DispatchEventUsingWindowDispatcher(&move); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -933,7 +946,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { kTouchId, tes.LeapForward(50)); move1.set_radius_x(16); move1.set_radius_y(16); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1); + DispatchEventUsingWindowDispatcher(&move1); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -948,7 +961,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { kTouchId, tes.LeapForward(50)); move2.set_radius_x(14); move2.set_radius_y(10); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); + DispatchEventUsingWindowDispatcher(&move2); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -964,7 +977,7 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { release.set_radius_x(8); release.set_radius_y(9); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -984,7 +997,12 @@ TEST_F(GestureRecognizerTest, GestureEventTapRegion) { } // Check that appropriate touch events generate scroll gesture events. -TEST_F(GestureRecognizerTest, GestureEventScroll) { +TEST_P(GestureRecognizerTest, GestureEventScroll) { + // We'll start by moving the touch point by (10.5, 10.5). We want 5 dips of + // that distance to be consumed by the slop, so we set the slop radius to + // sqrt(5 * 5 + 5 * 5). + ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click( + sqrt(static_cast<double>(5 * 5 + 5 * 5))); scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -998,7 +1016,7 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) { delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_TAP_DOWN); @@ -1007,13 +1025,15 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) { // should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures. // The first movement is diagonal, to ensure that we have a free scroll, // and not a rail scroll. - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 111.5, 211.5, kTouchId, + delegate.get()); EXPECT_3_EVENTS(delegate->events(), ui::ET_GESTURE_TAP_CANCEL, ui::ET_GESTURE_SCROLL_BEGIN, ui::ET_GESTURE_SCROLL_UPDATE); - EXPECT_EQ(29, delegate->scroll_x()); - EXPECT_EQ(29, delegate->scroll_y()); + // The slop consumed 5 dips + EXPECT_FLOAT_EQ(5.5, delegate->scroll_x()); + EXPECT_FLOAT_EQ(5.5, delegate->scroll_y()); EXPECT_EQ(gfx::Point(1, 1).ToString(), delegate->scroll_begin_position().ToString()); @@ -1021,14 +1041,15 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) { // be empty, since it's a single point and the radius for testing is zero. EXPECT_TRUE(delegate->bounding_box().IsEmpty()); - // Move some more to generate a few more scroll updates. - tes.SendScrollEvent(dispatcher(), 110, 211, kTouchId, delegate.get()); + // Move some more to generate a few more scroll updates. Make sure that we get + // out of the snap channel for the unified GR. + tes.SendScrollEvent(event_processor(), 20, 120, kTouchId, delegate.get()); EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE); - EXPECT_EQ(-20, delegate->scroll_x()); - EXPECT_EQ(-19, delegate->scroll_y()); + EXPECT_FLOAT_EQ(-91.5, delegate->scroll_x()); + EXPECT_FLOAT_EQ(-91.5, delegate->scroll_y()); EXPECT_TRUE(delegate->bounding_box().IsEmpty()); - tes.SendScrollEvent(dispatcher(), 140, 215, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 50, 124, kTouchId, delegate.get()); EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE); EXPECT_EQ(30, delegate->scroll_x()); EXPECT_EQ(4, delegate->scroll_y()); @@ -1039,7 +1060,7 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) { ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_2_EVENTS(delegate->events(), ui::ET_SCROLL_FLING_START, ui::ET_GESTURE_END); @@ -1047,16 +1068,22 @@ TEST_F(GestureRecognizerTest, GestureEventScroll) { } // Check that predicted scroll update positions are correct. -TEST_F(GestureRecognizerTest, GestureEventScrollPrediction) { +TEST_P(GestureRecognizerTest, GestureEventScrollPrediction) { const double prediction_interval = 0.03; ui::GestureConfiguration::set_scroll_prediction_seconds(prediction_interval); + // We'll start by moving the touch point by (5, 5). We want all of that + // distance to be consumed by the slop, so we set the slop radius to + // sqrt(5 * 5 + 5 * 5). + ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click( + sqrt(static_cast<double>(5 * 5 + 5 * 5))); + scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; const int kWindowWidth = 123; const int kWindowHeight = 45; const int kTouchId = 5; - gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight); + gfx::Rect bounds(95, 195, kWindowWidth, kWindowHeight); scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( delegate.get(), -1234, bounds, root_window())); @@ -1064,63 +1091,59 @@ TEST_F(GestureRecognizerTest, GestureEventScrollPrediction) { // Tracks the total scroll since we want to verify that the correct position // will be scrolled to throughout the prediction. gfx::Vector2dF total_scroll; - ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), + ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(96, 196), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_TAP_DOWN); + delegate->Reset(); + + // Get rid of touch slop. + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(111, 211), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move); + EXPECT_3_EVENTS(delegate->events(), + ui::ET_GESTURE_TAP_CANCEL, + ui::ET_GESTURE_SCROLL_BEGIN, + ui::ET_GESTURE_SCROLL_UPDATE); + total_scroll.set_x(total_scroll.x() + delegate->scroll_x()); + total_scroll.set_y(total_scroll.y() + delegate->scroll_y()); // Move the touch-point enough so that it is considered as a scroll. This // should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures. // The first movement is diagonal, to ensure that we have a free scroll, // and not a rail scroll. tes.LeapForward(30); - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get()); - EXPECT_3_EVENTS(delegate->events(), - ui::ET_GESTURE_TAP_CANCEL, - ui::ET_GESTURE_SCROLL_BEGIN, - ui::ET_GESTURE_SCROLL_UPDATE); - EXPECT_GT(delegate->scroll_velocity_x(), 0); - EXPECT_GT(delegate->scroll_velocity_y(), 0); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get()); + EXPECT_1_EVENT(delegate->events(), + ui::ET_GESTURE_SCROLL_UPDATE); total_scroll.set_x(total_scroll.x() + delegate->scroll_x()); total_scroll.set_y(total_scroll.y() + delegate->scroll_y()); - EXPECT_EQ((int)(29 + delegate->scroll_velocity_x() * prediction_interval), - (int)(total_scroll.x())); - EXPECT_EQ((int)(29 + delegate->scroll_velocity_y() * prediction_interval), - (int)(total_scroll.y())); // Move some more to generate a few more scroll updates. tes.LeapForward(30); - tes.SendScrollEvent(dispatcher(), 110, 211, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 110, 211, kTouchId, delegate.get()); EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE); total_scroll.set_x(total_scroll.x() + delegate->scroll_x()); total_scroll.set_y(total_scroll.y() + delegate->scroll_y()); - EXPECT_EQ((int)(9 + delegate->scroll_velocity_x() * prediction_interval), - (int)(total_scroll.x())); - EXPECT_EQ((int)(10 + delegate->scroll_velocity_y() * prediction_interval), - (int)(total_scroll.y())); tes.LeapForward(30); - tes.SendScrollEvent(dispatcher(), 140, 215, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 140, 215, kTouchId, delegate.get()); EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE); total_scroll.set_x(total_scroll.x() + delegate->scroll_x()); total_scroll.set_y(total_scroll.y() + delegate->scroll_y()); - EXPECT_EQ((int)(39 + delegate->scroll_velocity_x() * prediction_interval), - (int)(total_scroll.x())); - EXPECT_EQ((int)(14 + delegate->scroll_velocity_y() * prediction_interval), - (int)(total_scroll.y())); // Release the touch. This should end the scroll. delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); } // Check that the bounding box during a scroll event is correct. -TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) { +TEST_P(GestureRecognizerTest, GestureEventScrollBoundingBox) { TimedEvents tes; for (int radius = 1; radius <= 10; ++radius) { ui::GestureConfiguration::set_default_radius(radius); @@ -1140,7 +1163,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) { gfx::Point(kPositionX, kPositionY), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_EQ(gfx::Rect(kPositionX - radius, kPositionY - radius, radius * 2, @@ -1148,7 +1171,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) { delegate->bounding_box().ToString()); const int kScrollAmount = 50; - tes.SendScrollEvents(dispatcher(), kPositionX, kPositionY, + tes.SendScrollEvents(event_processor(), kPositionX, kPositionY, 1, 1, kTouchId, 1, kScrollAmount, delegate.get()); EXPECT_EQ(gfx::Point(1, 1).ToString(), delegate->scroll_begin_position().ToString()); @@ -1165,7 +1188,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) { kPositionY + kScrollAmount), kTouchId, press.time_stamp() + base::TimeDelta::FromMilliseconds(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_EQ(gfx::Rect(kPositionX + kScrollAmount - radius, kPositionY + kScrollAmount - radius, radius * 2, @@ -1177,7 +1200,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollBoundingBox) { // Check Scroll End Events report correct velocities // if the user was on a horizontal rail -TEST_F(GestureRecognizerTest, GestureEventHorizontalRailFling) { +TEST_P(GestureRecognizerTest, GestureEventHorizontalRailFling) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -1188,30 +1211,31 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailFling) { ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); + + // Get rid of touch slop. + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 0), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move); + delegate->Reset(); + // Move the touch-point horizontally enough that it is considered a // horizontal scroll. - tes.SendScrollEvent(dispatcher(), 20, 1, kTouchId, delegate.get()); - EXPECT_EQ(0, delegate->scroll_y()); - EXPECT_EQ(1, delegate->scroll_y_ordinal()); - EXPECT_EQ(20, delegate->scroll_x()); - EXPECT_EQ(20, delegate->scroll_x_ordinal()); + tes.SendScrollEvent(event_processor(), 30, 1, kTouchId, delegate.get()); + EXPECT_FLOAT_EQ(0, delegate->scroll_y()); + EXPECT_FLOAT_EQ(20, delegate->scroll_x()); // Get a high x velocity, while still staying on the rail - tes.SendScrollEvents(dispatcher(), 1, 1, + tes.SendScrollEvents(event_processor(), 1, 1, 100, 10, kTouchId, 1, ui::GestureConfiguration::points_buffered_for_velocity(), delegate.get()); - // The y-velocity during the scroll should be 0 since this is in a horizontal - // rail scroll. - EXPECT_GT(delegate->scroll_velocity_x(), 0); - EXPECT_EQ(0, delegate->scroll_velocity_y()); delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->fling()); EXPECT_FALSE(delegate->scroll_end()); @@ -1221,7 +1245,7 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailFling) { // Check Scroll End Events report correct velocities // if the user was on a vertical rail -TEST_F(GestureRecognizerTest, GestureEventVerticalRailFling) { +TEST_P(GestureRecognizerTest, GestureEventVerticalRailFling) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -1232,30 +1256,32 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailFling) { ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); + + // Get rid of touch slop. + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(0, 10), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move); + delegate->Reset(); // Move the touch-point vertically enough that it is considered a // vertical scroll. - tes.SendScrollEvent(dispatcher(), 1, 20, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 1, 30, kTouchId, delegate.get()); EXPECT_EQ(20, delegate->scroll_y()); - EXPECT_EQ(20, delegate->scroll_y_ordinal()); EXPECT_EQ(0, delegate->scroll_x()); - EXPECT_EQ(1, delegate->scroll_x_ordinal()); EXPECT_EQ(0, delegate->scroll_velocity_x()); - EXPECT_GT(delegate->scroll_velocity_x_ordinal(), 0); // Get a high y velocity, while still staying on the rail - tes.SendScrollEvents(dispatcher(), 1, 1, + tes.SendScrollEvents(event_processor(), 1, 6, 10, 100, kTouchId, 1, ui::GestureConfiguration::points_buffered_for_velocity(), delegate.get()); EXPECT_EQ(0, delegate->scroll_velocity_x()); - EXPECT_GT(delegate->scroll_velocity_y(), 0); delegate->Reset(); - ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), + ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 206), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->fling()); EXPECT_FALSE(delegate->scroll_end()); @@ -1263,9 +1289,10 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailFling) { EXPECT_GT(delegate->velocity_y(), 0); } -// Check Scroll End Events reports zero velocities -// if the user is not on a rail -TEST_F(GestureRecognizerTest, GestureEventNonRailFling) { +// Check Scroll End Events report non-zero velocities if the user is not on a +// rail +TEST_P(GestureRecognizerTest, GestureEventNonRailFling) { + ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(0); scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -1276,14 +1303,15 @@ TEST_F(GestureRecognizerTest, GestureEventNonRailFling) { ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); - // Move the touch-point such that a non-rail scroll begins - tes.SendScrollEvent(dispatcher(), 20, 20, kTouchId, delegate.get()); - EXPECT_EQ(20, delegate->scroll_y()); - EXPECT_EQ(20, delegate->scroll_x()); + // Move the touch-point such that a non-rail scroll begins, and we're outside + // the snap channel for the unified GR. + tes.SendScrollEvent(event_processor(), 50, 50, kTouchId, delegate.get()); + EXPECT_EQ(50, delegate->scroll_y()); + EXPECT_EQ(50, delegate->scroll_x()); - tes.SendScrollEvents(dispatcher(), 1, 1, + tes.SendScrollEvents(event_processor(), 1, 1, 10, 100, kTouchId, 1, ui::GestureConfiguration::points_buffered_for_velocity(), delegate.get()); @@ -1291,7 +1319,7 @@ TEST_F(GestureRecognizerTest, GestureEventNonRailFling) { delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->fling()); EXPECT_FALSE(delegate->scroll_end()); @@ -1300,10 +1328,12 @@ TEST_F(GestureRecognizerTest, GestureEventNonRailFling) { } // Check that appropriate touch events generate long press events -TEST_F(GestureRecognizerTest, GestureEventLongPress) { +TEST_P(GestureRecognizerTest, GestureEventLongPress) { + ui::GestureConfiguration::set_max_touch_down_duration_in_seconds_for_click( + 0.0025); + scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); - TimedEvents tes; const int kWindowWidth = 123; const int kWindowHeight = 45; const int kTouchId = 2; @@ -1318,9 +1348,11 @@ TEST_F(GestureRecognizerTest, GestureEventLongPress) { ScopedGestureRecognizerSetter gr_setter(gesture_recognizer); - ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), - kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, + gfx::Point(101, 201), + kTouchId, + ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_TRUE(delegate->tap_down()); EXPECT_TRUE(delegate->begin()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1331,25 +1363,26 @@ TEST_F(GestureRecognizerTest, GestureEventLongPress) { // Wait until the timer runs out delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS); EXPECT_TRUE(delegate->long_press()); - EXPECT_EQ(0, delegate->touch_id()); EXPECT_FALSE(delegate->tap_cancel()); delegate->Reset(); - ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), - kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, + gfx::Point(101, 201), + kTouchId, + ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->long_press()); - // Note the tap down isn't cancelled until the release + // Note the tap cancel isn't dispatched until the release EXPECT_TRUE(delegate->tap_cancel()); + EXPECT_FALSE(delegate->tap()); } // Check that scrolling cancels a long press -TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) { +TEST_P(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; - ui::GestureConfiguration::set_long_press_time_in_seconds(.01); const int kWindowWidth = 123; const int kWindowHeight = 45; const int kTouchId = 6; @@ -1369,7 +1402,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) { ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_TRUE(delegate->tap_down()); // We haven't pressed long enough for a long press to occur @@ -1377,7 +1410,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) { EXPECT_FALSE(delegate->tap_cancel()); // Scroll around, to cancel the long press - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get()); // Wait until the timer runs out gesture_sequence->ForceTimeout(); EXPECT_FALSE(delegate->long_press()); @@ -1386,16 +1419,17 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledByScroll) { delegate->Reset(); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(10)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->long_press()); EXPECT_FALSE(delegate->tap_cancel()); } // Check that appropriate touch events generate long tap events -TEST_F(GestureRecognizerTest, GestureEventLongTap) { +TEST_P(GestureRecognizerTest, GestureEventLongTap) { + ui::GestureConfiguration::set_max_touch_down_duration_in_seconds_for_click( + 0.0025); scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); - TimedEvents tes; const int kWindowWidth = 123; const int kWindowHeight = 45; const int kTouchId = 2; @@ -1410,9 +1444,11 @@ TEST_F(GestureRecognizerTest, GestureEventLongTap) { ScopedGestureRecognizerSetter gr_setter(gesture_recognizer); - ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), - kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, + gfx::Point(101, 201), + kTouchId, + ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_TRUE(delegate->tap_down()); EXPECT_TRUE(delegate->begin()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1423,26 +1459,27 @@ TEST_F(GestureRecognizerTest, GestureEventLongTap) { // Wait until the timer runs out delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS); EXPECT_TRUE(delegate->long_press()); - EXPECT_EQ(0, delegate->touch_id()); EXPECT_FALSE(delegate->tap_cancel()); delegate->Reset(); - ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), - kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, + gfx::Point(101, 201), + kTouchId, + ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->long_press()); EXPECT_TRUE(delegate->long_tap()); - // Note the tap down isn't cancelled until the release + // Note the tap cancel isn't dispatched until the release EXPECT_TRUE(delegate->tap_cancel()); + EXPECT_FALSE(delegate->tap()); } // Check that second tap cancels a long press -TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) { +TEST_P(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; - ui::GestureConfiguration::set_long_press_time_in_seconds(.01); const int kWindowWidth = 300; const int kWindowHeight = 400; const int kTouchId1 = 8; @@ -1462,7 +1499,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) { delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_TRUE(delegate->tap_down()); EXPECT_TRUE(delegate->begin()); @@ -1473,7 +1510,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) { delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_FALSE(delegate->tap_down()); // no touch down for second tap. EXPECT_TRUE(delegate->tap_cancel()); EXPECT_TRUE(delegate->begin()); @@ -1487,7 +1524,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) { delegate->Reset(); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->long_press()); EXPECT_TRUE(delegate->two_finger_tap()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1495,7 +1532,7 @@ TEST_F(GestureRecognizerTest, GestureEventLongPressCancelledBySecondTap) { // Check that horizontal scroll gestures cause scrolls on horizontal rails. // Also tests that horizontal rails can be broken. -TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) { +TEST_P(GestureRecognizerTest, GestureEventHorizontalRailScroll) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -1506,15 +1543,22 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) { ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); + + // Get rid of touch slop. + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(5, 0), + kTouchId, tes.Now()); + + DispatchEventUsingWindowDispatcher(&move); + delegate->Reset(); // Move the touch-point horizontally enough that it is considered a // horizontal scroll. - tes.SendScrollEvent(dispatcher(), 20, 1, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 25, 0, kTouchId, delegate.get()); EXPECT_EQ(0, delegate->scroll_y()); EXPECT_EQ(20, delegate->scroll_x()); - tes.SendScrollEvent(dispatcher(), 25, 6, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 30, 6, kTouchId, delegate.get()); EXPECT_TRUE(delegate->scroll_update()); EXPECT_EQ(5, delegate->scroll_x()); // y shouldn't change, as we're on a horizontal rail. @@ -1522,17 +1566,13 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) { // Send enough information that a velocity can be calculated for the gesture, // and we can break the rail - tes.SendScrollEvents(dispatcher(), 1, 1, - 1, 100, kTouchId, 1, + tes.SendScrollEvents(event_processor(), 1, 1, + 6, 100, kTouchId, 1, ui::GestureConfiguration::points_buffered_for_velocity(), delegate.get()); - // Since the scroll is not longer railing, the velocity should be set for both - // axis. - EXPECT_GT(delegate->scroll_velocity_x(), 0); - EXPECT_GT(delegate->scroll_velocity_y(), 0); - tes.SendScrollEvent(dispatcher(), 0, 0, kTouchId, delegate.get()); - tes.SendScrollEvent(dispatcher(), 5, 5, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 5, 0, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 10, 5, kTouchId, delegate.get()); // The rail should be broken EXPECT_TRUE(delegate->scroll_update()); @@ -1542,7 +1582,7 @@ TEST_F(GestureRecognizerTest, GestureEventHorizontalRailScroll) { // Check that vertical scroll gestures cause scrolls on vertical rails. // Also tests that vertical rails can be broken. -TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) { +TEST_P(GestureRecognizerTest, GestureEventVerticalRailScroll) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -1553,15 +1593,21 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) { ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); + + // Get rid of touch slop. + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(0, 5), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move); + delegate->Reset(); // Move the touch-point vertically enough that it is considered a // vertical scroll. - tes.SendScrollEvent(dispatcher(), 1, 20, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 0, 25, kTouchId, delegate.get()); EXPECT_EQ(0, delegate->scroll_x()); EXPECT_EQ(20, delegate->scroll_y()); - tes.SendScrollEvent(dispatcher(), 6, 25, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 6, 30, kTouchId, delegate.get()); EXPECT_TRUE(delegate->scroll_update()); EXPECT_EQ(5, delegate->scroll_y()); // x shouldn't change, as we're on a vertical rail. @@ -1570,15 +1616,13 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) { // Send enough information that a velocity can be calculated for the gesture, // and we can break the rail - tes.SendScrollEvents(dispatcher(), 1, 1, + tes.SendScrollEvents(event_processor(), 1, 6, 100, 1, kTouchId, 1, ui::GestureConfiguration::points_buffered_for_velocity(), delegate.get()); - EXPECT_GT(delegate->scroll_velocity_x(), 0); - EXPECT_GT(delegate->scroll_velocity_y(), 0); - tes.SendScrollEvent(dispatcher(), 0, 0, kTouchId, delegate.get()); - tes.SendScrollEvent(dispatcher(), 5, 5, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 0, 5, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 5, 10, kTouchId, delegate.get()); // The rail should be broken EXPECT_TRUE(delegate->scroll_update()); @@ -1586,7 +1630,13 @@ TEST_F(GestureRecognizerTest, GestureEventVerticalRailScroll) { EXPECT_EQ(5, delegate->scroll_y()); } -TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) { +TEST_P(GestureRecognizerTest, GestureTapFollowedByScroll) { + // We'll start by moving the touch point by (5, 5). We want all of that + // distance to be consumed by the slop, so we set the slop radius to + // sqrt(5 * 5 + 5 * 5). + ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click( + sqrt(static_cast<double>(5 * 5 + 5 * 5))); + // First, tap. Then, do a scroll using the same touch-id. scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); @@ -1601,7 +1651,7 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) { delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1614,7 +1664,7 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) { delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1627,7 +1677,7 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.LeapForward(1000)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1635,28 +1685,40 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) { EXPECT_FALSE(delegate->scroll_update()); EXPECT_FALSE(delegate->scroll_end()); + // Get rid of touch slop. + ui::TouchEvent move_remove_slop(ui::ET_TOUCH_MOVED, gfx::Point(116, 216), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move_remove_slop); + EXPECT_TRUE(delegate->tap_cancel()); + EXPECT_TRUE(delegate->scroll_begin()); + EXPECT_TRUE(delegate->scroll_update()); + EXPECT_EQ(15, delegate->scroll_x_hint()); + EXPECT_EQ(15, delegate->scroll_y_hint()); + + delegate->Reset(); + // Move the touch-point enough so that it is considered as a scroll. This // should generate both SCROLL_BEGIN and SCROLL_UPDATE gestures. // The first movement is diagonal, to ensure that we have a free scroll, // and not a rail scroll. delegate->Reset(); - ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(130, 230), + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(135, 235), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + DispatchEventUsingWindowDispatcher(&move); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); - EXPECT_TRUE(delegate->tap_cancel()); - EXPECT_TRUE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->tap_cancel()); + EXPECT_FALSE(delegate->scroll_begin()); EXPECT_TRUE(delegate->scroll_update()); EXPECT_FALSE(delegate->scroll_end()); - EXPECT_EQ(29, delegate->scroll_x()); - EXPECT_EQ(29, delegate->scroll_y()); + EXPECT_EQ(19, delegate->scroll_x()); + EXPECT_EQ(19, delegate->scroll_y()); // Move some more to generate a few more scroll updates. delegate->Reset(); - ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(110, 211), + ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(115, 216), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1); + DispatchEventUsingWindowDispatcher(&move1); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1665,11 +1727,13 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) { EXPECT_FALSE(delegate->scroll_end()); EXPECT_EQ(-20, delegate->scroll_x()); EXPECT_EQ(-19, delegate->scroll_y()); + EXPECT_EQ(0, delegate->scroll_x_hint()); + EXPECT_EQ(0, delegate->scroll_y_hint()); delegate->Reset(); - ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(140, 215), + ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(145, 220), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); + DispatchEventUsingWindowDispatcher(&move2); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1683,7 +1747,7 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) { delegate->Reset(); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1693,9 +1757,9 @@ TEST_F(GestureRecognizerTest, GestureTapFollowedByScroll) { EXPECT_TRUE(delegate->fling()); } -TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { +TEST_P(GestureRecognizerTest, AsynchronousGestureRecognition) { scoped_ptr<QueueTouchEventDelegate> queued_delegate( - new QueueTouchEventDelegate(dispatcher())); + new QueueTouchEventDelegate(host()->dispatcher())); const int kWindowWidth = 123; const int kWindowHeight = 45; const int kTouchId1 = 6; @@ -1710,7 +1774,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { queued_delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, GetTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_FALSE(queued_delegate->tap()); EXPECT_FALSE(queued_delegate->tap_down()); EXPECT_FALSE(queued_delegate->tap_cancel()); @@ -1725,7 +1789,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId1, press.time_stamp() + base::TimeDelta::FromMilliseconds(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_FALSE(queued_delegate->tap()); EXPECT_FALSE(queued_delegate->tap_down()); EXPECT_FALSE(queued_delegate->tap_cancel()); @@ -1744,7 +1808,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 20), kTouchId2, GetTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1756,7 +1820,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), kTouchId2, GetTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2); + DispatchEventUsingWindowDispatcher(&release2); // Process the first queued event. queued_delegate->Reset(); @@ -1787,7 +1851,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { queued_delegate->Reset(); ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, GetTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press3); + DispatchEventUsingWindowDispatcher(&press3); EXPECT_FALSE(queued_delegate->tap()); EXPECT_FALSE(queued_delegate->tap_down()); EXPECT_FALSE(queued_delegate->tap_cancel()); @@ -1803,7 +1867,7 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { delegate->Reset(); ui::TouchEvent press4(ui::ET_TOUCH_PRESSED, gfx::Point(103, 203), kTouchId2, GetTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press4); + DispatchEventUsingWindowDispatcher(&press4); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1826,9 +1890,9 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { queued_delegate->Reset(); delegate->Reset(); int x_move = ui::GestureConfiguration::max_touch_move_in_pixels_for_click(); - ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(103 + x_move, 203), + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(203 + x_move, 303), kTouchId2, GetTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + DispatchEventUsingWindowDispatcher(&move); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -1877,7 +1941,8 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { EXPECT_FALSE(queued_delegate->begin()); EXPECT_FALSE(queued_delegate->end()); EXPECT_TRUE(queued_delegate->scroll_begin()); - EXPECT_FALSE(queued_delegate->scroll_update()); + // TODO(tdresser): uncomment once we've switched to the unified GR. + // EXPECT_TRUE(queued_delegate->scroll_update()); EXPECT_FALSE(queued_delegate->scroll_end()); EXPECT_TRUE(queued_delegate->pinch_begin()); EXPECT_FALSE(queued_delegate->pinch_update()); @@ -1885,7 +1950,12 @@ TEST_F(GestureRecognizerTest, AsynchronousGestureRecognition) { } // Check that appropriate touch events generate pinch gesture events. -TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { +TEST_P(GestureRecognizerTest, GestureEventPinchFromScroll) { + // Disabled for unified GR due to differences in when pinch begin is sent. The + // Aura GR sends it earlier than is necessary. + if (UsingUnifiedGR()) + return; + scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -1897,12 +1967,10 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( delegate.get(), -1234, bounds, root_window())); - aura::RootWindow* root = dispatcher(); - delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_TAP_DOWN); @@ -1912,7 +1980,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { delegate->Reset(); ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(130, 301), kTouchId1, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + DispatchEventUsingWindowDispatcher(&move); EXPECT_3_EVENTS(delegate->events(), ui::ET_GESTURE_TAP_CANCEL, ui::ET_GESTURE_SCROLL_BEGIN, @@ -1923,7 +1991,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId2, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_PINCH_BEGIN); @@ -1934,7 +2002,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { delegate->Reset(); ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(95, 201), kTouchId1, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move3); + DispatchEventUsingWindowDispatcher(&move3); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_PINCH_UPDATE, ui::ET_GESTURE_SCROLL_UPDATE); @@ -1945,7 +2013,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { delegate->Reset(); ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(55, 15), kTouchId2, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move4); + DispatchEventUsingWindowDispatcher(&move4); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_PINCH_UPDATE, ui::ET_GESTURE_SCROLL_UPDATE); @@ -1956,7 +2024,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId1, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_PINCH_END, ui::ET_GESTURE_END); @@ -1967,12 +2035,12 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromScroll) { delegate->Reset(); ui::TouchEvent move5(ui::ET_TOUCH_MOVED, gfx::Point(25, 10), kTouchId2, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move5); + DispatchEventUsingWindowDispatcher(&move5); EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE); EXPECT_TRUE(delegate->bounding_box().IsEmpty()); } -TEST_F(GestureRecognizerTest, GestureEventPinchFromScrollFromPinch) { +TEST_P(GestureRecognizerTest, GestureEventPinchFromScrollFromPinch) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -1986,20 +2054,20 @@ scoped_ptr<GestureEventConsumeDelegate> delegate( ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 301), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_FALSE(delegate->pinch_begin()); // Touch move triggers pinch begin. - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId1, delegate.get()); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId1, delegate.get()); EXPECT_TRUE(delegate->pinch_begin()); EXPECT_FALSE(delegate->pinch_update()); // Touch move triggers pinch update. - tes.SendScrollEvent(dispatcher(), 160, 200, kTouchId1, delegate.get()); + tes.SendScrollEvent(event_processor(), 160, 200, kTouchId1, delegate.get()); EXPECT_FALSE(delegate->pinch_begin()); EXPECT_TRUE(delegate->pinch_update()); @@ -2007,29 +2075,33 @@ scoped_ptr<GestureEventConsumeDelegate> delegate( delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_TRUE(delegate->pinch_end()); - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId2, delegate.get()); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId2, delegate.get()); EXPECT_TRUE(delegate->scroll_update()); // Pinch again delegate->Reset(); ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press3); + DispatchEventUsingWindowDispatcher(&press3); // Now the touch points are close. So we will go into two finger tap. // Move the touch-point enough to break two-finger-tap and enter pinch. - ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(101, 202), + ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(101, 50), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); + DispatchEventUsingWindowDispatcher(&move2); EXPECT_TRUE(delegate->pinch_begin()); - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId1, delegate.get()); + tes.SendScrollEvent(event_processor(), 350, 350, kTouchId1, delegate.get()); EXPECT_TRUE(delegate->pinch_update()); } -TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) { +TEST_P(GestureRecognizerTest, GestureEventPinchFromTap) { + // TODO(tdresser): enable this test with unified GR once two finger tap. + if (UsingUnifiedGR()) + return; + scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -2041,12 +2113,10 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) { scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( delegate.get(), -1234, bounds, root_window())); - aura::RootWindow* root = dispatcher(); - delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 301), kTouchId1, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_BEGIN, ui::ET_GESTURE_TAP_DOWN); @@ -2056,7 +2126,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) { delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId2, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_TAP_CANCEL, ui::ET_GESTURE_BEGIN); @@ -2067,10 +2137,10 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) { delegate->Reset(); ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(65, 201), kTouchId1, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move3); + DispatchEventUsingWindowDispatcher(&move3); EXPECT_2_EVENTS(delegate->events(), - ui::ET_GESTURE_PINCH_BEGIN, - ui::ET_GESTURE_SCROLL_BEGIN); + ui::ET_GESTURE_SCROLL_BEGIN, + ui::ET_GESTURE_PINCH_BEGIN); EXPECT_EQ(gfx::Rect(10, 10, 55, 191).ToString(), delegate->bounding_box().ToString()); @@ -2078,7 +2148,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) { delegate->Reset(); ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(55, 15), kTouchId2, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move4); + DispatchEventUsingWindowDispatcher(&move4); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_PINCH_UPDATE, ui::ET_GESTURE_SCROLL_UPDATE); @@ -2089,7 +2159,7 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) { delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId1, tes.LeapForward(10)); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_PINCH_END, ui::ET_GESTURE_END); @@ -2100,26 +2170,26 @@ TEST_F(GestureRecognizerTest, GestureEventPinchFromTap) { delegate->Reset(); ui::TouchEvent move5(ui::ET_TOUCH_MOVED, gfx::Point(25, 10), kTouchId2, tes.Now()); - root->AsRootWindowHostDelegate()->OnHostTouchEvent(&move5); + DispatchEventUsingWindowDispatcher(&move5); EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE); EXPECT_TRUE(delegate->bounding_box().IsEmpty()); } -TEST_F(GestureRecognizerTest, GestureEventIgnoresDisconnectedEvents) { +TEST_P(GestureRecognizerTest, GestureEventIgnoresDisconnectedEvents) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), 6, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); } // Check that a touch is locked to the window of the closest current touch // within max_separation_for_gesture_touches_in_pixels -TEST_F(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) { +TEST_P(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) { ui::GestureRecognizer* gesture_recognizer = new ui::GestureRecognizerImpl(); TimedEvents tes; ScopedGestureRecognizerSetter gr_setter(gesture_recognizer); @@ -2150,50 +2220,50 @@ TEST_F(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) { windows[i]->set_id(i); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, window_bounds[i].origin(), i, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); } // Touches should now be associated with the closest touch within // ui::GestureConfiguration::max_separation_for_gesture_touches_in_pixels - target = gesture_recognizer->GetTargetForLocation(gfx::Point(11, 11)); + target = gesture_recognizer->GetTargetForLocation(gfx::Point(11, 11), -1); EXPECT_EQ("0", WindowIDAsString(target)); - target = gesture_recognizer->GetTargetForLocation(gfx::Point(511, 11)); + target = gesture_recognizer->GetTargetForLocation(gfx::Point(511, 11), -1); EXPECT_EQ("1", WindowIDAsString(target)); - target = gesture_recognizer->GetTargetForLocation(gfx::Point(11, 511)); + target = gesture_recognizer->GetTargetForLocation(gfx::Point(11, 511), -1); EXPECT_EQ("2", WindowIDAsString(target)); - target = gesture_recognizer->GetTargetForLocation(gfx::Point(511, 511)); + target = gesture_recognizer->GetTargetForLocation(gfx::Point(511, 511), -1); EXPECT_EQ("3", WindowIDAsString(target)); // Add a touch in the middle associated with windows[2] ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 500), kNumWindows, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(250, 250), kNumWindows, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + DispatchEventUsingWindowDispatcher(&move); - target = gesture_recognizer->GetTargetForLocation(gfx::Point(250, 250)); + target = gesture_recognizer->GetTargetForLocation(gfx::Point(250, 250), -1); EXPECT_EQ("2", WindowIDAsString(target)); // Make sure that ties are broken by distance to a current touch // Closer to the point in the bottom right. - target = gesture_recognizer->GetTargetForLocation(gfx::Point(380, 380)); + target = gesture_recognizer->GetTargetForLocation(gfx::Point(380, 380), -1); EXPECT_EQ("3", WindowIDAsString(target)); // This touch is closer to the point in the middle - target = gesture_recognizer->GetTargetForLocation(gfx::Point(300, 300)); + target = gesture_recognizer->GetTargetForLocation(gfx::Point(300, 300), -1); EXPECT_EQ("2", WindowIDAsString(target)); // A touch too far from other touches won't be locked to anything - target = gesture_recognizer->GetTargetForLocation(gfx::Point(1000, 1000)); + target = gesture_recognizer->GetTargetForLocation(gfx::Point(1000, 1000), -1); EXPECT_TRUE(target == NULL); // Move a touch associated with windows[2] to 1000, 1000 ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(1000, 1000), kNumWindows, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); + DispatchEventUsingWindowDispatcher(&move2); - target = gesture_recognizer->GetTargetForLocation(gfx::Point(1000, 1000)); + target = gesture_recognizer->GetTargetForLocation(gfx::Point(1000, 1000), -1); EXPECT_EQ("2", WindowIDAsString(target)); for (int i = 0; i < kNumWindows; ++i) { @@ -2203,9 +2273,43 @@ TEST_F(GestureRecognizerTest, GestureEventTouchLockSelectsCorrectWindow) { } } +// Check that a touch's target will not be effected by a touch on a different +// screen. +TEST_P(GestureRecognizerTest, GestureEventTouchLockIgnoresOtherScreens) { + scoped_ptr<GestureEventConsumeDelegate> delegate( + new GestureEventConsumeDelegate()); + gfx::Rect bounds(0, 0, 10, 10); + scoped_ptr<aura::Window> window( + CreateTestWindowWithDelegate(delegate.get(), 0, bounds, root_window())); + + const int kTouchId1 = 8; + const int kTouchId2 = 2; + TimedEvents tes; + + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(5, 5), + kTouchId1, tes.Now()); + press1.set_source_device_id(1); + DispatchEventUsingWindowDispatcher(&press1); + + ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(20, 20), + kTouchId2, tes.Now()); + press2.set_source_device_id(2); + DispatchEventUsingWindowDispatcher(&press2); + + // The second press should not have been locked to the same target as the + // first, as they occured on different displays. + EXPECT_NE( + ui::GestureRecognizer::Get()->GetTouchLockedTarget(press1), + ui::GestureRecognizer::Get()->GetTouchLockedTarget(press2)); +} + // Check that touch events outside the root window are still handled // by the root window's gesture sequence. -TEST_F(GestureRecognizerTest, GestureEventOutsideRootWindowTap) { +TEST_P(GestureRecognizerTest, GestureEventOutsideRootWindowTap) { + // TODO(tdresser): write a version of this test for the unified GR. + if (UsingUnifiedGR()) + return; + TestGestureRecognizer* gesture_recognizer = new TestGestureRecognizer(); TimedEvents tes; @@ -2222,11 +2326,11 @@ TEST_F(GestureRecognizerTest, GestureEventOutsideRootWindowTap) { gfx::Point pos1(-10, -10); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, pos1, 0, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); gfx::Point pos2(1000, 1000); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, pos2, 1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); // As these presses were outside the root window, they should be // associated with the root window. @@ -2234,9 +2338,9 @@ TEST_F(GestureRecognizerTest, GestureEventOutsideRootWindowTap) { EXPECT_EQ(2, root_window_gesture_sequence->point_count()); } -TEST_F(GestureRecognizerTest, NoTapWithPreventDefaultedRelease) { +TEST_P(GestureRecognizerTest, NoTapWithPreventDefaultedRelease) { scoped_ptr<QueueTouchEventDelegate> delegate( - new QueueTouchEventDelegate(dispatcher())); + new QueueTouchEventDelegate(host()->dispatcher())); TimedEvents tes; const int kTouchId = 2; gfx::Rect bounds(100, 200, 100, 100); @@ -2247,10 +2351,10 @@ TEST_F(GestureRecognizerTest, NoTapWithPreventDefaultedRelease) { delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); delegate->Reset(); delegate->ReceivedAck(); @@ -2261,9 +2365,14 @@ TEST_F(GestureRecognizerTest, NoTapWithPreventDefaultedRelease) { EXPECT_TRUE(delegate->tap_cancel()); } -TEST_F(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) { +TEST_P(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) { + // Disabled for unified GR due to differences in when pinch begin is sent. The + // Aura GR sends it earlier than is necessary. + if (UsingUnifiedGR()) + return; + scoped_ptr<QueueTouchEventDelegate> delegate( - new QueueTouchEventDelegate(dispatcher())); + new QueueTouchEventDelegate(host()->dispatcher())); TimedEvents tes; const int kTouchId1 = 7; const int kTouchId2 = 5; @@ -2280,9 +2389,9 @@ TEST_F(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) { tes.LeapForward(200)); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(15, 25), kTouchId1, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&press); + DispatchEventUsingWindowDispatcher(&move); + DispatchEventUsingWindowDispatcher(&release); delegate->Reset(); // Ack the press event. @@ -2316,12 +2425,12 @@ TEST_F(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) { tes.LeapForward(14)); // Do a pinch. - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2); + DispatchEventUsingWindowDispatcher(&press); + DispatchEventUsingWindowDispatcher(&move); + DispatchEventUsingWindowDispatcher(&press2); + DispatchEventUsingWindowDispatcher(&move2); + DispatchEventUsingWindowDispatcher(&release); + DispatchEventUsingWindowDispatcher(&release2); // Ack the press and move events. delegate->Reset(); @@ -2355,7 +2464,25 @@ TEST_F(GestureRecognizerTest, PinchScrollWithPreventDefaultedRelease) { EXPECT_TRUE(delegate->end()); } -TEST_F(GestureRecognizerTest, CaptureSendsGestureEnd) { +TEST_P(GestureRecognizerTest, GestureEndLocation) { + GestureEventConsumeDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, -1234, gfx::Rect(10, 10, 300, 300), root_window())); + EventGenerator generator(root_window(), window.get()); + const gfx::Point begin(20, 20); + const gfx::Point end(150, 150); + const gfx::Vector2d window_offset = + window->bounds().origin().OffsetFromOrigin(); + generator.GestureScrollSequence(begin, end, + base::TimeDelta::FromMilliseconds(20), + 10); + EXPECT_EQ((begin - window_offset).ToString(), + delegate.scroll_begin_position().ToString()); + EXPECT_EQ((end - window_offset).ToString(), + delegate.gesture_end_location().ToString()); +} + +TEST_P(GestureRecognizerTest, CaptureSendsGestureEnd) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TestGestureRecognizer* gesture_recognizer = @@ -2384,7 +2511,7 @@ TEST_F(GestureRecognizerTest, CaptureSendsGestureEnd) { // Check that previous touch actions that are completely finished (either // released or cancelled), do not receive extra synthetic cancels upon change of // capture. -TEST_F(GestureRecognizerTest, CaptureDoesNotCancelFinishedTouches) { +TEST_P(GestureRecognizerTest, CaptureDoesNotCancelFinishedTouches) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); scoped_ptr<TestEventHandler> handler(new TestEventHandler); @@ -2437,7 +2564,8 @@ TEST_F(GestureRecognizerTest, CaptureDoesNotCancelFinishedTouches) { root_window()->RemovePreTargetHandler(handler.get()); } -TEST_F(GestureRecognizerTest, PressDoesNotCrash) { +// Tests that a press with the same touch id as an existing touch is ignored. +TEST_P(GestureRecognizerTest, PressDoesNotCrash) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TestGestureRecognizer* gesture_recognizer = @@ -2450,14 +2578,14 @@ TEST_F(GestureRecognizerTest, PressDoesNotCrash) { ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(45, 45), 7, tes.Now()); press.set_radius_x(40); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_TRUE(delegate->tap_down()); EXPECT_EQ(gfx::Rect(5, 5, 80, 80).ToString(), delegate->bounding_box().ToString()); delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(55, 45), 7, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); // This new press should not generate a tap-down. EXPECT_FALSE(delegate->begin()); @@ -2466,7 +2594,12 @@ TEST_F(GestureRecognizerTest, PressDoesNotCrash) { EXPECT_FALSE(delegate->scroll_begin()); } -TEST_F(GestureRecognizerTest, TwoFingerTap) { +TEST_P(GestureRecognizerTest, TwoFingerTap) { + // TODO(tdresser): enable this test with unified GR once two finger tap is + // supported. See crbug.com/354396. + if (UsingUnifiedGR()) + return; + scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -2481,7 +2614,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -2494,7 +2627,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) { delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); // no touch down for second tap. EXPECT_TRUE(delegate->tap_cancel()); @@ -2508,10 +2641,10 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) { delegate->Reset(); ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(102, 202), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1); + DispatchEventUsingWindowDispatcher(&move1); ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(131, 202), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); + DispatchEventUsingWindowDispatcher(&move2); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -2527,11 +2660,11 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) { ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId1, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); - EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_TRUE(delegate->scroll_begin()); EXPECT_FALSE(delegate->scroll_update()); EXPECT_FALSE(delegate->scroll_end()); EXPECT_TRUE(delegate->two_finger_tap()); @@ -2543,7 +2676,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) { ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(130, 201), kTouchId2, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2); + DispatchEventUsingWindowDispatcher(&release2); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -2554,7 +2687,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTap) { EXPECT_FALSE(delegate->two_finger_tap()); } -TEST_F(GestureRecognizerTest, TwoFingerTapExpired) { +TEST_P(GestureRecognizerTest, TwoFingerTapExpired) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -2569,19 +2702,19 @@ TEST_F(GestureRecognizerTest, TwoFingerTapExpired) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); // Send release event after sufficient delay so that two finger time expires. delegate->Reset(); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId1, tes.LeapForward(1000)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->two_finger_tap()); // Lift second finger. @@ -2591,11 +2724,11 @@ TEST_F(GestureRecognizerTest, TwoFingerTapExpired) { ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(130, 201), kTouchId2, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2); + DispatchEventUsingWindowDispatcher(&release2); EXPECT_FALSE(delegate->two_finger_tap()); } -TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) { +TEST_P(GestureRecognizerTest, TwoFingerTapChangesToPinch) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -2613,14 +2746,14 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId1, delegate.get()); + tes.SendScrollEvent(event_processor(), 230, 330, kTouchId1, delegate.get()); EXPECT_FALSE(delegate->two_finger_tap()); EXPECT_TRUE(delegate->pinch_begin()); @@ -2630,7 +2763,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) { ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId2, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_FALSE(delegate->two_finger_tap()); EXPECT_TRUE(delegate->pinch_end()); } @@ -2644,14 +2777,14 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); - tes.SendScrollEvent(dispatcher(), 101, 230, kTouchId2, delegate.get()); + tes.SendScrollEvent(event_processor(), 301, 230, kTouchId2, delegate.get()); EXPECT_FALSE(delegate->two_finger_tap()); EXPECT_TRUE(delegate->pinch_begin()); @@ -2661,13 +2794,18 @@ TEST_F(GestureRecognizerTest, TwoFingerTapChangesToPinch) { ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId1, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_FALSE(delegate->two_finger_tap()); EXPECT_TRUE(delegate->pinch_end()); } } -TEST_F(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled) { +TEST_P(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled) { + // Disabled for unified GR due to differences in when pinch begin is sent. The + // Aura GR sends it earlier than is necessary. + if (UsingUnifiedGR()) + return; + scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -2683,13 +2821,13 @@ TEST_F(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId1, delegate.get()); + DispatchEventUsingWindowDispatcher(&press1); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId1, delegate.get()); delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_TRUE(delegate->pinch_begin()); @@ -2699,12 +2837,12 @@ TEST_F(GestureRecognizerTest, NoTwoFingerTapWhenFirstFingerHasScrolled) { ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId2, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_FALSE(delegate->two_finger_tap()); EXPECT_TRUE(delegate->pinch_end()); } -TEST_F(GestureRecognizerTest, MultiFingerSwipe) { +TEST_P(GestureRecognizerTest, MultiFingerSwipe) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -2725,26 +2863,33 @@ TEST_F(GestureRecognizerTest, MultiFingerSwipe) { aura::test::EventGenerator generator(root_window(), window.get()); + // The unified gesture recognizer assumes a finger has stopped if it hasn't + // moved for too long. See ui/events/gesture_detection/velocity_tracker.cc's + // kAssumePointerStoppedTimeMs. for (int count = 2; count <= kTouchPoints; ++count) { - generator.GestureMultiFingerScroll(count, points, 15, kSteps, 0, -150); + generator.GestureMultiFingerScroll( + count, points, 10, kSteps, 0, -11 * kSteps); EXPECT_TRUE(delegate->swipe_up()); delegate->Reset(); - generator.GestureMultiFingerScroll(count, points, 15, kSteps, 0, 150); + generator.GestureMultiFingerScroll( + count, points, 10, kSteps, 0, 11 * kSteps); EXPECT_TRUE(delegate->swipe_down()); delegate->Reset(); - generator.GestureMultiFingerScroll(count, points, 15, kSteps, -150, 0); + generator.GestureMultiFingerScroll( + count, points, 10, kSteps, -11 * kSteps, 0); EXPECT_TRUE(delegate->swipe_left()); delegate->Reset(); - generator.GestureMultiFingerScroll(count, points, 15, kSteps, 150, 0); + generator.GestureMultiFingerScroll( + count, points, 10, kSteps, 11 * kSteps, 0); EXPECT_TRUE(delegate->swipe_right()); delegate->Reset(); } } -TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) { +TEST_P(GestureRecognizerTest, TwoFingerTapCancelled) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -2762,17 +2907,17 @@ TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); delegate->Reset(); ui::TouchEvent cancel(ui::ET_TOUCH_CANCELLED, gfx::Point(130, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&cancel); + DispatchEventUsingWindowDispatcher(&cancel); EXPECT_FALSE(delegate->two_finger_tap()); // Make sure there is enough delay before the touch is released so that it @@ -2781,7 +2926,7 @@ TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) { ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId2, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_FALSE(delegate->two_finger_tap()); } @@ -2794,17 +2939,17 @@ TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); delegate->Reset(); ui::TouchEvent cancel(ui::ET_TOUCH_CANCELLED, gfx::Point(130, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&cancel); + DispatchEventUsingWindowDispatcher(&cancel); EXPECT_FALSE(delegate->two_finger_tap()); // Make sure there is enough delay before the touch is released so that it @@ -2813,12 +2958,18 @@ TEST_F(GestureRecognizerTest, TwoFingerTapCancelled) { ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId1, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_FALSE(delegate->two_finger_tap()); } } -TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) { +TEST_P(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) { + // Disabled for unified GR due to differences in when scroll update is + // sent. The Aura GR will never send a ScrollUpdate with a ScrollBegin, but + // the unified GR will. + if (UsingUnifiedGR()) + return; + scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 523; @@ -2833,7 +2984,7 @@ TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -2846,7 +2997,7 @@ TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) { delegate->Reset(); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(430, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); // no touch down for second tap. EXPECT_TRUE(delegate->tap_cancel()); @@ -2860,7 +3011,7 @@ TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) { delegate->Reset(); ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(530, 301), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); + DispatchEventUsingWindowDispatcher(&move2); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -2875,7 +3026,7 @@ TEST_F(GestureRecognizerTest, VeryWideTwoFingerTouchDownShouldBeAPinch) { // Verifies if a window is the target of multiple touch-ids and we hide the // window everything is cleaned up correctly. -TEST_F(GestureRecognizerTest, FlushAllOnHide) { +TEST_P(GestureRecognizerTest, FlushAllOnHide) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); gfx::Rect bounds(0, 0, 200, 200); @@ -2887,10 +3038,10 @@ TEST_F(GestureRecognizerTest, FlushAllOnHide) { ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(20, 20), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); window->Hide(); EXPECT_EQ(NULL, ui::GestureRecognizer::Get()->GetTouchLockedTarget(press1)); @@ -2898,9 +3049,13 @@ TEST_F(GestureRecognizerTest, FlushAllOnHide) { ui::GestureRecognizer::Get()->GetTouchLockedTarget(press2)); } -TEST_F(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves) { +TEST_P(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves) { + // TODO(tdresser): write a version of this test for the unified GR. + if (UsingUnifiedGR()) + return; + scoped_ptr<QueueTouchEventDelegate> delegate( - new QueueTouchEventDelegate(dispatcher())); + new QueueTouchEventDelegate(host()->dispatcher())); const int kTouchId = 2; gfx::Rect bounds(100, 200, 100, 100); scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( @@ -2919,9 +3074,9 @@ TEST_F(GestureRecognizerTest, LongPressTimerStopsOnPreventDefaultedTouchMoves) { delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); // Scroll around, to cancel the long press - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get()); delegate->Reset(); delegate->ReceivedAck(); @@ -2958,7 +3113,7 @@ class ConsumesTouchMovesDelegate : public GestureEventConsumeDelegate { // Same as GestureEventScroll, but tests that the behavior is the same // even if all the touch-move events are consumed. -TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) { +TEST_P(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) { scoped_ptr<ConsumesTouchMovesDelegate> delegate( new ConsumesTouchMovesDelegate()); const int kWindowWidth = 123; @@ -2972,7 +3127,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) { delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -2984,7 +3139,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) { // Move the touch-point enough so that it would normally be considered a // scroll. But since the touch-moves will be consumed, the scroll should not // start. - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get()); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_TRUE(delegate->tap_cancel()); @@ -2998,7 +3153,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) { delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(130, 230), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -3010,7 +3165,12 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMoveConsumed) { } // Tests the behavior of 2F scroll when all the touch-move events are consumed. -TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) { +TEST_P(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) { + // TODO(tdresser): enable this test with unified GR once two finger tap is + // supported. See crbug.com/354396. + if (UsingUnifiedGR()) + return; + scoped_ptr<ConsumesTouchMovesDelegate> delegate( new ConsumesTouchMovesDelegate()); const int kWindowWidth = 123; @@ -3026,8 +3186,8 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) { delegate->Reset(); ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); - tes.SendScrollEvent(dispatcher(), 131, 231, kTouchId1, delegate.get()); + DispatchEventUsingWindowDispatcher(&press1); + tes.SendScrollEvent(event_processor(), 131, 231, kTouchId1, delegate.get()); // First finger touches down and moves. EXPECT_FALSE(delegate->tap()); @@ -3039,8 +3199,8 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) { // Second finger touches down and moves. ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(130, 201), kTouchId2, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); - tes.SendScrollEvent(dispatcher(), 161, 231, kTouchId2, delegate.get()); + DispatchEventUsingWindowDispatcher(&press2); + tes.SendScrollEvent(event_processor(), 161, 231, kTouchId2, delegate.get()); // PinchBegin & ScrollBegin were not sent if the touch-move events were // consumed. @@ -3058,7 +3218,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) { delegate->Reset(); // Moves First finger again, no PinchUpdate & ScrollUpdate. - tes.SendScrollEvent(dispatcher(), 161, 261, kTouchId1, delegate.get()); + tes.SendScrollEvent(event_processor(), 161, 261, kTouchId1, delegate.get()); EXPECT_FALSE(delegate->pinch_update()); EXPECT_FALSE(delegate->pinch_end()); @@ -3070,7 +3230,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) { delegate->Reset(); // Making a pinch gesture. - tes.SendScrollEvent(dispatcher(), 161, 251, kTouchId1, delegate.get()); + tes.SendScrollEvent(event_processor(), 161, 251, kTouchId1, delegate.get()); // If touch moves are ever consumed, we should not see PinchBegin/Update // even touch moves become not consumed. EXPECT_FALSE(delegate->scroll_begin()); @@ -3082,7 +3242,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) { EXPECT_FALSE(delegate->pinch_end()); delegate->Reset(); - tes.SendScrollEvent(dispatcher(), 161, 241, kTouchId2, delegate.get()); + tes.SendScrollEvent(event_processor(), 161, 241, kTouchId2, delegate.get()); EXPECT_FALSE(delegate->scroll_begin()); EXPECT_FALSE(delegate->scroll_update()); EXPECT_FALSE(delegate->scroll_end()); @@ -3096,17 +3256,18 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) { kTouchId1, tes.Now()); ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(130, 201), kTouchId2, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2); + DispatchEventUsingWindowDispatcher(&release1); + DispatchEventUsingWindowDispatcher(&release2); EXPECT_FALSE(delegate->tap()); // Touch release is not consumed, so we still see two finger tap. EXPECT_TRUE(delegate->two_finger_tap()); - // Should not see PinchEnd & ScrollEnd. - EXPECT_FALSE(delegate->scroll_begin()); + // Should not see PinchEnd. + EXPECT_TRUE(delegate->scroll_begin()); EXPECT_FALSE(delegate->scroll_update()); EXPECT_FALSE(delegate->scroll_end()); + EXPECT_TRUE(delegate->fling()); EXPECT_FALSE(delegate->pinch_begin()); EXPECT_FALSE(delegate->pinch_update()); @@ -3116,7 +3277,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTwoFingerTouchMoveConsumed) { // Like as GestureEventTouchMoveConsumed but tests the different behavior // depending on whether the events were consumed before or after the scroll // started. -TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { +TEST_P(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { scoped_ptr<ConsumesTouchMovesDelegate> delegate( new ConsumesTouchMovesDelegate()); const int kWindowWidth = 123; @@ -3130,7 +3291,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { delegate->Reset(); ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -3142,7 +3303,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { // Move the touch-point enough so that it would normally be considered a // scroll. But since the touch-moves will be consumed, the scroll should not // start. - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get()); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_TRUE(delegate->tap_cancel()); @@ -3153,7 +3314,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { // Now, stop consuming touch-move events, and move the touch-point again. delegate->set_consume_touch_move(false); - tes.SendScrollEvent(dispatcher(), 159, 259, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 159, 259, kTouchId, delegate.get()); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -3171,7 +3332,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { delegate->set_consume_touch_move(true); // Move some more to generate a few more scroll updates. - tes.SendScrollEvent(dispatcher(), 110, 211, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 110, 211, kTouchId, delegate.get()); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -3182,7 +3343,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { EXPECT_EQ(0, delegate->scroll_x()); EXPECT_EQ(0, delegate->scroll_y()); - tes.SendScrollEvent(dispatcher(), 140, 215, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 140, 215, kTouchId, delegate.get()); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -3197,7 +3358,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { delegate->Reset(); ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_FALSE(delegate->tap_cancel()); @@ -3210,7 +3371,7 @@ TEST_F(GestureRecognizerTest, GestureEventScrollTouchMovePartialConsumed) { } // Check that appropriate touch events generate double tap gesture events. -TEST_F(GestureRecognizerTest, GestureEventDoubleTap) { +TEST_P(GestureRecognizerTest, GestureEventDoubleTap) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -3224,19 +3385,19 @@ TEST_F(GestureRecognizerTest, GestureEventDoubleTap) { // First tap (tested in GestureEventTap) ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(104, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(104, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); delegate->Reset(); // Second tap ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 203), kTouchId, tes.LeapForward(200)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2); + DispatchEventUsingWindowDispatcher(&release2); EXPECT_TRUE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); @@ -3251,7 +3412,7 @@ TEST_F(GestureRecognizerTest, GestureEventDoubleTap) { } // Check that appropriate touch events generate triple tap gesture events. -TEST_F(GestureRecognizerTest, GestureEventTripleTap) { +TEST_P(GestureRecognizerTest, GestureEventTripleTap) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -3265,10 +3426,10 @@ TEST_F(GestureRecognizerTest, GestureEventTripleTap) { // First tap (tested in GestureEventTap) ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(104, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(104, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_EQ(1, delegate->tap_count()); delegate->Reset(); @@ -3276,10 +3437,10 @@ TEST_F(GestureRecognizerTest, GestureEventTripleTap) { // Second tap (tested in GestureEventDoubleTap) ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 203), kTouchId, tes.LeapForward(200)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2); + DispatchEventUsingWindowDispatcher(&release2); EXPECT_EQ(2, delegate->tap_count()); delegate->Reset(); @@ -3287,26 +3448,44 @@ TEST_F(GestureRecognizerTest, GestureEventTripleTap) { // Third tap ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, gfx::Point(102, 206), kTouchId, tes.LeapForward(200)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press3); + DispatchEventUsingWindowDispatcher(&press3); ui::TouchEvent release3(ui::ET_TOUCH_RELEASED, gfx::Point(102, 206), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release3); - - - EXPECT_TRUE(delegate->tap()); - EXPECT_TRUE(delegate->tap_down()); - EXPECT_FALSE(delegate->tap_cancel()); - EXPECT_TRUE(delegate->begin()); - EXPECT_TRUE(delegate->end()); - EXPECT_FALSE(delegate->scroll_begin()); - EXPECT_FALSE(delegate->scroll_update()); - EXPECT_FALSE(delegate->scroll_end()); - - EXPECT_EQ(3, delegate->tap_count()); + DispatchEventUsingWindowDispatcher(&release3); + + // Third, Fourth and Fifth Taps. Taps after the third should have their + // |tap_count| wrap around back to 1. + for (int i = 3; i < 5; ++i) { + ui::TouchEvent press3(ui::ET_TOUCH_PRESSED, + gfx::Point(102, 206), + kTouchId, + tes.LeapForward(200)); + DispatchEventUsingWindowDispatcher(&press3); + ui::TouchEvent release3(ui::ET_TOUCH_RELEASED, + gfx::Point(102, 206), + kTouchId, + tes.LeapForward(50)); + DispatchEventUsingWindowDispatcher(&release3); + + EXPECT_TRUE(delegate->tap()); + EXPECT_TRUE(delegate->tap_down()); + EXPECT_FALSE(delegate->tap_cancel()); + EXPECT_TRUE(delegate->begin()); + EXPECT_TRUE(delegate->end()); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + EXPECT_FALSE(delegate->scroll_end()); + + // The behavior for the Aura GR is incorrect. + if (UsingUnifiedGR()) + EXPECT_EQ(1 + (i % 3), delegate->tap_count()); + else + EXPECT_EQ(3, delegate->tap_count()); + } } // Check that we don't get a double tap when the two taps are far apart. -TEST_F(GestureRecognizerTest, TwoTapsFarApart) { +TEST_P(GestureRecognizerTest, TwoTapsFarApart) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -3320,19 +3499,19 @@ TEST_F(GestureRecognizerTest, TwoTapsFarApart) { // First tap (tested in GestureEventTap) ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); delegate->Reset(); // Second tap, close in time but far in distance ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(201, 201), kTouchId, tes.LeapForward(200)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(201, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2); + DispatchEventUsingWindowDispatcher(&release2); EXPECT_TRUE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); @@ -3348,7 +3527,7 @@ TEST_F(GestureRecognizerTest, TwoTapsFarApart) { // Check that we don't get a double tap when the two taps have a long enough // delay in between. -TEST_F(GestureRecognizerTest, TwoTapsWithDelayBetween) { +TEST_P(GestureRecognizerTest, TwoTapsWithDelayBetween) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 123; @@ -3362,19 +3541,19 @@ TEST_F(GestureRecognizerTest, TwoTapsWithDelayBetween) { // First tap (tested in GestureEventTap) ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); delegate->Reset(); // Second tap, close in distance but after some delay ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.LeapForward(2000)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release2); + DispatchEventUsingWindowDispatcher(&release2); EXPECT_TRUE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); @@ -3391,7 +3570,12 @@ TEST_F(GestureRecognizerTest, TwoTapsWithDelayBetween) { // Checks that if the bounding-box of a gesture changes because of change in // radius of a touch-point, and not because of change in position, then there // are not gesture events from that. -TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) { +TEST_P(GestureRecognizerTest, BoundingBoxRadiusChange) { + // TODO(tdresser): enable this test with unified GR when (if?) bounding box + // behavior is unified. + if (UsingUnifiedGR()) + return; + scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); const int kWindowWidth = 234; @@ -3404,7 +3588,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) { ui::TouchEvent press1( ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_TRUE(delegate->bounding_box().IsEmpty()); delegate->Reset(); @@ -3413,7 +3597,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) { ui::ET_TOUCH_PRESSED, gfx::Point(201, 201), kTouchId2, tes.LeapForward(400)); press2.set_radius_x(5); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_FALSE(delegate->pinch_begin()); EXPECT_EQ(gfx::Rect(101, 201, 100, 0).ToString(), delegate->bounding_box().ToString()); @@ -3422,7 +3606,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) { ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(141, 201), kTouchId, tes.LeapForward(40)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1); + DispatchEventUsingWindowDispatcher(&move1); EXPECT_TRUE(delegate->pinch_begin()); EXPECT_EQ(gfx::Rect(141, 201, 60, 0).ToString(), delegate->bounding_box().ToString()); @@ -3434,7 +3618,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) { tes.LeapForward(40)); move2.set_radius_x(50); move2.set_radius_y(60); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); + DispatchEventUsingWindowDispatcher(&move2); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_cancel()); EXPECT_FALSE(delegate->scroll_update()); @@ -3445,7 +3629,7 @@ TEST_F(GestureRecognizerTest, BoundingBoxRadiusChange) { // Checks that slow scrolls deliver the correct deltas. // In particular, fix for http;//crbug.com/150573. -TEST_F(GestureRecognizerTest, NoDriftInScroll) { +TEST_P(GestureRecognizerTest, NoDriftInScroll) { ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(3); ui::GestureConfiguration::set_min_scroll_delta_squared(9); scoped_ptr<GestureEventConsumeDelegate> delegate( @@ -3460,38 +3644,40 @@ TEST_F(GestureRecognizerTest, NoDriftInScroll) { ui::TouchEvent press1( ui::ET_TOUCH_PRESSED, gfx::Point(101, 208), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_TRUE(delegate->begin()); delegate->Reset(); ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(101, 206), kTouchId, tes.LeapForward(40)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1); + DispatchEventUsingWindowDispatcher(&move1); EXPECT_FALSE(delegate->scroll_begin()); delegate->Reset(); ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(101, 204), kTouchId, tes.LeapForward(40)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); + DispatchEventUsingWindowDispatcher(&move2); EXPECT_TRUE(delegate->tap_cancel()); EXPECT_TRUE(delegate->scroll_begin()); EXPECT_TRUE(delegate->scroll_update()); - EXPECT_EQ(-4, delegate->scroll_y()); + // 3 px consumed by touch slop region. + EXPECT_EQ(-1, delegate->scroll_y()); + EXPECT_EQ(-4, delegate->scroll_y_hint()); delegate->Reset(); ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(101, 204), kTouchId, tes.LeapForward(40)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move3); + DispatchEventUsingWindowDispatcher(&move3); EXPECT_FALSE(delegate->scroll_update()); delegate->Reset(); ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(101, 203), kTouchId, tes.LeapForward(40)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move4); + DispatchEventUsingWindowDispatcher(&move4); EXPECT_TRUE(delegate->scroll_update()); EXPECT_EQ(-1, delegate->scroll_y()); @@ -3501,7 +3687,7 @@ TEST_F(GestureRecognizerTest, NoDriftInScroll) { // Ensure that move events which are preventDefaulted will cause a tap // cancel gesture event to be fired if the move would normally cause a // scroll. See bug http://crbug.com/146397. -TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel) { +TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel) { scoped_ptr<ConsumesTouchMovesDelegate> delegate( new ConsumesTouchMovesDelegate()); const int kTouchId = 5; @@ -3515,13 +3701,13 @@ TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel) { kTouchId, tes.Now()); delegate->set_consume_touch_move(false); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); delegate->set_consume_touch_move(true); delegate->Reset(); // Move the touch-point enough so that it would normally be considered a // scroll. But since the touch-moves will be consumed, the scroll should not // start. - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get()); EXPECT_FALSE(delegate->tap()); EXPECT_FALSE(delegate->tap_down()); EXPECT_TRUE(delegate->tap_cancel()); @@ -3531,7 +3717,7 @@ TEST_F(GestureRecognizerTest, GestureEventConsumedTouchMoveCanFireTapCancel) { EXPECT_FALSE(delegate->scroll_end()); } -TEST_F(GestureRecognizerTest, +TEST_P(GestureRecognizerTest, TransferEventDispatchesTouchCancel) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); @@ -3552,8 +3738,8 @@ TEST_F(GestureRecognizerTest, ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); ui::TouchEvent p2(ui::ET_TOUCH_PRESSED, gfx::Point(50, 50), 1, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&p2); + DispatchEventUsingWindowDispatcher(&press); + DispatchEventUsingWindowDispatcher(&p2); EXPECT_FALSE(delegate->tap()); EXPECT_TRUE(delegate->tap_down()); EXPECT_TRUE(delegate->tap_cancel()); @@ -3574,7 +3760,7 @@ TEST_F(GestureRecognizerTest, } // Check that appropriate touch events generate show press events -TEST_F(GestureRecognizerTest, GestureEventShowPress) { +TEST_P(GestureRecognizerTest, GestureEventShowPress) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -3594,7 +3780,7 @@ TEST_F(GestureRecognizerTest, GestureEventShowPress) { ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_TRUE(delegate->tap_down()); EXPECT_TRUE(delegate->begin()); EXPECT_FALSE(delegate->tap_cancel()); @@ -3610,15 +3796,16 @@ TEST_F(GestureRecognizerTest, GestureEventShowPress) { delegate->Reset(); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->long_press()); - // Note the tap down isn't cancelled until the release - EXPECT_TRUE(delegate->tap_cancel()); + // Note the tap isn't dispatched until the release + EXPECT_FALSE(delegate->tap_cancel()); + EXPECT_TRUE(delegate->tap()); } // Check that scrolling cancels a show press -TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) { +TEST_P(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -3642,7 +3829,7 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) { ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_TRUE(delegate->tap_down()); // We haven't pressed long enough for a show press to occur @@ -3650,7 +3837,7 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) { EXPECT_FALSE(delegate->tap_cancel()); // Scroll around, to cancel the show press - tes.SendScrollEvent(dispatcher(), 130, 230, kTouchId, delegate.get()); + tes.SendScrollEvent(event_processor(), 130, 230, kTouchId, delegate.get()); // Wait until the timer runs out gesture_sequence->ForceTimeout(); EXPECT_FALSE(delegate->show_press()); @@ -3659,13 +3846,13 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressCancelledByScroll) { delegate->Reset(); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(10)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_FALSE(delegate->show_press()); EXPECT_FALSE(delegate->tap_cancel()); } // Test that show press events are sent immediately on tap -TEST_F(GestureRecognizerTest, GestureEventShowPressSentOnTap) { +TEST_P(GestureRecognizerTest, GestureEventShowPressSentOnTap) { scoped_ptr<GestureEventConsumeDelegate> delegate( new GestureEventConsumeDelegate()); TimedEvents tes; @@ -3680,7 +3867,7 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressSentOnTap) { ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), kTouchId, tes.Now()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press1); + DispatchEventUsingWindowDispatcher(&press1); EXPECT_TRUE(delegate->tap_down()); // We haven't pressed long enough for a show press to occur @@ -3690,11 +3877,516 @@ TEST_F(GestureRecognizerTest, GestureEventShowPressSentOnTap) { delegate->Reset(); ui::TouchEvent release1(ui::ET_TOUCH_RELEASED, gfx::Point(101, 201), kTouchId, tes.LeapForward(50)); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release1); + DispatchEventUsingWindowDispatcher(&release1); EXPECT_TRUE(delegate->show_press()); EXPECT_FALSE(delegate->tap_cancel()); EXPECT_TRUE(delegate->tap()); } +// Test that consuming the first move touch event prevents a scroll. +TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMoveScrollTest) { + scoped_ptr<QueueTouchEventDelegate> delegate( + new QueueTouchEventDelegate(host()->dispatcher())); + TimedEvents tes; + const int kTouchId = 7; + gfx::Rect bounds(0, 0, 1000, 1000); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, root_window())); + + ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&press); + delegate->ReceivedAck(); + + // A touch move within the slop region is never consumed in web contents. The + // unified GR won't prevent scroll if a touch move within the slop region is + // consumed, so make sure this touch move exceeds the slop region. + ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(10, 10), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move1); + delegate->ReceivedAckPreventDefaulted(); + + ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move2); + delegate->ReceivedAck(); + + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); +} + +// Test that consuming the first touch move event of a touch point doesn't +// prevent pinching once an additional touch has been pressed. +TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMovePinchTest) { + // Consuming moves within the touch slop and the the disposition handling of + // pinch events behave differently between the Unified GR and the Aura GR. + if (UsingUnifiedGR()) + return; + + scoped_ptr<QueueTouchEventDelegate> delegate( + new QueueTouchEventDelegate(host()->dispatcher())); + TimedEvents tes; + const int kTouchId1 = 7; + const int kTouchId2 = 4; + gfx::Rect bounds(0, 0, 1000, 1000); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, root_window())); + + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), + kTouchId1, tes.Now()); + DispatchEventUsingWindowDispatcher(&press1); + delegate->ReceivedAck(); + + ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(2, 2), + kTouchId1, tes.Now()); + DispatchEventUsingWindowDispatcher(&move1); + delegate->ReceivedAckPreventDefaulted(); + + ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), + kTouchId1, tes.Now()); + DispatchEventUsingWindowDispatcher(&move2); + delegate->ReceivedAck(); + + // We can't scroll, because a move has been consumed. + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + EXPECT_FALSE(delegate->pinch_begin()); + + // An additional press will allow us to pinch. + ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), + kTouchId2, tes.Now()); + DispatchEventUsingWindowDispatcher(&press2); + delegate->ReceivedAck(); + + ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), + kTouchId2, tes.Now()); + DispatchEventUsingWindowDispatcher(&move3); + delegate->ReceivedAck(); + + EXPECT_TRUE(delegate->pinch_begin()); + EXPECT_FALSE(delegate->pinch_update()); + + delegate->Reset(); + + ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(40, 40), + kTouchId2, tes.Now()); + DispatchEventUsingWindowDispatcher(&move4); + delegate->ReceivedAck(); + + EXPECT_TRUE(delegate->pinch_update()); + EXPECT_EQ(10, delegate->scroll_x()); + EXPECT_EQ(10, delegate->scroll_y()); +} + +// Test that consuming the first move touch doesn't prevent a tap. +TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMoveTapTest) { + scoped_ptr<QueueTouchEventDelegate> delegate( + new QueueTouchEventDelegate(host()->dispatcher())); + TimedEvents tes; + const int kTouchId = 7; + gfx::Rect bounds(0, 0, 1000, 1000); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, root_window())); + + ui::TouchEvent press(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&press); + delegate->ReceivedAck(); + + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(2, 2), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move); + delegate->ReceivedAckPreventDefaulted(); + + ui::TouchEvent release(ui::ET_TOUCH_RELEASED, gfx::Point(2, 2), + kTouchId, tes.LeapForward(50)); + DispatchEventUsingWindowDispatcher(&release); + delegate->ReceivedAck(); + + EXPECT_TRUE(delegate->tap()); +} + +// Test that consuming the first move touch doesn't prevent a long press. +TEST_P(GestureRecognizerTest, GestureEventConsumedTouchMoveLongPressTest) { + scoped_ptr<QueueTouchEventDelegate> delegate( + new QueueTouchEventDelegate(host()->dispatcher())); + TimedEvents tes; + const int kWindowWidth = 123; + const int kWindowHeight = 45; + const int kTouchId = 2; + gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, root_window())); + + delegate->Reset(); + + TimerTestGestureRecognizer* gesture_recognizer = + new TimerTestGestureRecognizer(); + + ScopedGestureRecognizerSetter gr_setter(gesture_recognizer); + + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&press1); + delegate->ReceivedAck(); + + ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(103, 203), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move); + delegate->ReceivedAckPreventDefaulted(); + + // Wait until the timer runs out + delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS); + EXPECT_TRUE(delegate->long_press()); +} + +// Tests that the deltas are correct when leaving the slop region very slowly. +TEST_P(GestureRecognizerTest, TestExceedingSlopSlowly) { + // Disabled for unified GR due to subtle differences in touch slop handling. + if (UsingUnifiedGR()) + return; + + ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(3); + scoped_ptr<GestureEventConsumeDelegate> delegate( + new GestureEventConsumeDelegate()); + const int kWindowWidth = 234; + const int kWindowHeight = 345; + const int kTouchId = 5; + TimedEvents tes; + gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, root_window())); + + ui::TouchEvent press( + ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&press); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + delegate->Reset(); + + ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(11, 10), kTouchId, + tes.LeapForward(40)); + DispatchEventUsingWindowDispatcher(&move1); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + EXPECT_EQ(0, delegate->scroll_x()); + EXPECT_EQ(0, delegate->scroll_x_hint()); + delegate->Reset(); + + ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(12, 10), kTouchId, + tes.LeapForward(40)); + DispatchEventUsingWindowDispatcher(&move2); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + EXPECT_EQ(0, delegate->scroll_x()); + EXPECT_EQ(0, delegate->scroll_x_hint()); + delegate->Reset(); + + + ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(13, 10), kTouchId, + tes.LeapForward(40)); + DispatchEventUsingWindowDispatcher(&move3); + EXPECT_TRUE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + EXPECT_EQ(0, delegate->scroll_x()); + EXPECT_EQ(3, delegate->scroll_x_hint()); + delegate->Reset(); + + + ui::TouchEvent move4(ui::ET_TOUCH_MOVED, gfx::Point(14, 10), kTouchId, + tes.LeapForward(40)); + DispatchEventUsingWindowDispatcher(&move4); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_TRUE(delegate->scroll_update()); + EXPECT_EQ(1, delegate->scroll_x()); + EXPECT_EQ(0, delegate->scroll_x_hint()); + delegate->Reset(); +} + +TEST_P(GestureRecognizerTest, ScrollAlternatelyConsumedTest) { + scoped_ptr<QueueTouchEventDelegate> delegate( + new QueueTouchEventDelegate(host()->dispatcher())); + TimedEvents tes; + const int kWindowWidth = 3000; + const int kWindowHeight = 3000; + const int kTouchId = 2; + gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, root_window())); + + delegate->Reset(); + + int x = 0; + int y = 0; + + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(x, y), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&press1); + delegate->ReceivedAck(); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + delegate->Reset(); + + x += 100; + y += 100; + ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(x, y), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move1); + delegate->ReceivedAck(); + EXPECT_TRUE(delegate->scroll_begin()); + EXPECT_TRUE(delegate->scroll_update()); + delegate->Reset(); + + for (int i = 0; i < 3; ++i) { + x += 10; + y += 10; + ui::TouchEvent move2( + ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move2); + delegate->ReceivedAck(); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_TRUE(delegate->scroll_update()); + EXPECT_EQ(10, delegate->scroll_x()); + EXPECT_EQ(10, delegate->scroll_y()); + delegate->Reset(); + + x += 20; + y += 20; + ui::TouchEvent move3( + ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&move3); + delegate->ReceivedAckPreventDefaulted(); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + delegate->Reset(); + } +} + +TEST_P(GestureRecognizerTest, PinchAlternatelyConsumedTest) { + // Disabled for unified GR due to differences in when scroll update is + // sent. The Aura GR will never send a ScrollUpdate with a ScrollBegin, but + // the unified GR will. + if (UsingUnifiedGR()) + return; + + scoped_ptr<QueueTouchEventDelegate> delegate( + new QueueTouchEventDelegate(host()->dispatcher())); + TimedEvents tes; + const int kWindowWidth = 3000; + const int kWindowHeight = 3000; + const int kTouchId1 = 5; + const int kTouchId2 = 7; + gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, root_window())); + + delegate->Reset(); + + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), + kTouchId1, tes.Now()); + DispatchEventUsingWindowDispatcher(&press1); + delegate->ReceivedAck(); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + delegate->Reset(); + + int x = 0; + int y = 0; + + ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, gfx::Point(x, y), + kTouchId2, tes.Now()); + DispatchEventUsingWindowDispatcher(&press2); + delegate->ReceivedAck(); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + EXPECT_FALSE(delegate->pinch_begin()); + EXPECT_FALSE(delegate->pinch_update()); + + delegate->Reset(); + + x += 100; + y += 100; + ui::TouchEvent move1(ui::ET_TOUCH_MOVED, gfx::Point(x, y), + kTouchId2, tes.Now()); + DispatchEventUsingWindowDispatcher(&move1); + delegate->ReceivedAck(); + EXPECT_TRUE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + EXPECT_TRUE(delegate->pinch_begin()); + EXPECT_FALSE(delegate->pinch_update()); + delegate->Reset(); + + const float expected_scales[] = {1.5f, 1.2f, 1.125f}; + + for (int i = 0; i < 3; ++i) { + x += 50; + y += 50; + ui::TouchEvent move2( + ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId2, tes.Now()); + DispatchEventUsingWindowDispatcher(&move2); + delegate->ReceivedAck(); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_TRUE(delegate->scroll_update()); + EXPECT_FALSE(delegate->scroll_end()); + EXPECT_FALSE(delegate->pinch_begin()); + EXPECT_TRUE(delegate->pinch_update()); + EXPECT_FALSE(delegate->pinch_end()); + EXPECT_EQ(25, delegate->scroll_x()); + EXPECT_EQ(25, delegate->scroll_y()); + EXPECT_FLOAT_EQ(expected_scales[i], delegate->scale()); + delegate->Reset(); + + x += 100; + y += 100; + ui::TouchEvent move3( + ui::ET_TOUCH_MOVED, gfx::Point(x, y), kTouchId2, tes.Now()); + DispatchEventUsingWindowDispatcher(&move3); + delegate->ReceivedAckPreventDefaulted(); + EXPECT_FALSE(delegate->scroll_begin()); + EXPECT_FALSE(delegate->scroll_update()); + EXPECT_FALSE(delegate->scroll_end()); + EXPECT_FALSE(delegate->pinch_begin()); + EXPECT_FALSE(delegate->pinch_update()); + EXPECT_FALSE(delegate->pinch_end()); + delegate->Reset(); + } +} + +// Test that touch event flags are passed through to the gesture event. +TEST_P(GestureRecognizerTest, GestureEventFlagsPassedFromTouchEvent) { + scoped_ptr<GestureEventConsumeDelegate> delegate( + new GestureEventConsumeDelegate()); + TimedEvents tes; + const int kWindowWidth = 123; + const int kWindowHeight = 45; + const int kTouchId = 6; + gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, root_window())); + + delegate->Reset(); + + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), + kTouchId, tes.Now()); + DispatchEventUsingWindowDispatcher(&press1); + EXPECT_TRUE(delegate->tap_down()); + + int default_flags = delegate->flags(); + + ui::TouchEvent move1( + ui::ET_TOUCH_MOVED, gfx::Point(397, 149), kTouchId, tes.LeapForward(50)); + move1.set_flags(992); + + DispatchEventUsingWindowDispatcher(&move1); + EXPECT_NE(default_flags, delegate->flags()); +} + +// Test that latency info is passed through to the gesture event. +TEST_P(GestureRecognizerTest, LatencyPassedFromTouchEvent) { + scoped_ptr<GestureEventConsumeDelegate> delegate( + new GestureEventConsumeDelegate()); + TimedEvents tes; + const int kWindowWidth = 123; + const int kWindowHeight = 45; + const int kTouchId = 6; + + const base::TimeTicks time_original = base::TimeTicks::FromInternalValue(100); + const base::TimeTicks time_ui = base::TimeTicks::FromInternalValue(200); + const base::TimeTicks time_acked = base::TimeTicks::FromInternalValue(300); + + gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + delegate.get(), -1234, bounds, root_window())); + + delegate->Reset(); + + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, gfx::Point(101, 201), + kTouchId, tes.Now()); + + // Ensure the only components around are the ones we add. + press1.latency()->Clear(); + + press1.latency()->AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, time_original, 1); + + press1.latency()->AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0, time_ui, 1); + + press1.latency()->AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT, 0, 0, time_acked, 1); + + DispatchEventUsingWindowDispatcher(&press1); + EXPECT_TRUE(delegate->tap_down()); + + ui::LatencyInfo::LatencyComponent component; + + EXPECT_EQ(3U, delegate->latency_info().latency_components.size()); + ASSERT_TRUE(delegate->latency_info().FindLatency( + ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, &component)); + EXPECT_EQ(time_original, component.event_time); + + ASSERT_TRUE(delegate->latency_info().FindLatency( + ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, &component)); + EXPECT_EQ(time_ui, component.event_time); + + ASSERT_TRUE(delegate->latency_info().FindLatency( + ui::INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT, 0, &component)); + EXPECT_EQ(time_acked, component.event_time); + + delegate->WaitUntilReceivedGesture(ui::ET_GESTURE_SHOW_PRESS); + EXPECT_TRUE(delegate->show_press()); + EXPECT_EQ(0U, delegate->latency_info().latency_components.size()); +} + +// A delegate that deletes a window on long press. +class GestureEventDeleteWindowOnLongPress : public GestureEventConsumeDelegate { + public: + GestureEventDeleteWindowOnLongPress() + : window_(NULL) {} + + void set_window(aura::Window** window) { window_ = window; } + + virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE { + GestureEventConsumeDelegate::OnGestureEvent(gesture); + if (gesture->type() != ui::ET_GESTURE_LONG_PRESS) + return; + ui::GestureRecognizer::Get()->CleanupStateForConsumer(*window_); + delete *window_; + *window_ = NULL; + } + + private: + aura::Window** window_; + DISALLOW_COPY_AND_ASSIGN(GestureEventDeleteWindowOnLongPress); +}; + +// Check that deleting the window in response to a long press gesture doesn't +// crash. +TEST_P(GestureRecognizerTest, GestureEventLongPressDeletingWindow) { + GestureEventDeleteWindowOnLongPress delegate; + const int kWindowWidth = 123; + const int kWindowHeight = 45; + const int kTouchId = 2; + gfx::Rect bounds(100, 200, kWindowWidth, kWindowHeight); + aura::Window* window(CreateTestWindowWithDelegate( + &delegate, -1234, bounds, root_window())); + delegate.set_window(&window); + + ui::TouchEvent press1(ui::ET_TOUCH_PRESSED, + gfx::Point(101, 201), + kTouchId, + ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&press1); + EXPECT_TRUE(window != NULL); + + // Wait until the timer runs out. + delegate.WaitUntilReceivedGesture(ui::ET_GESTURE_LONG_PRESS); + EXPECT_EQ(NULL, window); +} + +INSTANTIATE_TEST_CASE_P(GestureRecognizer, + GestureRecognizerTest, + ::testing::Bool()); + } // namespace test } // namespace aura diff --git a/chromium/ui/aura/remote_root_window_host_win.h b/chromium/ui/aura/remote_root_window_host_win.h deleted file mode 100644 index 5c1066f80fa..00000000000 --- a/chromium/ui/aura/remote_root_window_host_win.h +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_REMOTE_ROOT_WINDOW_HOST_WIN_H_ -#define UI_AURA_REMOTE_ROOT_WINDOW_HOST_WIN_H_ - -#include <vector> - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/strings/string16.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/ime/remote_input_method_delegate_win.h" -#include "ui/events/event.h" -#include "ui/events/event_constants.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/metro_viewer/ime_types.h" - -namespace base { -class FilePath; -} - -namespace ui { -class RemoteInputMethodPrivateWin; -class ViewProp; -} - -namespace IPC { -class Message; -class Sender; -} - -namespace aura { - -typedef base::Callback<void(const base::FilePath&, int, void*)> - OpenFileCompletion; - -typedef base::Callback<void(const std::vector<base::FilePath>&, void*)> - OpenMultipleFilesCompletion; - -typedef base::Callback<void(const base::FilePath&, int, void*)> - SaveFileCompletion; - -typedef base::Callback<void(const base::FilePath&, int, void*)> - SelectFolderCompletion; - -typedef base::Callback<void(void*)> FileSelectionCanceled; - -// Handles the open file operation for Metro Chrome Ash. The on_success -// callback passed in is invoked when we receive the opened file name from -// the metro viewer. The on failure callback is invoked on failure. -AURA_EXPORT void HandleOpenFile(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenFileCompletion& on_success, - const FileSelectionCanceled& on_failure); - -// Handles the open multiple file operation for Metro Chrome Ash. The -// on_success callback passed in is invoked when we receive the opened file -// names from the metro viewer. The on failure callback is invoked on failure. -AURA_EXPORT void HandleOpenMultipleFiles( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenMultipleFilesCompletion& on_success, - const FileSelectionCanceled& on_failure); - -// Handles the save file operation for Metro Chrome Ash. The on_success -// callback passed in is invoked when we receive the saved file name from -// the metro viewer. The on failure callback is invoked on failure. -AURA_EXPORT void HandleSaveFile(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - int filter_index, - const base::string16& default_extension, - const SaveFileCompletion& on_success, - const FileSelectionCanceled& on_failure); - -// Handles the select folder for Metro Chrome Ash. The on_success -// callback passed in is invoked when we receive the folder name from the -// metro viewer. The on failure callback is invoked on failure. -AURA_EXPORT void HandleSelectFolder(const base::string16& title, - const SelectFolderCompletion& on_success, - const FileSelectionCanceled& on_failure); - -// Handles the activate desktop command for Metro Chrome Ash. The |ash_exit| -// parameter indicates whether the Ash process would be shutdown after -// activating the desktop. -AURA_EXPORT void HandleActivateDesktop( - const base::FilePath& shortcut, - bool ash_exit); - -// Handles the metro exit command. Notifies the metro viewer to shutdown -// gracefully. -AURA_EXPORT void HandleMetroExit(); - -// RootWindowHost implementaton that receives events from a different -// process. In the case of Windows this is the Windows 8 (aka Metro) -// frontend process, which forwards input events to this class. -class AURA_EXPORT RemoteRootWindowHostWin - : public RootWindowHost, - public ui::internal::RemoteInputMethodDelegateWin { - public: - // Returns the only RemoteRootWindowHostWin, if this is the first time - // this function is called, it will call Create() wiht empty bounds. - static RemoteRootWindowHostWin* Instance(); - static RemoteRootWindowHostWin* Create(const gfx::Rect& bounds); - - // Called when the remote process has established its IPC connection. - // The |host| can be used when we need to send a message to it and - // |remote_window| is the actual window owned by the viewer process. - void Connected(IPC::Sender* host, HWND remote_window); - // Called when the remote process has closed its IPC connection. - void Disconnected(); - - // Called when we have a message from the remote process. - bool OnMessageReceived(const IPC::Message& message); - - void HandleOpenURLOnDesktop(const base::FilePath& shortcut, - const base::string16& url); - - // The |ash_exit| parameter indicates whether the Ash process would be - // shutdown after activating the desktop. - void HandleActivateDesktop(const base::FilePath& shortcut, bool ash_exit); - - // Notify the metro viewer that it should shut itself down. - void HandleMetroExit(); - - void HandleOpenFile(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenFileCompletion& on_success, - const FileSelectionCanceled& on_failure); - - void HandleOpenMultipleFiles(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenMultipleFilesCompletion& on_success, - const FileSelectionCanceled& on_failure); - - void HandleSaveFile(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - int filter_index, - const base::string16& default_extension, - const SaveFileCompletion& on_success, - const FileSelectionCanceled& on_failure); - - void HandleSelectFolder(const base::string16& title, - const SelectFolderCompletion& on_success, - const FileSelectionCanceled& on_failure); - - void HandleWindowSizeChanged(uint32 width, uint32 height); - - // Returns the active ASH root window. - Window* GetAshWindow(); - - // Returns true if the remote window is the foreground window according to the - // OS. - bool IsForegroundWindow(); - - private: - explicit RemoteRootWindowHostWin(const gfx::Rect& bounds); - virtual ~RemoteRootWindowHostWin(); - - // IPC message handing methods: - void OnMouseMoved(int32 x, int32 y, int32 flags); - void OnMouseButton(int32 x, - int32 y, - int32 extra, - ui::EventType type, - ui::EventFlags flags); - void OnKeyDown(uint32 vkey, - uint32 repeat_count, - uint32 scan_code, - uint32 flags); - void OnKeyUp(uint32 vkey, - uint32 repeat_count, - uint32 scan_code, - uint32 flags); - void OnChar(uint32 key_code, - uint32 repeat_count, - uint32 scan_code, - uint32 flags); - void OnWindowActivated(); - void OnTouchDown(int32 x, int32 y, uint64 timestamp, uint32 pointer_id); - void OnTouchUp(int32 x, int32 y, uint64 timestamp, uint32 pointer_id); - void OnTouchMoved(int32 x, int32 y, uint64 timestamp, uint32 pointer_id); - void OnFileSaveAsDone(bool success, - const base::FilePath& filename, - int filter_index); - void OnFileOpenDone(bool success, const base::FilePath& filename); - void OnMultiFileOpenDone(bool success, - const std::vector<base::FilePath>& files); - void OnSelectFolderDone(bool success, const base::FilePath& folder); - void OnSetCursorPosAck(); - - // For Input Method support: - ui::RemoteInputMethodPrivateWin* GetRemoteInputMethodPrivate(); - void OnImeCandidatePopupChanged(bool visible); - void OnImeCompositionChanged( - const string16& text, - int32 selection_start, - int32 selection_end, - const std::vector<metro_viewer::UnderlineInfo>& underlines); - void OnImeTextCommitted(const string16& text); - void OnImeInputSourceChanged(uint16 language_id, bool is_ime); - - // RootWindowHost overrides: - virtual RootWindow* GetRootWindow() OVERRIDE; - virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; - virtual void Show() OVERRIDE; - virtual void Hide() OVERRIDE; - virtual void ToggleFullScreen() OVERRIDE; - virtual gfx::Rect GetBounds() const OVERRIDE; - virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; - virtual gfx::Insets GetInsets() const OVERRIDE; - virtual void SetInsets(const gfx::Insets& insets) OVERRIDE; - virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE; - virtual void SetCapture() OVERRIDE; - virtual void ReleaseCapture() OVERRIDE; - virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE; - virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE; - virtual bool ConfineCursorToRootWindow() OVERRIDE; - virtual void UnConfineCursor() OVERRIDE; - virtual void OnCursorVisibilityChanged(bool show) OVERRIDE; - virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE; - virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE; - virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; - virtual void PrepareForShutdown() OVERRIDE; - - // ui::internal::RemoteInputMethodDelegateWin overrides: - virtual void CancelComposition() OVERRIDE; - virtual void OnTextInputClientUpdated( - const std::vector<int32>& input_scopes, - const std::vector<gfx::Rect>& composition_character_bounds) OVERRIDE; - - // Helper function to dispatch a keyboard message to the desired target. - // The default target is the RootWindowHostDelegate. For nested message loop - // invocations we post a synthetic keyboard message directly into the message - // loop. The dispatcher for the nested loop would then decide how this - // message is routed. - void DispatchKeyboardMessage(ui::EventType type, - uint32 vkey, - uint32 repeat_count, - uint32 scan_code, - uint32 flags, - bool is_character); - - // Sets the event flags. |flags| is a bitmask of EventFlags. If there is a - // change the system virtual key state is updated as well. This way if chrome - // queries for key state it matches that of event being dispatched. - void SetEventFlags(uint32 flags); - - uint32 mouse_event_flags() const { - return event_flags_ & (ui::EF_LEFT_MOUSE_BUTTON | - ui::EF_MIDDLE_MOUSE_BUTTON | - ui::EF_RIGHT_MOUSE_BUTTON); - } - - uint32 key_event_flags() const { - return event_flags_ & (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | - ui::EF_ALT_DOWN | ui::EF_CAPS_LOCK_DOWN); - } - - HWND remote_window_; - IPC::Sender* host_; - scoped_ptr<ui::ViewProp> prop_; - - // Saved callbacks which inform the caller about the result of the open file/ - // save file/select operations. - OpenFileCompletion file_open_completion_callback_; - OpenMultipleFilesCompletion multi_file_open_completion_callback_; - SaveFileCompletion file_saveas_completion_callback_; - SelectFolderCompletion select_folder_completion_callback_; - FileSelectionCanceled failure_callback_; - - // Set to true if we need to ignore mouse messages until the SetCursorPos - // operation is acked by the viewer. - bool ignore_mouse_moves_until_set_cursor_ack_; - - // Tracking last click event for synthetically generated mouse events. - scoped_ptr<ui::MouseEvent> last_mouse_click_event_; - - // State of the keyboard/mouse at the time of the last input event. See - // description of SetEventFlags(). - uint32 event_flags_; - - // Current size of this root window. - gfx::Size window_size_; - - DISALLOW_COPY_AND_ASSIGN(RemoteRootWindowHostWin); -}; - -} // namespace aura - -#endif // UI_AURA_REMOTE_ROOT_WINDOW_HOST_WIN_H_ diff --git a/chromium/ui/aura/remote_root_window_host_win.cc b/chromium/ui/aura/remote_window_tree_host_win.cc index 3dba26aacc4..0cd5ee878e9 100644 --- a/chromium/ui/aura/remote_root_window_host_win.cc +++ b/chromium/ui/aura/remote_window_tree_host_win.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/aura/remote_root_window_host_win.h" +#include "ui/aura/remote_window_tree_host_win.h" #include <windows.h> @@ -13,24 +13,25 @@ #include "ipc/ipc_sender.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/cursor_client.h" -#include "ui/aura/root_window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_property.h" #include "ui/base/cursor/cursor_loader_win.h" #include "ui/base/ime/composition_text.h" #include "ui/base/ime/input_method.h" #include "ui/base/ime/remote_input_method_win.h" #include "ui/base/ime/text_input_client.h" +#include "ui/base/view_prop.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/keyboard_code_conversion_win.h" -#include "ui/base/view_prop.h" #include "ui/gfx/insets.h" +#include "ui/gfx/win/dpi.h" #include "ui/metro_viewer/metro_viewer_messages.h" namespace aura { namespace { -const char* kRootWindowHostWinKey = "__AURA_REMOTE_ROOT_WINDOW_HOST_WIN__"; +const char* kWindowTreeHostWinKey = "__AURA_REMOTE_WINDOW_TREE_HOST_WIN__"; // Sets the keystate for the virtual key passed in to down or up. void SetKeyState(uint8* key_states, bool key_down, uint32 virtual_key_code) { @@ -61,7 +62,7 @@ void SetVirtualKeyStates(uint32 flags) { } void FillCompositionText( - const string16& text, + const base::string16& text, int32 selection_start, int32 selection_end, const std::vector<metro_viewer::UnderlineInfo>& underlines, @@ -76,110 +77,58 @@ void FillCompositionText( composition_text->underlines[i].end_offset = underlines[i].end_offset; composition_text->underlines[i].color = SK_ColorBLACK; composition_text->underlines[i].thick = underlines[i].thick; + composition_text->underlines[i].background_color = SK_ColorTRANSPARENT; } } } // namespace -void HandleOpenFile(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenFileCompletion& on_success, - const FileSelectionCanceled& on_failure) { - DCHECK(aura::RemoteRootWindowHostWin::Instance()); - aura::RemoteRootWindowHostWin::Instance()->HandleOpenFile(title, - default_path, - filter, - on_success, - on_failure); -} - -void HandleOpenMultipleFiles(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenMultipleFilesCompletion& on_success, - const FileSelectionCanceled& on_failure) { - DCHECK(aura::RemoteRootWindowHostWin::Instance()); - aura::RemoteRootWindowHostWin::Instance()->HandleOpenMultipleFiles( - title, - default_path, - filter, - on_success, - on_failure); -} - -void HandleSaveFile(const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - int filter_index, - const base::string16& default_extension, - const SaveFileCompletion& on_success, - const FileSelectionCanceled& on_failure) { - DCHECK(aura::RemoteRootWindowHostWin::Instance()); - aura::RemoteRootWindowHostWin::Instance()->HandleSaveFile(title, - default_path, - filter, - filter_index, - default_extension, - on_success, - on_failure); -} - -void HandleSelectFolder(const base::string16& title, - const SelectFolderCompletion& on_success, - const FileSelectionCanceled& on_failure) { - DCHECK(aura::RemoteRootWindowHostWin::Instance()); - aura::RemoteRootWindowHostWin::Instance()->HandleSelectFolder(title, - on_success, - on_failure); -} - -void HandleActivateDesktop(const base::FilePath& shortcut, - bool ash_exit) { - DCHECK(aura::RemoteRootWindowHostWin::Instance()); - aura::RemoteRootWindowHostWin::Instance()->HandleActivateDesktop(shortcut, - ash_exit); -} - -void HandleMetroExit() { - DCHECK(aura::RemoteRootWindowHostWin::Instance()); - aura::RemoteRootWindowHostWin::Instance()->HandleMetroExit(); -} - -RemoteRootWindowHostWin* g_instance = NULL; - -RemoteRootWindowHostWin* RemoteRootWindowHostWin::Instance() { - if (g_instance) - return g_instance; - return Create(gfx::Rect()); -} - -RemoteRootWindowHostWin* RemoteRootWindowHostWin::Create( - const gfx::Rect& bounds) { - g_instance = g_instance ? g_instance : new RemoteRootWindowHostWin(bounds); +RemoteWindowTreeHostWin* g_instance = NULL; + +// static +RemoteWindowTreeHostWin* RemoteWindowTreeHostWin::Instance() { return g_instance; } -RemoteRootWindowHostWin::RemoteRootWindowHostWin(const gfx::Rect& bounds) +RemoteWindowTreeHostWin::RemoteWindowTreeHostWin() : remote_window_(NULL), host_(NULL), ignore_mouse_moves_until_set_cursor_ack_(false), event_flags_(0), - window_size_(aura::RootWindowHost::GetNativeScreenSize()) { - prop_.reset(new ui::ViewProp(NULL, kRootWindowHostWinKey, this)); + window_size_(aura::WindowTreeHost::GetNativeScreenSize()) { + CHECK(!g_instance); + g_instance = this; + prop_.reset(new ui::ViewProp(NULL, kWindowTreeHostWinKey, this)); + CreateCompositor(GetAcceleratedWidget()); } -RemoteRootWindowHostWin::~RemoteRootWindowHostWin() { +RemoteWindowTreeHostWin::~RemoteWindowTreeHostWin() { + DestroyCompositor(); + DestroyDispatcher(); + DCHECK_EQ(g_instance, this); g_instance = NULL; } -void RemoteRootWindowHostWin::Connected(IPC::Sender* host, HWND remote_window) { +// static +bool RemoteWindowTreeHostWin::IsValid() { + return Instance()->remote_window_ != NULL; +} + +void RemoteWindowTreeHostWin::SetRemoteWindowHandle(HWND remote_window) { + remote_window_ = remote_window; +} + +void RemoteWindowTreeHostWin::Connected(IPC::Sender* host) { CHECK(host_ == NULL); + DCHECK(remote_window_); host_ = host; - remote_window_ = remote_window; + // Recreate the compositor for the target surface represented by the + // remote_window HWND. + CreateCompositor(remote_window_); + InitCompositor(); } -void RemoteRootWindowHostWin::Disconnected() { +void RemoteWindowTreeHostWin::Disconnected() { // Don't CHECK here, Disconnected is called on a channel error which can // happen before we're successfully Connected. if (!host_) @@ -192,9 +141,9 @@ void RemoteRootWindowHostWin::Disconnected() { remote_window_ = NULL; } -bool RemoteRootWindowHostWin::OnMessageReceived(const IPC::Message& message) { +bool RemoteWindowTreeHostWin::OnMessageReceived(const IPC::Message& message) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP(RemoteRootWindowHostWin, message) + IPC_BEGIN_MESSAGE_MAP(RemoteWindowTreeHostWin, message) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseMoved, OnMouseMoved) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseButton, OnMouseButton) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyDown, OnKeyDown) @@ -202,20 +151,13 @@ bool RemoteRootWindowHostWin::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(MetroViewerHostMsg_Character, OnChar) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowActivated, OnWindowActivated) + IPC_MESSAGE_HANDLER(MetroViewerHostMsg_EdgeGesture, OnEdgeGesture) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchDown, OnTouchDown) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchUp, OnTouchUp) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchMoved, OnTouchMoved) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone, - OnFileSaveAsDone) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone, - OnFileOpenDone) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone, - OnMultiFileOpenDone) - IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone, - OnSelectFolderDone) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPosAck, OnSetCursorPosAck) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCandidatePopupChanged, @@ -231,7 +173,7 @@ bool RemoteRootWindowHostWin::OnMessageReceived(const IPC::Message& message) { return handled; } -void RemoteRootWindowHostWin::HandleOpenURLOnDesktop( +void RemoteWindowTreeHostWin::HandleOpenURLOnDesktop( const base::FilePath& shortcut, const base::string16& url) { if (!host_) @@ -239,203 +181,68 @@ void RemoteRootWindowHostWin::HandleOpenURLOnDesktop( host_->Send(new MetroViewerHostMsg_OpenURLOnDesktop(shortcut, url)); } -void RemoteRootWindowHostWin::HandleActivateDesktop( - const base::FilePath& shortcut, - bool ash_exit) { - if (!host_) - return; - host_->Send(new MetroViewerHostMsg_ActivateDesktop(shortcut, ash_exit)); -} - -void RemoteRootWindowHostWin::HandleMetroExit() { - if (!host_) - return; - host_->Send(new MetroViewerHostMsg_MetroExit()); -} - -void RemoteRootWindowHostWin::HandleOpenFile( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenFileCompletion& on_success, - const FileSelectionCanceled& on_failure) { - if (!host_) - return; - - // Can only have one of these operations in flight. - DCHECK(file_open_completion_callback_.is_null()); - DCHECK(failure_callback_.is_null()); - - file_open_completion_callback_ = on_success; - failure_callback_ = on_failure; - - host_->Send(new MetroViewerHostMsg_DisplayFileOpen(title, - filter, - default_path, - false)); -} - -void RemoteRootWindowHostWin::HandleOpenMultipleFiles( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - const OpenMultipleFilesCompletion& on_success, - const FileSelectionCanceled& on_failure) { - if (!host_) - return; - - // Can only have one of these operations in flight. - DCHECK(multi_file_open_completion_callback_.is_null()); - DCHECK(failure_callback_.is_null()); - multi_file_open_completion_callback_ = on_success; - failure_callback_ = on_failure; - - host_->Send(new MetroViewerHostMsg_DisplayFileOpen(title, - filter, - default_path, - true)); -} - -void RemoteRootWindowHostWin::HandleSaveFile( - const base::string16& title, - const base::FilePath& default_path, - const base::string16& filter, - int filter_index, - const base::string16& default_extension, - const SaveFileCompletion& on_success, - const FileSelectionCanceled& on_failure) { - if (!host_) - return; - - MetroViewerHostMsg_SaveAsDialogParams params; - params.title = title; - params.default_extension = default_extension; - params.filter = filter; - params.filter_index = filter_index; - params.suggested_name = default_path; - - // Can only have one of these operations in flight. - DCHECK(file_saveas_completion_callback_.is_null()); - DCHECK(failure_callback_.is_null()); - file_saveas_completion_callback_ = on_success; - failure_callback_ = on_failure; - - host_->Send(new MetroViewerHostMsg_DisplayFileSaveAs(params)); -} - -void RemoteRootWindowHostWin::HandleSelectFolder( - const base::string16& title, - const SelectFolderCompletion& on_success, - const FileSelectionCanceled& on_failure) { - if (!host_) - return; - - // Can only have one of these operations in flight. - DCHECK(select_folder_completion_callback_.is_null()); - DCHECK(failure_callback_.is_null()); - select_folder_completion_callback_ = on_success; - failure_callback_ = on_failure; - - host_->Send(new MetroViewerHostMsg_DisplaySelectFolder(title)); -} - -void RemoteRootWindowHostWin::HandleWindowSizeChanged(uint32 width, +void RemoteWindowTreeHostWin::HandleWindowSizeChanged(uint32 width, uint32 height) { SetBounds(gfx::Rect(0, 0, width, height)); } -bool RemoteRootWindowHostWin::IsForegroundWindow() { +bool RemoteWindowTreeHostWin::IsForegroundWindow() { return ::GetForegroundWindow() == remote_window_; } -Window* RemoteRootWindowHostWin::GetAshWindow() { - return GetRootWindow()->window(); +Window* RemoteWindowTreeHostWin::GetAshWindow() { + return window(); } -RootWindow* RemoteRootWindowHostWin::GetRootWindow() { - return delegate_->AsRootWindow(); +ui::EventSource* RemoteWindowTreeHostWin::GetEventSource() { + return this; } -gfx::AcceleratedWidget RemoteRootWindowHostWin::GetAcceleratedWidget() { +gfx::AcceleratedWidget RemoteWindowTreeHostWin::GetAcceleratedWidget() { if (remote_window_) return remote_window_; // Getting here should only happen for ash_unittests.exe and related code. return ::GetDesktopWindow(); } -void RemoteRootWindowHostWin::Show() { +void RemoteWindowTreeHostWin::Show() { ui::RemoteInputMethodPrivateWin* remote_input_method_private = GetRemoteInputMethodPrivate(); if (remote_input_method_private) remote_input_method_private->SetRemoteDelegate(this); } -void RemoteRootWindowHostWin::Hide() { +void RemoteWindowTreeHostWin::Hide() { NOTIMPLEMENTED(); } -void RemoteRootWindowHostWin::ToggleFullScreen() { -} - -gfx::Rect RemoteRootWindowHostWin::GetBounds() const { +gfx::Rect RemoteWindowTreeHostWin::GetBounds() const { return gfx::Rect(window_size_); } -void RemoteRootWindowHostWin::SetBounds(const gfx::Rect& bounds) { +void RemoteWindowTreeHostWin::SetBounds(const gfx::Rect& bounds) { window_size_ = bounds.size(); - delegate_->OnHostResized(bounds.size()); + OnHostResized(bounds.size()); } -gfx::Insets RemoteRootWindowHostWin::GetInsets() const { - return gfx::Insets(); +gfx::Point RemoteWindowTreeHostWin::GetLocationOnNativeScreen() const { + return gfx::Point(0, 0); } -void RemoteRootWindowHostWin::SetInsets(const gfx::Insets& insets) { +void RemoteWindowTreeHostWin::SetCapture() { } -gfx::Point RemoteRootWindowHostWin::GetLocationOnNativeScreen() const { - return gfx::Point(0, 0); +void RemoteWindowTreeHostWin::ReleaseCapture() { } -void RemoteRootWindowHostWin::SetCursor(gfx::NativeCursor native_cursor) { +void RemoteWindowTreeHostWin::SetCursorNative(gfx::NativeCursor native_cursor) { if (!host_) return; host_->Send( new MetroViewerHostMsg_SetCursor(uint64(native_cursor.platform()))); } -void RemoteRootWindowHostWin::SetCapture() { -} - -void RemoteRootWindowHostWin::ReleaseCapture() { -} - -bool RemoteRootWindowHostWin::QueryMouseLocation(gfx::Point* location_return) { - aura::client::CursorClient* cursor_client = - aura::client::GetCursorClient(GetRootWindow()->window()); - if (cursor_client && !cursor_client->IsMouseEventsEnabled()) { - *location_return = gfx::Point(0, 0); - return false; - } - POINT pt; - GetCursorPos(&pt); - *location_return = - gfx::Point(static_cast<int>(pt.x), static_cast<int>(pt.y)); - return true; -} - -bool RemoteRootWindowHostWin::ConfineCursorToRootWindow() { - return true; -} - -void RemoteRootWindowHostWin::UnConfineCursor() { -} - -void RemoteRootWindowHostWin::OnCursorVisibilityChanged(bool show) { - NOTIMPLEMENTED(); -} - -void RemoteRootWindowHostWin::MoveCursorTo(const gfx::Point& location) { +void RemoteWindowTreeHostWin::MoveCursorToNative(const gfx::Point& location) { VLOG(1) << "In MoveCursorTo: " << location.x() << ", " << location.y(); if (!host_) return; @@ -460,25 +267,34 @@ void RemoteRootWindowHostWin::MoveCursorTo(const gfx::Point& location) { host_->Send(new MetroViewerHostMsg_SetCursorPos(location.x(), location.y())); } -void RemoteRootWindowHostWin::PostNativeEvent( +void RemoteWindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) { + NOTIMPLEMENTED(); +} + +void RemoteWindowTreeHostWin::PostNativeEvent( const base::NativeEvent& native_event) { } -void RemoteRootWindowHostWin::OnDeviceScaleFactorChanged( +void RemoteWindowTreeHostWin::OnDeviceScaleFactorChanged( float device_scale_factor) { NOTIMPLEMENTED(); } -void RemoteRootWindowHostWin::PrepareForShutdown() { +ui::EventProcessor* RemoteWindowTreeHostWin::GetEventProcessor() { + return dispatcher(); } -void RemoteRootWindowHostWin::CancelComposition() { +void RemoteWindowTreeHostWin::CancelComposition() { + if (!host_) + return; host_->Send(new MetroViewerHostMsg_ImeCancelComposition); } -void RemoteRootWindowHostWin::OnTextInputClientUpdated( +void RemoteWindowTreeHostWin::OnTextInputClientUpdated( const std::vector<int32>& input_scopes, const std::vector<gfx::Rect>& composition_character_bounds) { + if (!host_) + return; std::vector<metro_viewer::CharacterBounds> character_bounds; for (size_t i = 0; i < composition_character_bounds.size(); ++i) { const gfx::Rect& rect = composition_character_bounds[i]; @@ -493,29 +309,35 @@ void RemoteRootWindowHostWin::OnTextInputClientUpdated( input_scopes, character_bounds)); } -void RemoteRootWindowHostWin::OnMouseMoved(int32 x, int32 y, int32 flags) { +gfx::Point PointFromNativeEvent(int32 x, int32 y) { + static float scale_factor = gfx::GetDPIScale(); + gfx::Point result( x * scale_factor, y * scale_factor); + return result; +} + +void RemoteWindowTreeHostWin::OnMouseMoved(int32 x, int32 y, int32 flags) { if (ignore_mouse_moves_until_set_cursor_ack_) return; - gfx::Point location(x, y); - ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location, flags); - delegate_->OnHostMouseEvent(&event); -} - -void RemoteRootWindowHostWin::OnMouseButton( - int32 x, - int32 y, - int32 extra, - ui::EventType type, - ui::EventFlags flags) { - gfx::Point location(x, y); - ui::MouseEvent mouse_event(type, location, location, flags); - - SetEventFlags(flags | key_event_flags()); - if (type == ui::ET_MOUSEWHEEL) { - ui::MouseWheelEvent wheel_event(mouse_event, 0, extra); - delegate_->OnHostMouseEvent(&wheel_event); - } else if (type == ui::ET_MOUSE_PRESSED) { + gfx::Point location = PointFromNativeEvent(x, y); + ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location, flags, 0); + SendEventToProcessor(&event); +} + +void RemoteWindowTreeHostWin::OnMouseButton( + const MetroViewerHostMsg_MouseButtonParams& params) { + gfx::Point location = PointFromNativeEvent(params.x, params.y); + ui::MouseEvent mouse_event(params.event_type, location, location, + static_cast<int>(params.flags), + static_cast<int>(params.changed_button)); + + SetEventFlags(params.flags | key_event_flags()); + if (params.event_type == ui::ET_MOUSEWHEEL) { + int x_offset = params.is_horizontal_wheel ? params.extra : 0; + int y_offset = !params.is_horizontal_wheel ? params.extra : 0; + ui::MouseWheelEvent wheel_event(mouse_event, x_offset, y_offset); + SendEventToProcessor(&wheel_event); + } else if (params.event_type == ui::ET_MOUSE_PRESSED) { // TODO(shrikant): Ideally modify code in event.cc by adding automatic // tracking of double clicks in synthetic MouseEvent constructor code. // Non-synthetic MouseEvent constructor code does automatically track @@ -530,13 +352,13 @@ void RemoteRootWindowHostWin::OnMouseButton( mouse_event.SetClickCount(1); } last_mouse_click_event_ .reset(new ui::MouseEvent(mouse_event)); - delegate_->OnHostMouseEvent(&mouse_event); + SendEventToProcessor(&mouse_event); } else { - delegate_->OnHostMouseEvent(&mouse_event); + SendEventToProcessor(&mouse_event); } } -void RemoteRootWindowHostWin::OnKeyDown(uint32 vkey, +void RemoteWindowTreeHostWin::OnKeyDown(uint32 vkey, uint32 repeat_count, uint32 scan_code, uint32 flags) { @@ -544,7 +366,7 @@ void RemoteRootWindowHostWin::OnKeyDown(uint32 vkey, flags, false); } -void RemoteRootWindowHostWin::OnKeyUp(uint32 vkey, +void RemoteWindowTreeHostWin::OnKeyUp(uint32 vkey, uint32 repeat_count, uint32 scan_code, uint32 flags) { @@ -552,7 +374,7 @@ void RemoteRootWindowHostWin::OnKeyUp(uint32 vkey, flags, false); } -void RemoteRootWindowHostWin::OnChar(uint32 key_code, +void RemoteWindowTreeHostWin::OnChar(uint32 key_code, uint32 repeat_count, uint32 scan_code, uint32 flags) { @@ -560,100 +382,71 @@ void RemoteRootWindowHostWin::OnChar(uint32 key_code, scan_code, flags, true); } -void RemoteRootWindowHostWin::OnWindowActivated() { - delegate_->OnHostActivated(); +void RemoteWindowTreeHostWin::OnWindowActivated() { + OnHostActivated(); } -void RemoteRootWindowHostWin::OnTouchDown(int32 x, +void RemoteWindowTreeHostWin::OnEdgeGesture() { + ui::GestureEvent event( + ui::ET_GESTURE_WIN8_EDGE_SWIPE, + 0, + 0, + 0, + ui::EventTimeForNow(), + ui::GestureEventDetails(ui::ET_GESTURE_WIN8_EDGE_SWIPE, 0, 0), + 0); + SendEventToProcessor(&event); +} + +void RemoteWindowTreeHostWin::OnTouchDown(int32 x, int32 y, uint64 timestamp, uint32 pointer_id) { + gfx::Point location = PointFromNativeEvent(x, y); ui::TouchEvent event(ui::ET_TOUCH_PRESSED, - gfx::Point(x, y), + location, pointer_id, base::TimeDelta::FromMicroseconds(timestamp)); - delegate_->OnHostTouchEvent(&event); + SendEventToProcessor(&event); } -void RemoteRootWindowHostWin::OnTouchUp(int32 x, +void RemoteWindowTreeHostWin::OnTouchUp(int32 x, int32 y, uint64 timestamp, uint32 pointer_id) { + gfx::Point location = PointFromNativeEvent(x, y); ui::TouchEvent event(ui::ET_TOUCH_RELEASED, - gfx::Point(x, y), + location, pointer_id, base::TimeDelta::FromMicroseconds(timestamp)); - delegate_->OnHostTouchEvent(&event); + SendEventToProcessor(&event); } -void RemoteRootWindowHostWin::OnTouchMoved(int32 x, +void RemoteWindowTreeHostWin::OnTouchMoved(int32 x, int32 y, uint64 timestamp, uint32 pointer_id) { + gfx::Point location = PointFromNativeEvent(x, y); ui::TouchEvent event(ui::ET_TOUCH_MOVED, - gfx::Point(x, y), + location, pointer_id, base::TimeDelta::FromMicroseconds(timestamp)); - delegate_->OnHostTouchEvent(&event); -} - -void RemoteRootWindowHostWin::OnFileSaveAsDone(bool success, - const base::FilePath& filename, - int filter_index) { - if (success) - file_saveas_completion_callback_.Run(filename, filter_index, NULL); - else - failure_callback_.Run(NULL); - file_saveas_completion_callback_.Reset(); - failure_callback_.Reset(); -} - - -void RemoteRootWindowHostWin::OnFileOpenDone(bool success, - const base::FilePath& filename) { - if (success) - file_open_completion_callback_.Run(base::FilePath(filename), 0, NULL); - else - failure_callback_.Run(NULL); - file_open_completion_callback_.Reset(); - failure_callback_.Reset(); -} - -void RemoteRootWindowHostWin::OnMultiFileOpenDone( - bool success, - const std::vector<base::FilePath>& files) { - if (success) - multi_file_open_completion_callback_.Run(files, NULL); - else - failure_callback_.Run(NULL); - multi_file_open_completion_callback_.Reset(); - failure_callback_.Reset(); -} - -void RemoteRootWindowHostWin::OnSelectFolderDone( - bool success, - const base::FilePath& folder) { - if (success) - select_folder_completion_callback_.Run(base::FilePath(folder), 0, NULL); - else - failure_callback_.Run(NULL); - select_folder_completion_callback_.Reset(); - failure_callback_.Reset(); + SendEventToProcessor(&event); } -void RemoteRootWindowHostWin::OnSetCursorPosAck() { +void RemoteWindowTreeHostWin::OnSetCursorPosAck() { DCHECK(ignore_mouse_moves_until_set_cursor_ack_); ignore_mouse_moves_until_set_cursor_ack_ = false; } ui::RemoteInputMethodPrivateWin* -RemoteRootWindowHostWin::GetRemoteInputMethodPrivate() { +RemoteWindowTreeHostWin::GetRemoteInputMethodPrivate() { ui::InputMethod* input_method = GetAshWindow()->GetProperty( aura::client::kRootWindowInputMethodKey); return ui::RemoteInputMethodPrivateWin::Get(input_method); } -void RemoteRootWindowHostWin::OnImeCandidatePopupChanged(bool visible) { +void RemoteWindowTreeHostWin::OnImeCandidatePopupChanged(bool visible) { ui::RemoteInputMethodPrivateWin* remote_input_method_private = GetRemoteInputMethodPrivate(); if (!remote_input_method_private) @@ -661,8 +454,8 @@ void RemoteRootWindowHostWin::OnImeCandidatePopupChanged(bool visible) { remote_input_method_private->OnCandidatePopupChanged(visible); } -void RemoteRootWindowHostWin::OnImeCompositionChanged( - const string16& text, +void RemoteWindowTreeHostWin::OnImeCompositionChanged( + const base::string16& text, int32 selection_start, int32 selection_end, const std::vector<metro_viewer::UnderlineInfo>& underlines) { @@ -676,7 +469,7 @@ void RemoteRootWindowHostWin::OnImeCompositionChanged( remote_input_method_private->OnCompositionChanged(composition_text); } -void RemoteRootWindowHostWin::OnImeTextCommitted(const string16& text) { +void RemoteWindowTreeHostWin::OnImeTextCommitted(const base::string16& text) { ui::RemoteInputMethodPrivateWin* remote_input_method_private = GetRemoteInputMethodPrivate(); if (!remote_input_method_private) @@ -684,7 +477,7 @@ void RemoteRootWindowHostWin::OnImeTextCommitted(const string16& text) { remote_input_method_private->OnTextCommitted(text); } -void RemoteRootWindowHostWin::OnImeInputSourceChanged(uint16 language_id, +void RemoteWindowTreeHostWin::OnImeInputSourceChanged(uint16 language_id, bool is_ime) { ui::RemoteInputMethodPrivateWin* remote_input_method_private = GetRemoteInputMethodPrivate(); @@ -693,7 +486,7 @@ void RemoteRootWindowHostWin::OnImeInputSourceChanged(uint16 language_id, remote_input_method_private->OnInputSourceChanged(language_id, is_ime); } -void RemoteRootWindowHostWin::DispatchKeyboardMessage(ui::EventType type, +void RemoteWindowTreeHostWin::DispatchKeyboardMessage(ui::EventType type, uint32 vkey, uint32 repeat_count, uint32 scan_code, @@ -718,11 +511,11 @@ void RemoteRootWindowHostWin::DispatchKeyboardMessage(ui::EventType type, ui::KeyboardCodeForWindowsKeyCode(vkey), flags, is_character); - delegate_->OnHostKeyEvent(&event); + SendEventToProcessor(&event); } } -void RemoteRootWindowHostWin::SetEventFlags(uint32 flags) { +void RemoteWindowTreeHostWin::SetEventFlags(uint32 flags) { if (flags == event_flags_) return; event_flags_ = flags; diff --git a/chromium/ui/aura/remote_window_tree_host_win.h b/chromium/ui/aura/remote_window_tree_host_win.h new file mode 100644 index 00000000000..ae63b744715 --- /dev/null +++ b/chromium/ui/aura/remote_window_tree_host_win.h @@ -0,0 +1,194 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_ +#define UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_ + +#include <vector> + +#include "base/compiler_specific.h" +#include "base/strings/string16.h" +#include "ui/aura/window_tree_host.h" +#include "ui/base/ime/remote_input_method_delegate_win.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" +#include "ui/events/event_source.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/metro_viewer/ime_types.h" + +struct MetroViewerHostMsg_MouseButtonParams; + +namespace base { +class FilePath; +} + +namespace ui { +class RemoteInputMethodPrivateWin; +class ViewProp; +} + +namespace IPC { +class Message; +class Sender; +} + +namespace aura { + +// WindowTreeHost implementaton that receives events from a different +// process. In the case of Windows this is the Windows 8 (aka Metro) +// frontend process, which forwards input events to this class. +class AURA_EXPORT RemoteWindowTreeHostWin + : public WindowTreeHost, + public ui::EventSource, + public ui::internal::RemoteInputMethodDelegateWin { + public: + // Returns the current RemoteWindowTreeHostWin. This does *not* create a + // RemoteWindowTreeHostWin. + static RemoteWindowTreeHostWin* Instance(); + + // Returns true if there is a RemoteWindowTreeHostWin and it has a valid + // HWND. A return value of false typically indicates we're not in metro mode. + static bool IsValid(); + + // Sets the handle to the remote window. The |remote_window| is the actual + // window owned by the viewer process. Call this before Connected() for some + // customers like input method initialization which needs the handle. + void SetRemoteWindowHandle(HWND remote_window); + HWND remote_window() { return remote_window_; } + + // The |host| can be used when we need to send a message to it. + void Connected(IPC::Sender* host); + // Called when the remote process has closed its IPC connection. + void Disconnected(); + + // Called when we have a message from the remote process. + bool OnMessageReceived(const IPC::Message& message); + + void HandleOpenURLOnDesktop(const base::FilePath& shortcut, + const base::string16& url); + + void HandleWindowSizeChanged(uint32 width, uint32 height); + + // Returns the active ASH root window. + Window* GetAshWindow(); + + // Returns true if the remote window is the foreground window according to the + // OS. + bool IsForegroundWindow(); + + protected: + RemoteWindowTreeHostWin(); + virtual ~RemoteWindowTreeHostWin(); + + private: + // IPC message handing methods: + void OnMouseMoved(int32 x, int32 y, int32 flags); + void OnMouseButton(const MetroViewerHostMsg_MouseButtonParams& params); + void OnKeyDown(uint32 vkey, + uint32 repeat_count, + uint32 scan_code, + uint32 flags); + void OnKeyUp(uint32 vkey, + uint32 repeat_count, + uint32 scan_code, + uint32 flags); + void OnChar(uint32 key_code, + uint32 repeat_count, + uint32 scan_code, + uint32 flags); + void OnWindowActivated(); + void OnEdgeGesture(); + void OnTouchDown(int32 x, int32 y, uint64 timestamp, uint32 pointer_id); + void OnTouchUp(int32 x, int32 y, uint64 timestamp, uint32 pointer_id); + void OnTouchMoved(int32 x, int32 y, uint64 timestamp, uint32 pointer_id); + void OnSetCursorPosAck(); + + // For Input Method support: + ui::RemoteInputMethodPrivateWin* GetRemoteInputMethodPrivate(); + void OnImeCandidatePopupChanged(bool visible); + void OnImeCompositionChanged( + const base::string16& text, + int32 selection_start, + int32 selection_end, + const std::vector<metro_viewer::UnderlineInfo>& underlines); + void OnImeTextCommitted(const base::string16& text); + void OnImeInputSourceChanged(uint16 language_id, bool is_ime); + + // WindowTreeHost overrides: + virtual ui::EventSource* GetEventSource() OVERRIDE; + virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; + virtual gfx::Rect GetBounds() const OVERRIDE; + virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; + virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE; + virtual void SetCapture() OVERRIDE; + virtual void ReleaseCapture() OVERRIDE; + virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE; + virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; + virtual void SetCursorNative(gfx::NativeCursor cursor) OVERRIDE; + virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE; + virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE; + + // ui::EventSource: + virtual ui::EventProcessor* GetEventProcessor() OVERRIDE; + + // ui::internal::RemoteInputMethodDelegateWin overrides: + virtual void CancelComposition() OVERRIDE; + virtual void OnTextInputClientUpdated( + const std::vector<int32>& input_scopes, + const std::vector<gfx::Rect>& composition_character_bounds) OVERRIDE; + + // Helper function to dispatch a keyboard message to the desired target. + // The default target is the WindowEventDispatcher. For nested message loop + // invocations we post a synthetic keyboard message directly into the message + // loop. The dispatcher for the nested loop would then decide how this + // message is routed. + void DispatchKeyboardMessage(ui::EventType type, + uint32 vkey, + uint32 repeat_count, + uint32 scan_code, + uint32 flags, + bool is_character); + + // Sets the event flags. |flags| is a bitmask of EventFlags. If there is a + // change the system virtual key state is updated as well. This way if chrome + // queries for key state it matches that of event being dispatched. + void SetEventFlags(uint32 flags); + + uint32 mouse_event_flags() const { + return event_flags_ & (ui::EF_LEFT_MOUSE_BUTTON | + ui::EF_MIDDLE_MOUSE_BUTTON | + ui::EF_RIGHT_MOUSE_BUTTON); + } + + uint32 key_event_flags() const { + return event_flags_ & (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | + ui::EF_ALT_DOWN | ui::EF_CAPS_LOCK_DOWN); + } + + HWND remote_window_; + IPC::Sender* host_; + scoped_ptr<ui::ViewProp> prop_; + + // Set to true if we need to ignore mouse messages until the SetCursorPos + // operation is acked by the viewer. + bool ignore_mouse_moves_until_set_cursor_ack_; + + // Tracking last click event for synthetically generated mouse events. + scoped_ptr<ui::MouseEvent> last_mouse_click_event_; + + // State of the keyboard/mouse at the time of the last input event. See + // description of SetEventFlags(). + uint32 event_flags_; + + // Current size of this root window. + gfx::Size window_size_; + + DISALLOW_COPY_AND_ASSIGN(RemoteWindowTreeHostWin); +}; + +} // namespace aura + +#endif // UI_AURA_REMOTE_WINDOW_TREE_HOST_WIN_H_ diff --git a/chromium/ui/aura/root_window.cc b/chromium/ui/aura/root_window.cc deleted file mode 100644 index 58790da1c36..00000000000 --- a/chromium/ui/aura/root_window.cc +++ /dev/null @@ -1,1172 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/root_window.h" - -#include <vector> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/debug/trace_event.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "ui/aura/client/capture_client.h" -#include "ui/aura/client/cursor_client.h" -#include "ui/aura/client/event_client.h" -#include "ui/aura/client/focus_client.h" -#include "ui/aura/client/screen_position_client.h" -#include "ui/aura/env.h" -#include "ui/aura/root_window_observer.h" -#include "ui/aura/root_window_transformer.h" -#include "ui/aura/window.h" -#include "ui/aura/window_delegate.h" -#include "ui/aura/window_targeter.h" -#include "ui/aura/window_tracker.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/hit_test.h" -#include "ui/base/view_prop.h" -#include "ui/compositor/dip_util.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/layer_animator.h" -#include "ui/events/event.h" -#include "ui/events/gestures/gesture_recognizer.h" -#include "ui/events/gestures/gesture_types.h" -#include "ui/gfx/display.h" -#include "ui/gfx/point3_f.h" -#include "ui/gfx/point_conversions.h" -#include "ui/gfx/screen.h" -#include "ui/gfx/size_conversions.h" - -using std::vector; - -typedef ui::EventDispatchDetails DispatchDetails; - -namespace aura { - -namespace { - -const char kRootWindowForAcceleratedWidget[] = - "__AURA_ROOT_WINDOW_ACCELERATED_WIDGET__"; - -// Returns true if |target| has a non-client (frame) component at |location|, -// in window coordinates. -bool IsNonClientLocation(Window* target, const gfx::Point& location) { - if (!target->delegate()) - return false; - int hit_test_code = target->delegate()->GetNonClientComponent(location); - return hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE; -} - -float GetDeviceScaleFactorFromDisplay(Window* window) { - gfx::Display display = gfx::Screen::GetScreenFor(window)-> - GetDisplayNearestWindow(window); - DCHECK(display.is_valid()); - return display.device_scale_factor(); -} - -Window* ConsumerToWindow(ui::GestureConsumer* consumer) { - return consumer ? static_cast<Window*>(consumer) : NULL; -} - -void SetLastMouseLocation(const Window* root_window, - const gfx::Point& location_in_root) { - client::ScreenPositionClient* client = - client::GetScreenPositionClient(root_window); - if (client) { - gfx::Point location_in_screen = location_in_root; - client->ConvertPointToScreen(root_window, &location_in_screen); - Env::GetInstance()->set_last_mouse_location(location_in_screen); - } else { - Env::GetInstance()->set_last_mouse_location(location_in_root); - } -} - -RootWindowHost* CreateHost(RootWindow* root_window, - const RootWindow::CreateParams& params) { - RootWindowHost* host = params.host ? - params.host : RootWindowHost::Create(params.initial_bounds); - host->set_delegate(root_window); - return host; -} - -bool IsUsingEventProcessorForDispatch(const ui::Event& event) { - return event.IsKeyEvent() || - event.IsScrollEvent(); -} - -class SimpleRootWindowTransformer : public RootWindowTransformer { - public: - SimpleRootWindowTransformer(const Window* root_window, - const gfx::Transform& transform) - : root_window_(root_window), - transform_(transform) { - } - - // RootWindowTransformer overrides: - virtual gfx::Transform GetTransform() const OVERRIDE { - return transform_; - } - - virtual gfx::Transform GetInverseTransform() const OVERRIDE { - gfx::Transform invert; - if (!transform_.GetInverse(&invert)) - return transform_; - return invert; - } - - virtual gfx::Rect GetRootWindowBounds( - const gfx::Size& host_size) const OVERRIDE { - gfx::Rect bounds(host_size); - gfx::RectF new_bounds(ui::ConvertRectToDIP(root_window_->layer(), bounds)); - transform_.TransformRect(&new_bounds); - return gfx::Rect(gfx::ToFlooredSize(new_bounds.size())); - } - - virtual gfx::Insets GetHostInsets() const OVERRIDE { - return gfx::Insets(); - } - - private: - virtual ~SimpleRootWindowTransformer() {} - - const Window* root_window_; - const gfx::Transform transform_; - - DISALLOW_COPY_AND_ASSIGN(SimpleRootWindowTransformer); -}; - -} // namespace - -RootWindow::CreateParams::CreateParams(const gfx::Rect& a_initial_bounds) - : initial_bounds(a_initial_bounds), - host(NULL) { -} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindow, public: - -RootWindow::RootWindow(const CreateParams& params) - : window_(new Window(NULL)), - host_(CreateHost(this, params)), - touch_ids_down_(0), - last_cursor_(ui::kCursorNull), - mouse_pressed_handler_(NULL), - mouse_moved_handler_(NULL), - event_dispatch_target_(NULL), - old_dispatch_target_(NULL), - synthesize_mouse_move_(false), - move_hold_count_(0), - dispatching_held_event_(false), - repost_event_factory_(this), - held_event_factory_(this) { - window()->set_dispatcher(this); - window()->SetName("RootWindow"); - window()->set_event_targeter( - scoped_ptr<ui::EventTargeter>(new WindowTargeter())); - - compositor_.reset(new ui::Compositor(host_->GetAcceleratedWidget())); - DCHECK(compositor_.get()); - - prop_.reset(new ui::ViewProp(host_->GetAcceleratedWidget(), - kRootWindowForAcceleratedWidget, - this)); - ui::GestureRecognizer::Get()->AddGestureEventHelper(this); -} - -RootWindow::~RootWindow() { - TRACE_EVENT0("shutdown", "RootWindow::Destructor"); - - ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this); - - // Make sure to destroy the compositor before terminating so that state is - // cleared and we don't hit asserts. - compositor_.reset(); - - // An observer may have been added by an animation on the RootWindow. - window()->layer()->GetAnimator()->RemoveObserver(this); - - // Destroy child windows while we're still valid. This is also done by - // ~Window, but by that time any calls to virtual methods overriden here (such - // as GetRootWindow()) result in Window's implementation. By destroying here - // we ensure GetRootWindow() still returns this. - window()->RemoveOrDestroyChildren(); - - // Destroying/removing child windows may try to access |host_| (eg. - // GetAcceleratedWidget()) - host_.reset(NULL); - - window()->set_dispatcher(NULL); -} - -// static -RootWindow* RootWindow::GetForAcceleratedWidget( - gfx::AcceleratedWidget widget) { - return reinterpret_cast<RootWindow*>( - ui::ViewProp::GetValue(widget, kRootWindowForAcceleratedWidget)); -} - -void RootWindow::Init() { - compositor()->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()), - host_->GetBounds().size()); - window()->Init(ui::LAYER_NOT_DRAWN); - compositor()->SetRootLayer(window()->layer()); - transformer_.reset( - new SimpleRootWindowTransformer(window(), gfx::Transform())); - UpdateRootWindowSize(host_->GetBounds().size()); - Env::GetInstance()->NotifyRootWindowInitialized(this); - window()->Show(); -} - -void RootWindow::PrepareForShutdown() { - host_->PrepareForShutdown(); - // discard synthesize event request as well. - synthesize_mouse_move_ = false; -} - -void RootWindow::RepostEvent(const ui::LocatedEvent& event) { - DCHECK(event.type() == ui::ET_MOUSE_PRESSED || - event.type() == ui::ET_GESTURE_TAP_DOWN); - // We allow for only one outstanding repostable event. This is used - // in exiting context menus. A dropped repost request is allowed. - if (event.type() == ui::ET_MOUSE_PRESSED) { - held_repostable_event_.reset( - new ui::MouseEvent( - static_cast<const ui::MouseEvent&>(event), - static_cast<aura::Window*>(event.target()), - window())); - base::MessageLoop::current()->PostNonNestableTask( - FROM_HERE, - base::Bind(base::IgnoreResult(&RootWindow::DispatchHeldEvents), - repost_event_factory_.GetWeakPtr())); - } else { - DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN); - held_repostable_event_.reset(); - // TODO(rbyers): Reposing of gestures is tricky to get - // right, so it's not yet supported. crbug.com/170987. - } -} - -RootWindowHostDelegate* RootWindow::AsRootWindowHostDelegate() { - return this; -} - -void RootWindow::SetHostSize(const gfx::Size& size_in_pixel) { - DispatchDetails details = DispatchHeldEvents(); - if (details.dispatcher_destroyed) - return; - gfx::Rect bounds = host_->GetBounds(); - bounds.set_size(size_in_pixel); - host_->SetBounds(bounds); - - // Requery the location to constrain it within the new root window size. - gfx::Point point; - if (host_->QueryMouseLocation(&point)) { - SetLastMouseLocation(window(), - ui::ConvertPointToDIP(window()->layer(), point)); - } - - synthesize_mouse_move_ = false; -} - -void RootWindow::SetHostBounds(const gfx::Rect& bounds_in_pixel) { - DCHECK(!bounds_in_pixel.IsEmpty()); - DispatchDetails details = DispatchHeldEvents(); - if (details.dispatcher_destroyed) - return; - host_->SetBounds(bounds_in_pixel); - synthesize_mouse_move_ = false; -} - -void RootWindow::SetCursor(gfx::NativeCursor cursor) { - last_cursor_ = cursor; - // A lot of code seems to depend on NULL cursors actually showing an arrow, - // so just pass everything along to the host. - host_->SetCursor(cursor); -} - -void RootWindow::OnCursorVisibilityChanged(bool show) { - // Clear any existing mouse hover effects when the cursor becomes invisible. - // Note we do not need to dispatch a mouse enter when the cursor becomes - // visible because that can only happen in response to a mouse event, which - // will trigger its own mouse enter. - if (!show) - DispatchMouseExitAtPoint(GetLastMouseLocationInRoot()); - - host_->OnCursorVisibilityChanged(show); -} - -void RootWindow::OnMouseEventsEnableStateChanged(bool enabled) { - // Send entered / exited so that visual state can be updated to match - // mouse events state. - PostMouseMoveEventAfterWindowChange(); - // TODO(mazda): Add code to disable mouse events when |enabled| == false. -} - -void RootWindow::MoveCursorTo(const gfx::Point& location_in_dip) { - gfx::Point host_location(location_in_dip); - ConvertPointToHost(&host_location); - MoveCursorToInternal(location_in_dip, host_location); -} - -void RootWindow::MoveCursorToHostLocation(const gfx::Point& host_location) { - gfx::Point root_location(host_location); - ConvertPointFromHost(&root_location); - MoveCursorToInternal(root_location, host_location); -} - -void RootWindow::ScheduleRedrawRect(const gfx::Rect& damage_rect) { - compositor_->ScheduleRedrawRect(damage_rect); -} - -Window* RootWindow::GetGestureTarget(ui::GestureEvent* event) { - Window* target = NULL; - if (!event->IsEndingEvent()) { - // The window that received the start event (e.g. scroll begin) needs to - // receive the end event (e.g. scroll end). - target = client::GetCaptureWindow(window()); - } - if (!target) { - target = ConsumerToWindow( - ui::GestureRecognizer::Get()->GetTargetForGestureEvent(*event)); - } - - return target; -} - -void RootWindow::DispatchGestureEvent(ui::GestureEvent* event) { - DispatchDetails details = DispatchHeldEvents(); - if (details.dispatcher_destroyed) - return; - - Window* target = GetGestureTarget(event); - if (target) { - event->ConvertLocationToTarget(window(), target); - DispatchDetails details = DispatchEvent(target, event); - if (details.dispatcher_destroyed) - return; - } -} - -void RootWindow::OnWindowDestroying(Window* window) { - DispatchMouseExitToHidingWindow(window); - OnWindowHidden(window, WINDOW_DESTROYED); - - if (window->IsVisible() && - window->ContainsPointInRoot(GetLastMouseLocationInRoot())) { - PostMouseMoveEventAfterWindowChange(); - } -} - -void RootWindow::OnWindowBoundsChanged(Window* window, - bool contained_mouse_point) { - if (contained_mouse_point || - (window->IsVisible() && - window->ContainsPointInRoot(GetLastMouseLocationInRoot()))) { - PostMouseMoveEventAfterWindowChange(); - } -} - -void RootWindow::DispatchMouseExitToHidingWindow(Window* window) { - // The mouse capture is intentionally ignored. Think that a mouse enters - // to a window, the window sets the capture, the mouse exits the window, - // and then it releases the capture. In that case OnMouseExited won't - // be called. So it is natural not to emit OnMouseExited even though - // |window| is the capture window. - gfx::Point last_mouse_location = GetLastMouseLocationInRoot(); - if (window->Contains(mouse_moved_handler_) && - window->ContainsPointInRoot(last_mouse_location)) - DispatchMouseExitAtPoint(last_mouse_location); -} - -void RootWindow::DispatchMouseExitAtPoint(const gfx::Point& point) { - ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE); - DispatchDetails details = - DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED); - if (details.dispatcher_destroyed) - return; -} - -void RootWindow::OnWindowVisibilityChanged(Window* window, bool is_visible) { - if (!is_visible) - OnWindowHidden(window, WINDOW_HIDDEN); - - if (window->ContainsPointInRoot(GetLastMouseLocationInRoot())) - PostMouseMoveEventAfterWindowChange(); -} - -void RootWindow::OnWindowTransformed(Window* window, bool contained_mouse) { - if (contained_mouse || - (window->IsVisible() && - window->ContainsPointInRoot(GetLastMouseLocationInRoot()))) { - PostMouseMoveEventAfterWindowChange(); - } -} - -void RootWindow::OnKeyboardMappingChanged() { - FOR_EACH_OBSERVER(RootWindowObserver, observers_, - OnKeyboardMappingChanged(this)); -} - -void RootWindow::OnRootWindowHostCloseRequested() { - FOR_EACH_OBSERVER(RootWindowObserver, observers_, - OnRootWindowHostCloseRequested(this)); -} - -void RootWindow::AddRootWindowObserver(RootWindowObserver* observer) { - observers_.AddObserver(observer); -} - -void RootWindow::RemoveRootWindowObserver(RootWindowObserver* observer) { - observers_.RemoveObserver(observer); -} - -void RootWindow::ConvertPointToHost(gfx::Point* point) const { - gfx::Point3F point_3f(*point); - GetRootTransform().TransformPoint(&point_3f); - *point = gfx::ToFlooredPoint(point_3f.AsPointF()); -} - -void RootWindow::ConvertPointFromHost(gfx::Point* point) const { - gfx::Point3F point_3f(*point); - GetInverseRootTransform().TransformPoint(&point_3f); - *point = gfx::ToFlooredPoint(point_3f.AsPointF()); -} - -void RootWindow::ProcessedTouchEvent(ui::TouchEvent* event, - Window* window, - ui::EventResult result) { - scoped_ptr<ui::GestureRecognizer::Gestures> gestures; - gestures.reset(ui::GestureRecognizer::Get()-> - ProcessTouchEventForGesture(*event, result, window)); - DispatchDetails details = ProcessGestures(gestures.get()); - if (details.dispatcher_destroyed) - return; -} - -void RootWindow::HoldPointerMoves() { - if (!move_hold_count_) - held_event_factory_.InvalidateWeakPtrs(); - ++move_hold_count_; - TRACE_EVENT_ASYNC_BEGIN0("ui", "RootWindow::HoldPointerMoves", this); -} - -void RootWindow::ReleasePointerMoves() { - --move_hold_count_; - DCHECK_GE(move_hold_count_, 0); - if (!move_hold_count_ && held_move_event_) { - // We don't want to call DispatchHeldEvents directly, because this might be - // called from a deep stack while another event, in which case dispatching - // another one may not be safe/expected. Instead we post a task, that we - // may cancel if HoldPointerMoves is called again before it executes. - base::MessageLoop::current()->PostNonNestableTask( - FROM_HERE, - base::Bind(base::IgnoreResult(&RootWindow::DispatchHeldEvents), - held_event_factory_.GetWeakPtr())); - } - TRACE_EVENT_ASYNC_END0("ui", "RootWindow::HoldPointerMoves", this); -} - -gfx::Point RootWindow::GetLastMouseLocationInRoot() const { - gfx::Point location = Env::GetInstance()->last_mouse_location(); - client::ScreenPositionClient* client = - client::GetScreenPositionClient(window()); - if (client) - client->ConvertPointFromScreen(window(), &location); - return location; -} - -void RootWindow::SetRootWindowTransformer( - scoped_ptr<RootWindowTransformer> transformer) { - transformer_ = transformer.Pass(); - host_->SetInsets(transformer_->GetHostInsets()); - window()->SetTransform(transformer_->GetTransform()); - // If the layer is not animating, then we need to update the root window - // size immediately. - if (!window()->layer()->GetAnimator()->is_animating()) - UpdateRootWindowSize(host_->GetBounds().size()); -} - -gfx::Transform RootWindow::GetRootTransform() const { - float scale = ui::GetDeviceScaleFactor(window()->layer()); - gfx::Transform transform; - transform.Scale(scale, scale); - transform *= transformer_->GetTransform(); - return transform; -} - -void RootWindow::SetTransform(const gfx::Transform& transform) { - scoped_ptr<RootWindowTransformer> transformer( - new SimpleRootWindowTransformer(window(), transform)); - SetRootWindowTransformer(transformer.Pass()); -} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindow, private: - -void RootWindow::TransformEventForDeviceScaleFactor(ui::LocatedEvent* event) { - event->UpdateForRootTransform(GetInverseRootTransform()); -} - -void RootWindow::MoveCursorToInternal(const gfx::Point& root_location, - const gfx::Point& host_location) { - host_->MoveCursorTo(host_location); - SetLastMouseLocation(window(), root_location); - client::CursorClient* cursor_client = client::GetCursorClient(window()); - if (cursor_client) { - const gfx::Display& display = - gfx::Screen::GetScreenFor(window())->GetDisplayNearestWindow(window()); - cursor_client->SetDisplay(display); - } - synthesize_mouse_move_ = false; -} - -ui::EventDispatchDetails RootWindow::DispatchMouseEnterOrExit( - const ui::MouseEvent& event, - ui::EventType type) { - if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate()) - return DispatchDetails(); - - ui::MouseEvent translated_event(event, - window(), - mouse_moved_handler_, - type, - event.flags() | ui::EF_IS_SYNTHESIZED); - return DispatchEvent(mouse_moved_handler_, &translated_event); -} - -ui::EventDispatchDetails RootWindow::ProcessGestures( - ui::GestureRecognizer::Gestures* gestures) { - DispatchDetails details; - if (!gestures || gestures->empty()) - return details; - - Window* target = GetGestureTarget(gestures->get().at(0)); - for (size_t i = 0; i < gestures->size(); ++i) { - ui::GestureEvent* event = gestures->get().at(i); - event->ConvertLocationToTarget(window(), target); - details = DispatchEvent(target, event); - if (details.dispatcher_destroyed || details.target_destroyed) - break; - } - return details; -} - -void RootWindow::OnWindowAddedToRootWindow(Window* attached) { - if (attached->IsVisible() && - attached->ContainsPointInRoot(GetLastMouseLocationInRoot())) { - PostMouseMoveEventAfterWindowChange(); - } -} - -void RootWindow::OnWindowRemovedFromRootWindow(Window* detached, - Window* new_root) { - DCHECK(aura::client::GetCaptureWindow(window()) != window()); - - DispatchMouseExitToHidingWindow(detached); - OnWindowHidden(detached, new_root ? WINDOW_MOVING : WINDOW_HIDDEN); - - if (detached->IsVisible() && - detached->ContainsPointInRoot(GetLastMouseLocationInRoot())) { - PostMouseMoveEventAfterWindowChange(); - } -} - -void RootWindow::OnWindowHidden(Window* invisible, WindowHiddenReason reason) { - // Do not clear the capture, and the |event_dispatch_target_| if the - // window is moving across root windows, because the target itself - // is actually still visible and clearing them stops further event - // processing, which can cause unexpected behaviors. See - // crbug.com/157583 - if (reason != WINDOW_MOVING) { - Window* capture_window = aura::client::GetCaptureWindow(window()); - // If the ancestor of the capture window is hidden, - // release the capture. - if (invisible->Contains(capture_window) && invisible != window()) - capture_window->ReleaseCapture(); - - if (invisible->Contains(event_dispatch_target_)) - event_dispatch_target_ = NULL; - - if (invisible->Contains(old_dispatch_target_)) - old_dispatch_target_ = NULL; - } - - // If the ancestor of any event handler windows are invisible, release the - // pointer to those windows. - if (invisible->Contains(mouse_pressed_handler_)) - mouse_pressed_handler_ = NULL; - if (invisible->Contains(mouse_moved_handler_)) - mouse_moved_handler_ = NULL; - - CleanupGestureState(invisible); -} - -void RootWindow::CleanupGestureState(Window* window) { - ui::GestureRecognizer::Get()->CancelActiveTouches(window); - ui::GestureRecognizer::Get()->CleanupStateForConsumer(window); - const Window::Windows& windows = window->children(); - for (Window::Windows::const_iterator iter = windows.begin(); - iter != windows.end(); - ++iter) { - CleanupGestureState(*iter); - } -} - -void RootWindow::UpdateRootWindowSize(const gfx::Size& host_size) { - window()->SetBounds(transformer_->GetRootWindowBounds(host_size)); -} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindow, aura::client::CaptureDelegate implementation: - -void RootWindow::UpdateCapture(Window* old_capture, - Window* new_capture) { - // |mouse_moved_handler_| may have been set to a Window in a different root - // (see below). Clear it here to ensure we don't end up referencing a stale - // Window. - if (mouse_moved_handler_ && !window()->Contains(mouse_moved_handler_)) - mouse_moved_handler_ = NULL; - - if (old_capture && old_capture->GetRootWindow() == window() && - old_capture->delegate()) { - // Send a capture changed event with bogus location data. - ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(), - gfx::Point(), 0); - - DispatchDetails details = DispatchEvent(old_capture, &event); - if (details.dispatcher_destroyed) - return; - - old_capture->delegate()->OnCaptureLost(); - } - - if (new_capture) { - // Make all subsequent mouse events go to the capture window. We shouldn't - // need to send an event here as OnCaptureLost() should take care of that. - if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown()) - mouse_moved_handler_ = new_capture; - } else { - // Make sure mouse_moved_handler gets updated. - DispatchDetails details = SynthesizeMouseMoveEvent(); - if (details.dispatcher_destroyed) - return; - } - mouse_pressed_handler_ = NULL; -} - -void RootWindow::OnOtherRootGotCapture() { - mouse_moved_handler_ = NULL; - mouse_pressed_handler_ = NULL; -} - -void RootWindow::SetNativeCapture() { - host_->SetCapture(); -} - -void RootWindow::ReleaseNativeCapture() { - host_->ReleaseCapture(); -} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindow, ui::EventProcessor implementation: -ui::EventTarget* RootWindow::GetRootTarget() { - return window(); -} - -void RootWindow::PrepareEventForDispatch(ui::Event* event) { - if (event->IsMouseEvent() || - event->IsScrollEvent() || - event->IsTouchEvent() || - event->IsGestureEvent()) { - TransformEventForDeviceScaleFactor(static_cast<ui::LocatedEvent*>(event)); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindow, ui::EventDispatcherDelegate implementation: - -bool RootWindow::CanDispatchToTarget(ui::EventTarget* target) { - return event_dispatch_target_ == target; -} - -ui::EventDispatchDetails RootWindow::PreDispatchEvent(ui::EventTarget* target, - ui::Event* event) { - if (!dispatching_held_event_ && IsUsingEventProcessorForDispatch(*event)) { - DispatchDetails details = DispatchHeldEvents(); - if (details.dispatcher_destroyed || details.target_destroyed) - return details; - - Window* target_window = static_cast<Window*>(target); - if (event->IsScrollEvent()) { - PreDispatchLocatedEvent(target_window, - static_cast<ui::ScrollEvent*>(event)); - } - } - old_dispatch_target_ = event_dispatch_target_; - event_dispatch_target_ = static_cast<Window*>(target); - return DispatchDetails(); -} - -ui::EventDispatchDetails RootWindow::PostDispatchEvent(ui::EventTarget* target, - const ui::Event& event) { - DispatchDetails details; - if (target != event_dispatch_target_) - details.target_destroyed = true; - event_dispatch_target_ = old_dispatch_target_; - old_dispatch_target_ = NULL; -#ifndef NDEBUG - DCHECK(!event_dispatch_target_ || window()->Contains(event_dispatch_target_)); -#endif - return details; -} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindow, ui::GestureEventHelper implementation: - -bool RootWindow::CanDispatchToConsumer(ui::GestureConsumer* consumer) { - Window* consumer_window = ConsumerToWindow(consumer);; - return (consumer_window && consumer_window->GetRootWindow() == window()); -} - -void RootWindow::DispatchPostponedGestureEvent(ui::GestureEvent* event) { - DispatchGestureEvent(event); -} - -void RootWindow::DispatchCancelTouchEvent(ui::TouchEvent* event) { - OnHostTouchEvent(event); -} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindow, ui::LayerAnimationObserver implementation: - -void RootWindow::OnLayerAnimationEnded( - ui::LayerAnimationSequence* animation) { - UpdateRootWindowSize(host_->GetBounds().size()); -} - -void RootWindow::OnLayerAnimationScheduled( - ui::LayerAnimationSequence* animation) { -} - -void RootWindow::OnLayerAnimationAborted( - ui::LayerAnimationSequence* animation) { -} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindow, RootWindowHostDelegate implementation: - -bool RootWindow::OnHostKeyEvent(ui::KeyEvent* event) { - DispatchDetails details = OnEventFromSource(event); - if (details.dispatcher_destroyed) - event->SetHandled(); - return event->handled(); -} - -bool RootWindow::OnHostMouseEvent(ui::MouseEvent* event) { - DispatchDetails details = OnHostMouseEventImpl(event); - return event->handled() || details.dispatcher_destroyed; -} - -bool RootWindow::OnHostScrollEvent(ui::ScrollEvent* event) { - DispatchDetails details = OnEventFromSource(event); - if (details.dispatcher_destroyed) - event->SetHandled(); - return event->handled(); -} - -bool RootWindow::OnHostTouchEvent(ui::TouchEvent* event) { - if ((event->type() == ui::ET_TOUCH_MOVED)) { - if (move_hold_count_) { - Window* null_window = static_cast<Window*>(NULL); - held_move_event_.reset( - new ui::TouchEvent(*event, null_window, null_window)); - return true; - } else { - // We may have a held event for a period between the time move_hold_count_ - // fell to 0 and the DispatchHeldEvents executes. Since we're going to - // dispatch the new event directly below, we can reset the old one. - held_move_event_.reset(); - } - } - DispatchDetails details = DispatchHeldEvents(); - if (details.dispatcher_destroyed) - return false; - details = DispatchTouchEventImpl(event); - if (details.dispatcher_destroyed) - return true; - return event->handled(); -} - -void RootWindow::OnHostCancelMode() { - ui::CancelModeEvent event; - Window* focused_window = client::GetFocusClient(window())->GetFocusedWindow(); - DispatchDetails details = - DispatchEvent(focused_window ? focused_window : window(), &event); - if (details.dispatcher_destroyed) - return; -} - -void RootWindow::OnHostActivated() { - Env::GetInstance()->RootWindowActivated(this); -} - -void RootWindow::OnHostLostWindowCapture() { - Window* capture_window = client::GetCaptureWindow(window()); - if (capture_window && capture_window->GetRootWindow() == window()) - capture_window->ReleaseCapture(); -} - -void RootWindow::OnHostLostMouseGrab() { - mouse_pressed_handler_ = NULL; - mouse_moved_handler_ = NULL; -} - -void RootWindow::OnHostPaint(const gfx::Rect& damage_rect) { - compositor_->ScheduleRedrawRect(damage_rect); -} - -void RootWindow::OnHostMoved(const gfx::Point& origin) { - TRACE_EVENT1("ui", "RootWindow::OnHostMoved", - "origin", origin.ToString()); - - FOR_EACH_OBSERVER(RootWindowObserver, observers_, - OnRootWindowHostMoved(this, origin)); -} - -void RootWindow::OnHostResized(const gfx::Size& size) { - TRACE_EVENT1("ui", "RootWindow::OnHostResized", - "size", size.ToString()); - - DispatchDetails details = DispatchHeldEvents(); - if (details.dispatcher_destroyed) - return; - // The compositor should have the same size as the native root window host. - // Get the latest scale from display because it might have been changed. - compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()), size); - - // The layer, and the observers should be notified of the - // transformed size of the root window. - UpdateRootWindowSize(host_->GetBounds().size()); - FOR_EACH_OBSERVER(RootWindowObserver, observers_, - OnRootWindowHostResized(this)); -} - -float RootWindow::GetDeviceScaleFactor() { - return compositor()->device_scale_factor(); -} - -RootWindow* RootWindow::AsRootWindow() { - return this; -} - -const RootWindow* RootWindow::AsRootWindow() const { - return this; -} - -ui::EventProcessor* RootWindow::GetEventProcessor() { - return this; -} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindow, private: - -ui::EventDispatchDetails RootWindow::OnHostMouseEventImpl( - ui::MouseEvent* event) { - if (event->type() == ui::ET_MOUSE_DRAGGED || - (event->flags() & ui::EF_IS_SYNTHESIZED)) { - if (move_hold_count_) { - Window* null_window = static_cast<Window*>(NULL); - held_move_event_.reset( - new ui::MouseEvent(*event, null_window, null_window)); - event->SetHandled(); - return DispatchDetails(); - } else { - // We may have a held event for a period between the time move_hold_count_ - // fell to 0 and the DispatchHeldEvents executes. Since we're going to - // dispatch the new event directly below, we can reset the old one. - held_move_event_.reset(); - } - } - DispatchDetails details = DispatchHeldEvents(); - if (details.dispatcher_destroyed) - return details; - return DispatchMouseEventImpl(event); -} - -ui::EventDispatchDetails RootWindow::DispatchMouseEventImpl( - ui::MouseEvent* event) { - TransformEventForDeviceScaleFactor(event); - Window* target = mouse_pressed_handler_ ? - mouse_pressed_handler_ : client::GetCaptureWindow(window()); - if (!target) - target = window()->GetEventHandlerForPoint(event->location()); - return DispatchMouseEventToTarget(event, target); -} - -ui::EventDispatchDetails RootWindow::DispatchMouseEventRepost( - ui::MouseEvent* event) { - if (event->type() != ui::ET_MOUSE_PRESSED) - return DispatchDetails(); - Window* target = client::GetCaptureWindow(window()); - WindowEventDispatcher* dispatcher = this; - if (!target) { - target = window()->GetEventHandlerForPoint(event->location()); - } else { - dispatcher = target->GetDispatcher(); - CHECK(dispatcher); // Capture window better be in valid root. - } - dispatcher->mouse_pressed_handler_ = NULL; - return dispatcher->DispatchMouseEventToTarget(event, target); -} - -ui::EventDispatchDetails RootWindow::DispatchMouseEventToTarget( - ui::MouseEvent* event, - Window* target) { - client::CursorClient* cursor_client = client::GetCursorClient(window()); - if (cursor_client && - !cursor_client->IsMouseEventsEnabled() && - (event->flags() & ui::EF_IS_SYNTHESIZED)) - return DispatchDetails(); - - static const int kMouseButtonFlagMask = - ui::EF_LEFT_MOUSE_BUTTON | - ui::EF_MIDDLE_MOUSE_BUTTON | - ui::EF_RIGHT_MOUSE_BUTTON; - // WARNING: because of nested message loops |this| may be deleted after - // dispatching any event. Do not use AutoReset or the like here. - SetLastMouseLocation(window(), event->location()); - synthesize_mouse_move_ = false; - switch (event->type()) { - case ui::ET_MOUSE_EXITED: - if (!target) { - DispatchDetails details = - DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); - if (details.dispatcher_destroyed) - return details; - mouse_moved_handler_ = NULL; - } - break; - case ui::ET_MOUSE_MOVED: - // Send an exit to the current |mouse_moved_handler_| and an enter to - // |target|. Take care that both us and |target| aren't destroyed during - // dispatch. - if (target != mouse_moved_handler_) { - aura::Window* old_mouse_moved_handler = mouse_moved_handler_; - WindowTracker destroyed_tracker; - if (target) - destroyed_tracker.Add(target); - DispatchDetails details = - DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); - if (details.dispatcher_destroyed) - return details; - // If the |mouse_moved_handler_| changes out from under us, assume a - // nested message loop ran and we don't need to do anything. - if (mouse_moved_handler_ != old_mouse_moved_handler) - return DispatchDetails(); - if (destroyed_tracker.Contains(target)) { - destroyed_tracker.Remove(target); - mouse_moved_handler_ = target; - DispatchDetails details = - DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED); - if (details.dispatcher_destroyed) - return details; - } else { - mouse_moved_handler_ = NULL; - return DispatchDetails(); - } - } - break; - case ui::ET_MOUSE_PRESSED: - // Don't set the mouse pressed handler for non client mouse down events. - // These are only sent by Windows and are not always followed with non - // client mouse up events which causes subsequent mouse events to be - // sent to the wrong target. - if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_) - mouse_pressed_handler_ = target; - Env::GetInstance()->set_mouse_button_flags( - event->flags() & kMouseButtonFlagMask); - break; - case ui::ET_MOUSE_RELEASED: - mouse_pressed_handler_ = NULL; - Env::GetInstance()->set_mouse_button_flags(event->flags() & - kMouseButtonFlagMask & ~event->changed_button_flags()); - break; - default: - break; - } - if (target) { - event->ConvertLocationToTarget(window(), target); - if (IsNonClientLocation(target, event->location())) - event->set_flags(event->flags() | ui::EF_IS_NON_CLIENT); - return DispatchEvent(target, event); - } - return DispatchDetails(); -} - -ui::EventDispatchDetails RootWindow::DispatchTouchEventImpl( - ui::TouchEvent* event) { - switch (event->type()) { - case ui::ET_TOUCH_PRESSED: - touch_ids_down_ |= (1 << event->touch_id()); - Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); - break; - - // Handle ET_TOUCH_CANCELLED only if it has a native event. - case ui::ET_TOUCH_CANCELLED: - if (!event->HasNativeEvent()) - break; - // fallthrough - case ui::ET_TOUCH_RELEASED: - touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^ - (1 << event->touch_id()); - Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); - break; - - default: - break; - } - TransformEventForDeviceScaleFactor(event); - Window* target = client::GetCaptureWindow(window()); - if (!target) { - target = ConsumerToWindow( - ui::GestureRecognizer::Get()->GetTouchLockedTarget(*event)); - if (!target) { - target = ConsumerToWindow(ui::GestureRecognizer::Get()-> - GetTargetForLocation(event->location())); - } - } - - // The gesture recognizer processes touch events in the system coordinates. So - // keep a copy of the touch event here before possibly converting the event to - // a window's local coordinate system. - ui::TouchEvent event_for_gr(*event); - - ui::EventResult result = ui::ER_UNHANDLED; - if (!target && !window()->bounds().Contains(event->location())) { - // If the initial touch is outside the root window, target the root. - target = window(); - DispatchDetails details = DispatchEvent(target ? target : NULL, event); - if (details.dispatcher_destroyed) - return details; - result = event->result(); - } else { - // We only come here when the first contact was within the root window. - if (!target) { - target = window()->GetEventHandlerForPoint(event->location()); - if (!target) - return DispatchDetails(); - } - - event->ConvertLocationToTarget(window(), target); - DispatchDetails details = DispatchEvent(target, event); - if (details.dispatcher_destroyed) - return details; - result = event->result(); - } - - // Get the list of GestureEvents from GestureRecognizer. - scoped_ptr<ui::GestureRecognizer::Gestures> gestures; - gestures.reset(ui::GestureRecognizer::Get()-> - ProcessTouchEventForGesture(event_for_gr, result, target)); - - return ProcessGestures(gestures.get()); -} - -ui::EventDispatchDetails RootWindow::DispatchHeldEvents() { - if (!held_repostable_event_ && !held_move_event_) - return DispatchDetails(); - - CHECK(!dispatching_held_event_); - dispatching_held_event_ = true; - - DispatchDetails dispatch_details; - if (held_repostable_event_) { - if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) { - scoped_ptr<ui::MouseEvent> mouse_event( - static_cast<ui::MouseEvent*>(held_repostable_event_.release())); - dispatch_details = DispatchMouseEventRepost(mouse_event.get()); - } else { - // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987. - NOTREACHED(); - } - if (dispatch_details.dispatcher_destroyed) - return dispatch_details; - } - - if (held_move_event_ && held_move_event_->IsMouseEvent()) { - // If a mouse move has been synthesized, the target location is suspect, - // so drop the held event. - if (!synthesize_mouse_move_) { - dispatch_details = DispatchMouseEventImpl( - static_cast<ui::MouseEvent*>(held_move_event_.get())); - } - if (!dispatch_details.dispatcher_destroyed) - held_move_event_.reset(); - } else if (held_move_event_ && held_move_event_->IsTouchEvent()) { - dispatch_details = DispatchTouchEventImpl( - static_cast<ui::TouchEvent*>(held_move_event_.get())); - if (!dispatch_details.dispatcher_destroyed) - held_move_event_.reset(); - } - - if (!dispatch_details.dispatcher_destroyed) - dispatching_held_event_ = false; - return dispatch_details; -} - -void RootWindow::PostMouseMoveEventAfterWindowChange() { - if (synthesize_mouse_move_) - return; - synthesize_mouse_move_ = true; - base::MessageLoop::current()->PostNonNestableTask( - FROM_HERE, - base::Bind(&RootWindow::SynthesizeMouseMoveEventAsync, - held_event_factory_.GetWeakPtr())); -} - -ui::EventDispatchDetails RootWindow::SynthesizeMouseMoveEvent() { - DispatchDetails details; - if (!synthesize_mouse_move_) - return details; - synthesize_mouse_move_ = false; - gfx::Point root_mouse_location = GetLastMouseLocationInRoot(); - if (!window()->bounds().Contains(root_mouse_location)) - return details; - gfx::Point host_mouse_location = root_mouse_location; - ConvertPointToHost(&host_mouse_location); - - ui::MouseEvent event(ui::ET_MOUSE_MOVED, - host_mouse_location, - host_mouse_location, - ui::EF_IS_SYNTHESIZED); - return OnHostMouseEventImpl(&event); -} - -void RootWindow::SynthesizeMouseMoveEventAsync() { - DispatchDetails details = SynthesizeMouseMoveEvent(); - if (details.dispatcher_destroyed) - return; -} - -gfx::Transform RootWindow::GetInverseRootTransform() const { - float scale = ui::GetDeviceScaleFactor(window()->layer()); - gfx::Transform transform; - transform.Scale(1.0f / scale, 1.0f / scale); - return transformer_->GetInverseTransform() * transform; -} - -void RootWindow::PreDispatchLocatedEvent(Window* target, - ui::LocatedEvent* event) { - int flags = event->flags(); - if (IsNonClientLocation(target, event->location())) - flags |= ui::EF_IS_NON_CLIENT; - event->set_flags(flags); - - if (!dispatching_held_event_) { - SetLastMouseLocation(window(), event->location()); - synthesize_mouse_move_ = false; - } -} - -} // namespace aura diff --git a/chromium/ui/aura/root_window.h b/chromium/ui/aura/root_window.h deleted file mode 100644 index e6b46d0f132..00000000000 --- a/chromium/ui/aura/root_window.h +++ /dev/null @@ -1,401 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_ROOT_WINDOW_H_ -#define UI_AURA_ROOT_WINDOW_H_ - -#include <vector> - -#include "base/basictypes.h" -#include "base/gtest_prod_util.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "ui/aura/aura_export.h" -#include "ui/aura/client/capture_delegate.h" -#include "ui/aura/window_tree_host.h" -#include "ui/aura/window_tree_host_delegate.h" -#include "ui/base/cursor/cursor.h" -#include "ui/compositor/compositor.h" -#include "ui/compositor/layer_animation_observer.h" -#include "ui/events/event_constants.h" -#include "ui/events/event_processor.h" -#include "ui/events/event_targeter.h" -#include "ui/events/gestures/gesture_recognizer.h" -#include "ui/events/gestures/gesture_types.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/point.h" -#include "ui/gfx/transform.h" - -namespace gfx { -class Size; -class Transform; -} - -namespace ui { -class GestureEvent; -class GestureRecognizer; -class KeyEvent; -class LayerAnimationSequence; -class MouseEvent; -class ScrollEvent; -class TouchEvent; -class ViewProp; -} - -namespace aura { -class RootWindow; -class RootWindowHost; -class RootWindowObserver; -class RootWindowTransformer; -class TestScreen; -class WindowTargeter; - -// RootWindow is responsible for hosting a set of windows. -class AURA_EXPORT RootWindow : public ui::EventProcessor, - public ui::GestureEventHelper, - public ui::LayerAnimationObserver, - public aura::client::CaptureDelegate, - public aura::RootWindowHostDelegate { - public: - struct AURA_EXPORT CreateParams { - // CreateParams with initial_bounds and default host in pixel. - explicit CreateParams(const gfx::Rect& initial_bounds); - ~CreateParams() {} - - gfx::Rect initial_bounds; - - // A host to use in place of the default one that RootWindow will create. - // NULL by default. - RootWindowHost* host; - }; - - explicit RootWindow(const CreateParams& params); - virtual ~RootWindow(); - - // Returns the RootWindowHost for the specified accelerated widget, or NULL - // if there is none associated. - static RootWindow* GetForAcceleratedWidget(gfx::AcceleratedWidget widget); - - Window* window() { - return const_cast<Window*>(const_cast<const RootWindow*>(this)->window()); - } - const Window* window() const { return window_.get(); } - RootWindowHost* host() { - return const_cast<RootWindowHost*>( - const_cast<const RootWindow*>(this)->host()); - } - const RootWindowHost* host() const { return host_.get(); } - ui::Compositor* compositor() { return compositor_.get(); } - gfx::NativeCursor last_cursor() const { return last_cursor_; } - Window* mouse_pressed_handler() { return mouse_pressed_handler_; } - Window* mouse_moved_handler() { return mouse_moved_handler_; } - - // Initializes the root window. - void Init(); - - // Stop listening events in preparation for shutdown. - void PrepareForShutdown(); - - // Repost event for re-processing. Used when exiting context menus. - // We only support the ET_MOUSE_PRESSED and ET_GESTURE_TAP_DOWN event - // types (although the latter is currently a no-op). - void RepostEvent(const ui::LocatedEvent& event); - - RootWindowHostDelegate* AsRootWindowHostDelegate(); - - // Gets/sets the size of the host window. - void SetHostSize(const gfx::Size& size_in_pixel); - - // Sets the bounds of the host window. - void SetHostBounds(const gfx::Rect& size_in_pizel); - - // Sets the currently-displayed cursor. If the cursor was previously hidden - // via ShowCursor(false), it will remain hidden until ShowCursor(true) is - // called, at which point the cursor that was last set via SetCursor() will be - // used. - void SetCursor(gfx::NativeCursor cursor); - - // Invoked when the cursor's visibility has changed. - void OnCursorVisibilityChanged(bool visible); - - // Invoked when the mouse events get enabled or disabled. - void OnMouseEventsEnableStateChanged(bool enabled); - - // Moves the cursor to the specified location relative to the root window. - void MoveCursorTo(const gfx::Point& location); - - // Moves the cursor to the |host_location| given in host coordinates. - void MoveCursorToHostLocation(const gfx::Point& host_location); - - // Draw the damage_rect. - void ScheduleRedrawRect(const gfx::Rect& damage_rect); - - // Returns a target window for the given gesture event. - Window* GetGestureTarget(ui::GestureEvent* event); - - // Handles a gesture event. Returns true if handled. Unlike the other - // event-dispatching function (e.g. for touch/mouse/keyboard events), gesture - // events are dispatched from GestureRecognizer instead of RootWindowHost. - void DispatchGestureEvent(ui::GestureEvent* event); - - // Invoked when |window| is being destroyed. - void OnWindowDestroying(Window* window); - - // Invoked when |window|'s bounds have changed. |contained_mouse| indicates if - // the bounds before change contained the |last_moust_location()|. - void OnWindowBoundsChanged(Window* window, bool contained_mouse); - - // Dispatches OnMouseExited to the |window| which is hiding if nessessary. - void DispatchMouseExitToHidingWindow(Window* window); - - // Dispatches a ui::ET_MOUSE_EXITED event at |point|. - void DispatchMouseExitAtPoint(const gfx::Point& point); - - // Invoked when |window|'s visibility has changed. - void OnWindowVisibilityChanged(Window* window, bool is_visible); - - // Invoked when |window|'s tranfrom has changed. |contained_mouse| - // indicates if the bounds before change contained the - // |last_moust_location()|. - void OnWindowTransformed(Window* window, bool contained_mouse); - - // Invoked when the keyboard mapping (in X11 terms: the mapping between - // keycodes and keysyms) has changed. - void OnKeyboardMappingChanged(); - - // The system windowing system has sent a request that we close our window. - void OnRootWindowHostCloseRequested(); - - // Add/remove observer. There is no need to remove the observer if - // the root window is being deleted. In particular, you SHOULD NOT remove - // in |WindowObserver::OnWindowDestroying| of the observer observing - // the root window because it is too late to remove it. - void AddRootWindowObserver(RootWindowObserver* observer); - void RemoveRootWindowObserver(RootWindowObserver* observer); - - // Converts |point| from the root window's coordinate system to the - // host window's. - void ConvertPointToHost(gfx::Point* point) const; - - // Converts |point| from the host window's coordinate system to the - // root window's. - void ConvertPointFromHost(gfx::Point* point) const; - - // Gesture Recognition ------------------------------------------------------- - - // When a touch event is dispatched to a Window, it may want to process the - // touch event asynchronously. In such cases, the window should consume the - // event during the event dispatch. Once the event is properly processed, the - // window should let the RootWindow know about the result of the event - // processing, so that gesture events can be properly created and dispatched. - void ProcessedTouchEvent(ui::TouchEvent* event, - Window* window, - ui::EventResult result); - - // These methods are used to defer the processing of mouse/touch events - // related to resize. A client (typically a RenderWidgetHostViewAura) can call - // HoldPointerMoves when an resize is initiated and then ReleasePointerMoves - // once the resize is completed. - // - // More than one hold can be invoked and each hold must be cancelled by a - // release before we resume normal operation. - void HoldPointerMoves(); - void ReleasePointerMoves(); - - // Gets the last location seen in a mouse event in this root window's - // coordinates. This may return a point outside the root window's bounds. - gfx::Point GetLastMouseLocationInRoot() const; - - void SetRootWindowTransformer(scoped_ptr<RootWindowTransformer> transformer); - gfx::Transform GetRootTransform() const; - - void SetTransform(const gfx::Transform& transform); - - private: - FRIEND_TEST_ALL_PREFIXES(RootWindowTest, KeepTranslatedEventInRoot); - - friend class Window; - friend class TestScreen; - - // The parameter for OnWindowHidden() to specify why window is hidden. - enum WindowHiddenReason { - WINDOW_DESTROYED, // Window is destroyed. - WINDOW_HIDDEN, // Window is hidden. - WINDOW_MOVING, // Window is temporarily marked as hidden due to move - // across root windows. - }; - - // Updates the event with the appropriate transform for the device scale - // factor. The RootWindowHostDelegate dispatches events in the physical pixel - // coordinate. But the event processing from RootWindow onwards happen in - // device-independent pixel coordinate. So it is necessary to update the event - // received from the host. - void TransformEventForDeviceScaleFactor(ui::LocatedEvent* event); - - // Moves the cursor to the specified location. This method is internally used - // by MoveCursorTo() and MoveCursorToHostLocation(). - void MoveCursorToInternal(const gfx::Point& root_location, - const gfx::Point& host_location); - - // Dispatches the specified event type (intended for enter/exit) to the - // |mouse_moved_handler_|. - ui::EventDispatchDetails DispatchMouseEnterOrExit( - const ui::MouseEvent& event, - ui::EventType type) WARN_UNUSED_RESULT; - ui::EventDispatchDetails ProcessGestures( - ui::GestureRecognizer::Gestures* gestures) WARN_UNUSED_RESULT; - - // Called when a Window is attached or detached from the RootWindow. - void OnWindowAddedToRootWindow(Window* window); - void OnWindowRemovedFromRootWindow(Window* window, Window* new_root); - - // Called when a window becomes invisible, either by being removed - // from root window hierarchy, via SetVisible(false) or being destroyed. - // |reason| specifies what triggered the hiding. - void OnWindowHidden(Window* invisible, WindowHiddenReason reason); - - // Cleans up the state of gestures for all windows in |window| (including - // |window| itself). This includes cancelling active touch points. - void CleanupGestureState(Window* window); - - // Updates the root window's size using |host_size|, current - // transform and insets. - void UpdateRootWindowSize(const gfx::Size& host_size); - - // Overridden from aura::client::CaptureDelegate: - virtual void UpdateCapture(Window* old_capture, Window* new_capture) OVERRIDE; - virtual void OnOtherRootGotCapture() OVERRIDE; - virtual void SetNativeCapture() OVERRIDE; - virtual void ReleaseNativeCapture() OVERRIDE; - - // Overridden from ui::EventProcessor: - virtual ui::EventTarget* GetRootTarget() OVERRIDE; - virtual void PrepareEventForDispatch(ui::Event* event) OVERRIDE; - - // Overridden from ui::EventDispatcherDelegate. - virtual bool CanDispatchToTarget(ui::EventTarget* target) OVERRIDE; - virtual ui::EventDispatchDetails PreDispatchEvent(ui::EventTarget* target, - ui::Event* event) OVERRIDE; - virtual ui::EventDispatchDetails PostDispatchEvent( - ui::EventTarget* target, const ui::Event& event) OVERRIDE; - - // Overridden from ui::GestureEventHelper. - virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE; - virtual void DispatchPostponedGestureEvent(ui::GestureEvent* event) OVERRIDE; - virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE; - - // Overridden from ui::LayerAnimationObserver: - virtual void OnLayerAnimationEnded( - ui::LayerAnimationSequence* animation) OVERRIDE; - virtual void OnLayerAnimationScheduled( - ui::LayerAnimationSequence* animation) OVERRIDE; - virtual void OnLayerAnimationAborted( - ui::LayerAnimationSequence* animation) OVERRIDE; - - // Overridden from aura::RootWindowHostDelegate: - virtual bool OnHostKeyEvent(ui::KeyEvent* event) OVERRIDE; - virtual bool OnHostMouseEvent(ui::MouseEvent* event) OVERRIDE; - virtual bool OnHostScrollEvent(ui::ScrollEvent* event) OVERRIDE; - virtual bool OnHostTouchEvent(ui::TouchEvent* event) OVERRIDE; - virtual void OnHostCancelMode() OVERRIDE; - virtual void OnHostActivated() OVERRIDE; - virtual void OnHostLostWindowCapture() OVERRIDE; - virtual void OnHostLostMouseGrab() OVERRIDE; - virtual void OnHostPaint(const gfx::Rect& damage_rect) OVERRIDE; - virtual void OnHostMoved(const gfx::Point& origin) OVERRIDE; - virtual void OnHostResized(const gfx::Size& size) OVERRIDE; - virtual float GetDeviceScaleFactor() OVERRIDE; - virtual RootWindow* AsRootWindow() OVERRIDE; - virtual const RootWindow* AsRootWindow() const OVERRIDE; - virtual ui::EventProcessor* GetEventProcessor() OVERRIDE; - - ui::EventDispatchDetails OnHostMouseEventImpl(ui::MouseEvent* event) - WARN_UNUSED_RESULT; - - // We hold and aggregate mouse drags and touch moves as a way of throttling - // resizes when HoldMouseMoves() is called. The following methods are used to - // dispatch held and newly incoming mouse and touch events, typically when an - // event other than one of these needs dispatching or a matching - // ReleaseMouseMoves()/ReleaseTouchMoves() is called. NOTE: because these - // methods dispatch events from RootWindowHost the coordinates are in terms of - // the root. - ui::EventDispatchDetails DispatchMouseEventImpl(ui::MouseEvent* event) - WARN_UNUSED_RESULT; - ui::EventDispatchDetails DispatchMouseEventRepost(ui::MouseEvent* event) - WARN_UNUSED_RESULT; - ui::EventDispatchDetails DispatchMouseEventToTarget(ui::MouseEvent* event, - Window* target) - WARN_UNUSED_RESULT; - ui::EventDispatchDetails DispatchTouchEventImpl(ui::TouchEvent* event) - WARN_UNUSED_RESULT; - ui::EventDispatchDetails DispatchHeldEvents() WARN_UNUSED_RESULT; - // Creates and dispatches synthesized mouse move event using the - // current mouse location. - ui::EventDispatchDetails SynthesizeMouseMoveEvent() WARN_UNUSED_RESULT; - - void SynthesizeMouseMoveEventAsync(); - - // Posts a task to send synthesized mouse move event if there - // is no a pending task. - void PostMouseMoveEventAfterWindowChange(); - - gfx::Transform GetInverseRootTransform() const; - - void PreDispatchLocatedEvent(Window* target, ui::LocatedEvent* event); - - // TODO(beng): evaluate the ideal ownership model. - scoped_ptr<Window> window_; - - scoped_ptr<ui::Compositor> compositor_; - - scoped_ptr<RootWindowHost> host_; - - // Touch ids that are currently down. - uint32 touch_ids_down_; - - // Last cursor set. Used for testing. - gfx::NativeCursor last_cursor_; - - ObserverList<RootWindowObserver> observers_; - - Window* mouse_pressed_handler_; - Window* mouse_moved_handler_; - Window* event_dispatch_target_; - Window* old_dispatch_target_; - - bool synthesize_mouse_move_; - bool waiting_on_compositing_end_; - bool draw_on_compositing_end_; - - bool defer_draw_scheduling_; - - // How many move holds are outstanding. We try to defer dispatching - // touch/mouse moves while the count is > 0. - int move_hold_count_; - scoped_ptr<ui::LocatedEvent> held_move_event_; - - // Allowing for reposting of events. Used when exiting context menus. - scoped_ptr<ui::LocatedEvent> held_repostable_event_; - - // Set when dispatching a held event. - bool dispatching_held_event_; - - scoped_ptr<ui::ViewProp> prop_; - - scoped_ptr<RootWindowTransformer> transformer_; - - // Used to schedule reposting an event. - base::WeakPtrFactory<RootWindow> repost_event_factory_; - - // Used to schedule DispatchHeldEvents() when |move_hold_count_| goes to 0. - base::WeakPtrFactory<RootWindow> held_event_factory_; - - DISALLOW_COPY_AND_ASSIGN(RootWindow); -}; - -} // namespace aura - -#endif // UI_AURA_ROOT_WINDOW_H_ diff --git a/chromium/ui/aura/root_window_host_ozone.cc b/chromium/ui/aura/root_window_host_ozone.cc deleted file mode 100644 index 937b70f65be..00000000000 --- a/chromium/ui/aura/root_window_host_ozone.cc +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/root_window_host_ozone.h" - -#include "ui/aura/root_window.h" -#include "ui/events/ozone/event_factory_ozone.h" -#include "ui/gfx/ozone/surface_factory_ozone.h" -#include "ui/ozone/ozone_platform.h" - -namespace aura { - -RootWindowHostOzone::RootWindowHostOzone(const gfx::Rect& bounds) - : widget_(0), - bounds_(bounds) { - ui::OzonePlatform::Initialize(); - - // EventFactoryOzone creates converters that obtain input events from the - // underlying input system and dispatch them as |ui::Event| instances into - // Aura. - ui::EventFactoryOzone::GetInstance()->StartProcessingEvents(); - - gfx::SurfaceFactoryOzone* surface_factory = - gfx::SurfaceFactoryOzone::GetInstance(); - widget_ = surface_factory->GetAcceleratedWidget(); - - surface_factory->AttemptToResizeAcceleratedWidget(widget_, bounds_); - - base::MessagePumpOzone::Current()->AddDispatcherForRootWindow(this); -} - -RootWindowHostOzone::~RootWindowHostOzone() { - base::MessagePumpOzone::Current()->RemoveDispatcherForRootWindow(0); -} - -bool RootWindowHostOzone::Dispatch(const base::NativeEvent& ne) { - ui::Event* event = static_cast<ui::Event*>(ne); - if (event->IsTouchEvent()) { - ui::TouchEvent* touchev = static_cast<ui::TouchEvent*>(ne); - delegate_->OnHostTouchEvent(touchev); - } else if (event->IsKeyEvent()) { - ui::KeyEvent* keyev = static_cast<ui::KeyEvent*>(ne); - delegate_->OnHostKeyEvent(keyev); - } else if (event->IsMouseEvent()) { - ui::MouseEvent* mouseev = static_cast<ui::MouseEvent*>(ne); - delegate_->OnHostMouseEvent(mouseev); - } - return true; -} - -RootWindow* RootWindowHostOzone::GetRootWindow() { - return delegate_->AsRootWindow(); -} - -gfx::AcceleratedWidget RootWindowHostOzone::GetAcceleratedWidget() { - return widget_; -} - -void RootWindowHostOzone::Show() { NOTIMPLEMENTED(); } - -void RootWindowHostOzone::Hide() { NOTIMPLEMENTED(); } - -void RootWindowHostOzone::ToggleFullScreen() { NOTIMPLEMENTED(); } - -gfx::Rect RootWindowHostOzone::GetBounds() const { return bounds_; } - -void RootWindowHostOzone::SetBounds(const gfx::Rect& bounds) { - NOTIMPLEMENTED(); -} - -gfx::Insets RootWindowHostOzone::GetInsets() const { return gfx::Insets(); } - -void RootWindowHostOzone::SetInsets(const gfx::Insets& insets) { - NOTIMPLEMENTED(); -} - -gfx::Point RootWindowHostOzone::GetLocationOnNativeScreen() const { - return bounds_.origin(); -} - -void RootWindowHostOzone::SetCapture() { NOTIMPLEMENTED(); } - -void RootWindowHostOzone::ReleaseCapture() { NOTIMPLEMENTED(); } - -void RootWindowHostOzone::SetCursor(gfx::NativeCursor cursor) { - NOTIMPLEMENTED(); -} - -bool RootWindowHostOzone::QueryMouseLocation(gfx::Point* location_return) { - NOTIMPLEMENTED(); - return false; -} - -bool RootWindowHostOzone::ConfineCursorToRootWindow() { - NOTIMPLEMENTED(); - return false; -} - -void RootWindowHostOzone::UnConfineCursor() { NOTIMPLEMENTED(); } - -void RootWindowHostOzone::OnCursorVisibilityChanged(bool show) { - NOTIMPLEMENTED(); -} - -void RootWindowHostOzone::MoveCursorTo(const gfx::Point& location) { - NOTIMPLEMENTED(); -} - -void RootWindowHostOzone::PostNativeEvent( - const base::NativeEvent& native_event) { - NOTIMPLEMENTED(); -} - -void RootWindowHostOzone::OnDeviceScaleFactorChanged( - float device_scale_factor) { - NOTIMPLEMENTED(); -} - -void RootWindowHostOzone::PrepareForShutdown() { NOTIMPLEMENTED(); } - -// static -RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) { - return new RootWindowHostOzone(bounds); -} - -// static -gfx::Size RootWindowHost::GetNativeScreenSize() { - NOTIMPLEMENTED(); - return gfx::Size(); -} - -} // namespace aura diff --git a/chromium/ui/aura/root_window_host_ozone.h b/chromium/ui/aura/root_window_host_ozone.h deleted file mode 100644 index 41f6a8e181f..00000000000 --- a/chromium/ui/aura/root_window_host_ozone.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_ROOT_WINDOW_HOST_OZONE_H_ -#define UI_AURA_ROOT_WINDOW_HOST_OZONE_H_ - -#include <vector> - -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "ui/aura/window_tree_host.h" -#include "ui/gfx/insets.h" -#include "ui/gfx/rect.h" - -namespace aura { - -class RootWindowHostOzone : public RootWindowHost, - public base::MessageLoop::Dispatcher { - public: - explicit RootWindowHostOzone(const gfx::Rect& bounds); - virtual ~RootWindowHostOzone(); - - private: - // Overridden from Dispatcher overrides: - virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; - - // RootWindowHost Overrides. - virtual RootWindow* GetRootWindow() OVERRIDE; - virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; - virtual void Show() OVERRIDE; - virtual void Hide() OVERRIDE; - virtual void ToggleFullScreen() OVERRIDE; - virtual gfx::Rect GetBounds() const OVERRIDE; - virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; - virtual gfx::Insets GetInsets() const OVERRIDE; - virtual void SetInsets(const gfx::Insets& bounds) OVERRIDE; - virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE; - virtual void SetCapture() OVERRIDE; - virtual void ReleaseCapture() OVERRIDE; - virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE; - virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE; - virtual bool ConfineCursorToRootWindow() OVERRIDE; - virtual void UnConfineCursor() OVERRIDE; - virtual void OnCursorVisibilityChanged(bool show) OVERRIDE; - virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE; - virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE; - virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; - virtual void PrepareForShutdown() OVERRIDE; - - gfx::AcceleratedWidget widget_; - gfx::Rect bounds_; - - DISALLOW_COPY_AND_ASSIGN(RootWindowHostOzone); -}; - -} // namespace aura - -#endif // UI_AURA_ROOT_WINDOW_HOST_OZONE_H_ diff --git a/chromium/ui/aura/root_window_host_win.cc b/chromium/ui/aura/root_window_host_win.cc deleted file mode 100644 index 931c11e5179..00000000000 --- a/chromium/ui/aura/root_window_host_win.cc +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/root_window_host_win.h" - -#include <windows.h> - -#include <algorithm> - -#include "base/message_loop/message_loop.h" -#include "ui/aura/client/cursor_client.h" -#include "ui/aura/root_window.h" -#include "ui/base/cursor/cursor_loader_win.h" -#include "ui/events/event.h" -#include "ui/base/view_prop.h" -#include "ui/gfx/display.h" -#include "ui/gfx/insets.h" -#include "ui/gfx/screen.h" - -using std::max; -using std::min; - -namespace aura { -namespace { - -bool use_popup_as_root_window_for_test = false; - -} // namespace - -// static -RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) { - return new RootWindowHostWin(bounds); -} - -// static -gfx::Size RootWindowHost::GetNativeScreenSize() { - return gfx::Size(GetSystemMetrics(SM_CXSCREEN), - GetSystemMetrics(SM_CYSCREEN)); -} - -RootWindowHostWin::RootWindowHostWin(const gfx::Rect& bounds) - : fullscreen_(false), - has_capture_(false), - saved_window_style_(0), - saved_window_ex_style_(0) { - if (use_popup_as_root_window_for_test) - set_window_style(WS_POPUP); - Init(NULL, bounds); - SetWindowText(hwnd(), L"aura::RootWindow!"); -} - -RootWindowHostWin::~RootWindowHostWin() { - DestroyWindow(hwnd()); -} - -RootWindow* RootWindowHostWin::GetRootWindow() { - return delegate_->AsRootWindow(); -} - -gfx::AcceleratedWidget RootWindowHostWin::GetAcceleratedWidget() { - return hwnd(); -} - -void RootWindowHostWin::Show() { - ShowWindow(hwnd(), SW_SHOWNORMAL); -} - -void RootWindowHostWin::Hide() { - NOTIMPLEMENTED(); -} - -void RootWindowHostWin::ToggleFullScreen() { - gfx::Rect target_rect; - if (!fullscreen_) { - fullscreen_ = true; - saved_window_style_ = GetWindowLong(hwnd(), GWL_STYLE); - saved_window_ex_style_ = GetWindowLong(hwnd(), GWL_EXSTYLE); - GetWindowRect(hwnd(), &saved_window_rect_); - SetWindowLong(hwnd(), GWL_STYLE, - saved_window_style_ & ~(WS_CAPTION | WS_THICKFRAME)); - SetWindowLong(hwnd(), GWL_EXSTYLE, - saved_window_ex_style_ & ~(WS_EX_DLGMODALFRAME | - WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); - - MONITORINFO mi; - mi.cbSize = sizeof(mi); - GetMonitorInfo(MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST), &mi); - target_rect = gfx::Rect(mi.rcMonitor); - } else { - fullscreen_ = false; - SetWindowLong(hwnd(), GWL_STYLE, saved_window_style_); - SetWindowLong(hwnd(), GWL_EXSTYLE, saved_window_ex_style_); - target_rect = gfx::Rect(saved_window_rect_); - } - SetWindowPos(hwnd(), - NULL, - target_rect.x(), - target_rect.y(), - target_rect.width(), - target_rect.height(), - SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); -} - -gfx::Rect RootWindowHostWin::GetBounds() const { - RECT r; - GetClientRect(hwnd(), &r); - return gfx::Rect(r); -} - -void RootWindowHostWin::SetBounds(const gfx::Rect& bounds) { - if (fullscreen_) { - saved_window_rect_.right = saved_window_rect_.left + bounds.width(); - saved_window_rect_.bottom = saved_window_rect_.top + bounds.height(); - return; - } - RECT window_rect; - window_rect.left = bounds.x(); - window_rect.top = bounds.y(); - window_rect.right = bounds.right() ; - window_rect.bottom = bounds.bottom(); - AdjustWindowRectEx(&window_rect, - GetWindowLong(hwnd(), GWL_STYLE), - FALSE, - GetWindowLong(hwnd(), GWL_EXSTYLE)); - SetWindowPos( - hwnd(), - NULL, - window_rect.left, - window_rect.top, - window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top, - SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOREPOSITION); - - // Explicity call OnHostResized when the scale has changed because - // the window size may not have changed. - float current_scale = delegate_->GetDeviceScaleFactor(); - float new_scale = gfx::Screen::GetScreenFor( - delegate_->AsRootWindow()->window())->GetDisplayNearestWindow( - delegate_->AsRootWindow()->window()).device_scale_factor(); - if (current_scale != new_scale) - delegate_->OnHostResized(bounds.size()); -} - -gfx::Insets RootWindowHostWin::GetInsets() const { - return gfx::Insets(); -} - -void RootWindowHostWin::SetInsets(const gfx::Insets& insets) { -} - -gfx::Point RootWindowHostWin::GetLocationOnNativeScreen() const { - RECT r; - GetClientRect(hwnd(), &r); - return gfx::Point(r.left, r.top); -} - - -void RootWindowHostWin::SetCursor(gfx::NativeCursor native_cursor) { - // Custom web cursors are handled directly. - if (native_cursor == ui::kCursorCustom) - return; - - ui::CursorLoaderWin cursor_loader; - cursor_loader.SetPlatformCursor(&native_cursor); - ::SetCursor(native_cursor.platform()); -} - -void RootWindowHostWin::SetCapture() { - if (!has_capture_) { - has_capture_ = true; - ::SetCapture(hwnd()); - } -} - -void RootWindowHostWin::ReleaseCapture() { - if (has_capture_) { - has_capture_ = false; - ::ReleaseCapture(); - } -} - -bool RootWindowHostWin::QueryMouseLocation(gfx::Point* location_return) { - client::CursorClient* cursor_client = - client::GetCursorClient(GetRootWindow()->window()); - if (cursor_client && !cursor_client->IsMouseEventsEnabled()) { - *location_return = gfx::Point(0, 0); - return false; - } - - POINT pt; - GetCursorPos(&pt); - ScreenToClient(hwnd(), &pt); - const gfx::Size size = GetBounds().size(); - *location_return = - gfx::Point(max(0, min(size.width(), static_cast<int>(pt.x))), - max(0, min(size.height(), static_cast<int>(pt.y)))); - return (pt.x >= 0 && static_cast<int>(pt.x) < size.width() && - pt.y >= 0 && static_cast<int>(pt.y) < size.height()); -} - -bool RootWindowHostWin::ConfineCursorToRootWindow() { - RECT window_rect; - GetWindowRect(hwnd(), &window_rect); - return ClipCursor(&window_rect) != 0; -} - -void RootWindowHostWin::UnConfineCursor() { - ClipCursor(NULL); -} - -void RootWindowHostWin::OnCursorVisibilityChanged(bool show) { - NOTIMPLEMENTED(); -} - -void RootWindowHostWin::MoveCursorTo(const gfx::Point& location) { - // Deliberately not implemented. -} - -void RootWindowHostWin::PostNativeEvent(const base::NativeEvent& native_event) { - ::PostMessage( - hwnd(), native_event.message, native_event.wParam, native_event.lParam); -} - -void RootWindowHostWin::OnDeviceScaleFactorChanged( - float device_scale_factor) { - NOTIMPLEMENTED(); -} - -void RootWindowHostWin::PrepareForShutdown() { - NOTIMPLEMENTED(); -} - -void RootWindowHostWin::OnClose() { - // TODO: this obviously shouldn't be here. - base::MessageLoopForUI::current()->Quit(); -} - -LRESULT RootWindowHostWin::OnKeyEvent(UINT message, - WPARAM w_param, - LPARAM l_param) { - MSG msg = { hwnd(), message, w_param, l_param }; - ui::KeyEvent keyev(msg, message == WM_CHAR); - SetMsgHandled(delegate_->OnHostKeyEvent(&keyev)); - return 0; -} - -LRESULT RootWindowHostWin::OnMouseRange(UINT message, - WPARAM w_param, - LPARAM l_param) { - MSG msg = { hwnd(), message, w_param, l_param, 0, - { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) } }; - ui::MouseEvent event(msg); - bool handled = false; - if (!(event.flags() & ui::EF_IS_NON_CLIENT)) - handled = delegate_->OnHostMouseEvent(&event); - SetMsgHandled(handled); - return 0; -} - -LRESULT RootWindowHostWin::OnCaptureChanged(UINT message, - WPARAM w_param, - LPARAM l_param) { - if (has_capture_) { - has_capture_ = false; - delegate_->OnHostLostWindowCapture(); - } - return 0; -} - -LRESULT RootWindowHostWin::OnNCActivate(UINT message, - WPARAM w_param, - LPARAM l_param) { - if (!!w_param) - delegate_->OnHostActivated(); - return DefWindowProc(hwnd(), message, w_param, l_param); -} - -void RootWindowHostWin::OnMove(const CPoint& point) { - if (delegate_) - delegate_->OnHostMoved(gfx::Point(point.x, point.y)); -} - -void RootWindowHostWin::OnPaint(HDC dc) { - gfx::Rect damage_rect; - RECT update_rect = {0}; - if (GetUpdateRect(hwnd(), &update_rect, FALSE)) - damage_rect = gfx::Rect(update_rect); - delegate_->OnHostPaint(damage_rect); - ValidateRect(hwnd(), NULL); -} - -void RootWindowHostWin::OnSize(UINT param, const CSize& size) { - // Minimizing resizes the window to 0x0 which causes our layout to go all - // screwy, so we just ignore it. - if (delegate_ && param != SIZE_MINIMIZED) - delegate_->OnHostResized(gfx::Size(size.cx, size.cy)); -} - -namespace test { - -// static -void SetUsePopupAsRootWindowForTest(bool use) { - use_popup_as_root_window_for_test = use; -} - -} // namespace test - -} // namespace aura diff --git a/chromium/ui/aura/root_window_host_win.h b/chromium/ui/aura/root_window_host_win.h deleted file mode 100644 index 3d99821400a..00000000000 --- a/chromium/ui/aura/root_window_host_win.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_ROOT_WINDOW_HOST_WIN_H_ -#define UI_AURA_ROOT_WINDOW_HOST_WIN_H_ - -#include "base/compiler_specific.h" -#include "ui/aura/aura_export.h" -#include "ui/aura/window_tree_host.h" -#include "ui/gfx/win/window_impl.h" - -namespace aura { - -class RootWindowHostWin : public RootWindowHost, public gfx::WindowImpl { - public: - RootWindowHostWin(const gfx::Rect& bounds); - virtual ~RootWindowHostWin(); - // RootWindowHost: - virtual RootWindow* GetRootWindow() OVERRIDE; - virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; - virtual void Show() OVERRIDE; - virtual void Hide() OVERRIDE; - virtual void ToggleFullScreen() OVERRIDE; - virtual gfx::Rect GetBounds() const OVERRIDE; - virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; - virtual gfx::Insets GetInsets() const OVERRIDE; - virtual void SetInsets(const gfx::Insets& insets) OVERRIDE; - virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE; - virtual void SetCapture() OVERRIDE; - virtual void ReleaseCapture() OVERRIDE; - virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE; - virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE; - virtual bool ConfineCursorToRootWindow() OVERRIDE; - virtual void UnConfineCursor() OVERRIDE; - virtual void OnCursorVisibilityChanged(bool show) OVERRIDE; - virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE; - virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE; - virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; - virtual void PrepareForShutdown() OVERRIDE; - - private: - BEGIN_MSG_MAP_EX(RootWindowHostWin) - // Range handlers must go first! - MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange) - MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange) - - // Mouse capture events. - MESSAGE_HANDLER_EX(WM_CAPTURECHANGED, OnCaptureChanged) - - // Key events. - MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent) - MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent) - MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyEvent) - MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyEvent) - MESSAGE_HANDLER_EX(WM_CHAR, OnKeyEvent) - MESSAGE_HANDLER_EX(WM_SYSCHAR, OnKeyEvent) - MESSAGE_HANDLER_EX(WM_IME_CHAR, OnKeyEvent) - MESSAGE_HANDLER_EX(WM_NCACTIVATE, OnNCActivate) - - MSG_WM_CLOSE(OnClose) - MSG_WM_MOVE(OnMove) - MSG_WM_PAINT(OnPaint) - MSG_WM_SIZE(OnSize) - END_MSG_MAP() - - void OnClose(); - LRESULT OnKeyEvent(UINT message, WPARAM w_param, LPARAM l_param); - LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param); - LRESULT OnCaptureChanged(UINT message, WPARAM w_param, LPARAM l_param); - LRESULT OnNCActivate(UINT message, WPARAM w_param, LPARAM l_param); - void OnMove(const CPoint& point); - void OnPaint(HDC dc); - void OnSize(UINT param, const CSize& size); - - bool fullscreen_; - bool has_capture_; - RECT saved_window_rect_; - DWORD saved_window_style_; - DWORD saved_window_ex_style_; - - DISALLOW_COPY_AND_ASSIGN(RootWindowHostWin); -}; - -namespace test { - -// Set true to let RootWindowHostWin use a popup window -// with no frame/title so that the window size and test's -// expectations matches. -AURA_EXPORT void SetUsePopupAsRootWindowForTest(bool use); - -} // namespace - -} // namespace aura - -#endif // UI_AURA_ROOT_WINDOW_HOST_WIN_H_ diff --git a/chromium/ui/aura/root_window_host_x11.h b/chromium/ui/aura/root_window_host_x11.h deleted file mode 100644 index d4b35186a8b..00000000000 --- a/chromium/ui/aura/root_window_host_x11.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_ROOT_WINDOW_HOST_X11_H_ -#define UI_AURA_ROOT_WINDOW_HOST_X11_H_ - -#include <X11/Xlib.h> - -#include <vector> - -// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. -#undef RootWindow - -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "ui/aura/aura_export.h" -#include "ui/aura/env_observer.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/x/x11_util.h" -#include "ui/events/event_source.h" -#include "ui/gfx/insets.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/x/x11_atom_cache.h" - -namespace ui { -class MouseEvent; -} - -namespace aura { - -namespace internal { -class TouchEventCalibrate; -} - -class AURA_EXPORT RootWindowHostX11 : public RootWindowHost, - public base::MessageLoop::Dispatcher, - public ui::EventSource, - public EnvObserver { - public: - explicit RootWindowHostX11(const gfx::Rect& bounds); - virtual ~RootWindowHostX11(); - - // Overridden from Dispatcher overrides: - virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; - - // RootWindowHost Overrides. - virtual RootWindow* GetRootWindow() OVERRIDE; - virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; - virtual void Show() OVERRIDE; - virtual void Hide() OVERRIDE; - virtual void ToggleFullScreen() OVERRIDE; - virtual gfx::Rect GetBounds() const OVERRIDE; - virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; - virtual gfx::Insets GetInsets() const OVERRIDE; - virtual void SetInsets(const gfx::Insets& insets) OVERRIDE; - virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE; - virtual void SetCapture() OVERRIDE; - virtual void ReleaseCapture() OVERRIDE; - virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE; - virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE; - virtual bool ConfineCursorToRootWindow() OVERRIDE; - virtual void UnConfineCursor() OVERRIDE; - virtual void OnCursorVisibilityChanged(bool show) OVERRIDE; - virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE; - virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE; - virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; - virtual void PrepareForShutdown() OVERRIDE; - - // EnvObserver overrides. - virtual void OnWindowInitialized(Window* window) OVERRIDE; - virtual void OnRootWindowInitialized(RootWindow* root_window) OVERRIDE; - - // ui::EventSource overrides. - virtual ui::EventProcessor* GetEventProcessor() OVERRIDE; - - private: - class MouseMoveFilter; - - bool DispatchEventForRootWindow(const base::NativeEvent& event); - - // Dispatches XI2 events. Note that some events targetted for the X root - // window are dispatched to the aura root window (e.g. touch events after - // calibration). - void DispatchXI2Event(const base::NativeEvent& event); - - // Returns true if there's an X window manager present... in most cases. Some - // window managers (notably, ion3) don't implement enough of ICCCM for us to - // detect that they're there. - bool IsWindowManagerPresent(); - - // Sets the cursor on |xwindow_| to |cursor|. Does not check or update - // |current_cursor_|. - void SetCursorInternal(gfx::NativeCursor cursor); - - // Translates the native mouse location into screen coordinates and and - // dispatches the event to RootWindowHostDelegate. - void TranslateAndDispatchMouseEvent(ui::MouseEvent* event); - - // Update is_internal_display_ based on delegate_ state - void UpdateIsInternalDisplay(); - - // Set the CrOS touchpad "tap paused" property. It is used to temporarily - // turn off the Tap-to-click feature when the mouse pointer is invisible. - void SetCrOSTapPaused(bool state); - - // The display and the native X window hosting the root window. - XDisplay* xdisplay_; - ::Window xwindow_; - - // The native root window. - ::Window x_root_window_; - - // Current Aura cursor. - gfx::NativeCursor current_cursor_; - - // Is the window mapped to the screen? - bool window_mapped_; - - // The bounds of |xwindow_|. - gfx::Rect bounds_; - - // The insets that specifies the effective area within the |window_|. - gfx::Insets insets_; - - // True if the root host resides on the internal display - bool is_internal_display_; - - scoped_ptr<XID[]> pointer_barriers_; - - scoped_ptr<internal::TouchEventCalibrate> touch_calibrate_; - - scoped_ptr<MouseMoveFilter> mouse_move_filter_; - - ui::X11AtomCache atom_cache_; - - // Touch ids of which the touch press happens at side bezel region. - uint32 bezel_tracking_ids_; - - DISALLOW_COPY_AND_ASSIGN(RootWindowHostX11); -}; - -namespace test { - -// Set the default value of the override redirect flag used to -// create a X window for RootWindowHostX11. -AURA_EXPORT void SetUseOverrideRedirectWindowByDefault(bool override_redirect); - -} // namespace test -} // namespace aura - -#endif // UI_AURA_ROOT_WINDOW_HOST_X11_H_ diff --git a/chromium/ui/aura/root_window_host_x11_unittest.cc b/chromium/ui/aura/root_window_host_x11_unittest.cc deleted file mode 100644 index 576707a09c7..00000000000 --- a/chromium/ui/aura/root_window_host_x11_unittest.cc +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - - -#include "base/sys_info.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/aura/root_window.h" -#include "ui/aura/root_window_host_x11.h" -#include "ui/aura/test/aura_test_base.h" -#include "ui/aura/window_tree_host_delegate.h" -#include "ui/events/event_processor.h" -#include "ui/events/event_target.h" -#include "ui/events/event_target_iterator.h" -#include "ui/events/test/events_test_utils_x11.h" - -namespace { -class TestRootWindowHostDelegate : public aura::RootWindowHostDelegate, - public ui::EventProcessor, - public ui::EventTarget { - public: - TestRootWindowHostDelegate() : last_touch_type_(ui::ET_UNKNOWN), - last_touch_id_(-1), - last_touch_location_(0, 0) { - } - virtual ~TestRootWindowHostDelegate() {} - - // aura::RootWindowHostDelegate: - virtual bool OnHostKeyEvent(ui::KeyEvent* event) OVERRIDE { - return true; - } - virtual bool OnHostMouseEvent(ui::MouseEvent* event) OVERRIDE { - return true; - } - virtual bool OnHostScrollEvent(ui::ScrollEvent* event) OVERRIDE { - return true; - } - virtual bool OnHostTouchEvent(ui::TouchEvent* event) OVERRIDE { - last_touch_id_ = event->touch_id(); - last_touch_type_ = event->type(); - last_touch_location_ = event->location(); - return true; - } - - virtual void OnHostCancelMode() OVERRIDE {} - virtual void OnHostActivated() OVERRIDE {} - virtual void OnHostLostWindowCapture() OVERRIDE {} - virtual void OnHostLostMouseGrab() OVERRIDE {} - virtual void OnHostPaint(const gfx::Rect& damage_rect) OVERRIDE {} - virtual void OnHostMoved(const gfx::Point& origin) OVERRIDE {} - virtual void OnHostResized(const gfx::Size& size) OVERRIDE {} - virtual float GetDeviceScaleFactor() OVERRIDE { return 1.0f; } - virtual aura::RootWindow* AsRootWindow() OVERRIDE { return NULL; } - virtual const aura::RootWindow* AsRootWindow() const OVERRIDE { return NULL; } - virtual ui::EventProcessor* GetEventProcessor() OVERRIDE { - return this; - } - - // ui::EventProcessor: - virtual ui::EventTarget* GetRootTarget() OVERRIDE { return this; } - virtual bool CanDispatchToTarget(ui::EventTarget* target) OVERRIDE { - return true; - } - - // ui::EventHandler: - virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE { - last_touch_id_ = event->touch_id(); - last_touch_type_ = event->type(); - last_touch_location_ = event->location(); - } - - // ui::EventTarget: - virtual bool CanAcceptEvent(const ui::Event& event) OVERRIDE { - return true; - } - virtual ui::EventTarget* GetParentTarget() OVERRIDE { return NULL; } - virtual scoped_ptr<ui::EventTargetIterator> - GetChildIterator() const OVERRIDE { - return scoped_ptr<ui::EventTargetIterator>(); - } - virtual ui::EventTargeter* GetEventTargeter() OVERRIDE { return &targeter_; } - - ui::EventType last_touch_type() { - return last_touch_type_; - } - - int last_touch_id() { - return last_touch_id_; - } - - gfx::Point last_touch_location() { - return last_touch_location_; - } - - private: - ui::EventType last_touch_type_; - int last_touch_id_; - gfx::Point last_touch_location_; - ui::EventTargeter targeter_; - - DISALLOW_COPY_AND_ASSIGN(TestRootWindowHostDelegate); -}; - -} // namespace - -namespace aura { - -typedef test::AuraTestBase RootWindowHostX11Test; - -// Send X touch events to one RootWindowHost. The RootWindowHost's -// delegate will get corresponding ui::TouchEvent if the touch events -// are winthin the bound of the RootWindowHost. -TEST_F(RootWindowHostX11Test, DispatchTouchEventToOneRootWindow) { -#if defined(OS_CHROMEOS) - // Fake a ChromeOS running env. - const char* kLsbRelease = "CHROMEOS_RELEASE_NAME=Chromium OS\n"; - base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time()); -#endif // defined(OS_CHROMEOS) - - scoped_ptr<RootWindowHostX11> root_window_host( - new RootWindowHostX11(gfx::Rect(0, 0, 2560, 1700))); - scoped_ptr<TestRootWindowHostDelegate> delegate( - new TestRootWindowHostDelegate()); - root_window_host->set_delegate(delegate.get()); - - std::vector<unsigned int> devices; - devices.push_back(0); - ui::SetUpTouchDevicesForTest(devices); - std::vector<ui::Valuator> valuators; - - EXPECT_EQ(ui::ET_UNKNOWN, delegate->last_touch_type()); - EXPECT_EQ(-1, delegate->last_touch_id()); - - ui::ScopedXI2Event scoped_xevent; -#if defined(OS_CHROMEOS) - // This touch is out of bounds. - scoped_xevent.InitTouchEvent( - 0, XI_TouchBegin, 5, gfx::Point(1500, 2500), valuators); - root_window_host->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_UNKNOWN, delegate->last_touch_type()); - EXPECT_EQ(-1, delegate->last_touch_id()); - EXPECT_EQ(gfx::Point(0, 0), delegate->last_touch_location()); -#endif // defined(OS_CHROMEOS) - - // Following touchs are within bounds and are passed to delegate. - scoped_xevent.InitTouchEvent( - 0, XI_TouchBegin, 5, gfx::Point(1500, 1500), valuators); - root_window_host->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_TOUCH_PRESSED, delegate->last_touch_type()); - EXPECT_EQ(0, delegate->last_touch_id()); - EXPECT_EQ(gfx::Point(1500, 1500), delegate->last_touch_location()); - - scoped_xevent.InitTouchEvent( - 0, XI_TouchUpdate, 5, gfx::Point(1500, 1600), valuators); - root_window_host->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_TOUCH_MOVED, delegate->last_touch_type()); - EXPECT_EQ(0, delegate->last_touch_id()); - EXPECT_EQ(gfx::Point(1500, 1600), delegate->last_touch_location()); - - scoped_xevent.InitTouchEvent( - 0, XI_TouchEnd, 5, gfx::Point(1500, 1600), valuators); - root_window_host->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_TOUCH_RELEASED, delegate->last_touch_type()); - EXPECT_EQ(0, delegate->last_touch_id()); - EXPECT_EQ(gfx::Point(1500, 1600), delegate->last_touch_location()); - - // Revert the CrOS testing env otherwise the following non-CrOS aura - // tests will fail. -#if defined(OS_CHROMEOS) - // Fake a ChromeOS running env. - kLsbRelease = ""; - base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time()); -#endif // defined(OS_CHROMEOS) -} - -// Send X touch events to two RootWindowHost. The RootWindowHost which is -// the event target of the X touch events should generate the corresponding -// ui::TouchEvent for its delegate. -#if defined(OS_CHROMEOS) -TEST_F(RootWindowHostX11Test, DispatchTouchEventToTwoRootWindow) { - // Fake a ChromeOS running env. - const char* kLsbRelease = "CHROMEOS_RELEASE_NAME=Chromium OS\n"; - base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time()); - - scoped_ptr<RootWindowHostX11> root_window_host1( - new RootWindowHostX11(gfx::Rect(0, 0, 2560, 1700))); - scoped_ptr<TestRootWindowHostDelegate> delegate1( - new TestRootWindowHostDelegate()); - root_window_host1->set_delegate(delegate1.get()); - - int host2_y_offset = 1700; - scoped_ptr<RootWindowHostX11> root_window_host2( - new RootWindowHostX11(gfx::Rect(0, host2_y_offset, 1920, 1080))); - scoped_ptr<TestRootWindowHostDelegate> delegate2( - new TestRootWindowHostDelegate()); - root_window_host2->set_delegate(delegate2.get()); - - std::vector<unsigned int> devices; - devices.push_back(0); - ui::SetUpTouchDevicesForTest(devices); - std::vector<ui::Valuator> valuators; - - EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type()); - EXPECT_EQ(-1, delegate1->last_touch_id()); - EXPECT_EQ(ui::ET_UNKNOWN, delegate2->last_touch_type()); - EXPECT_EQ(-1, delegate2->last_touch_id()); - - // 2 Touch events are targeted at the second RootWindowHost. - ui::ScopedXI2Event scoped_xevent; - scoped_xevent.InitTouchEvent( - 0, XI_TouchBegin, 5, gfx::Point(1500, 2500), valuators); - root_window_host1->Dispatch(scoped_xevent); - root_window_host2->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type()); - EXPECT_EQ(-1, delegate1->last_touch_id()); - EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location()); - EXPECT_EQ(ui::ET_TOUCH_PRESSED, delegate2->last_touch_type()); - EXPECT_EQ(0, delegate2->last_touch_id()); - EXPECT_EQ(gfx::Point(1500, 2500 - host2_y_offset), - delegate2->last_touch_location()); - - scoped_xevent.InitTouchEvent( - 0, XI_TouchBegin, 6, gfx::Point(1600, 2600), valuators); - root_window_host1->Dispatch(scoped_xevent); - root_window_host2->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type()); - EXPECT_EQ(-1, delegate1->last_touch_id()); - EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location()); - EXPECT_EQ(ui::ET_TOUCH_PRESSED, delegate2->last_touch_type()); - EXPECT_EQ(1, delegate2->last_touch_id()); - EXPECT_EQ(gfx::Point(1600, 2600 - host2_y_offset), - delegate2->last_touch_location()); - - scoped_xevent.InitTouchEvent( - 0, XI_TouchUpdate, 5, gfx::Point(1500, 2550), valuators); - root_window_host1->Dispatch(scoped_xevent); - root_window_host2->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type()); - EXPECT_EQ(-1, delegate1->last_touch_id()); - EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location()); - EXPECT_EQ(ui::ET_TOUCH_MOVED, delegate2->last_touch_type()); - EXPECT_EQ(0, delegate2->last_touch_id()); - EXPECT_EQ(gfx::Point(1500, 2550 - host2_y_offset), - delegate2->last_touch_location()); - - scoped_xevent.InitTouchEvent( - 0, XI_TouchUpdate, 6, gfx::Point(1600, 2650), valuators); - root_window_host1->Dispatch(scoped_xevent); - root_window_host2->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type()); - EXPECT_EQ(-1, delegate1->last_touch_id()); - EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location()); - EXPECT_EQ(ui::ET_TOUCH_MOVED, delegate2->last_touch_type()); - EXPECT_EQ(1, delegate2->last_touch_id()); - EXPECT_EQ(gfx::Point(1600, 2650 - host2_y_offset), - delegate2->last_touch_location()); - - scoped_xevent.InitTouchEvent( - 0, XI_TouchEnd, 5, gfx::Point(1500, 2550), valuators); - root_window_host1->Dispatch(scoped_xevent); - root_window_host2->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type()); - EXPECT_EQ(-1, delegate1->last_touch_id()); - EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location()); - EXPECT_EQ(ui::ET_TOUCH_RELEASED, delegate2->last_touch_type()); - EXPECT_EQ(0, delegate2->last_touch_id()); - EXPECT_EQ(gfx::Point(1500, 2550 - host2_y_offset), - delegate2->last_touch_location()); - - scoped_xevent.InitTouchEvent( - 0, XI_TouchEnd, 6, gfx::Point(1600, 2650), valuators); - root_window_host1->Dispatch(scoped_xevent); - root_window_host2->Dispatch(scoped_xevent); - EXPECT_EQ(ui::ET_UNKNOWN, delegate1->last_touch_type()); - EXPECT_EQ(-1, delegate1->last_touch_id()); - EXPECT_EQ(gfx::Point(0, 0), delegate1->last_touch_location()); - EXPECT_EQ(ui::ET_TOUCH_RELEASED, delegate2->last_touch_type()); - EXPECT_EQ(1, delegate2->last_touch_id()); - EXPECT_EQ(gfx::Point(1600, 2650 - host2_y_offset), - delegate2->last_touch_location()); - - // Revert the CrOS testing env otherwise the following non-CrOS aura - // tests will fail. - // Fake a ChromeOS running env. - kLsbRelease = ""; - base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time()); -} -#endif // defined(OS_CHROMEOS) - -} // namespace aura diff --git a/chromium/ui/aura/root_window_observer.h b/chromium/ui/aura/root_window_observer.h deleted file mode 100644 index bfb8e65c518..00000000000 --- a/chromium/ui/aura/root_window_observer.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_ROOT_WINDOW_OBSERVER_H_ -#define UI_AURA_ROOT_WINDOW_OBSERVER_H_ - -#include "ui/aura/aura_export.h" - -namespace gfx { -class Point; -class Size; -} - -namespace aura { -class RootWindow; -class Window; - -class AURA_EXPORT RootWindowObserver { - public: - // Invoked after the RootWindow's host has been resized. - virtual void OnRootWindowHostResized(const RootWindow* root) {} - - // Invoked after the RootWindow's host has been moved on screen. - virtual void OnRootWindowHostMoved(const RootWindow* root, - const gfx::Point& new_origin) {} - - // Invoked when the native windowing system sends us a request to close our - // window. - virtual void OnRootWindowHostCloseRequested(const RootWindow* root) {} - - // Invoked when the keyboard mapping has changed. - virtual void OnKeyboardMappingChanged(const RootWindow* root) {} - - protected: - virtual ~RootWindowObserver() {} -}; - -} // namespace aura - -#endif // UI_AURA_ROOT_WINDOW_OBSERVER_H_ diff --git a/chromium/ui/aura/root_window_transformer.h b/chromium/ui/aura/root_window_transformer.h deleted file mode 100644 index 89d67f28e6d..00000000000 --- a/chromium/ui/aura/root_window_transformer.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_ROOT_WINDOW_TRANSFORMER_H_ -#define UI_AURA_ROOT_WINDOW_TRANSFORMER_H_ - -#include "ui/aura/aura_export.h" - -namespace gfx { -class Insets; -class Rect; -class Size; -class Transform; -} - -namespace aura { - -// RootWindowTransformer controls how RootWindow should be placed and -// transformed inside the host window. -class AURA_EXPORT RootWindowTransformer { - public: - virtual ~RootWindowTransformer() {} - - // Returns the transform the root window in DIP. - virtual gfx::Transform GetTransform() const = 0; - - // Returns the inverse of the transform above. This method is to - // provie an accurate inverse of the transform because the result of - // |gfx::Transform::GetInverse| may contains computational error. - virtual gfx::Transform GetInverseTransform() const = 0; - - // Returns the root window's bounds for given host window size in DIP. - // This is necessary to handle the case where the root window's size - // is bigger than the host window. (Screen magnifier for example). - virtual gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const = 0; - - // Returns the insets that specifies the effective area of - // the host window. - virtual gfx::Insets GetHostInsets() const = 0; -}; - -} // namespace aura - -#endif // UI_AURA_ROOT_WINDOW_TRANSFORMER_H_ diff --git a/chromium/ui/aura/root_window_unittest.cc b/chromium/ui/aura/root_window_unittest.cc deleted file mode 100644 index 2d135249bc8..00000000000 --- a/chromium/ui/aura/root_window_unittest.cc +++ /dev/null @@ -1,1530 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura/root_window.h" - -#include <vector> - -#include "base/bind.h" -#include "base/run_loop.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/aura/client/event_client.h" -#include "ui/aura/client/focus_client.h" -#include "ui/aura/env.h" -#include "ui/aura/test/aura_test_base.h" -#include "ui/aura/test/event_generator.h" -#include "ui/aura/test/test_cursor_client.h" -#include "ui/aura/test/test_event_handler.h" -#include "ui/aura/test/test_window_delegate.h" -#include "ui/aura/test/test_windows.h" -#include "ui/aura/window.h" -#include "ui/aura/window_tracker.h" -#include "ui/base/hit_test.h" -#include "ui/events/event.h" -#include "ui/events/event_handler.h" -#include "ui/events/event_utils.h" -#include "ui/events/gestures/gesture_configuration.h" -#include "ui/events/keycodes/keyboard_codes.h" -#include "ui/gfx/point.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/screen.h" -#include "ui/gfx/transform.h" - -namespace aura { -namespace { - -// A delegate that always returns a non-client component for hit tests. -class NonClientDelegate : public test::TestWindowDelegate { - public: - NonClientDelegate() - : non_client_count_(0), - mouse_event_count_(0), - mouse_event_flags_(0x0) { - } - virtual ~NonClientDelegate() {} - - int non_client_count() const { return non_client_count_; } - gfx::Point non_client_location() const { return non_client_location_; } - int mouse_event_count() const { return mouse_event_count_; } - gfx::Point mouse_event_location() const { return mouse_event_location_; } - int mouse_event_flags() const { return mouse_event_flags_; } - - virtual int GetNonClientComponent(const gfx::Point& location) const OVERRIDE { - NonClientDelegate* self = const_cast<NonClientDelegate*>(this); - self->non_client_count_++; - self->non_client_location_ = location; - return HTTOPLEFT; - } - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { - mouse_event_count_++; - mouse_event_location_ = event->location(); - mouse_event_flags_ = event->flags(); - event->SetHandled(); - } - - private: - int non_client_count_; - gfx::Point non_client_location_; - int mouse_event_count_; - gfx::Point mouse_event_location_; - int mouse_event_flags_; - - DISALLOW_COPY_AND_ASSIGN(NonClientDelegate); -}; - -// A simple event handler that consumes key events. -class ConsumeKeyHandler : public test::TestEventHandler { - public: - ConsumeKeyHandler() {} - virtual ~ConsumeKeyHandler() {} - - // Overridden from ui::EventHandler: - virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { - test::TestEventHandler::OnKeyEvent(event); - event->StopPropagation(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ConsumeKeyHandler); -}; - -bool IsFocusedWindow(aura::Window* window) { - return client::GetFocusClient(window)->GetFocusedWindow() == window; -} - -} // namespace - -typedef test::AuraTestBase RootWindowTest; - -TEST_F(RootWindowTest, OnHostMouseEvent) { - // Create two non-overlapping windows so we don't have to worry about which - // is on top. - scoped_ptr<NonClientDelegate> delegate1(new NonClientDelegate()); - scoped_ptr<NonClientDelegate> delegate2(new NonClientDelegate()); - const int kWindowWidth = 123; - const int kWindowHeight = 45; - gfx::Rect bounds1(100, 200, kWindowWidth, kWindowHeight); - gfx::Rect bounds2(300, 400, kWindowWidth, kWindowHeight); - scoped_ptr<aura::Window> window1(CreateTestWindowWithDelegate( - delegate1.get(), -1234, bounds1, root_window())); - scoped_ptr<aura::Window> window2(CreateTestWindowWithDelegate( - delegate2.get(), -5678, bounds2, root_window())); - - // Send a mouse event to window1. - gfx::Point point(101, 201); - ui::MouseEvent event1( - ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&event1); - - // Event was tested for non-client area for the target window. - EXPECT_EQ(1, delegate1->non_client_count()); - EXPECT_EQ(0, delegate2->non_client_count()); - // The non-client component test was in local coordinates. - EXPECT_EQ(gfx::Point(1, 1), delegate1->non_client_location()); - // Mouse event was received by target window. - EXPECT_EQ(1, delegate1->mouse_event_count()); - EXPECT_EQ(0, delegate2->mouse_event_count()); - // Event was in local coordinates. - EXPECT_EQ(gfx::Point(1, 1), delegate1->mouse_event_location()); - // Non-client flag was set. - EXPECT_TRUE(delegate1->mouse_event_flags() & ui::EF_IS_NON_CLIENT); -} - -TEST_F(RootWindowTest, RepostEvent) { - // Test RepostEvent in RootWindow. It only works for Mouse Press. - EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); - gfx::Point point(10, 10); - ui::MouseEvent event( - ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON); - dispatcher()->RepostEvent(event); - RunAllPendingInMessageLoop(); - EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); -} - -// Check that we correctly track the state of the mouse buttons in response to -// button press and release events. -TEST_F(RootWindowTest, MouseButtonState) { - EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); - - gfx::Point location; - scoped_ptr<ui::MouseEvent> event; - - // Press the left button. - event.reset(new ui::MouseEvent( - ui::ET_MOUSE_PRESSED, - location, - location, - ui::EF_LEFT_MOUSE_BUTTON)); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get()); - EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); - - // Additionally press the right. - event.reset(new ui::MouseEvent( - ui::ET_MOUSE_PRESSED, - location, - location, - ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON)); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get()); - EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); - - // Release the left button. - event.reset(new ui::MouseEvent( - ui::ET_MOUSE_RELEASED, - location, - location, - ui::EF_RIGHT_MOUSE_BUTTON)); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get()); - EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); - - // Release the right button. We should ignore the Shift-is-down flag. - event.reset(new ui::MouseEvent( - ui::ET_MOUSE_RELEASED, - location, - location, - ui::EF_SHIFT_DOWN)); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get()); - EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); - - // Press the middle button. - event.reset(new ui::MouseEvent( - ui::ET_MOUSE_PRESSED, - location, - location, - ui::EF_MIDDLE_MOUSE_BUTTON)); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(event.get()); - EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); -} - -TEST_F(RootWindowTest, TranslatedEvent) { - scoped_ptr<Window> w1(test::CreateTestWindowWithDelegate(NULL, 1, - gfx::Rect(50, 50, 100, 100), root_window())); - - gfx::Point origin(100, 100); - ui::MouseEvent root(ui::ET_MOUSE_PRESSED, origin, origin, 0); - - EXPECT_EQ("100,100", root.location().ToString()); - EXPECT_EQ("100,100", root.root_location().ToString()); - - ui::MouseEvent translated_event( - root, static_cast<Window*>(root_window()), w1.get(), - ui::ET_MOUSE_ENTERED, root.flags()); - EXPECT_EQ("50,50", translated_event.location().ToString()); - EXPECT_EQ("100,100", translated_event.root_location().ToString()); -} - -namespace { - -class TestEventClient : public client::EventClient { - public: - static const int kNonLockWindowId = 100; - static const int kLockWindowId = 200; - - explicit TestEventClient(Window* root_window) - : root_window_(root_window), - lock_(false) { - client::SetEventClient(root_window_, this); - Window* lock_window = - test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_); - lock_window->set_id(kLockWindowId); - Window* non_lock_window = - test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_); - non_lock_window->set_id(kNonLockWindowId); - } - virtual ~TestEventClient() { - client::SetEventClient(root_window_, NULL); - } - - // Starts/stops locking. Locking prevents windows other than those inside - // the lock container from receiving events, getting focus etc. - void Lock() { - lock_ = true; - } - void Unlock() { - lock_ = false; - } - - Window* GetLockWindow() { - return const_cast<Window*>( - static_cast<const TestEventClient*>(this)->GetLockWindow()); - } - const Window* GetLockWindow() const { - return root_window_->GetChildById(kLockWindowId); - } - Window* GetNonLockWindow() { - return root_window_->GetChildById(kNonLockWindowId); - } - - private: - // Overridden from client::EventClient: - virtual bool CanProcessEventsWithinSubtree( - const Window* window) const OVERRIDE { - return lock_ ? - window->Contains(GetLockWindow()) || GetLockWindow()->Contains(window) : - true; - } - - virtual ui::EventTarget* GetToplevelEventTarget() OVERRIDE { - return NULL; - } - - Window* root_window_; - bool lock_; - - DISALLOW_COPY_AND_ASSIGN(TestEventClient); -}; - -} // namespace - -TEST_F(RootWindowTest, CanProcessEventsWithinSubtree) { - TestEventClient client(root_window()); - test::TestWindowDelegate d; - - test::TestEventHandler* nonlock_ef = new test::TestEventHandler; - test::TestEventHandler* lock_ef = new test::TestEventHandler; - client.GetNonLockWindow()->SetEventFilter(nonlock_ef); - client.GetLockWindow()->SetEventFilter(lock_ef); - - Window* w1 = test::CreateTestWindowWithBounds(gfx::Rect(10, 10, 20, 20), - client.GetNonLockWindow()); - w1->set_id(1); - Window* w2 = test::CreateTestWindowWithBounds(gfx::Rect(30, 30, 20, 20), - client.GetNonLockWindow()); - w2->set_id(2); - scoped_ptr<Window> w3( - test::CreateTestWindowWithDelegate(&d, 3, gfx::Rect(30, 30, 20, 20), - client.GetLockWindow())); - - w1->Focus(); - EXPECT_TRUE(IsFocusedWindow(w1)); - - client.Lock(); - - // Since we're locked, the attempt to focus w2 will be ignored. - w2->Focus(); - EXPECT_TRUE(IsFocusedWindow(w1)); - EXPECT_FALSE(IsFocusedWindow(w2)); - - { - // Attempting to send a key event to w1 (not in the lock container) should - // cause focus to be reset. - test::EventGenerator generator(root_window()); - generator.PressKey(ui::VKEY_SPACE, 0); - EXPECT_EQ(NULL, client::GetFocusClient(w1)->GetFocusedWindow()); - } - - { - // Events sent to a window not in the lock container will not be processed. - // i.e. never sent to the non-lock container's event filter. - test::EventGenerator generator(root_window(), w1); - generator.PressLeftButton(); - EXPECT_EQ(0, nonlock_ef->num_mouse_events()); - - // Events sent to a window in the lock container will be processed. - test::EventGenerator generator3(root_window(), w3.get()); - generator3.PressLeftButton(); - EXPECT_EQ(1, lock_ef->num_mouse_events()); - } - - // Prevent w3 from being deleted by the hierarchy since its delegate is owned - // by this scope. - w3->parent()->RemoveChild(w3.get()); -} - -TEST_F(RootWindowTest, IgnoreUnknownKeys) { - test::TestEventHandler* filter = new ConsumeKeyHandler; - root_window()->SetEventFilter(filter); // passes ownership - - ui::KeyEvent unknown_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 0, false); - EXPECT_FALSE(dispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent( - &unknown_event)); - EXPECT_EQ(0, filter->num_key_events()); - - ui::KeyEvent known_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false); - EXPECT_TRUE(dispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent( - &known_event)); - EXPECT_EQ(1, filter->num_key_events()); -} - -TEST_F(RootWindowTest, NoDelegateWindowReceivesKeyEvents) { - scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); - w1->Show(); - w1->Focus(); - - test::TestEventHandler handler; - w1->AddPreTargetHandler(&handler); - ui::KeyEvent key_press(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false); - EXPECT_TRUE(dispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent( - &key_press)); - EXPECT_EQ(1, handler.num_key_events()); - - w1->RemovePreTargetHandler(&handler); -} - -// Tests that touch-events that are beyond the bounds of the root-window do get -// propagated to the event filters correctly with the root as the target. -TEST_F(RootWindowTest, TouchEventsOutsideBounds) { - test::TestEventHandler* filter = new test::TestEventHandler; - root_window()->SetEventFilter(filter); // passes ownership - - gfx::Point position = root_window()->bounds().origin(); - position.Offset(-10, -10); - ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position, 0, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); - EXPECT_EQ(1, filter->num_touch_events()); - - position = root_window()->bounds().origin(); - position.Offset(root_window()->bounds().width() + 10, - root_window()->bounds().height() + 10); - ui::TouchEvent release(ui::ET_TOUCH_RELEASED, position, 0, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); - EXPECT_EQ(2, filter->num_touch_events()); -} - -// Tests that scroll events are dispatched correctly. -TEST_F(RootWindowTest, ScrollEventDispatch) { - base::TimeDelta now = ui::EventTimeForNow(); - test::TestEventHandler* filter = new test::TestEventHandler; - root_window()->SetEventFilter(filter); - - test::TestWindowDelegate delegate; - scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate)); - w1->SetBounds(gfx::Rect(20, 20, 40, 40)); - - // A scroll event on the root-window itself is dispatched. - ui::ScrollEvent scroll1(ui::ET_SCROLL, - gfx::Point(10, 10), - now, - 0, - 0, -10, - 0, -10, - 2); - dispatcher()->AsRootWindowHostDelegate()->OnHostScrollEvent(&scroll1); - EXPECT_EQ(1, filter->num_scroll_events()); - - // Scroll event on a window should be dispatched properly. - ui::ScrollEvent scroll2(ui::ET_SCROLL, - gfx::Point(25, 30), - now, - 0, - -10, 0, - -10, 0, - 2); - dispatcher()->AsRootWindowHostDelegate()->OnHostScrollEvent(&scroll2); - EXPECT_EQ(2, filter->num_scroll_events()); -} - -namespace { - -// FilterFilter that tracks the types of events it's seen. -class EventFilterRecorder : public ui::EventHandler { - public: - typedef std::vector<ui::EventType> Events; - typedef std::vector<gfx::Point> MouseEventLocations; - - EventFilterRecorder() {} - - Events& events() { return events_; } - - MouseEventLocations& mouse_locations() { return mouse_locations_; } - gfx::Point mouse_location(int i) const { return mouse_locations_[i]; } - -Events GetAndResetEvents() { - Events events = events_; - events_.clear(); - return events; - } - - // ui::EventHandler overrides: - virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { - events_.push_back(event->type()); - } - - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { - events_.push_back(event->type()); - mouse_locations_.push_back(event->location()); - } - - virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE { - events_.push_back(event->type()); - } - - virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE { - events_.push_back(event->type()); - } - - virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { - events_.push_back(event->type()); - } - - private: - Events events_; - MouseEventLocations mouse_locations_; - - DISALLOW_COPY_AND_ASSIGN(EventFilterRecorder); -}; - -// Converts an EventType to a string. -std::string EventTypeToString(ui::EventType type) { - switch (type) { - case ui::ET_TOUCH_RELEASED: - return "TOUCH_RELEASED"; - - case ui::ET_TOUCH_CANCELLED: - return "TOUCH_CANCELLED"; - - case ui::ET_TOUCH_PRESSED: - return "TOUCH_PRESSED"; - - case ui::ET_TOUCH_MOVED: - return "TOUCH_MOVED"; - - case ui::ET_MOUSE_PRESSED: - return "MOUSE_PRESSED"; - - case ui::ET_MOUSE_DRAGGED: - return "MOUSE_DRAGGED"; - - case ui::ET_MOUSE_RELEASED: - return "MOUSE_RELEASED"; - - case ui::ET_MOUSE_MOVED: - return "MOUSE_MOVED"; - - case ui::ET_MOUSE_ENTERED: - return "MOUSE_ENTERED"; - - case ui::ET_MOUSE_EXITED: - return "MOUSE_EXITED"; - - case ui::ET_GESTURE_SCROLL_BEGIN: - return "GESTURE_SCROLL_BEGIN"; - - case ui::ET_GESTURE_SCROLL_END: - return "GESTURE_SCROLL_END"; - - case ui::ET_GESTURE_SCROLL_UPDATE: - return "GESTURE_SCROLL_UPDATE"; - - case ui::ET_GESTURE_PINCH_BEGIN: - return "GESTURE_PINCH_BEGIN"; - - case ui::ET_GESTURE_PINCH_END: - return "GESTURE_PINCH_END"; - - case ui::ET_GESTURE_PINCH_UPDATE: - return "GESTURE_PINCH_UPDATE"; - - case ui::ET_GESTURE_TAP: - return "GESTURE_TAP"; - - case ui::ET_GESTURE_TAP_DOWN: - return "GESTURE_TAP_DOWN"; - - case ui::ET_GESTURE_TAP_CANCEL: - return "GESTURE_TAP_CANCEL"; - - case ui::ET_GESTURE_SHOW_PRESS: - return "GESTURE_SHOW_PRESS"; - - case ui::ET_GESTURE_BEGIN: - return "GESTURE_BEGIN"; - - case ui::ET_GESTURE_END: - return "GESTURE_END"; - - default: - // We should explicitly require each event type. - NOTREACHED(); - break; - } - return ""; -} - -std::string EventTypesToString(const EventFilterRecorder::Events& events) { - std::string result; - for (size_t i = 0; i < events.size(); ++i) { - if (i != 0) - result += " "; - result += EventTypeToString(events[i]); - } - return result; -} - -} // namespace - -// Verifies a repost mouse event targets the window with capture (if there is -// one). -TEST_F(RootWindowTest, RepostTargetsCaptureWindow) { - // Set capture on |window| generate a mouse event (that is reposted) and not - // over |window| and verify |window| gets it (|window| gets it because it has - // capture). - EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); - scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), NULL)); - window->SetBounds(gfx::Rect(20, 20, 40, 30)); - EventFilterRecorder* recorder = new EventFilterRecorder; - window->SetEventFilter(recorder); // Takes ownership. - window->SetCapture(); - const ui::MouseEvent press_event( - ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EF_LEFT_MOUSE_BUTTON); - dispatcher()->RepostEvent(press_event); - RunAllPendingInMessageLoop(); // Necessitated by RepostEvent(). - // Mouse moves/enters may be generated. We only care about a pressed. - EXPECT_TRUE(EventTypesToString(recorder->events()).find("MOUSE_PRESSED") != - std::string::npos) << EventTypesToString(recorder->events()); -} - -TEST_F(RootWindowTest, MouseMovesHeld) { - EventFilterRecorder* filter = new EventFilterRecorder; - root_window()->SetEventFilter(filter); // passes ownership - - test::TestWindowDelegate delegate; - scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( - &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); - - ui::MouseEvent mouse_move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0), - gfx::Point(0, 0), 0); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_move_event); - // Discard MOUSE_ENTER. - filter->events().clear(); - - dispatcher()->HoldPointerMoves(); - - // Check that we don't immediately dispatch the MOUSE_DRAGGED event. - ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0), - gfx::Point(0, 0), 0); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_dragged_event); - EXPECT_TRUE(filter->events().empty()); - - // Check that we do dispatch the held MOUSE_DRAGGED event before another type - // of event. - ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0), - gfx::Point(0, 0), 0); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_pressed_event); - EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED", - EventTypesToString(filter->events())); - filter->events().clear(); - - // Check that we coalesce held MOUSE_DRAGGED events. - ui::MouseEvent mouse_dragged_event2(ui::ET_MOUSE_DRAGGED, gfx::Point(1, 1), - gfx::Point(1, 1), 0); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_dragged_event); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_dragged_event2); - EXPECT_TRUE(filter->events().empty()); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_pressed_event); - EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED", - EventTypesToString(filter->events())); - filter->events().clear(); - - // Check that on ReleasePointerMoves, held events are not dispatched - // immediately, but posted instead. - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_dragged_event); - dispatcher()->ReleasePointerMoves(); - EXPECT_TRUE(filter->events().empty()); - RunAllPendingInMessageLoop(); - EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(filter->events())); - filter->events().clear(); - - // However if another message comes in before the dispatch of the posted - // event, check that the posted event is dispatched before this new event. - dispatcher()->HoldPointerMoves(); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_dragged_event); - dispatcher()->ReleasePointerMoves(); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_pressed_event); - EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED", - EventTypesToString(filter->events())); - filter->events().clear(); - RunAllPendingInMessageLoop(); - EXPECT_TRUE(filter->events().empty()); - - // Check that if the other message is another MOUSE_DRAGGED, we still coalesce - // them. - dispatcher()->HoldPointerMoves(); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_dragged_event); - dispatcher()->ReleasePointerMoves(); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent( - &mouse_dragged_event2); - EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(filter->events())); - filter->events().clear(); - RunAllPendingInMessageLoop(); - EXPECT_TRUE(filter->events().empty()); -} - -TEST_F(RootWindowTest, TouchMovesHeld) { - EventFilterRecorder* filter = new EventFilterRecorder; - root_window()->SetEventFilter(filter); // passes ownership - - test::TestWindowDelegate delegate; - scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( - &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); - - // Starting the touch and throwing out the first few events, since the system - // is going to generate synthetic mouse events that are not relevant to the - // test. - ui::TouchEvent touch_pressed_event(ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), - 0, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent( - &touch_pressed_event); - RunAllPendingInMessageLoop(); - filter->events().clear(); - - dispatcher()->HoldPointerMoves(); - - // Check that we don't immediately dispatch the TOUCH_MOVED event. - ui::TouchEvent touch_moved_event(ui::ET_TOUCH_MOVED, gfx::Point(0, 0), - 0, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent( - &touch_moved_event); - EXPECT_TRUE(filter->events().empty()); - - // Check that on ReleasePointerMoves, held events are not dispatched - // immediately, but posted instead. - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent( - &touch_moved_event); - dispatcher()->ReleasePointerMoves(); - EXPECT_TRUE(filter->events().empty()); - RunAllPendingInMessageLoop(); - EXPECT_EQ("TOUCH_MOVED", EventTypesToString(filter->events())); - filter->events().clear(); - - // If another touch event occurs then the held touch should be dispatched - // immediately before it. - ui::TouchEvent touch_released_event(ui::ET_TOUCH_RELEASED, gfx::Point(0, 0), - 0, base::TimeDelta()); - filter->events().clear(); - dispatcher()->HoldPointerMoves(); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent( - &touch_moved_event); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent( - &touch_released_event); - EXPECT_EQ("TOUCH_MOVED TOUCH_RELEASED GESTURE_TAP_CANCEL GESTURE_END", - EventTypesToString(filter->events())); - filter->events().clear(); - dispatcher()->ReleasePointerMoves(); - RunAllPendingInMessageLoop(); - EXPECT_TRUE(filter->events().empty()); -} - -// Tests that synthetic mouse events are ignored when mouse -// events are disabled. -TEST_F(RootWindowTest, DispatchSyntheticMouseEvents) { - EventFilterRecorder* filter = new EventFilterRecorder; - root_window()->SetEventFilter(filter); // passes ownership - - test::TestWindowDelegate delegate; - scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( - &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window())); - window->Show(); - window->SetCapture(); - - test::TestCursorClient cursor_client(root_window()); - - // Dispatch a non-synthetic mouse event when mouse events are enabled. - ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), - gfx::Point(10, 10), 0); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse1); - EXPECT_FALSE(filter->events().empty()); - filter->events().clear(); - - // Dispatch a synthetic mouse event when mouse events are enabled. - ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), - gfx::Point(10, 10), ui::EF_IS_SYNTHESIZED); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse2); - EXPECT_FALSE(filter->events().empty()); - filter->events().clear(); - - // Dispatch a synthetic mouse event when mouse events are disabled. - cursor_client.DisableMouseEvents(); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse2); - EXPECT_TRUE(filter->events().empty()); -} - -// Tests that a mouse exit is dispatched to the last known cursor location -// when the cursor becomes invisible. -TEST_F(RootWindowTest, DispatchMouseExitWhenCursorHidden) { - EventFilterRecorder* filter = new EventFilterRecorder; - root_window()->SetEventFilter(filter); // passes ownership - - test::TestWindowDelegate delegate; - gfx::Point window_origin(7, 18); - scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( - &delegate, 1234, gfx::Rect(window_origin, - gfx::Size(100, 100)), root_window())); - window->Show(); - - // Dispatch a mouse move event into the window. - gfx::Point mouse_location(gfx::Point(15, 25)); - ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location, - mouse_location, 0); - EXPECT_TRUE(filter->events().empty()); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouse1); - EXPECT_FALSE(filter->events().empty()); - filter->events().clear(); - - // Hide the cursor and verify a mouse exit was dispatched. - dispatcher()->OnCursorVisibilityChanged(false); - EXPECT_FALSE(filter->events().empty()); - EXPECT_EQ("MOUSE_EXITED", EventTypesToString(filter->events())); - - // Verify the mouse exit was dispatched at the correct location - // (in the correct coordinate space). - int translated_x = mouse_location.x() - window_origin.x(); - int translated_y = mouse_location.y() - window_origin.y(); - gfx::Point translated_point(translated_x, translated_y); - EXPECT_EQ(filter->mouse_location(0).ToString(), translated_point.ToString()); -} - -class DeletingEventFilter : public ui::EventHandler { - public: - DeletingEventFilter() - : delete_during_pre_handle_(false) {} - virtual ~DeletingEventFilter() {} - - void Reset(bool delete_during_pre_handle) { - delete_during_pre_handle_ = delete_during_pre_handle; - } - - private: - // Overridden from ui::EventHandler: - virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { - if (delete_during_pre_handle_) - delete event->target(); - } - - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { - if (delete_during_pre_handle_) - delete event->target(); - } - - bool delete_during_pre_handle_; - - DISALLOW_COPY_AND_ASSIGN(DeletingEventFilter); -}; - -class DeletingWindowDelegate : public test::TestWindowDelegate { - public: - DeletingWindowDelegate() - : window_(NULL), - delete_during_handle_(false), - got_event_(false) {} - virtual ~DeletingWindowDelegate() {} - - void Reset(Window* window, bool delete_during_handle) { - window_ = window; - delete_during_handle_ = delete_during_handle; - got_event_ = false; - } - bool got_event() const { return got_event_; } - - private: - // Overridden from WindowDelegate: - virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { - if (delete_during_handle_) - delete window_; - got_event_ = true; - } - - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { - if (delete_during_handle_) - delete window_; - got_event_ = true; - } - - Window* window_; - bool delete_during_handle_; - bool got_event_; - - DISALLOW_COPY_AND_ASSIGN(DeletingWindowDelegate); -}; - -TEST_F(RootWindowTest, DeleteWindowDuringDispatch) { - // Verifies that we can delete a window during each phase of event handling. - // Deleting the window should not cause a crash, only prevent further - // processing from occurring. - scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); - DeletingWindowDelegate d11; - Window* w11 = CreateNormalWindow(11, w1.get(), &d11); - WindowTracker tracker; - DeletingEventFilter* w1_filter = new DeletingEventFilter; - w1->SetEventFilter(w1_filter); - client::GetFocusClient(w1.get())->FocusWindow(w11); - - test::EventGenerator generator(root_window(), w11); - - // First up, no one deletes anything. - tracker.Add(w11); - d11.Reset(w11, false); - - generator.PressLeftButton(); - EXPECT_TRUE(tracker.Contains(w11)); - EXPECT_TRUE(d11.got_event()); - generator.ReleaseLeftButton(); - - // Delegate deletes w11. This will prevent the post-handle step from applying. - w1_filter->Reset(false); - d11.Reset(w11, true); - generator.PressKey(ui::VKEY_A, 0); - EXPECT_FALSE(tracker.Contains(w11)); - EXPECT_TRUE(d11.got_event()); - - // Pre-handle step deletes w11. This will prevent the delegate and the post- - // handle steps from applying. - w11 = CreateNormalWindow(11, w1.get(), &d11); - w1_filter->Reset(true); - d11.Reset(w11, false); - generator.PressLeftButton(); - EXPECT_FALSE(tracker.Contains(w11)); - EXPECT_FALSE(d11.got_event()); -} - -namespace { - -// A window delegate that detaches the parent of the target's parent window when -// it receives a tap event. -class DetachesParentOnTapDelegate : public test::TestWindowDelegate { - public: - DetachesParentOnTapDelegate() {} - virtual ~DetachesParentOnTapDelegate() {} - - private: - virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - event->SetHandled(); - return; - } - - if (event->type() == ui::ET_GESTURE_TAP) { - Window* parent = static_cast<Window*>(event->target())->parent(); - parent->parent()->RemoveChild(parent); - event->SetHandled(); - } - } - - DISALLOW_COPY_AND_ASSIGN(DetachesParentOnTapDelegate); -}; - -} // namespace - -// Tests that the gesture recognizer is reset for all child windows when a -// window hides. No expectations, just checks that the test does not crash. -TEST_F(RootWindowTest, GestureRecognizerResetsTargetWhenParentHides) { - scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); - DetachesParentOnTapDelegate delegate; - scoped_ptr<Window> parent(CreateNormalWindow(22, w1.get(), NULL)); - Window* child = CreateNormalWindow(11, parent.get(), &delegate); - test::EventGenerator generator(root_window(), child); - generator.GestureTapAt(gfx::Point(40, 40)); -} - -namespace { - -// A window delegate that processes nested gestures on tap. -class NestedGestureDelegate : public test::TestWindowDelegate { - public: - NestedGestureDelegate(test::EventGenerator* generator, - const gfx::Point tap_location) - : generator_(generator), - tap_location_(tap_location), - gesture_end_count_(0) {} - virtual ~NestedGestureDelegate() {} - - int gesture_end_count() const { return gesture_end_count_; } - - private: - virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { - switch (event->type()) { - case ui::ET_GESTURE_TAP_DOWN: - event->SetHandled(); - break; - case ui::ET_GESTURE_TAP: - if (generator_) - generator_->GestureTapAt(tap_location_); - event->SetHandled(); - break; - case ui::ET_GESTURE_END: - ++gesture_end_count_; - break; - default: - break; - } - } - - test::EventGenerator* generator_; - const gfx::Point tap_location_; - int gesture_end_count_; - DISALLOW_COPY_AND_ASSIGN(NestedGestureDelegate); -}; - -} // namespace - -// Tests that gesture end is delivered after nested gesture processing. -TEST_F(RootWindowTest, GestureEndDeliveredAfterNestedGestures) { - NestedGestureDelegate d1(NULL, gfx::Point()); - scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &d1)); - w1->SetBounds(gfx::Rect(0, 0, 100, 100)); - - test::EventGenerator nested_generator(root_window(), w1.get()); - NestedGestureDelegate d2(&nested_generator, w1->bounds().CenterPoint()); - scoped_ptr<Window> w2(CreateNormalWindow(1, root_window(), &d2)); - w2->SetBounds(gfx::Rect(100, 0, 100, 100)); - - // Tap on w2 which triggers nested gestures for w1. - test::EventGenerator generator(root_window(), w2.get()); - generator.GestureTapAt(w2->bounds().CenterPoint()); - - // Both windows should get their gesture end events. - EXPECT_EQ(1, d1.gesture_end_count()); - EXPECT_EQ(1, d2.gesture_end_count()); -} - -// Tests whether we can repost the Tap down gesture event. -TEST_F(RootWindowTest, RepostTapdownGestureTest) { - EventFilterRecorder* filter = new EventFilterRecorder; - root_window()->SetEventFilter(filter); // passes ownership - - test::TestWindowDelegate delegate; - scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( - &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); - - ui::GestureEventDetails details(ui::ET_GESTURE_TAP_DOWN, 0.0f, 0.0f); - gfx::Point point(10, 10); - ui::GestureEvent event( - ui::ET_GESTURE_TAP_DOWN, - point.x(), - point.y(), - 0, - ui::EventTimeForNow(), - details, - 0); - dispatcher()->RepostEvent(event); - RunAllPendingInMessageLoop(); - // TODO(rbyers): Currently disabled - crbug.com/170987 - EXPECT_FALSE(EventTypesToString(filter->events()).find("GESTURE_TAP_DOWN") != - std::string::npos); - filter->events().clear(); -} - -// This class inherits from the EventFilterRecorder class which provides a -// facility to record events. This class additionally provides a facility to -// repost the ET_GESTURE_TAP_DOWN gesture to the target window and records -// events after that. -class RepostGestureEventRecorder : public EventFilterRecorder { - public: - RepostGestureEventRecorder(aura::Window* repost_source, - aura::Window* repost_target) - : repost_source_(repost_source), - repost_target_(repost_target), - reposted_(false), - done_cleanup_(false) {} - - virtual ~RepostGestureEventRecorder() {} - - virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE { - if (reposted_ && event->type() == ui::ET_TOUCH_PRESSED) { - done_cleanup_ = true; - events().clear(); - } - EventFilterRecorder::OnTouchEvent(event); - } - - virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { - EXPECT_EQ(done_cleanup_ ? repost_target_ : repost_source_, event->target()); - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - if (!reposted_) { - EXPECT_NE(repost_target_, event->target()); - reposted_ = true; - repost_target_->GetDispatcher()->RepostEvent(*event); - // Ensure that the reposted gesture event above goes to the - // repost_target_; - repost_source_->GetRootWindow()->RemoveChild(repost_source_); - return; - } - } - EventFilterRecorder::OnGestureEvent(event); - } - - // Ignore mouse events as they don't fire at all times. This causes - // the GestureRepostEventOrder test to fail randomly. - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {} - - private: - aura::Window* repost_source_; - aura::Window* repost_target_; - // set to true if we reposted the ET_GESTURE_TAP_DOWN event. - bool reposted_; - // set true if we're done cleaning up after hiding repost_source_; - bool done_cleanup_; - DISALLOW_COPY_AND_ASSIGN(RepostGestureEventRecorder); -}; - -// Tests whether events which are generated after the reposted gesture event -// are received after that. In this case the scroll sequence events should -// be received after the reposted gesture event. -TEST_F(RootWindowTest, GestureRepostEventOrder) { - // Expected events at the end for the repost_target window defined below. - const char kExpectedTargetEvents[] = - // TODO)(rbyers): Gesture event reposting is disabled - crbug.com/279039. - // "GESTURE_BEGIN GESTURE_TAP_DOWN " - "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " - "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE TOUCH_MOVED " - "GESTURE_SCROLL_UPDATE TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED " - "GESTURE_SCROLL_END GESTURE_END"; - // We create two windows. - // The first window (repost_source) is the one to which the initial tap - // gesture is sent. It reposts this event to the second window - // (repost_target). - // We then generate the scroll sequence for repost_target and look for two - // ET_GESTURE_TAP_DOWN events in the event list at the end. - test::TestWindowDelegate delegate; - scoped_ptr<aura::Window> repost_target(CreateTestWindowWithDelegate( - &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); - - scoped_ptr<aura::Window> repost_source(CreateTestWindowWithDelegate( - &delegate, 1, gfx::Rect(0, 0, 50, 50), root_window())); - - RepostGestureEventRecorder* repost_event_recorder = - new RepostGestureEventRecorder(repost_source.get(), repost_target.get()); - root_window()->SetEventFilter(repost_event_recorder); // passes ownership - - // Generate a tap down gesture for the repost_source. This will be reposted - // to repost_target. - test::EventGenerator repost_generator(root_window(), repost_source.get()); - repost_generator.GestureTapAt(gfx::Point(40, 40)); - RunAllPendingInMessageLoop(); - - test::EventGenerator scroll_generator(root_window(), repost_target.get()); - scroll_generator.GestureScrollSequence( - gfx::Point(80, 80), - gfx::Point(100, 100), - base::TimeDelta::FromMilliseconds(100), - 3); - RunAllPendingInMessageLoop(); - - int tap_down_count = 0; - for (size_t i = 0; i < repost_event_recorder->events().size(); ++i) { - if (repost_event_recorder->events()[i] == ui::ET_GESTURE_TAP_DOWN) - ++tap_down_count; - } - - // We expect two tap down events. One from the repost and the other one from - // the scroll sequence posted above. - // TODO(rbyers): Currently disabled - crbug.com/170987 - EXPECT_EQ(1, tap_down_count); - - EXPECT_EQ(kExpectedTargetEvents, - EventTypesToString(repost_event_recorder->events())); -} - -class OnMouseExitDeletingEventFilter : public EventFilterRecorder { - public: - OnMouseExitDeletingEventFilter() : window_to_delete_(NULL) {} - virtual ~OnMouseExitDeletingEventFilter() {} - - void set_window_to_delete(Window* window_to_delete) { - window_to_delete_ = window_to_delete; - } - - private: - // Overridden from ui::EventHandler: - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { - EventFilterRecorder::OnMouseEvent(event); - if (window_to_delete_) { - delete window_to_delete_; - window_to_delete_ = NULL; - } - } - - Window* window_to_delete_; - - DISALLOW_COPY_AND_ASSIGN(OnMouseExitDeletingEventFilter); -}; - -// Tests that RootWindow drops mouse-moved event that is supposed to be sent to -// a child, but the child is destroyed because of the synthesized mouse-exit -// event generated on the previous mouse_moved_handler_. -TEST_F(RootWindowTest, DeleteWindowDuringMouseMovedDispatch) { - // Create window 1 and set its event filter. Window 1 will take ownership of - // the event filter. - scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); - OnMouseExitDeletingEventFilter* w1_filter = - new OnMouseExitDeletingEventFilter(); - w1->SetEventFilter(w1_filter); - w1->SetBounds(gfx::Rect(20, 20, 60, 60)); - EXPECT_EQ(NULL, dispatcher()->mouse_moved_handler()); - - test::EventGenerator generator(root_window(), w1.get()); - - // Move mouse over window 1 to set it as the |mouse_moved_handler_| for the - // root window. - generator.MoveMouseTo(51, 51); - EXPECT_EQ(w1.get(), dispatcher()->mouse_moved_handler()); - - // Create window 2 under the mouse cursor and stack it above window 1. - Window* w2 = CreateNormalWindow(2, root_window(), NULL); - w2->SetBounds(gfx::Rect(30, 30, 40, 40)); - root_window()->StackChildAbove(w2, w1.get()); - - // Set window 2 as the window that is to be deleted when a mouse-exited event - // happens on window 1. - w1_filter->set_window_to_delete(w2); - - // Move mosue over window 2. This should generate a mouse-exited event for - // window 1 resulting in deletion of window 2. The original mouse-moved event - // that was targeted to window 2 should be dropped since window 2 is - // destroyed. This test passes if no crash happens. - generator.MoveMouseTo(52, 52); - EXPECT_EQ(NULL, dispatcher()->mouse_moved_handler()); - - // Check events received by window 1. - EXPECT_EQ("MOUSE_ENTERED MOUSE_MOVED MOUSE_EXITED", - EventTypesToString(w1_filter->events())); -} - -namespace { - -// Used to track if OnWindowDestroying() is invoked and if there is a valid -// RootWindow at such time. -class ValidRootDuringDestructionWindowObserver : public aura::WindowObserver { - public: - ValidRootDuringDestructionWindowObserver(bool* got_destroying, - bool* has_valid_root) - : got_destroying_(got_destroying), - has_valid_root_(has_valid_root) { - } - - // WindowObserver: - virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { - *got_destroying_ = true; - *has_valid_root_ = (window->GetRootWindow() != NULL); - } - - private: - bool* got_destroying_; - bool* has_valid_root_; - - DISALLOW_COPY_AND_ASSIGN(ValidRootDuringDestructionWindowObserver); -}; - -} // namespace - -#if defined(USE_OZONE) -// Creating multiple RootWindowHostOzone instances is broken. -#define MAYBE_ValidRootDuringDestruction DISABLED_ValidRootDuringDestruction -#else -#define MAYBE_ValidRootDuringDestruction ValidRootDuringDestruction -#endif - -// Verifies GetRootWindow() from ~Window returns a valid root. -TEST_F(RootWindowTest, MAYBE_ValidRootDuringDestruction) { - bool got_destroying = false; - bool has_valid_root = false; - ValidRootDuringDestructionWindowObserver observer(&got_destroying, - &has_valid_root); - { - scoped_ptr<RootWindow> root_window( - new RootWindow(RootWindow::CreateParams(gfx::Rect(0, 0, 100, 100)))); - root_window->Init(); - // Owned by RootWindow. - Window* w1 = CreateNormalWindow(1, root_window->window(), NULL); - w1->AddObserver(&observer); - } - EXPECT_TRUE(got_destroying); - EXPECT_TRUE(has_valid_root); -} - -namespace { - -// See description above DontResetHeldEvent for details. -class DontResetHeldEventWindowDelegate : public test::TestWindowDelegate { - public: - explicit DontResetHeldEventWindowDelegate(aura::Window* root) - : root_(root), - mouse_event_count_(0) {} - virtual ~DontResetHeldEventWindowDelegate() {} - - int mouse_event_count() const { return mouse_event_count_; } - - // TestWindowDelegate: - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { - if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && - mouse_event_count_++ == 0) { - ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, - gfx::Point(10, 10), gfx::Point(10, 10), - ui::EF_SHIFT_DOWN); - root_->GetDispatcher()->RepostEvent(mouse_event); - } - } - - private: - Window* root_; - int mouse_event_count_; - - DISALLOW_COPY_AND_ASSIGN(DontResetHeldEventWindowDelegate); -}; - -} // namespace - -// Verifies RootWindow doesn't reset |RootWindow::held_repostable_event_| after -// dispatching. This is done by using DontResetHeldEventWindowDelegate, which -// tracks the number of events with ui::EF_SHIFT_DOWN set (all reposted events -// have EF_SHIFT_DOWN). When the first event is seen RepostEvent() is used to -// schedule another reposted event. -TEST_F(RootWindowTest, DontResetHeldEvent) { - DontResetHeldEventWindowDelegate delegate(root_window()); - scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate)); - RootWindowHostDelegate* root_window_delegate = - static_cast<RootWindowHostDelegate*>(root_window()->GetDispatcher()); - w1->SetBounds(gfx::Rect(0, 0, 40, 40)); - ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, - gfx::Point(10, 10), gfx::Point(10, 10), - ui::EF_SHIFT_DOWN); - root_window()->GetDispatcher()->RepostEvent(pressed); - ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, - gfx::Point(10, 10), gfx::Point(10, 10), 0); - // Invoke OnHostMouseEvent() to flush event scheduled by way of RepostEvent(). - root_window_delegate->OnHostMouseEvent(&pressed2); - // Delegate should have seen reposted event (identified by way of - // EF_SHIFT_DOWN). Invoke OnHostMouseEvent() to flush the second - // RepostedEvent(). - EXPECT_EQ(1, delegate.mouse_event_count()); - root_window_delegate->OnHostMouseEvent(&pressed2); - EXPECT_EQ(2, delegate.mouse_event_count()); -} - -namespace { - -// See description above DeleteRootFromHeldMouseEvent for details. -class DeleteRootFromHeldMouseEventDelegate : public test::TestWindowDelegate { - public: - explicit DeleteRootFromHeldMouseEventDelegate(aura::RootWindow* root) - : root_(root), - got_mouse_event_(false), - got_destroy_(false) { - } - virtual ~DeleteRootFromHeldMouseEventDelegate() {} - - bool got_mouse_event() const { return got_mouse_event_; } - bool got_destroy() const { return got_destroy_; } - - // TestWindowDelegate: - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { - if ((event->flags() & ui::EF_SHIFT_DOWN) != 0) { - got_mouse_event_ = true; - delete root_; - } - } - virtual void OnWindowDestroyed() OVERRIDE { - got_destroy_ = true; - } - - private: - RootWindow* root_; - bool got_mouse_event_; - bool got_destroy_; - - DISALLOW_COPY_AND_ASSIGN(DeleteRootFromHeldMouseEventDelegate); -}; - -} // namespace - -#if defined(USE_OZONE) -// Creating multiple RootWindowHostOzone instances is broken. -#define MAYBE_DeleteRootFromHeldMouseEvent DISABLED_DeleteRootFromHeldMouseEvent -#else -#define MAYBE_DeleteRootFromHeldMouseEvent DeleteRootFromHeldMouseEvent -#endif - -// Verifies if a RootWindow is deleted from dispatching a held mouse event we -// don't crash. -TEST_F(RootWindowTest, MAYBE_DeleteRootFromHeldMouseEvent) { - // Should be deleted by |delegate|. - RootWindow* r2 = - new RootWindow(RootWindow::CreateParams(gfx::Rect(0, 0, 100, 100))); - r2->Init(); - DeleteRootFromHeldMouseEventDelegate delegate(r2); - // Owned by |r2|. - Window* w1 = CreateNormalWindow(1, r2->window(), &delegate); - w1->SetBounds(gfx::Rect(0, 0, 40, 40)); - ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, - gfx::Point(10, 10), gfx::Point(10, 10), - ui::EF_SHIFT_DOWN); - r2->RepostEvent(pressed); - // RunAllPendingInMessageLoop() to make sure the |pressed| is run. - RunAllPendingInMessageLoop(); - EXPECT_TRUE(delegate.got_mouse_event()); - EXPECT_TRUE(delegate.got_destroy()); -} - -TEST_F(RootWindowTest, WindowHideCancelsActiveTouches) { - EventFilterRecorder* filter = new EventFilterRecorder; - root_window()->SetEventFilter(filter); // passes ownership - - test::TestWindowDelegate delegate; - scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( - &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); - - gfx::Point position1 = root_window()->bounds().origin(); - ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position1, 0, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); - - EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN", - EventTypesToString(filter->GetAndResetEvents())); - - window->Hide(); - - EXPECT_EQ("TOUCH_CANCELLED GESTURE_TAP_CANCEL GESTURE_END", - EventTypesToString(filter->events())); -} - -TEST_F(RootWindowTest, WindowHideCancelsActiveGestures) { - EventFilterRecorder* filter = new EventFilterRecorder; - root_window()->SetEventFilter(filter); // passes ownership - - test::TestWindowDelegate delegate; - scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( - &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); - - gfx::Point position1 = root_window()->bounds().origin(); - gfx::Point position2 = root_window()->bounds().CenterPoint(); - ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position1, 0, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); - - ui::TouchEvent move(ui::ET_TOUCH_MOVED, position2, 0, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); - - ui::TouchEvent press2(ui::ET_TOUCH_PRESSED, position1, 1, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); - - EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " - "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE " - "TOUCH_PRESSED GESTURE_BEGIN GESTURE_PINCH_BEGIN", - EventTypesToString(filter->GetAndResetEvents())); - - window->Hide(); - - EXPECT_EQ("TOUCH_CANCELLED GESTURE_PINCH_END GESTURE_END TOUCH_CANCELLED " - "GESTURE_SCROLL_END GESTURE_END", - EventTypesToString(filter->events())); -} - -// Places two windows side by side. Presses down on one window, and starts a -// scroll. Sets capture on the other window and ensures that the "ending" events -// aren't sent to the window which gained capture. -TEST_F(RootWindowTest, EndingEventDoesntRetarget) { - scoped_ptr<Window> window1(CreateNormalWindow(1, root_window(), NULL)); - window1->SetBounds(gfx::Rect(0, 0, 40, 40)); - - scoped_ptr<Window> window2(CreateNormalWindow(2, root_window(), NULL)); - window2->SetBounds(gfx::Rect(40, 0, 40, 40)); - - EventFilterRecorder* filter1 = new EventFilterRecorder(); - window1->SetEventFilter(filter1); // passes ownership - EventFilterRecorder* filter2 = new EventFilterRecorder(); - window2->SetEventFilter(filter2); // passes ownership - - gfx::Point position = window1->bounds().origin(); - ui::TouchEvent press(ui::ET_TOUCH_PRESSED, position, 0, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); - - gfx::Point position2 = window1->bounds().CenterPoint(); - ui::TouchEvent move(ui::ET_TOUCH_MOVED, position2, 0, base::TimeDelta()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); - - window2->SetCapture(); - - EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " - "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE " - "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END", - EventTypesToString(filter1->events())); - - EXPECT_TRUE(filter2->events().empty()); -} - -class ExitMessageLoopOnMousePress : public test::TestEventHandler { - public: - ExitMessageLoopOnMousePress() {} - virtual ~ExitMessageLoopOnMousePress() {} - - protected: - virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { - test::TestEventHandler::OnMouseEvent(event); - if (event->type() == ui::ET_MOUSE_PRESSED) - base::MessageLoopForUI::current()->Quit(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ExitMessageLoopOnMousePress); -}; - -class RootWindowTestWithMessageLoop : public RootWindowTest { - public: - RootWindowTestWithMessageLoop() {} - virtual ~RootWindowTestWithMessageLoop() {} - - void RunTest() { - // Start a nested message-loop, post an event to be dispatched, and then - // terminate the message-loop. When the message-loop unwinds and gets back, - // the reposted event should not have fired. - ui::MouseEvent mouse(ui::ET_MOUSE_PRESSED, gfx::Point(10, 10), - gfx::Point(10, 10), ui::EF_NONE); - message_loop()->PostTask(FROM_HERE, - base::Bind(&RootWindow::RepostEvent, - base::Unretained(dispatcher()), - mouse)); - message_loop()->PostTask(FROM_HERE, - message_loop()->QuitClosure()); - - base::MessageLoop::ScopedNestableTaskAllower allow(message_loop()); - base::RunLoop loop; - loop.Run(); - EXPECT_EQ(0, handler_.num_mouse_events()); - - // Let the current message-loop run. The event-handler will terminate the - // message-loop when it receives the reposted event. - } - - base::MessageLoop* message_loop() { - return base::MessageLoopForUI::current(); - } - - protected: - virtual void SetUp() OVERRIDE { - RootWindowTest::SetUp(); - window_.reset(CreateNormalWindow(1, root_window(), NULL)); - window_->AddPreTargetHandler(&handler_); - } - - virtual void TearDown() OVERRIDE { - window_.reset(); - RootWindowTest::TearDown(); - } - - private: - scoped_ptr<Window> window_; - ExitMessageLoopOnMousePress handler_; - - DISALLOW_COPY_AND_ASSIGN(RootWindowTestWithMessageLoop); -}; - -TEST_F(RootWindowTestWithMessageLoop, EventRepostedInNonNestedLoop) { - CHECK(!message_loop()->is_running()); - // Perform the test in a callback, so that it runs after the message-loop - // starts. - message_loop()->PostTask(FROM_HERE, - base::Bind(&RootWindowTestWithMessageLoop::RunTest, - base::Unretained(this))); - message_loop()->Run(); -} - -} // namespace aura diff --git a/chromium/ui/aura/scoped_window_targeter.cc b/chromium/ui/aura/scoped_window_targeter.cc new file mode 100644 index 00000000000..96355246245 --- /dev/null +++ b/chromium/ui/aura/scoped_window_targeter.cc @@ -0,0 +1,29 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura/scoped_window_targeter.h" + +#include "ui/aura/window.h" + +namespace aura { + +ScopedWindowTargeter::ScopedWindowTargeter( + Window* window, + scoped_ptr<ui::EventTargeter> new_targeter) + : window_(window), + old_targeter_(window->SetEventTargeter(new_targeter.Pass())) { +} + +ScopedWindowTargeter::~ScopedWindowTargeter() { + if (window_) + window_->SetEventTargeter(old_targeter_.Pass()); +} + +void ScopedWindowTargeter::OnWindowDestroyed(Window* window) { + CHECK_EQ(window_, window); + window_ = NULL; + old_targeter_.reset(); +} + +} // namespace aura diff --git a/chromium/ui/aura/scoped_window_targeter.h b/chromium/ui/aura/scoped_window_targeter.h new file mode 100644 index 00000000000..f8546c57d0e --- /dev/null +++ b/chromium/ui/aura/scoped_window_targeter.h @@ -0,0 +1,46 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_SCOPED_WINDOW_TARGETER_H_ +#define UI_AURA_SCOPED_WINDOW_TARGETER_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "ui/aura/window_observer.h" + +namespace ui { +class EventTargeter; +} + +namespace aura { + +class Window; + +// ScopedWindowTargeter is used to temporarily replace the event-targeter for a +// window. Upon construction, it installs a new targeter on the window, and upon +// destruction, it restores the previous event-targeter on the window. +class AURA_EXPORT ScopedWindowTargeter : public WindowObserver { + public: + ScopedWindowTargeter(Window* window, + scoped_ptr<ui::EventTargeter> new_targeter); + + virtual ~ScopedWindowTargeter(); + + ui::EventTargeter* old_targeter() { + return old_targeter_.get(); + } + + private: + // WindowObserver: + virtual void OnWindowDestroyed(Window* window) OVERRIDE; + + Window* window_; + scoped_ptr<ui::EventTargeter> old_targeter_; + + DISALLOW_COPY_AND_ASSIGN(ScopedWindowTargeter); +}; + +} // namespace aura + +#endif // UI_AURA_SCOPED_WINDOW_TARGETER_H_ diff --git a/chromium/ui/aura/window.cc b/chromium/ui/aura/window.cc index 4836a15aae0..35b29245800 100644 --- a/chromium/ui/aura/window.cc +++ b/chromium/ui/aura/window.cc @@ -10,7 +10,6 @@ #include "base/bind_helpers.h" #include "base/callback.h" #include "base/logging.h" -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -23,15 +22,14 @@ #include "ui/aura/client/window_stacking_client.h" #include "ui/aura/env.h" #include "ui/aura/layout_manager.h" -#include "ui/aura/root_window.h" #include "ui/aura/window_delegate.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_observer.h" #include "ui/aura/window_tracker.h" #include "ui/aura/window_tree_host.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" #include "ui/events/event_target_iterator.h" -#include "ui/gfx/animation/multi_animation.h" #include "ui/gfx/canvas.h" #include "ui/gfx/path.h" #include "ui/gfx/scoped_canvas.h" @@ -41,19 +39,6 @@ namespace aura { namespace { -WindowLayerType UILayerTypeToWindowLayerType(ui::LayerType layer_type) { - switch (layer_type) { - case ui::LAYER_NOT_DRAWN: - return WINDOW_LAYER_NOT_DRAWN; - case ui::LAYER_TEXTURED: - return WINDOW_LAYER_TEXTURED; - case ui::LAYER_SOLID_COLOR: - return WINDOW_LAYER_SOLID_COLOR; - } - NOTREACHED(); - return WINDOW_LAYER_NOT_DRAWN; -} - ui::LayerType WindowLayerTypeToUILayerType(WindowLayerType window_layer_type) { switch (window_layer_type) { case WINDOW_LAYER_NONE: @@ -176,7 +161,7 @@ class ScopedCursorHider { explicit ScopedCursorHider(Window* window) : window_(window), hid_cursor_(false) { - if (!window_->HasDispatcher()) + if (!window_->IsRootWindow()) return; const bool cursor_is_in_bounds = window_->GetBoundsInScreen().Contains( Env::GetInstance()->last_mouse_location()); @@ -188,7 +173,7 @@ class ScopedCursorHider { } } ~ScopedCursorHider() { - if (!window_->HasDispatcher()) + if (!window_->IsRootWindow()) return; // Update the device scale factor of the cursor client only when the last @@ -213,12 +198,11 @@ class ScopedCursorHider { }; Window::Window(WindowDelegate* delegate) - : dispatcher_(NULL), - type_(client::WINDOW_TYPE_UNKNOWN), + : host_(NULL), + type_(ui::wm::WINDOW_TYPE_UNKNOWN), owned_by_parent_(true), delegate_(delegate), parent_(NULL), - transient_parent_(NULL), visible_(false), id_(-1), transparent_(false), @@ -232,43 +216,46 @@ Window::Window(WindowDelegate* delegate) } Window::~Window() { - // |layer_| can be NULL during tests, or if this Window is layerless. - if (layer_) - layer_->SuppressPaint(); + // |layer()| can be NULL during tests, or if this Window is layerless. + if (layer()) { + if (layer()->owner() == this) + layer()->CompleteAllAnimations(); + layer()->SuppressPaint(); + } // Let the delegate know we're in the processing of destroying. if (delegate_) - delegate_->OnWindowDestroying(); + delegate_->OnWindowDestroying(this); FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this)); - // Let the root know so that it can remove any references to us. - WindowEventDispatcher* dispatcher = GetDispatcher(); - if (dispatcher) - dispatcher->OnWindowDestroying(this); + // TODO(beng): See comment in window_event_dispatcher.h. This shouldn't be + // necessary but unfortunately is right now due to ordering + // peculiarities. WED must be notified _after_ other observers + // are notified of pending teardown but before the hierarchy + // is actually torn down. + WindowTreeHost* host = GetHost(); + if (host) + host->dispatcher()->OnPostNotifiedWindowDestroying(this); + + // The window should have already had its state cleaned up in + // WindowEventDispatcher::OnWindowHidden(), but there have been some crashes + // involving windows being destroyed without being hidden first. See + // crbug.com/342040. This should help us debug the issue. TODO(tdresser): + // remove this once we determine why we have windows that are destroyed + // without being hidden. + bool window_incorrectly_cleaned_up = CleanupGestureState(); + CHECK(!window_incorrectly_cleaned_up); // Then destroy the children. RemoveOrDestroyChildren(); - // Removes ourselves from our transient parent (if it hasn't been done by the - // RootWindow). - if (transient_parent_) - transient_parent_->RemoveTransientChild(this); - // The window needs to be removed from the parent before calling the // WindowDestroyed callbacks of delegate and the observers. if (parent_) parent_->RemoveChild(this); - // Destroy transient children, only after we've removed ourselves from our - // parent, as destroying an active transient child may otherwise attempt to - // refocus us. - Windows transient_children(transient_children_); - STLDeleteElements(&transient_children); - DCHECK(transient_children_.empty()); - - // Delegate and observers need to be notified after transients are deleted. if (delegate_) - delegate_->OnWindowDestroyed(); + delegate_->OnWindowDestroyed(this); ObserverListBase<WindowObserver>::Iterator iter(observers_); WindowObserver* observer; while ((observer = iter.GetNext())) { @@ -288,83 +275,45 @@ Window::~Window() { // If we have layer it will either be destroyed by |layer_owner_|'s dtor, or // by whoever acquired it. We don't have a layer if Init() wasn't invoked or // we are layerless. - if (layer_) { - layer_->set_delegate(NULL); - layer_ = NULL; - } -} - -void Window::Init(ui::LayerType layer_type) { - InitWithWindowLayerType(UILayerTypeToWindowLayerType(layer_type)); + if (layer()) + layer()->set_delegate(NULL); + DestroyLayer(); } -void Window::InitWithWindowLayerType(WindowLayerType window_layer_type) { +void Window::Init(WindowLayerType window_layer_type) { if (window_layer_type != WINDOW_LAYER_NONE) { - layer_ = new ui::Layer(WindowLayerTypeToUILayerType(window_layer_type)); - layer_owner_.reset(layer_); - layer_->SetVisible(false); - layer_->set_delegate(this); - UpdateLayerName(name_); - layer_->SetFillsBoundsOpaquely(!transparent_); + SetLayer(new ui::Layer(WindowLayerTypeToUILayerType(window_layer_type))); + layer()->SetVisible(false); + layer()->set_delegate(this); + UpdateLayerName(); + layer()->SetFillsBoundsOpaquely(!transparent_); } Env::GetInstance()->NotifyWindowInitialized(this); } -ui::Layer* Window::RecreateLayer() { - // Disconnect the old layer, but don't delete it. - ui::Layer* old_layer = AcquireLayer(); - if (!old_layer) - return NULL; - - old_layer->set_delegate(NULL); - - layer_ = new ui::Layer(old_layer->type()); - layer_owner_.reset(layer_); - layer_->SetVisible(old_layer->visible()); - layer_->set_scale_content(old_layer->scale_content()); - layer_->set_delegate(this); - layer_->SetMasksToBounds(old_layer->GetMasksToBounds()); - - if (delegate_) - delegate_->DidRecreateLayer(old_layer, layer_); - - UpdateLayerName(name_); - layer_->SetFillsBoundsOpaquely(!transparent_); - // Install new layer as a sibling of the old layer, stacked below it. - if (old_layer->parent()) { - old_layer->parent()->Add(layer_); - old_layer->parent()->StackBelow(layer_, old_layer); - } - // Migrate all the child layers over to the new layer. Copy the list because - // the items are removed during iteration. - std::vector<ui::Layer*> children_copy = old_layer->children(); - for (std::vector<ui::Layer*>::const_iterator it = children_copy.begin(); - it != children_copy.end(); - ++it) { - ui::Layer* child = *it; - layer_->Add(child); - } - return old_layer; -} - -void Window::SetType(client::WindowType type) { +void Window::SetType(ui::wm::WindowType type) { // Cannot change type after the window is initialized. - DCHECK(!layer_); + DCHECK(!layer()); type_ = type; } void Window::SetName(const std::string& name) { name_ = name; - if (layer_) - UpdateLayerName(name_); + if (layer()) + UpdateLayerName(); } void Window::SetTransparent(bool transparent) { transparent_ = transparent; - if (layer_) - layer_->SetFillsBoundsOpaquely(!transparent_); + if (layer()) + layer()->SetFillsBoundsOpaquely(!transparent_); +} + +void Window::SetFillsBoundsCompletely(bool fills_bounds) { + if (layer()) + layer()->SetFillsBoundsCompletely(fills_bounds); } Window* Window::GetRootWindow() { @@ -373,30 +322,33 @@ Window* Window::GetRootWindow() { } const Window* Window::GetRootWindow() const { - return dispatcher_ ? this : parent_ ? parent_->GetRootWindow() : NULL; + return IsRootWindow() ? this : parent_ ? parent_->GetRootWindow() : NULL; } -WindowEventDispatcher* Window::GetDispatcher() { - return const_cast<WindowEventDispatcher*>(const_cast<const Window*>(this)-> - GetDispatcher()); +WindowTreeHost* Window::GetHost() { + return const_cast<WindowTreeHost*>(const_cast<const Window*>(this)-> + GetHost()); } -const WindowEventDispatcher* Window::GetDispatcher() const { +const WindowTreeHost* Window::GetHost() const { const Window* root_window = GetRootWindow(); - return root_window ? root_window->dispatcher_ : NULL; + return root_window ? root_window->host_ : NULL; } void Window::Show() { + if (layer()) { + DCHECK_EQ(visible_, layer()->GetTargetVisibility()); + // It is not allowed that a window is visible but the layers alpha is fully + // transparent since the window would still be considered to be active but + // could not be seen. + DCHECK(!(visible_ && layer()->GetTargetOpacity() == 0.0f)); + } SetVisible(true); } void Window::Hide() { - for (Windows::iterator it = transient_children_.begin(); - it != transient_children_.end(); ++it) { - (*it)->Hide(); - } + // RootWindow::OnVisibilityChanged will call ReleaseCapture. SetVisible(false); - ReleaseCapture(); } bool Window::IsVisible() const { @@ -407,8 +359,8 @@ bool Window::IsVisible() const { for (const Window* window = this; window; window = window->parent()) { if (!window->visible_) return false; - if (window->layer_) - return window->layer_->IsDrawn(); + if (window->layer()) + return window->layer()->IsDrawn(); } return false; } @@ -440,17 +392,16 @@ gfx::Rect Window::GetBoundsInScreen() const { } void Window::SetTransform(const gfx::Transform& transform) { - if (!layer_) { + if (!layer()) { // Transforms aren't supported on layerless windows. NOTREACHED(); return; } - WindowEventDispatcher* dispatcher = GetDispatcher(); - bool contained_mouse = IsVisible() && dispatcher && - ContainsPointInRoot(dispatcher->GetLastMouseLocationInRoot()); - layer_->SetTransform(transform); - if (dispatcher) - dispatcher->OnWindowTransformed(this, contained_mouse); + FOR_EACH_OBSERVER(WindowObserver, observers_, + OnWindowTransforming(this)); + layer()->SetTransform(transform); + FOR_EACH_OBSERVER(WindowObserver, observers_, + OnWindowTransformed(this)); } void Window::SetLayoutManager(LayoutManager* layout_manager) { @@ -467,11 +418,27 @@ void Window::SetLayoutManager(LayoutManager* layout_manager) { layout_manager_->OnWindowAddedToLayout(*it); } +scoped_ptr<ui::EventTargeter> +Window::SetEventTargeter(scoped_ptr<ui::EventTargeter> targeter) { + scoped_ptr<ui::EventTargeter> old_targeter = targeter_.Pass(); + targeter_ = targeter.Pass(); + return old_targeter.Pass(); +} + void Window::SetBounds(const gfx::Rect& new_bounds) { if (parent_ && parent_->layout_manager()) parent_->layout_manager()->SetChildBounds(this, new_bounds); - else - SetBoundsInternal(new_bounds); + else { + // Ensure we don't go smaller than our minimum bounds. + gfx::Rect final_bounds(new_bounds); + if (delegate_) { + const gfx::Size& min_size = delegate_->GetMinimumSize(); + final_bounds.set_width(std::max(min_size.width(), final_bounds.width())); + final_bounds.set_height(std::max(min_size.height(), + final_bounds.height())); + } + SetBoundsInternal(final_bounds); + } } void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen, @@ -488,11 +455,11 @@ void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen, } gfx::Rect Window::GetTargetBounds() const { - if (!layer_) + if (!layer()) return bounds(); - if (!parent_ || parent_->layer_) - return layer_->GetTargetBounds(); + if (!parent_ || parent_->layer()) + return layer()->GetTargetBounds(); // We have a layer but our parent (who is valid) doesn't. This means the // coordinates of the layer are relative to the first ancestor with a layer; @@ -501,15 +468,15 @@ gfx::Rect Window::GetTargetBounds() const { const aura::Window* ancestor_with_layer = parent_->GetAncestorWithLayer(&offset); if (!ancestor_with_layer) - return layer_->GetTargetBounds(); + return layer()->GetTargetBounds(); - gfx::Rect layer_target_bounds = layer_->GetTargetBounds(); + gfx::Rect layer_target_bounds = layer()->GetTargetBounds(); layer_target_bounds -= offset; return layer_target_bounds; } void Window::SchedulePaintInRect(const gfx::Rect& rect) { - if (!layer_ && parent_) { + if (!layer() && parent_) { // Notification of paint scheduled happens for the window with a layer. gfx::Rect parent_rect(bounds().size()); parent_rect.Intersect(rect); @@ -517,7 +484,7 @@ void Window::SchedulePaintInRect(const gfx::Rect& rect) { parent_rect.Offset(bounds().origin().OffsetFromOrigin()); parent_->SchedulePaintInRect(parent_rect); } - } else if (layer_ && layer_->SchedulePaint(rect)) { + } else if (layer() && layer()->SchedulePaint(rect)) { FOR_EACH_OBSERVER( WindowObserver, observers_, OnWindowPaintScheduled(this, rect)); } @@ -560,13 +527,14 @@ void Window::AddChild(Window* child) { gfx::Vector2d offset; aura::Window* ancestor_with_layer = GetAncestorWithLayer(&offset); + + child->parent_ = this; + if (ancestor_with_layer) { offset += child->bounds().OffsetFromOrigin(); child->ReparentLayers(ancestor_with_layer->layer(), offset); } - child->parent_ = this; - children_.push_back(child); if (layout_manager_) layout_manager_->OnWindowAddedToLayout(child); @@ -575,7 +543,7 @@ void Window::AddChild(Window* child) { Window* root_window = GetRootWindow(); if (root_window && old_root != root_window) { - root_window->GetDispatcher()->OnWindowAddedToRootWindow(child); + root_window->GetHost()->dispatcher()->OnWindowAddedToRootWindow(child); child->NotifyAddedToRootWindow(); } @@ -605,28 +573,6 @@ bool Window::Contains(const Window* other) const { return false; } -void Window::AddTransientChild(Window* child) { - if (child->transient_parent_) - child->transient_parent_->RemoveTransientChild(child); - DCHECK(std::find(transient_children_.begin(), transient_children_.end(), - child) == transient_children_.end()); - transient_children_.push_back(child); - child->transient_parent_ = this; - FOR_EACH_OBSERVER(WindowObserver, observers_, - OnAddTransientChild(this, child)); -} - -void Window::RemoveTransientChild(Window* child) { - Windows::iterator i = - std::find(transient_children_.begin(), transient_children_.end(), child); - DCHECK(i != transient_children_.end()); - transient_children_.erase(i); - if (child->transient_parent_ == this) - child->transient_parent_ = NULL; - FOR_EACH_OBSERVER(WindowObserver, observers_, - OnRemoveTransientChild(this, child)); -} - Window* Window::GetChildById(int id) { return const_cast<Window*>(const_cast<const Window*>(this)->GetChildById(id)); } @@ -652,53 +598,61 @@ void Window::ConvertPointToTarget(const Window* source, if (source->GetRootWindow() != target->GetRootWindow()) { client::ScreenPositionClient* source_client = client::GetScreenPositionClient(source->GetRootWindow()); - source_client->ConvertPointToScreen(source, point); + // |source_client| can be NULL in tests. + if (source_client) + source_client->ConvertPointToScreen(source, point); client::ScreenPositionClient* target_client = client::GetScreenPositionClient(target->GetRootWindow()); - target_client->ConvertPointFromScreen(target, point); - } else if ((source != target) && (!source->layer_ || !target->layer_)) { - if (!source->layer_) { + // |target_client| can be NULL in tests. + if (target_client) + target_client->ConvertPointFromScreen(target, point); + } else if ((source != target) && (!source->layer() || !target->layer())) { + if (!source->layer()) { gfx::Vector2d offset_to_layer; source = source->GetAncestorWithLayer(&offset_to_layer); *point += offset_to_layer; } - if (!target->layer_) { + if (!target->layer()) { gfx::Vector2d offset_to_layer; target = target->GetAncestorWithLayer(&offset_to_layer); *point -= offset_to_layer; } - ui::Layer::ConvertPointToLayer(source->layer_, target->layer_, point); + ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point); } else { - ui::Layer::ConvertPointToLayer(source->layer_, target->layer_, point); + ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point); } } +// static +void Window::ConvertRectToTarget(const Window* source, + const Window* target, + gfx::Rect* rect) { + DCHECK(rect); + gfx::Point origin = rect->origin(); + ConvertPointToTarget(source, target, &origin); + rect->set_origin(origin); +} + void Window::MoveCursorTo(const gfx::Point& point_in_window) { Window* root_window = GetRootWindow(); DCHECK(root_window); gfx::Point point_in_root(point_in_window); ConvertPointToTarget(this, root_window, &point_in_root); - root_window->GetDispatcher()->MoveCursorTo(point_in_root); + root_window->GetHost()->MoveCursorTo(point_in_root); } gfx::NativeCursor Window::GetCursor(const gfx::Point& point) const { return delegate_ ? delegate_->GetCursor(point) : gfx::kNullCursor; } -void Window::SetEventFilter(ui::EventHandler* event_filter) { - if (event_filter_) - RemovePreTargetHandler(event_filter_.get()); - event_filter_.reset(event_filter); - if (event_filter) - AddPreTargetHandler(event_filter); -} - void Window::AddObserver(WindowObserver* observer) { + observer->OnObservingWindow(this); observers_.AddObserver(observer); } void Window::RemoveObserver(WindowObserver* observer) { + observer->OnUnobservingWindow(this); observers_.RemoveObserver(observer); } @@ -719,28 +673,6 @@ bool Window::ContainsPoint(const gfx::Point& local_point) const { return gfx::Rect(bounds().size()).Contains(local_point); } -bool Window::HitTest(const gfx::Point& local_point) { - // Expand my bounds for hit testing (override is usually zero but it's - // probably cheaper to do the math every time than to branch). - gfx::Rect local_bounds(gfx::Point(), bounds().size()); - local_bounds.Inset(aura::Env::GetInstance()->is_touch_down() ? - hit_test_bounds_override_outer_touch_ : - hit_test_bounds_override_outer_mouse_); - - if (!delegate_ || !delegate_->HasHitTestMask()) - return local_bounds.Contains(local_point); - - gfx::Path mask; - delegate_->GetHitTestMask(&mask); - - SkRegion clip_region; - clip_region.setRect(local_bounds.x(), local_bounds.y(), - local_bounds.width(), local_bounds.height()); - SkRegion mask_region; - return mask_region.setPath(mask, clip_region) && - mask_region.contains(local_point.x(), local_point.y()); -} - Window* Window::GetEventHandlerForPoint(const gfx::Point& local_point) { return GetWindowForPoint(local_point, true, true); } @@ -776,7 +708,7 @@ bool Window::HasFocus() const { } bool Window::CanFocus() const { - if (dispatcher_) + if (IsRootWindow()) return IsVisible(); // NOTE: as part of focusing the window the ActivationClient may make the @@ -795,7 +727,7 @@ bool Window::CanFocus() const { } bool Window::CanReceiveEvents() const { - if (dispatcher_) + if (IsRootWindow()) return IsVisible(); // The client may forbid certain windows from receiving events at a given @@ -833,8 +765,8 @@ bool Window::HasCapture() { } void Window::SuppressPaint() { - if (layer_) - layer_->SuppressPaint(); + if (layer()) + layer()->SuppressPaint(); } // {Set,Get,Clear}Property are implemented in window_property.h. @@ -850,8 +782,8 @@ void* Window::GetNativeWindowProperty(const char* key) const { void Window::OnDeviceScaleFactorChanged(float device_scale_factor) { ScopedCursorHider hider(this); - if (dispatcher_) - dispatcher_->host()->OnDeviceScaleFactorChanged(device_scale_factor); + if (IsRootWindow()) + host_->OnDeviceScaleFactorChanged(device_scale_factor); if (delegate_) delegate_->OnDeviceScaleFactorChanged(device_scale_factor); } @@ -863,10 +795,10 @@ std::string Window::GetDebugInfo() const { name().empty() ? "Unknown" : name().c_str(), id(), bounds().x(), bounds().y(), bounds().width(), bounds().height(), visible_ ? "WindowVisible" : "WindowHidden", - layer_ ? - (layer_->GetTargetVisibility() ? "LayerVisible" : "LayerHidden") : + layer() ? + (layer()->GetTargetVisibility() ? "LayerVisible" : "LayerHidden") : "NoLayer", - layer_ ? layer_->opacity() : 1.0f); + layer() ? layer()->opacity() : 1.0f); } void Window::PrintWindowHierarchy(int depth) const { @@ -928,63 +860,65 @@ int64 Window::GetPropertyInternal(const void* key, return iter->second.value; } -void Window::SetBoundsInternal(const gfx::Rect& new_bounds) { - gfx::Rect actual_new_bounds(new_bounds); +bool Window::HitTest(const gfx::Point& local_point) { + gfx::Rect local_bounds(bounds().size()); + if (!delegate_ || !delegate_->HasHitTestMask()) + return local_bounds.Contains(local_point); - // Ensure we don't go smaller than our minimum bounds. - if (delegate_) { - const gfx::Size& min_size = delegate_->GetMinimumSize(); - actual_new_bounds.set_width( - std::max(min_size.width(), actual_new_bounds.width())); - actual_new_bounds.set_height( - std::max(min_size.height(), actual_new_bounds.height())); - } + gfx::Path mask; + delegate_->GetHitTestMask(&mask); + SkRegion clip_region; + clip_region.setRect(local_bounds.x(), local_bounds.y(), + local_bounds.width(), local_bounds.height()); + SkRegion mask_region; + return mask_region.setPath(mask, clip_region) && + mask_region.contains(local_point.x(), local_point.y()); +} + +void Window::SetBoundsInternal(const gfx::Rect& new_bounds) { + gfx::Rect actual_new_bounds(new_bounds); gfx::Rect old_bounds = GetTargetBounds(); // Always need to set the layer's bounds -- even if it is to the same thing. // This may cause important side effects such as stopping animation. - if (!layer_) { + if (!layer()) { const gfx::Vector2d origin_delta = new_bounds.OffsetFromOrigin() - bounds_.OffsetFromOrigin(); bounds_ = new_bounds; OffsetLayerBounds(origin_delta); } else { - if (parent_ && !parent_->layer_) { + if (parent_ && !parent_->layer()) { gfx::Vector2d offset; const aura::Window* ancestor_with_layer = parent_->GetAncestorWithLayer(&offset); if (ancestor_with_layer) actual_new_bounds.Offset(offset); } - layer_->SetBounds(actual_new_bounds); + layer()->SetBounds(actual_new_bounds); } // If we are currently not the layer's delegate, we will not get bounds // changed notification from the layer (this typically happens after animating // hidden). We must notify ourselves. - if (!layer_ || layer_->delegate() != this) - OnWindowBoundsChanged(old_bounds, ContainsMouse()); + if (!layer() || layer()->delegate() != this) + OnWindowBoundsChanged(old_bounds); } void Window::SetVisible(bool visible) { - if ((layer_ && visible == layer_->GetTargetVisibility()) || - (!layer_ && visible == visible_)) + if ((layer() && visible == layer()->GetTargetVisibility()) || + (!layer() && visible == visible_)) return; // No change. FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowVisibilityChanging(this, visible)); - WindowEventDispatcher* dispatcher = GetDispatcher(); - if (dispatcher) - dispatcher->DispatchMouseExitToHidingWindow(this); - client::VisibilityClient* visibility_client = client::GetVisibilityClient(this); if (visibility_client) visibility_client->UpdateLayerVisibility(this, visible); - else if (layer_) - layer_->SetVisible(visible); + else if (layer()) + layer()->SetVisible(visible); visible_ = visible; SchedulePaint(); if (parent_ && parent_->layout_manager_) @@ -994,9 +928,6 @@ void Window::SetVisible(bool visible) { delegate_->OnWindowTargetVisibilityChanged(visible); NotifyWindowVisibilityChanged(this, visible); - - if (dispatcher) - dispatcher->OnWindowVisibilityChanged(this, visible); } void Window::SchedulePaint() { @@ -1012,9 +943,10 @@ void Window::Paint(gfx::Canvas* canvas) { void Window::PaintLayerlessChildren(gfx::Canvas* canvas) { for (size_t i = 0, count = children_.size(); i < count; ++i) { Window* child = children_[i]; - if (!child->layer_ && child->visible_) { + if (!child->layer() && child->visible_) { gfx::ScopedCanvas scoped_canvas(canvas); - if (canvas->ClipRect(child->bounds())) { + canvas->ClipRect(child->bounds()); + if (!canvas->IsClipEmpty()) { canvas->Translate(child->bounds().OffsetFromOrigin()); child->Paint(canvas); } @@ -1083,15 +1015,12 @@ void Window::RemoveChildImpl(Window* child, Window* new_parent) { FOR_EACH_OBSERVER(WindowObserver, observers_, OnWillRemoveWindow(child)); Window* root_window = child->GetRootWindow(); Window* new_root_window = new_parent ? new_parent->GetRootWindow() : NULL; - if (root_window && root_window != new_root_window) { - root_window->GetDispatcher()->OnWindowRemovedFromRootWindow( - child, new_root_window); - child->NotifyRemovingFromRootWindow(); - } + if (root_window && root_window != new_root_window) + child->NotifyRemovingFromRootWindow(new_root_window); gfx::Vector2d offset; GetAncestorWithLayer(&offset); - child->UnparentLayers(!layer_, offset); + child->UnparentLayers(!layer(), offset); child->parent_ = NULL; Windows::iterator i = std::find(children_.begin(), children_.end(), child); DCHECK(i != children_.end()); @@ -1103,7 +1032,7 @@ void Window::RemoveChildImpl(Window* child, Window* new_parent) { void Window::UnparentLayers(bool has_layerless_ancestor, const gfx::Vector2d& offset) { - if (!layer_) { + if (!layer()) { const gfx::Vector2d new_offset = offset + bounds().OffsetFromOrigin(); for (size_t i = 0; i < children_.size(); ++i) { children_[i]->UnparentLayers(true, new_offset); @@ -1112,14 +1041,14 @@ void Window::UnparentLayers(bool has_layerless_ancestor, // Only remove the layer if we still own it. Someone else may have acquired // ownership of it via AcquireLayer() and may expect the hierarchy to go // unchanged as the Window is destroyed. - if (layer_owner_) { - if (layer_->parent()) - layer_->parent()->Remove(layer_); + if (OwnsLayer()) { + if (layer()->parent()) + layer()->parent()->Remove(layer()); if (has_layerless_ancestor) { const gfx::Rect real_bounds(bounds_); - gfx::Rect layer_bounds(layer_->bounds()); + gfx::Rect layer_bounds(layer()->bounds()); layer_bounds.Offset(-offset); - layer_->SetBounds(layer_bounds); + layer()->SetBounds(layer_bounds); bounds_ = real_bounds; } } @@ -1128,7 +1057,7 @@ void Window::UnparentLayers(bool has_layerless_ancestor, void Window::ReparentLayers(ui::Layer* parent_layer, const gfx::Vector2d& offset) { - if (!layer_) { + if (!layer()) { for (size_t i = 0; i < children_.size(); ++i) { children_[i]->ReparentLayers( parent_layer, @@ -1136,22 +1065,22 @@ void Window::ReparentLayers(ui::Layer* parent_layer, } } else { const gfx::Rect real_bounds(bounds()); - parent_layer->Add(layer_); - gfx::Rect layer_bounds(layer_->bounds().size()); + parent_layer->Add(layer()); + gfx::Rect layer_bounds(layer()->bounds().size()); layer_bounds += offset; - layer_->SetBounds(layer_bounds); + layer()->SetBounds(layer_bounds); bounds_ = real_bounds; } } void Window::OffsetLayerBounds(const gfx::Vector2d& offset) { - if (!layer_) { + if (!layer()) { for (size_t i = 0; i < children_.size(); ++i) children_[i]->OffsetLayerBounds(offset); } else { - gfx::Rect layer_bounds(layer_->bounds()); + gfx::Rect layer_bounds(layer()->bounds()); layer_bounds += offset; - layer_->SetBounds(layer_bounds); + layer()->SetBounds(layer_bounds); } } @@ -1160,34 +1089,6 @@ void Window::OnParentChanged() { WindowObserver, observers_, OnWindowParentChanged(this, parent_)); } -bool Window::HasTransientAncestor(const Window* ancestor) const { - if (transient_parent_ == ancestor) - return true; - return transient_parent_ ? - transient_parent_->HasTransientAncestor(ancestor) : false; -} - -void Window::SkipNullDelegatesForStacking(StackDirection direction, - Window** target) const { - DCHECK_EQ(this, (*target)->parent()); - size_t target_i = - std::find(children_.begin(), children_.end(), *target) - - children_.begin(); - - // By convention we don't stack on top of windows with layers with NULL - // delegates. Walk backward to find a valid target window. - // See tests WindowTest.StackingMadrigal and StackOverClosingTransient - // for an explanation of this. - while (target_i > 0) { - const size_t index = direction == STACK_ABOVE ? target_i : target_i - 1; - if (!children_[index]->layer_ || - children_[index]->layer_->delegate() != NULL) - break; - --target_i; - } - *target = children_[target_i]; -} - void Window::StackChildRelativeTo(Window* child, Window* target, StackDirection direction) { @@ -1199,47 +1100,10 @@ void Window::StackChildRelativeTo(Window* child, client::WindowStackingClient* stacking_client = client::GetWindowStackingClient(); - if (stacking_client) - stacking_client->AdjustStacking(&child, &target, &direction); - - SkipNullDelegatesForStacking(direction, &target); - - // If we couldn't find a valid target position, don't move anything. - if (direction == STACK_ABOVE && - (target->layer_ && target->layer_->delegate() == NULL)) + if (stacking_client && + !stacking_client->AdjustStacking(&child, &target, &direction)) return; - // Don't try to stack a child above itself. - if (child == target) - return; - - // Move the child. - StackChildRelativeToImpl(child, target, direction); - - // Stack any transient children that share the same parent to be in front of - // 'child'. Preserve the existing stacking order by iterating in the order - // those children appear in children_ array. - Window* last_transient = child; - Windows children(children_); - for (Windows::iterator it = children.begin(); it != children.end(); ++it) { - Window* transient_child = *it; - if (transient_child != last_transient && - transient_child->HasTransientAncestor(child)) { - StackChildRelativeToImpl(transient_child, last_transient, STACK_ABOVE); - last_transient = transient_child; - } - } -} - -void Window::StackChildRelativeToImpl(Window* child, - Window* target, - StackDirection direction) { - DCHECK_NE(child, target); - DCHECK(child); - DCHECK(target); - DCHECK_EQ(this, child->parent()); - DCHECK_EQ(this, target->parent()); - const size_t child_i = std::find(children_.begin(), children_.end(), child) - children_.begin(); const size_t target_i = @@ -1271,11 +1135,11 @@ void Window::StackChildLayerRelativeTo(Window* child, if (!ancestor_layer) return; - if (child->layer_ && target->layer_) { + if (child->layer() && target->layer()) { if (direction == STACK_ABOVE) - ancestor_layer->StackAbove(child->layer_, target->layer_); + ancestor_layer->StackAbove(child->layer(), target->layer()); else - ancestor_layer->StackBelow(child->layer_, target->layer_); + ancestor_layer->StackBelow(child->layer(), target->layer()); return; } typedef std::vector<ui::Layer*> Layers; @@ -1295,8 +1159,8 @@ void Window::StackChildLayerRelativeTo(Window* child, if (!target_layer) { if (direction == STACK_ABOVE) { - for (Layers::const_reverse_iterator i = layers.rbegin(); - i != layers.rend(); ++i) { + for (Layers::const_reverse_iterator i = layers.rbegin(), + rend = layers.rend(); i != rend; ++i) { ancestor_layer->StackAtBottom(*i); } } else { @@ -1307,8 +1171,8 @@ void Window::StackChildLayerRelativeTo(Window* child, } if (direction == STACK_ABOVE) { - for (Layers::const_reverse_iterator i = layers.rbegin(); - i != layers.rend(); ++i) { + for (Layers::const_reverse_iterator i = layers.rbegin(), + rend = layers.rend(); i != rend; ++i) { ancestor_layer->StackAbove(*i, target_layer); } } else { @@ -1321,12 +1185,12 @@ void Window::OnStackingChanged() { FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowStackingChanged(this)); } -void Window::NotifyRemovingFromRootWindow() { +void Window::NotifyRemovingFromRootWindow(Window* new_root) { FOR_EACH_OBSERVER(WindowObserver, observers_, - OnWindowRemovingFromRootWindow(this)); + OnWindowRemovingFromRootWindow(this, new_root)); for (Window::Windows::const_iterator it = children_.begin(); it != children_.end(); ++it) { - (*it)->NotifyRemovingFromRootWindow(); + (*it)->NotifyRemovingFromRootWindow(new_root); } } @@ -1443,11 +1307,10 @@ void Window::NotifyWindowVisibilityChangedUp(aura::Window* target, } } -void Window::OnWindowBoundsChanged(const gfx::Rect& old_bounds, - bool contained_mouse) { - if (layer_) { - bounds_ = layer_->bounds(); - if (parent_ && !parent_->layer_) { +void Window::OnWindowBoundsChanged(const gfx::Rect& old_bounds) { + if (layer()) { + bounds_ = layer()->bounds(); + if (parent_ && !parent_->layer()) { gfx::Vector2d offset; aura::Window* ancestor_with_layer = parent_->GetAncestorWithLayer(&offset); @@ -1463,9 +1326,19 @@ void Window::OnWindowBoundsChanged(const gfx::Rect& old_bounds, FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowBoundsChanged(this, old_bounds, bounds())); - WindowEventDispatcher* dispatcher = GetDispatcher(); - if (dispatcher) - dispatcher->OnWindowBoundsChanged(this, contained_mouse); +} + +bool Window::CleanupGestureState() { + bool state_modified = false; + state_modified |= ui::GestureRecognizer::Get()->CancelActiveTouches(this); + state_modified |= + ui::GestureRecognizer::Get()->CleanupStateForConsumer(this); + for (Window::Windows::iterator iter = children_.begin(); + iter != children_.end(); + ++iter) { + state_modified |= (*iter)->CleanupGestureState(); + } + return state_modified; } void Window::OnPaintLayer(gfx::Canvas* canvas) { @@ -1474,7 +1347,7 @@ void Window::OnPaintLayer(gfx::Canvas* canvas) { base::Closure Window::PrepareForLayerBoundsChange() { return base::Bind(&Window::OnWindowBoundsChanged, base::Unretained(this), - bounds(), ContainsMouse()); + bounds()); } bool Window::CanAcceptEvent(const ui::Event& event) { @@ -1498,13 +1371,14 @@ bool Window::CanAcceptEvent(const ui::Event& event) { return true; // For located events (i.e. mouse, touch etc.), an assumption is made that - // windows that don't have a delegate cannot process the event (see more in - // GetWindowForPoint()). This assumption is not made for key events. - return event.IsKeyEvent() || delegate_; + // windows that don't have a default event-handler cannot process the event + // (see more in GetWindowForPoint()). This assumption is not made for key + // events. + return event.IsKeyEvent() || target_handler(); } ui::EventTarget* Window::GetParentTarget() { - if (dispatcher_) { + if (IsRootWindow()) { return client::GetEventClient(this) ? client::GetEventClient(this)->GetToplevelEventTarget() : Env::GetInstance(); @@ -1527,9 +1401,9 @@ void Window::ConvertEventToTarget(ui::EventTarget* target, static_cast<Window*>(target)); } -void Window::UpdateLayerName(const std::string& name) { +void Window::UpdateLayerName() { #if !defined(NDEBUG) - DCHECK(layer_); + DCHECK(layer()); std::string layer_name(name_); if (layer_name.empty()) @@ -1538,23 +1412,23 @@ void Window::UpdateLayerName(const std::string& name) { if (id_ != -1) layer_name += " " + base::IntToString(id_); - layer_->set_name(layer_name); + layer()->set_name(layer_name); #endif } bool Window::ContainsMouse() { bool contains_mouse = false; if (IsVisible()) { - WindowEventDispatcher* dispatcher = GetDispatcher(); - contains_mouse = dispatcher && - ContainsPointInRoot(dispatcher->GetLastMouseLocationInRoot()); + WindowTreeHost* host = GetHost(); + contains_mouse = host && + ContainsPointInRoot(host->dispatcher()->GetLastMouseLocationInRoot()); } return contains_mouse; } const Window* Window::GetAncestorWithLayer(gfx::Vector2d* offset) const { for (const aura::Window* window = this; window; window = window->parent()) { - if (window->layer_) + if (window->layer()) return window; if (offset) *offset += window->bounds().OffsetFromOrigin(); diff --git a/chromium/ui/aura/window.h b/chromium/ui/aura/window.h index d69d88e0089..bc970f4a1f5 100644 --- a/chromium/ui/aura/window.h +++ b/chromium/ui/aura/window.h @@ -15,13 +15,11 @@ #include "base/observer_list.h" #include "base/strings/string16.h" #include "ui/aura/aura_export.h" -#include "ui/aura/client/window_types.h" #include "ui/aura/window_layer_type.h" #include "ui/aura/window_observer.h" #include "ui/compositor/layer_animator.h" #include "ui/compositor/layer_delegate.h" #include "ui/compositor/layer_owner.h" -#include "ui/compositor/layer_type.h" #include "ui/events/event_constants.h" #include "ui/events/event_target.h" #include "ui/events/event_targeter.h" @@ -29,6 +27,7 @@ #include "ui/gfx/insets.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/rect.h" +#include "ui/wm/public/window_types.h" namespace gfx { class Display; @@ -45,12 +44,9 @@ class Texture; namespace aura { class LayoutManager; -class RootWindow; class WindowDelegate; class WindowObserver; - -// TODO(beng): remove once RootWindow is renamed. -typedef RootWindow WindowEventDispatcher; +class WindowTreeHost; // Defined in window_property.h (which we do not include) template<typename T> @@ -80,17 +76,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate, virtual ~Window(); // Initializes the window. This creates the window's layer. - void Init(ui::LayerType layer_type); - - // TODO(sky): replace other Init() with this once m32 is more baked. - void InitWithWindowLayerType(WindowLayerType layer_type); - - // Creates a new layer for the window. Erases the layer-owned bounds, so the - // caller may wish to set new bounds and other state on the window/layer. - // Returns the old layer, which can be used for animations. Caller owns the - // memory for the returned layer and must delete it when animation completes. - // Returns NULL and does not recreate layer if window does not own its layer. - ui::Layer* RecreateLayer() WARN_UNUSED_RESULT; + void Init(WindowLayerType layer_type); void set_owned_by_parent(bool owned_by_parent) { owned_by_parent_ = owned_by_parent; @@ -100,8 +86,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // A type is used to identify a class of Windows and customize behavior such // as event handling and parenting. This field should only be consumed by the // shell -- Aura itself shouldn't contain type-specific logic. - client::WindowType type() const { return type_; } - void SetType(client::WindowType type); + ui::wm::WindowType type() const { return type_; } + void SetType(ui::wm::WindowType type); int id() const { return id_; } void set_id(int id) { id_ = id; } @@ -115,6 +101,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate, bool transparent() const { return transparent_; } void SetTransparent(bool transparent); + // See description in Layer::SetFillsBoundsCompletely. + void SetFillsBoundsCompletely(bool fills_bounds); + WindowDelegate* delegate() { return delegate_; } const WindowDelegate* delegate() const { return delegate_; } @@ -127,15 +116,13 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // defined as the Window that has a dispatcher. These functions return NULL if // the Window is contained in a hierarchy that does not have a dispatcher at // its root. - virtual Window* GetRootWindow(); - virtual const Window* GetRootWindow() const; + Window* GetRootWindow(); + const Window* GetRootWindow() const; - WindowEventDispatcher* GetDispatcher(); - const WindowEventDispatcher* GetDispatcher() const; - void set_dispatcher(WindowEventDispatcher* dispatcher) { - dispatcher_ = dispatcher; - } - bool HasDispatcher() const { return !!dispatcher_; } + WindowTreeHost* GetHost(); + const WindowTreeHost* GetHost() const; + void set_host(WindowTreeHost* host) { host_ = host; } + bool IsRootWindow() const { return !!host_; } // The Window does not own this object. void set_user_data(void* user_data) { user_data_ = user_data; } @@ -160,16 +147,17 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // |aura::client::ScreenPositionClient| interface. gfx::Rect GetBoundsInScreen() const; - virtual void SetTransform(const gfx::Transform& transform); + void SetTransform(const gfx::Transform& transform); // Assigns a LayoutManager to size and place child windows. // The Window takes ownership of the LayoutManager. void SetLayoutManager(LayoutManager* layout_manager); LayoutManager* layout_manager() { return layout_manager_.get(); } - void set_event_targeter(scoped_ptr<ui::EventTargeter> targeter) { - targeter_ = targeter.Pass(); - } + // Sets a new event-targeter for the window, and returns the previous + // event-targeter. + scoped_ptr<ui::EventTargeter> SetEventTargeter( + scoped_ptr<ui::EventTargeter> targeter); // Changes the bounds of the window. If present, the window's parent's // LayoutManager may adjust the bounds. @@ -211,22 +199,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Returns true if this Window contains |other| somewhere in its children. bool Contains(const Window* other) const; - // Adds or removes |child| as a transient child of this window. Transient - // children get the following behavior: - // . The transient parent destroys any transient children when it is - // destroyed. This means a transient child is destroyed if either its parent - // or transient parent is destroyed. - // . If a transient child and its transient parent share the same parent, then - // transient children are always ordered above the transient parent. - // Transient windows are typically used for popups and menus. - void AddTransientChild(Window* child); - void RemoveTransientChild(Window* child); - - const Windows& transient_children() const { return transient_children_; } - - Window* transient_parent() { return transient_parent_; } - const Window* transient_parent() const { return transient_parent_; } - // Retrieves the first-level child with the specified id, or NULL if no first- // level child is found matching |id|. Window* GetChildById(int id); @@ -238,19 +210,16 @@ class AURA_EXPORT Window : public ui::LayerDelegate, static void ConvertPointToTarget(const Window* source, const Window* target, gfx::Point* point); + static void ConvertRectToTarget(const Window* source, + const Window* target, + gfx::Rect* rect); // Moves the cursor to the specified location relative to the window. - virtual void MoveCursorTo(const gfx::Point& point_in_window); + void MoveCursorTo(const gfx::Point& point_in_window); // Returns the cursor for the specified point, in window coordinates. gfx::NativeCursor GetCursor(const gfx::Point& point) const; - // Sets an 'event filter' for the window. An 'event filter' for a Window is - // a pre-target event handler, where the window owns the handler. A window - // can have only one such event filter. Setting a new filter removes and - // destroys any previously installed filter. - void SetEventFilter(ui::EventHandler* event_filter); - // Add/remove observer. void AddObserver(WindowObserver* observer); void RemoveObserver(WindowObserver* observer); @@ -259,24 +228,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate, void set_ignore_events(bool ignore_events) { ignore_events_ = ignore_events; } bool ignore_events() const { return ignore_events_; } - // Sets the window to grab hits for mouse and touch to an area extending - // -|mouse_insets| and -|touch_insets| pixels outside its bounds. This can be - // used to create an invisible non-client area, for example if your windows - // have no visible frames but still need to have resize edges. - void SetHitTestBoundsOverrideOuter(const gfx::Insets& mouse_insets, - const gfx::Insets& touch_insets) { - hit_test_bounds_override_outer_mouse_ = mouse_insets; - hit_test_bounds_override_outer_touch_ = touch_insets; - } - - gfx::Insets hit_test_bounds_override_outer_touch() const { - return hit_test_bounds_override_outer_touch_; - } - - gfx::Insets hit_test_bounds_override_outer_mouse() const { - return hit_test_bounds_override_outer_mouse_; - } - // Sets the window to grab hits for an area extending |insets| pixels inside // its bounds (even if that inner region overlaps a child window). This can be // used to create an invisible non-client area that overlaps the client area. @@ -296,13 +247,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // within this Window's bounds. bool ContainsPoint(const gfx::Point& local_point) const; - // Returns true if the mouse pointer at relative-to-this-Window's-origin - // |local_point| can trigger an event for this Window. - // TODO(beng): A Window can supply a hit-test mask to cause some portions of - // itself to not trigger events, causing the events to fall through to the - // Window behind. - bool HitTest(const gfx::Point& local_point); - // Returns the Window that most closely encloses |local_point| for the // purposes of event targeting. Window* GetEventHandlerForPoint(const gfx::Point& local_point); @@ -322,10 +266,10 @@ class AURA_EXPORT Window : public ui::LayerDelegate, bool HasFocus() const; // Returns true if the Window can be focused. - virtual bool CanFocus() const; + bool CanFocus() const; // Returns true if the Window can receive events. - virtual bool CanReceiveEvents() const; + bool CanReceiveEvents() const; // Does a capture on the window. This does nothing if the window isn't showing // (VISIBILITY_SHOWN) or isn't contained in a valid window hierarchy. @@ -376,6 +320,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate, void PrintWindowHierarchy(int depth) const; #endif + // Returns true if there was state needing to be cleaned up. + bool CleanupGestureState(); + protected: // Deletes (or removes if not owned by parent) all child windows. Intended for // use from the destructor. @@ -384,7 +331,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate, private: friend class test::WindowTestApi; friend class LayoutManager; - friend class RootWindow; friend class WindowTargeter; // Called by the public {Set,Get,Clear}Property functions. @@ -395,6 +341,13 @@ class AURA_EXPORT Window : public ui::LayerDelegate, int64 default_value); int64 GetPropertyInternal(const void* key, int64 default_value) const; + // Returns true if the mouse pointer at relative-to-this-Window's-origin + // |local_point| can trigger an event for this Window. + // TODO(beng): A Window can supply a hit-test mask to cause some portions of + // itself to not trigger events, causing the events to fall through to the + // Window behind. + bool HitTest(const gfx::Point& local_point); + // Changes the bounds of the window without condition. void SetBoundsInternal(const gfx::Rect& new_bounds); @@ -445,26 +398,12 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Called when this window's parent has changed. void OnParentChanged(); - // Returns true when |ancestor| is a transient ancestor of |this|. - bool HasTransientAncestor(const Window* ancestor) const; - - // Adjusts |target| so that we don't attempt to stack on top of a window with - // a NULL delegate. See implementation for details. - void SkipNullDelegatesForStacking(StackDirection direction, - Window** target) const; - - // Determines the real location for stacking |child| and invokes - // StackChildRelativeToImpl(). + // The various stacking functions call into this to do the actual stacking. void StackChildRelativeTo(Window* child, Window* target, StackDirection direction); - // Implementation of StackChildRelativeTo(). - void StackChildRelativeToImpl(Window* child, - Window* target, - StackDirection direction); - - // Invoked from StackChildRelativeToImpl() to stack the layers appropriately + // Invoked from StackChildRelativeTo() to stack the layers appropriately // when stacking |child| relative to |target|. void StackChildLayerRelativeTo(Window* child, Window* target, @@ -475,7 +414,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Notifies observers registered with this Window (and its subtree) when the // Window has been added or is about to be removed from a RootWindow. - void NotifyRemovingFromRootWindow(); + void NotifyRemovingFromRootWindow(Window* new_root); void NotifyAddedToRootWindow(); // Methods implementing hierarchy change notifications. See WindowObserver for @@ -508,10 +447,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Invoked when the bounds of the window changes. This may be invoked directly // by us, or from the closure returned by PrepareForLayerBoundsChange() after - // the bounds of the layer has changed. |old_bounds| is the previous bounds, - // and |contained_mouse| is true if the mouse was previously within the - // window's bounds. - void OnWindowBoundsChanged(const gfx::Rect& old_bounds, bool contained_mouse); + // the bounds of the layer has changed. |old_bounds| is the previous bounds. + void OnWindowBoundsChanged(const gfx::Rect& old_bounds); // Overridden from ui::LayerDelegate: virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE; @@ -525,8 +462,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate, virtual void ConvertEventToTarget(ui::EventTarget* target, ui::LocatedEvent* event) OVERRIDE; - // Updates the layer name with a name based on the window's name and id. - void UpdateLayerName(const std::string& name); + // Updates the layer name based on the window's name and id. + void UpdateLayerName(); // Returns true if the mouse is currently within our bounds. bool ContainsMouse(); @@ -546,9 +483,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // is relative to the parent Window. gfx::Rect bounds_; - WindowEventDispatcher* dispatcher_; + WindowTreeHost* host_; - client::WindowType type_; + ui::wm::WindowType type_; // True if the Window is owned by its parent - i.e. it will be deleted by its // parent during its parents destruction. True is the default. @@ -562,11 +499,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Child windows. Topmost is last. Windows children_; - // Transient windows. - Windows transient_children_; - - Window* transient_parent_; - // The visibility state of the window as set by Show()/Hide(). This may differ // from the visibility of the underlying layer, which may remain visible after // the window is hidden (e.g. to animate its disappearance). @@ -580,7 +512,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Whether layer is initialized as non-opaque. bool transparent_; - scoped_ptr<ui::EventHandler> event_filter_; scoped_ptr<LayoutManager> layout_manager_; scoped_ptr<ui::EventTargeter> targeter_; @@ -589,9 +520,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate, // Makes the window pass all events through to any windows behind it. bool ignore_events_; - // See set_hit_test_outer_override(). - gfx::Insets hit_test_bounds_override_outer_mouse_; - gfx::Insets hit_test_bounds_override_outer_touch_; + // See set_hit_test_bounds_override_inner(). gfx::Insets hit_test_bounds_override_inner_; ObserverList<WindowObserver, true> observers_; diff --git a/chromium/ui/aura/window_delegate.h b/chromium/ui/aura/window_delegate.h index ff941ef95b3..90e978a39c2 100644 --- a/chromium/ui/aura/window_delegate.h +++ b/chromium/ui/aura/window_delegate.h @@ -73,13 +73,17 @@ class AURA_EXPORT WindowDelegate : public ui::EventHandler { // Called from Window's destructor before OnWindowDestroyed and before the // children have been destroyed and the window has been removed from its // parent. - virtual void OnWindowDestroying() = 0; + // This method takes the window because the delegate implementation may no + // longer have a route back to the window by the time this method is called. + virtual void OnWindowDestroying(Window* window) = 0; // Called when the Window has been destroyed (i.e. from its destructor). This // is called after OnWindowDestroying and after the children have been // deleted and the window has been removed from its parent. // The delegate can use this as an opportunity to delete itself if necessary. - virtual void OnWindowDestroyed() = 0; + // This method takes the window because the delegate implementation may no + // longer have a route back to the window by the time this method is called. + virtual void OnWindowDestroyed(Window* window) = 0; // Called when the TargetVisibility() of a Window changes. |visible| // corresponds to the target visibility of the window. See @@ -96,13 +100,6 @@ class AURA_EXPORT WindowDelegate : public ui::EventHandler { // above returns true. virtual void GetHitTestMask(gfx::Path* mask) const = 0; - // Called from RecreateLayer() after the new layer was created. old_layer is - // the layer that will be returned to the caller of RecreateLayer, new_layer - // will be the layer now used on the Window. The implementation only has to do - // anything if the layer has external content (SetExternalTexture / - // SetTextureMailbox / SetDelegatedFrame was called). - virtual void DidRecreateLayer(ui::Layer* old_layer, ui::Layer* new_layer) = 0; - protected: virtual ~WindowDelegate() {} }; diff --git a/chromium/ui/aura/window_event_dispatcher.cc b/chromium/ui/aura/window_event_dispatcher.cc new file mode 100644 index 00000000000..87d25b1cfd8 --- /dev/null +++ b/chromium/ui/aura/window_event_dispatcher.cc @@ -0,0 +1,861 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura/window_event_dispatcher.h" + +#include "base/bind.h" +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "ui/aura/client/capture_client.h" +#include "ui/aura/client/cursor_client.h" +#include "ui/aura/client/event_client.h" +#include "ui/aura/client/focus_client.h" +#include "ui/aura/client/screen_position_client.h" +#include "ui/aura/env.h" +#include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" +#include "ui/aura/window_targeter.h" +#include "ui/aura/window_tracker.h" +#include "ui/aura/window_tree_host.h" +#include "ui/base/hit_test.h" +#include "ui/compositor/dip_util.h" +#include "ui/events/event.h" +#include "ui/events/gestures/gesture_recognizer.h" +#include "ui/events/gestures/gesture_types.h" + +typedef ui::EventDispatchDetails DispatchDetails; + +namespace aura { + +namespace { + +// Returns true if |target| has a non-client (frame) component at |location|, +// in window coordinates. +bool IsNonClientLocation(Window* target, const gfx::Point& location) { + if (!target->delegate()) + return false; + int hit_test_code = target->delegate()->GetNonClientComponent(location); + return hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE; +} + +Window* ConsumerToWindow(ui::GestureConsumer* consumer) { + return consumer ? static_cast<Window*>(consumer) : NULL; +} + +void SetLastMouseLocation(const Window* root_window, + const gfx::Point& location_in_root) { + client::ScreenPositionClient* client = + client::GetScreenPositionClient(root_window); + if (client) { + gfx::Point location_in_screen = location_in_root; + client->ConvertPointToScreen(root_window, &location_in_screen); + Env::GetInstance()->set_last_mouse_location(location_in_screen); + } else { + Env::GetInstance()->set_last_mouse_location(location_in_root); + } +} + +bool IsEventCandidateForHold(const ui::Event& event) { + if (event.type() == ui::ET_TOUCH_MOVED) + return true; + if (event.type() == ui::ET_MOUSE_DRAGGED) + return true; + if (event.IsMouseEvent() && (event.flags() & ui::EF_IS_SYNTHESIZED)) + return true; + return false; +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// WindowEventDispatcher, public: + +WindowEventDispatcher::WindowEventDispatcher(WindowTreeHost* host) + : host_(host), + touch_ids_down_(0), + mouse_pressed_handler_(NULL), + mouse_moved_handler_(NULL), + event_dispatch_target_(NULL), + old_dispatch_target_(NULL), + synthesize_mouse_move_(false), + move_hold_count_(0), + dispatching_held_event_(false), + observer_manager_(this), + repost_event_factory_(this), + held_event_factory_(this) { + ui::GestureRecognizer::Get()->AddGestureEventHelper(this); + Env::GetInstance()->AddObserver(this); +} + +WindowEventDispatcher::~WindowEventDispatcher() { + TRACE_EVENT0("shutdown", "WindowEventDispatcher::Destructor"); + Env::GetInstance()->RemoveObserver(this); + ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this); +} + +void WindowEventDispatcher::RepostEvent(const ui::LocatedEvent& event) { + DCHECK(event.type() == ui::ET_MOUSE_PRESSED || + event.type() == ui::ET_GESTURE_TAP_DOWN); + // We allow for only one outstanding repostable event. This is used + // in exiting context menus. A dropped repost request is allowed. + if (event.type() == ui::ET_MOUSE_PRESSED) { + held_repostable_event_.reset( + new ui::MouseEvent( + static_cast<const ui::MouseEvent&>(event), + static_cast<aura::Window*>(event.target()), + window())); + base::MessageLoop::current()->PostNonNestableTask( + FROM_HERE, base::Bind( + base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents), + repost_event_factory_.GetWeakPtr())); + } else { + DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN); + held_repostable_event_.reset(); + // TODO(rbyers): Reposing of gestures is tricky to get + // right, so it's not yet supported. crbug.com/170987. + } +} + +void WindowEventDispatcher::OnMouseEventsEnableStateChanged(bool enabled) { + // Send entered / exited so that visual state can be updated to match + // mouse events state. + PostSynthesizeMouseMove(); + // TODO(mazda): Add code to disable mouse events when |enabled| == false. +} + +void WindowEventDispatcher::DispatchCancelModeEvent() { + ui::CancelModeEvent event; + Window* focused_window = client::GetFocusClient(window())->GetFocusedWindow(); + if (focused_window && !window()->Contains(focused_window)) + focused_window = NULL; + DispatchDetails details = + DispatchEvent(focused_window ? focused_window : window(), &event); + if (details.dispatcher_destroyed) + return; +} + +void WindowEventDispatcher::DispatchGestureEvent(ui::GestureEvent* event) { + DispatchDetails details = DispatchHeldEvents(); + if (details.dispatcher_destroyed) + return; + + Window* target = GetGestureTarget(event); + if (target) { + event->ConvertLocationToTarget(window(), target); + DispatchDetails details = DispatchEvent(target, event); + if (details.dispatcher_destroyed) + return; + } +} + +void WindowEventDispatcher::DispatchMouseExitAtPoint(const gfx::Point& point) { + ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE, + ui::EF_NONE); + DispatchDetails details = + DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED); + if (details.dispatcher_destroyed) + return; +} + +void WindowEventDispatcher::ProcessedTouchEvent(ui::TouchEvent* event, + Window* window, + ui::EventResult result) { + scoped_ptr<ui::GestureRecognizer::Gestures> gestures; + gestures.reset(ui::GestureRecognizer::Get()-> + ProcessTouchEventForGesture(*event, result, window)); + DispatchDetails details = ProcessGestures(gestures.get()); + if (details.dispatcher_destroyed) + return; +} + +void WindowEventDispatcher::HoldPointerMoves() { + if (!move_hold_count_) + held_event_factory_.InvalidateWeakPtrs(); + ++move_hold_count_; + TRACE_EVENT_ASYNC_BEGIN0("ui", "WindowEventDispatcher::HoldPointerMoves", + this); +} + +void WindowEventDispatcher::ReleasePointerMoves() { + --move_hold_count_; + DCHECK_GE(move_hold_count_, 0); + if (!move_hold_count_ && held_move_event_) { + // We don't want to call DispatchHeldEvents directly, because this might be + // called from a deep stack while another event, in which case dispatching + // another one may not be safe/expected. Instead we post a task, that we + // may cancel if HoldPointerMoves is called again before it executes. + base::MessageLoop::current()->PostNonNestableTask( + FROM_HERE, base::Bind( + base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents), + held_event_factory_.GetWeakPtr())); + } + TRACE_EVENT_ASYNC_END0("ui", "WindowEventDispatcher::HoldPointerMoves", this); +} + +gfx::Point WindowEventDispatcher::GetLastMouseLocationInRoot() const { + gfx::Point location = Env::GetInstance()->last_mouse_location(); + client::ScreenPositionClient* client = + client::GetScreenPositionClient(window()); + if (client) + client->ConvertPointFromScreen(window(), &location); + return location; +} + +void WindowEventDispatcher::OnHostLostMouseGrab() { + mouse_pressed_handler_ = NULL; + mouse_moved_handler_ = NULL; +} + +void WindowEventDispatcher::OnCursorMovedToRootLocation( + const gfx::Point& root_location) { + SetLastMouseLocation(window(), root_location); + synthesize_mouse_move_ = false; +} + +void WindowEventDispatcher::OnPostNotifiedWindowDestroying(Window* window) { + OnWindowHidden(window, WINDOW_DESTROYED); +} + +//////////////////////////////////////////////////////////////////////////////// +// WindowEventDispatcher, private: + +Window* WindowEventDispatcher::window() { + return host_->window(); +} + +const Window* WindowEventDispatcher::window() const { + return host_->window(); +} + +void WindowEventDispatcher::TransformEventForDeviceScaleFactor( + ui::LocatedEvent* event) { + event->UpdateForRootTransform(host_->GetInverseRootTransform()); +} + +void WindowEventDispatcher::DispatchMouseExitToHidingWindow(Window* window) { + // The mouse capture is intentionally ignored. Think that a mouse enters + // to a window, the window sets the capture, the mouse exits the window, + // and then it releases the capture. In that case OnMouseExited won't + // be called. So it is natural not to emit OnMouseExited even though + // |window| is the capture window. + gfx::Point last_mouse_location = GetLastMouseLocationInRoot(); + if (window->Contains(mouse_moved_handler_) && + window->ContainsPointInRoot(last_mouse_location)) + DispatchMouseExitAtPoint(last_mouse_location); +} + +ui::EventDispatchDetails WindowEventDispatcher::DispatchMouseEnterOrExit( + const ui::MouseEvent& event, + ui::EventType type) { + if (event.type() != ui::ET_MOUSE_CAPTURE_CHANGED && + !(event.flags() & ui::EF_IS_SYNTHESIZED)) { + SetLastMouseLocation(window(), event.root_location()); + } + + if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate() || + !window()->Contains(mouse_moved_handler_)) + return DispatchDetails(); + + // |event| may be an event in the process of being dispatched to a target (in + // which case its locations will be in the event's target's coordinate + // system), or a synthetic event created in root-window (in which case, the + // event's target will be NULL, and the event will be in the root-window's + // coordinate system. + aura::Window* target = static_cast<Window*>(event.target()); + if (!target) + target = window(); + ui::MouseEvent translated_event(event, + target, + mouse_moved_handler_, + type, + event.flags() | ui::EF_IS_SYNTHESIZED); + return DispatchEvent(mouse_moved_handler_, &translated_event); +} + +ui::EventDispatchDetails WindowEventDispatcher::ProcessGestures( + ui::GestureRecognizer::Gestures* gestures) { + DispatchDetails details; + if (!gestures || gestures->empty()) + return details; + + Window* target = GetGestureTarget(gestures->get().at(0)); + for (size_t i = 0; i < gestures->size(); ++i) { + ui::GestureEvent* event = gestures->get().at(i); + event->ConvertLocationToTarget(window(), target); + details = DispatchEvent(target, event); + if (details.dispatcher_destroyed || details.target_destroyed) + break; + } + return details; +} + +void WindowEventDispatcher::OnWindowHidden(Window* invisible, + WindowHiddenReason reason) { + // If the window the mouse was pressed in becomes invisible, it should no + // longer receive mouse events. + if (invisible->Contains(mouse_pressed_handler_)) + mouse_pressed_handler_ = NULL; + if (invisible->Contains(mouse_moved_handler_)) + mouse_moved_handler_ = NULL; + + // If events are being dispatched from a nested message-loop, and the target + // of the outer loop is hidden or moved to another dispatcher during + // dispatching events in the inner loop, then reset the target for the outer + // loop. + if (invisible->Contains(old_dispatch_target_)) + old_dispatch_target_ = NULL; + + invisible->CleanupGestureState(); + + // Do not clear the capture, and the |event_dispatch_target_| if the + // window is moving across hosts, because the target itself is actually still + // visible and clearing them stops further event processing, which can cause + // unexpected behaviors. See crbug.com/157583 + if (reason != WINDOW_MOVING) { + // We don't ask |invisible| here, because invisible may have been removed + // from the window hierarchy already by the time this function is called + // (OnWindowDestroyed). + client::CaptureClient* capture_client = + client::GetCaptureClient(host_->window()); + Window* capture_window = + capture_client ? capture_client->GetCaptureWindow() : NULL; + + if (invisible->Contains(event_dispatch_target_)) + event_dispatch_target_ = NULL; + + // If the ancestor of the capture window is hidden, release the capture. + // Note that this may delete the window so do not use capture_window + // after this. + if (invisible->Contains(capture_window) && invisible != window()) + capture_window->ReleaseCapture(); + } +} + +Window* WindowEventDispatcher::GetGestureTarget(ui::GestureEvent* event) { + Window* target = NULL; + if (!event->IsEndingEvent()) { + // The window that received the start event (e.g. scroll begin) needs to + // receive the end event (e.g. scroll end). + target = client::GetCaptureWindow(window()); + } + if (!target) { + target = ConsumerToWindow( + ui::GestureRecognizer::Get()->GetTargetForGestureEvent(*event)); + } + + return target; +} + +//////////////////////////////////////////////////////////////////////////////// +// WindowEventDispatcher, aura::client::CaptureDelegate implementation: + +void WindowEventDispatcher::UpdateCapture(Window* old_capture, + Window* new_capture) { + // |mouse_moved_handler_| may have been set to a Window in a different root + // (see below). Clear it here to ensure we don't end up referencing a stale + // Window. + if (mouse_moved_handler_ && !window()->Contains(mouse_moved_handler_)) + mouse_moved_handler_ = NULL; + + if (old_capture && old_capture->GetRootWindow() == window() && + old_capture->delegate()) { + // Send a capture changed event with bogus location data. + ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(), + gfx::Point(), 0, 0); + + DispatchDetails details = DispatchEvent(old_capture, &event); + if (details.dispatcher_destroyed) + return; + + old_capture->delegate()->OnCaptureLost(); + } + + if (new_capture) { + // Make all subsequent mouse events go to the capture window. We shouldn't + // need to send an event here as OnCaptureLost() should take care of that. + if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown()) + mouse_moved_handler_ = new_capture; + } else { + // Make sure mouse_moved_handler gets updated. + DispatchDetails details = SynthesizeMouseMoveEvent(); + if (details.dispatcher_destroyed) + return; + } + mouse_pressed_handler_ = NULL; +} + +void WindowEventDispatcher::OnOtherRootGotCapture() { + mouse_moved_handler_ = NULL; + mouse_pressed_handler_ = NULL; +} + +void WindowEventDispatcher::SetNativeCapture() { + host_->SetCapture(); +} + +void WindowEventDispatcher::ReleaseNativeCapture() { + host_->ReleaseCapture(); +} + +//////////////////////////////////////////////////////////////////////////////// +// WindowEventDispatcher, ui::EventProcessor implementation: +ui::EventTarget* WindowEventDispatcher::GetRootTarget() { + return window(); +} + +void WindowEventDispatcher::PrepareEventForDispatch(ui::Event* event) { + if (dispatching_held_event_) { + // The held events are already in |window()|'s coordinate system. So it is + // not necessary to apply the transform to convert from the host's + // coordinate system to |window()|'s coordinate system. + return; + } + if (event->IsMouseEvent() || + event->IsScrollEvent() || + event->IsTouchEvent() || + event->IsGestureEvent()) { + TransformEventForDeviceScaleFactor(static_cast<ui::LocatedEvent*>(event)); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// WindowEventDispatcher, ui::EventDispatcherDelegate implementation: + +bool WindowEventDispatcher::CanDispatchToTarget(ui::EventTarget* target) { + return event_dispatch_target_ == target; +} + +ui::EventDispatchDetails WindowEventDispatcher::PreDispatchEvent( + ui::EventTarget* target, + ui::Event* event) { + Window* target_window = static_cast<Window*>(target); + CHECK(window()->Contains(target_window)); + + if (!dispatching_held_event_) { + bool can_be_held = IsEventCandidateForHold(*event); + if (!move_hold_count_ || !can_be_held) { + if (can_be_held) + held_move_event_.reset(); + DispatchDetails details = DispatchHeldEvents(); + if (details.dispatcher_destroyed || details.target_destroyed) + return details; + } + } + + if (event->IsMouseEvent()) { + PreDispatchMouseEvent(target_window, static_cast<ui::MouseEvent*>(event)); + } else if (event->IsScrollEvent()) { + PreDispatchLocatedEvent(target_window, + static_cast<ui::ScrollEvent*>(event)); + } else if (event->IsTouchEvent()) { + PreDispatchTouchEvent(target_window, static_cast<ui::TouchEvent*>(event)); + } + old_dispatch_target_ = event_dispatch_target_; + event_dispatch_target_ = static_cast<Window*>(target); + return DispatchDetails(); +} + +ui::EventDispatchDetails WindowEventDispatcher::PostDispatchEvent( + ui::EventTarget* target, + const ui::Event& event) { + DispatchDetails details; + if (!target || target != event_dispatch_target_) + details.target_destroyed = true; + event_dispatch_target_ = old_dispatch_target_; + old_dispatch_target_ = NULL; +#ifndef NDEBUG + DCHECK(!event_dispatch_target_ || window()->Contains(event_dispatch_target_)); +#endif + + if (event.IsTouchEvent() && !details.target_destroyed) { + // Do not let 'held' touch events contribute to any gestures unless it is + // being dispatched. + if (dispatching_held_event_ || !held_move_event_ || + !held_move_event_->IsTouchEvent()) { + ui::TouchEvent orig_event(static_cast<const ui::TouchEvent&>(event), + static_cast<Window*>(event.target()), window()); + // Get the list of GestureEvents from GestureRecognizer. + scoped_ptr<ui::GestureRecognizer::Gestures> gestures; + gestures.reset(ui::GestureRecognizer::Get()-> + ProcessTouchEventForGesture(orig_event, event.result(), + static_cast<Window*>(target))); + return ProcessGestures(gestures.get()); + } + } + + return details; +} + +//////////////////////////////////////////////////////////////////////////////// +// WindowEventDispatcher, ui::GestureEventHelper implementation: + +bool WindowEventDispatcher::CanDispatchToConsumer( + ui::GestureConsumer* consumer) { + Window* consumer_window = ConsumerToWindow(consumer); + return (consumer_window && consumer_window->GetRootWindow() == window()); +} + +void WindowEventDispatcher::DispatchCancelTouchEvent(ui::TouchEvent* event) { + DispatchDetails details = OnEventFromSource(event); + if (details.dispatcher_destroyed) + return; +} + +//////////////////////////////////////////////////////////////////////////////// +// WindowEventDispatcher, WindowObserver implementation: + +void WindowEventDispatcher::OnWindowDestroying(Window* window) { + if (!host_->window()->Contains(window)) + return; + + DispatchMouseExitToHidingWindow(window); + SynthesizeMouseMoveAfterChangeToWindow(window); +} + +void WindowEventDispatcher::OnWindowDestroyed(Window* window) { + // We observe all windows regardless of what root Window (if any) they're + // attached to. + observer_manager_.Remove(window); +} + +void WindowEventDispatcher::OnWindowAddedToRootWindow(Window* attached) { + if (!observer_manager_.IsObserving(attached)) + observer_manager_.Add(attached); + + if (!host_->window()->Contains(attached)) + return; + + SynthesizeMouseMoveAfterChangeToWindow(attached); +} + +void WindowEventDispatcher::OnWindowRemovingFromRootWindow(Window* detached, + Window* new_root) { + if (!host_->window()->Contains(detached)) + return; + + DCHECK(client::GetCaptureWindow(window()) != window()); + + DispatchMouseExitToHidingWindow(detached); + SynthesizeMouseMoveAfterChangeToWindow(detached); + + // Hiding the window releases capture which can implicitly destroy the window + // so the window may no longer be valid after this call. + OnWindowHidden(detached, new_root ? WINDOW_MOVING : WINDOW_HIDDEN); +} + +void WindowEventDispatcher::OnWindowVisibilityChanging(Window* window, + bool visible) { + if (!host_->window()->Contains(window)) + return; + + DispatchMouseExitToHidingWindow(window); +} + +void WindowEventDispatcher::OnWindowVisibilityChanged(Window* window, + bool visible) { + if (!host_->window()->Contains(window)) + return; + + if (window->ContainsPointInRoot(GetLastMouseLocationInRoot())) + PostSynthesizeMouseMove(); + + // Hiding the window releases capture which can implicitly destroy the window + // so the window may no longer be valid after this call. + if (!visible) + OnWindowHidden(window, WINDOW_HIDDEN); +} + +void WindowEventDispatcher::OnWindowBoundsChanged(Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + if (!host_->window()->Contains(window)) + return; + + if (window == host_->window()) { + TRACE_EVENT1("ui", "WindowEventDispatcher::OnWindowBoundsChanged(root)", + "size", new_bounds.size().ToString()); + + DispatchDetails details = DispatchHeldEvents(); + if (details.dispatcher_destroyed) + return; + + synthesize_mouse_move_ = false; + } + + if (window->IsVisible() && !window->ignore_events()) { + gfx::Rect old_bounds_in_root = old_bounds, new_bounds_in_root = new_bounds; + Window::ConvertRectToTarget(window->parent(), host_->window(), + &old_bounds_in_root); + Window::ConvertRectToTarget(window->parent(), host_->window(), + &new_bounds_in_root); + gfx::Point last_mouse_location = GetLastMouseLocationInRoot(); + if (old_bounds_in_root.Contains(last_mouse_location) != + new_bounds_in_root.Contains(last_mouse_location)) { + PostSynthesizeMouseMove(); + } + } +} + +void WindowEventDispatcher::OnWindowTransforming(Window* window) { + if (!host_->window()->Contains(window)) + return; + + SynthesizeMouseMoveAfterChangeToWindow(window); +} + +void WindowEventDispatcher::OnWindowTransformed(Window* window) { + if (!host_->window()->Contains(window)) + return; + + SynthesizeMouseMoveAfterChangeToWindow(window); +} + +/////////////////////////////////////////////////////////////////////////////// +// WindowEventDispatcher, EnvObserver implementation: + +void WindowEventDispatcher::OnWindowInitialized(Window* window) { + observer_manager_.Add(window); +} + +//////////////////////////////////////////////////////////////////////////////// +// WindowEventDispatcher, private: + +ui::EventDispatchDetails WindowEventDispatcher::DispatchHeldEvents() { + if (!held_repostable_event_ && !held_move_event_) + return DispatchDetails(); + + CHECK(!dispatching_held_event_); + dispatching_held_event_ = true; + + DispatchDetails dispatch_details; + if (held_repostable_event_) { + if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) { + scoped_ptr<ui::MouseEvent> mouse_event( + static_cast<ui::MouseEvent*>(held_repostable_event_.release())); + dispatch_details = OnEventFromSource(mouse_event.get()); + } else { + // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987. + NOTREACHED(); + } + if (dispatch_details.dispatcher_destroyed) + return dispatch_details; + } + + if (held_move_event_) { + // If a mouse move has been synthesized, the target location is suspect, + // so drop the held mouse event. + if (held_move_event_->IsTouchEvent() || + (held_move_event_->IsMouseEvent() && !synthesize_mouse_move_)) { + dispatch_details = OnEventFromSource(held_move_event_.get()); + } + if (!dispatch_details.dispatcher_destroyed) + held_move_event_.reset(); + } + + if (!dispatch_details.dispatcher_destroyed) + dispatching_held_event_ = false; + return dispatch_details; +} + +void WindowEventDispatcher::PostSynthesizeMouseMove() { + if (synthesize_mouse_move_) + return; + synthesize_mouse_move_ = true; + base::MessageLoop::current()->PostNonNestableTask( + FROM_HERE, + base::Bind(base::IgnoreResult( + &WindowEventDispatcher::SynthesizeMouseMoveEvent), + held_event_factory_.GetWeakPtr())); +} + +void WindowEventDispatcher::SynthesizeMouseMoveAfterChangeToWindow( + Window* window) { + if (window->IsVisible() && + window->ContainsPointInRoot(GetLastMouseLocationInRoot())) { + PostSynthesizeMouseMove(); + } +} + +ui::EventDispatchDetails WindowEventDispatcher::SynthesizeMouseMoveEvent() { + DispatchDetails details; + if (!synthesize_mouse_move_) + return details; + synthesize_mouse_move_ = false; + + // If one of the mouse buttons is currently down, then do not synthesize a + // mouse-move event. In such cases, aura could synthesize a DRAGGED event + // instead of a MOVED event, but in multi-display/multi-host scenarios, the + // DRAGGED event can be synthesized in the incorrect host. So avoid + // synthesizing any events at all. + if (Env::GetInstance()->mouse_button_flags()) + return details; + + gfx::Point root_mouse_location = GetLastMouseLocationInRoot(); + if (!window()->bounds().Contains(root_mouse_location)) + return details; + gfx::Point host_mouse_location = root_mouse_location; + host_->ConvertPointToHost(&host_mouse_location); + ui::MouseEvent event(ui::ET_MOUSE_MOVED, + host_mouse_location, + host_mouse_location, + ui::EF_IS_SYNTHESIZED, + 0); + return OnEventFromSource(&event); +} + +void WindowEventDispatcher::PreDispatchLocatedEvent(Window* target, + ui::LocatedEvent* event) { + int flags = event->flags(); + if (IsNonClientLocation(target, event->location())) + flags |= ui::EF_IS_NON_CLIENT; + event->set_flags(flags); + + if (!dispatching_held_event_ && + (event->IsMouseEvent() || event->IsScrollEvent()) && + !(event->flags() & ui::EF_IS_SYNTHESIZED)) { + if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) + SetLastMouseLocation(window(), event->root_location()); + synthesize_mouse_move_ = false; + } +} + +void WindowEventDispatcher::PreDispatchMouseEvent(Window* target, + ui::MouseEvent* event) { + client::CursorClient* cursor_client = client::GetCursorClient(window()); + // We allow synthesized mouse exit events through even if mouse events are + // disabled. This ensures that hover state, etc on controls like buttons is + // cleared. + if (cursor_client && + !cursor_client->IsMouseEventsEnabled() && + (event->flags() & ui::EF_IS_SYNTHESIZED) && + (event->type() != ui::ET_MOUSE_EXITED)) { + event->SetHandled(); + return; + } + + if (IsEventCandidateForHold(*event) && !dispatching_held_event_) { + if (move_hold_count_) { + if (!(event->flags() & ui::EF_IS_SYNTHESIZED) && + event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) { + SetLastMouseLocation(window(), event->root_location()); + } + held_move_event_.reset(new ui::MouseEvent(*event, target, window())); + event->SetHandled(); + return; + } else { + // We may have a held event for a period between the time move_hold_count_ + // fell to 0 and the DispatchHeldEvents executes. Since we're going to + // dispatch the new event directly below, we can reset the old one. + held_move_event_.reset(); + } + } + + const int kMouseButtonFlagMask = ui::EF_LEFT_MOUSE_BUTTON | + ui::EF_MIDDLE_MOUSE_BUTTON | + ui::EF_RIGHT_MOUSE_BUTTON; + switch (event->type()) { + case ui::ET_MOUSE_EXITED: + if (!target || target == window()) { + DispatchDetails details = + DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); + if (details.dispatcher_destroyed) { + event->SetHandled(); + return; + } + mouse_moved_handler_ = NULL; + } + break; + case ui::ET_MOUSE_MOVED: + // Send an exit to the current |mouse_moved_handler_| and an enter to + // |target|. Take care that both us and |target| aren't destroyed during + // dispatch. + if (target != mouse_moved_handler_) { + aura::Window* old_mouse_moved_handler = mouse_moved_handler_; + WindowTracker live_window; + live_window.Add(target); + DispatchDetails details = + DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); + if (details.dispatcher_destroyed) { + event->SetHandled(); + return; + } + // If the |mouse_moved_handler_| changes out from under us, assume a + // nested message loop ran and we don't need to do anything. + if (mouse_moved_handler_ != old_mouse_moved_handler) { + event->SetHandled(); + return; + } + if (!live_window.Contains(target) || details.target_destroyed) { + mouse_moved_handler_ = NULL; + event->SetHandled(); + return; + } + live_window.Remove(target); + + mouse_moved_handler_ = target; + details = DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED); + if (details.dispatcher_destroyed || details.target_destroyed) { + event->SetHandled(); + return; + } + } + break; + case ui::ET_MOUSE_PRESSED: + // Don't set the mouse pressed handler for non client mouse down events. + // These are only sent by Windows and are not always followed with non + // client mouse up events which causes subsequent mouse events to be + // sent to the wrong target. + if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_) + mouse_pressed_handler_ = target; + Env::GetInstance()->set_mouse_button_flags( + event->flags() & kMouseButtonFlagMask); + break; + case ui::ET_MOUSE_RELEASED: + mouse_pressed_handler_ = NULL; + Env::GetInstance()->set_mouse_button_flags(event->flags() & + kMouseButtonFlagMask & ~event->changed_button_flags()); + break; + default: + break; + } + + PreDispatchLocatedEvent(target, event); +} + +void WindowEventDispatcher::PreDispatchTouchEvent(Window* target, + ui::TouchEvent* event) { + switch (event->type()) { + case ui::ET_TOUCH_PRESSED: + touch_ids_down_ |= (1 << event->touch_id()); + Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); + break; + + // Handle ET_TOUCH_CANCELLED only if it has a native event. + case ui::ET_TOUCH_CANCELLED: + if (!event->HasNativeEvent()) + break; + // fallthrough + case ui::ET_TOUCH_RELEASED: + touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^ + (1 << event->touch_id()); + Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); + break; + + case ui::ET_TOUCH_MOVED: + if (move_hold_count_ && !dispatching_held_event_) { + held_move_event_.reset(new ui::TouchEvent(*event, target, window())); + event->SetHandled(); + return; + } + break; + + default: + NOTREACHED(); + break; + } + PreDispatchLocatedEvent(target, event); +} + +} // namespace aura diff --git a/chromium/ui/aura/window_event_dispatcher.h b/chromium/ui/aura/window_event_dispatcher.h new file mode 100644 index 00000000000..79ba3c7b2cb --- /dev/null +++ b/chromium/ui/aura/window_event_dispatcher.h @@ -0,0 +1,265 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_WINDOW_EVENT_DISPATCHER_H_ +#define UI_AURA_WINDOW_EVENT_DISPATCHER_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/gtest_prod_util.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/scoped_observer.h" +#include "ui/aura/aura_export.h" +#include "ui/aura/client/capture_delegate.h" +#include "ui/aura/env_observer.h" +#include "ui/aura/window_observer.h" +#include "ui/base/cursor/cursor.h" +#include "ui/events/event_constants.h" +#include "ui/events/event_processor.h" +#include "ui/events/event_targeter.h" +#include "ui/events/gestures/gesture_recognizer.h" +#include "ui/events/gestures/gesture_types.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/point.h" + +namespace gfx { +class Size; +class Transform; +} + +namespace ui { +class GestureEvent; +class GestureRecognizer; +class KeyEvent; +class MouseEvent; +class ScrollEvent; +class TouchEvent; +} + +namespace aura { +class TestScreen; +class WindowTargeter; +class WindowTreeHost; + +// WindowEventDispatcher orchestrates event dispatch within a window tree +// owned by WindowTreeHost. WTH also owns the WED. +// TODO(beng): In progress, remove functionality not directly related to +// event dispatch. +class AURA_EXPORT WindowEventDispatcher : public ui::EventProcessor, + public ui::GestureEventHelper, + public client::CaptureDelegate, + public WindowObserver, + public EnvObserver { + public: + explicit WindowEventDispatcher(WindowTreeHost* host); + virtual ~WindowEventDispatcher(); + + Window* mouse_pressed_handler() { return mouse_pressed_handler_; } + Window* mouse_moved_handler() { return mouse_moved_handler_; } + + // Repost event for re-processing. Used when exiting context menus. + // We only support the ET_MOUSE_PRESSED and ET_GESTURE_TAP_DOWN event + // types (although the latter is currently a no-op). + void RepostEvent(const ui::LocatedEvent& event); + + // Invoked when the mouse events get enabled or disabled. + void OnMouseEventsEnableStateChanged(bool enabled); + + void DispatchCancelModeEvent(); + + // Dispatches a ui::ET_MOUSE_EXITED event at |point|. + // TODO(beng): needed only for WTH::OnCursorVisibilityChanged(). + void DispatchMouseExitAtPoint(const gfx::Point& point); + + // Gesture Recognition ------------------------------------------------------- + + // When a touch event is dispatched to a Window, it may want to process the + // touch event asynchronously. In such cases, the window should consume the + // event during the event dispatch. Once the event is properly processed, the + // window should let the WindowEventDispatcher know about the result of the + // event processing, so that gesture events can be properly created and + // dispatched. + void ProcessedTouchEvent(ui::TouchEvent* event, + Window* window, + ui::EventResult result); + + // These methods are used to defer the processing of mouse/touch events + // related to resize. A client (typically a RenderWidgetHostViewAura) can call + // HoldPointerMoves when an resize is initiated and then ReleasePointerMoves + // once the resize is completed. + // + // More than one hold can be invoked and each hold must be cancelled by a + // release before we resume normal operation. + void HoldPointerMoves(); + void ReleasePointerMoves(); + + // Gets the last location seen in a mouse event in this root window's + // coordinates. This may return a point outside the root window's bounds. + gfx::Point GetLastMouseLocationInRoot() const; + + void OnHostLostMouseGrab(); + void OnCursorMovedToRootLocation(const gfx::Point& root_location); + + // TODO(beng): This is only needed because this cleanup needs to happen after + // all other observers are notified of OnWindowDestroying() but + // before OnWindowDestroyed() is sent (i.e. while the window + // hierarchy is still intact). This didn't seem worth adding a + // generic notification for as only this class needs to implement + // it. I would however like to find a way to do this via an + // observer. + void OnPostNotifiedWindowDestroying(Window* window); + + private: + FRIEND_TEST_ALL_PREFIXES(WindowEventDispatcherTest, + KeepTranslatedEventInRoot); + + friend class Window; + friend class TestScreen; + + // The parameter for OnWindowHidden() to specify why window is hidden. + enum WindowHiddenReason { + WINDOW_DESTROYED, // Window is destroyed. + WINDOW_HIDDEN, // Window is hidden. + WINDOW_MOVING, // Window is temporarily marked as hidden due to move + // across root windows. + }; + + Window* window(); + const Window* window() const; + + // Updates the event with the appropriate transform for the device scale + // factor. The WindowEventDispatcher dispatches events in the physical pixel + // coordinate. But the event processing from WindowEventDispatcher onwards + // happen in device-independent pixel coordinate. So it is necessary to update + // the event received from the host. + void TransformEventForDeviceScaleFactor(ui::LocatedEvent* event); + + // Dispatches OnMouseExited to the |window| which is hiding if necessary. + void DispatchMouseExitToHidingWindow(Window* window); + + // Dispatches the specified event type (intended for enter/exit) to the + // |mouse_moved_handler_|. + ui::EventDispatchDetails DispatchMouseEnterOrExit( + const ui::MouseEvent& event, + ui::EventType type) WARN_UNUSED_RESULT; + ui::EventDispatchDetails ProcessGestures( + ui::GestureRecognizer::Gestures* gestures) WARN_UNUSED_RESULT; + + // Called when a window becomes invisible, either by being removed + // from root window hierarchy, via SetVisible(false) or being destroyed. + // |reason| specifies what triggered the hiding. Note that becoming invisible + // will cause a window to lose capture and some windows may destroy themselves + // on capture (like DragDropTracker). + void OnWindowHidden(Window* invisible, WindowHiddenReason reason); + + // Returns a target window for the given gesture event. + Window* GetGestureTarget(ui::GestureEvent* event); + + // Overridden from aura::client::CaptureDelegate: + virtual void UpdateCapture(Window* old_capture, Window* new_capture) OVERRIDE; + virtual void OnOtherRootGotCapture() OVERRIDE; + virtual void SetNativeCapture() OVERRIDE; + virtual void ReleaseNativeCapture() OVERRIDE; + + // Overridden from ui::EventProcessor: + virtual ui::EventTarget* GetRootTarget() OVERRIDE; + virtual void PrepareEventForDispatch(ui::Event* event) OVERRIDE; + + // Overridden from ui::EventDispatcherDelegate. + virtual bool CanDispatchToTarget(ui::EventTarget* target) OVERRIDE; + virtual ui::EventDispatchDetails PreDispatchEvent(ui::EventTarget* target, + ui::Event* event) OVERRIDE; + virtual ui::EventDispatchDetails PostDispatchEvent( + ui::EventTarget* target, const ui::Event& event) OVERRIDE; + + // Overridden from ui::GestureEventHelper. + virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE; + virtual void DispatchGestureEvent(ui::GestureEvent* event) OVERRIDE; + virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE; + + // Overridden from WindowObserver: + virtual void OnWindowDestroying(Window* window) OVERRIDE; + virtual void OnWindowDestroyed(Window* window) OVERRIDE; + virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE; + virtual void OnWindowRemovingFromRootWindow(Window* window, + Window* new_root) OVERRIDE; + virtual void OnWindowVisibilityChanging(Window* window, + bool visible) OVERRIDE; + virtual void OnWindowVisibilityChanged(Window* window, bool visible) OVERRIDE; + virtual void OnWindowBoundsChanged(Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) OVERRIDE; + virtual void OnWindowTransforming(Window* window) OVERRIDE; + virtual void OnWindowTransformed(Window* window) OVERRIDE; + + // Overridden from EnvObserver: + virtual void OnWindowInitialized(Window* window) OVERRIDE; + + // We hold and aggregate mouse drags and touch moves as a way of throttling + // resizes when HoldMouseMoves() is called. The following methods are used to + // dispatch held and newly incoming mouse and touch events, typically when an + // event other than one of these needs dispatching or a matching + // ReleaseMouseMoves()/ReleaseTouchMoves() is called. NOTE: because these + // methods dispatch events from WindowTreeHost the coordinates are in terms of + // the root. + ui::EventDispatchDetails DispatchHeldEvents() WARN_UNUSED_RESULT; + + // Posts a task to send synthesized mouse move event if there is no a pending + // task. + void PostSynthesizeMouseMove(); + + // Creates and dispatches synthesized mouse move event using the current mouse + // location. + ui::EventDispatchDetails SynthesizeMouseMoveEvent() WARN_UNUSED_RESULT; + + // Calls SynthesizeMouseMove() if |window| is currently visible and contains + // the mouse cursor. + void SynthesizeMouseMoveAfterChangeToWindow(Window* window); + + void PreDispatchLocatedEvent(Window* target, ui::LocatedEvent* event); + void PreDispatchMouseEvent(Window* target, ui::MouseEvent* event); + void PreDispatchTouchEvent(Window* target, ui::TouchEvent* event); + + WindowTreeHost* host_; + + // Touch ids that are currently down. + uint32 touch_ids_down_; + + Window* mouse_pressed_handler_; + Window* mouse_moved_handler_; + Window* event_dispatch_target_; + Window* old_dispatch_target_; + + bool synthesize_mouse_move_; + + // How many move holds are outstanding. We try to defer dispatching + // touch/mouse moves while the count is > 0. + int move_hold_count_; + // The location of |held_move_event_| is in |window_|'s coordinate. + scoped_ptr<ui::LocatedEvent> held_move_event_; + + // Allowing for reposting of events. Used when exiting context menus. + scoped_ptr<ui::LocatedEvent> held_repostable_event_; + + // Set when dispatching a held event. + bool dispatching_held_event_; + + ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_; + + // Used to schedule reposting an event. + base::WeakPtrFactory<WindowEventDispatcher> repost_event_factory_; + + // Used to schedule DispatchHeldEvents() when |move_hold_count_| goes to 0. + base::WeakPtrFactory<WindowEventDispatcher> held_event_factory_; + + DISALLOW_COPY_AND_ASSIGN(WindowEventDispatcher); +}; + +} // namespace aura + +#endif // UI_AURA_WINDOW_EVENT_DISPATCHER_H_ diff --git a/chromium/ui/aura/window_event_dispatcher_unittest.cc b/chromium/ui/aura/window_event_dispatcher_unittest.cc new file mode 100644 index 00000000000..11eeaa0d2c4 --- /dev/null +++ b/chromium/ui/aura/window_event_dispatcher_unittest.cc @@ -0,0 +1,2219 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura/window_event_dispatcher.h" + +#include <vector> + +#include "base/bind.h" +#include "base/run_loop.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/aura/client/event_client.h" +#include "ui/aura/client/focus_client.h" +#include "ui/aura/env.h" +#include "ui/aura/test/aura_test_base.h" +#include "ui/aura/test/env_test_helper.h" +#include "ui/aura/test/event_generator.h" +#include "ui/aura/test/test_cursor_client.h" +#include "ui/aura/test/test_screen.h" +#include "ui/aura/test/test_window_delegate.h" +#include "ui/aura/test/test_windows.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tracker.h" +#include "ui/base/hit_test.h" +#include "ui/events/event.h" +#include "ui/events/event_handler.h" +#include "ui/events/event_utils.h" +#include "ui/events/gestures/gesture_configuration.h" +#include "ui/events/keycodes/keyboard_codes.h" +#include "ui/events/test/test_event_handler.h" +#include "ui/gfx/point.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/screen.h" +#include "ui/gfx/transform.h" + +namespace aura { +namespace { + +// A delegate that always returns a non-client component for hit tests. +class NonClientDelegate : public test::TestWindowDelegate { + public: + NonClientDelegate() + : non_client_count_(0), + mouse_event_count_(0), + mouse_event_flags_(0x0) { + } + virtual ~NonClientDelegate() {} + + int non_client_count() const { return non_client_count_; } + gfx::Point non_client_location() const { return non_client_location_; } + int mouse_event_count() const { return mouse_event_count_; } + gfx::Point mouse_event_location() const { return mouse_event_location_; } + int mouse_event_flags() const { return mouse_event_flags_; } + + virtual int GetNonClientComponent(const gfx::Point& location) const OVERRIDE { + NonClientDelegate* self = const_cast<NonClientDelegate*>(this); + self->non_client_count_++; + self->non_client_location_ = location; + return HTTOPLEFT; + } + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + mouse_event_count_++; + mouse_event_location_ = event->location(); + mouse_event_flags_ = event->flags(); + event->SetHandled(); + } + + private: + int non_client_count_; + gfx::Point non_client_location_; + int mouse_event_count_; + gfx::Point mouse_event_location_; + int mouse_event_flags_; + + DISALLOW_COPY_AND_ASSIGN(NonClientDelegate); +}; + +// A simple event handler that consumes key events. +class ConsumeKeyHandler : public ui::test::TestEventHandler { + public: + ConsumeKeyHandler() {} + virtual ~ConsumeKeyHandler() {} + + // Overridden from ui::EventHandler: + virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { + ui::test::TestEventHandler::OnKeyEvent(event); + event->StopPropagation(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ConsumeKeyHandler); +}; + +bool IsFocusedWindow(aura::Window* window) { + return client::GetFocusClient(window)->GetFocusedWindow() == window; +} + +} // namespace + +typedef test::AuraTestBase WindowEventDispatcherTest; + +TEST_F(WindowEventDispatcherTest, OnHostMouseEvent) { + // Create two non-overlapping windows so we don't have to worry about which + // is on top. + scoped_ptr<NonClientDelegate> delegate1(new NonClientDelegate()); + scoped_ptr<NonClientDelegate> delegate2(new NonClientDelegate()); + const int kWindowWidth = 123; + const int kWindowHeight = 45; + gfx::Rect bounds1(100, 200, kWindowWidth, kWindowHeight); + gfx::Rect bounds2(300, 400, kWindowWidth, kWindowHeight); + scoped_ptr<aura::Window> window1(CreateTestWindowWithDelegate( + delegate1.get(), -1234, bounds1, root_window())); + scoped_ptr<aura::Window> window2(CreateTestWindowWithDelegate( + delegate2.get(), -5678, bounds2, root_window())); + + // Send a mouse event to window1. + gfx::Point point(101, 201); + ui::MouseEvent event1( + ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON); + DispatchEventUsingWindowDispatcher(&event1); + + // Event was tested for non-client area for the target window. + EXPECT_EQ(1, delegate1->non_client_count()); + EXPECT_EQ(0, delegate2->non_client_count()); + // The non-client component test was in local coordinates. + EXPECT_EQ(gfx::Point(1, 1), delegate1->non_client_location()); + // Mouse event was received by target window. + EXPECT_EQ(1, delegate1->mouse_event_count()); + EXPECT_EQ(0, delegate2->mouse_event_count()); + // Event was in local coordinates. + EXPECT_EQ(gfx::Point(1, 1), delegate1->mouse_event_location()); + // Non-client flag was set. + EXPECT_TRUE(delegate1->mouse_event_flags() & ui::EF_IS_NON_CLIENT); +} + +TEST_F(WindowEventDispatcherTest, RepostEvent) { + // Test RepostEvent in RootWindow. It only works for Mouse Press. + EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); + gfx::Point point(10, 10); + ui::MouseEvent event( + ui::ET_MOUSE_PRESSED, point, point, ui::EF_LEFT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON); + host()->dispatcher()->RepostEvent(event); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); +} + +// Check that we correctly track the state of the mouse buttons in response to +// button press and release events. +TEST_F(WindowEventDispatcherTest, MouseButtonState) { + EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); + + gfx::Point location; + scoped_ptr<ui::MouseEvent> event; + + // Press the left button. + event.reset(new ui::MouseEvent( + ui::ET_MOUSE_PRESSED, + location, + location, + ui::EF_LEFT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON)); + DispatchEventUsingWindowDispatcher(event.get()); + EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); + + // Additionally press the right. + event.reset(new ui::MouseEvent( + ui::ET_MOUSE_PRESSED, + location, + location, + ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON, + ui::EF_RIGHT_MOUSE_BUTTON)); + DispatchEventUsingWindowDispatcher(event.get()); + EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); + + // Release the left button. + event.reset(new ui::MouseEvent( + ui::ET_MOUSE_RELEASED, + location, + location, + ui::EF_RIGHT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON)); + DispatchEventUsingWindowDispatcher(event.get()); + EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); + + // Release the right button. We should ignore the Shift-is-down flag. + event.reset(new ui::MouseEvent( + ui::ET_MOUSE_RELEASED, + location, + location, + ui::EF_SHIFT_DOWN, + ui::EF_RIGHT_MOUSE_BUTTON)); + DispatchEventUsingWindowDispatcher(event.get()); + EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); + + // Press the middle button. + event.reset(new ui::MouseEvent( + ui::ET_MOUSE_PRESSED, + location, + location, + ui::EF_MIDDLE_MOUSE_BUTTON, + ui::EF_MIDDLE_MOUSE_BUTTON)); + DispatchEventUsingWindowDispatcher(event.get()); + EXPECT_TRUE(Env::GetInstance()->IsMouseButtonDown()); +} + +TEST_F(WindowEventDispatcherTest, TranslatedEvent) { + scoped_ptr<Window> w1(test::CreateTestWindowWithDelegate(NULL, 1, + gfx::Rect(50, 50, 100, 100), root_window())); + + gfx::Point origin(100, 100); + ui::MouseEvent root(ui::ET_MOUSE_PRESSED, origin, origin, 0, 0); + + EXPECT_EQ("100,100", root.location().ToString()); + EXPECT_EQ("100,100", root.root_location().ToString()); + + ui::MouseEvent translated_event( + root, static_cast<Window*>(root_window()), w1.get(), + ui::ET_MOUSE_ENTERED, root.flags()); + EXPECT_EQ("50,50", translated_event.location().ToString()); + EXPECT_EQ("100,100", translated_event.root_location().ToString()); +} + +namespace { + +class TestEventClient : public client::EventClient { + public: + static const int kNonLockWindowId = 100; + static const int kLockWindowId = 200; + + explicit TestEventClient(Window* root_window) + : root_window_(root_window), + lock_(false) { + client::SetEventClient(root_window_, this); + Window* lock_window = + test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_); + lock_window->set_id(kLockWindowId); + Window* non_lock_window = + test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_); + non_lock_window->set_id(kNonLockWindowId); + } + virtual ~TestEventClient() { + client::SetEventClient(root_window_, NULL); + } + + // Starts/stops locking. Locking prevents windows other than those inside + // the lock container from receiving events, getting focus etc. + void Lock() { + lock_ = true; + } + void Unlock() { + lock_ = false; + } + + Window* GetLockWindow() { + return const_cast<Window*>( + static_cast<const TestEventClient*>(this)->GetLockWindow()); + } + const Window* GetLockWindow() const { + return root_window_->GetChildById(kLockWindowId); + } + Window* GetNonLockWindow() { + return root_window_->GetChildById(kNonLockWindowId); + } + + private: + // Overridden from client::EventClient: + virtual bool CanProcessEventsWithinSubtree( + const Window* window) const OVERRIDE { + return lock_ ? + window->Contains(GetLockWindow()) || GetLockWindow()->Contains(window) : + true; + } + + virtual ui::EventTarget* GetToplevelEventTarget() OVERRIDE { + return NULL; + } + + Window* root_window_; + bool lock_; + + DISALLOW_COPY_AND_ASSIGN(TestEventClient); +}; + +} // namespace + +TEST_F(WindowEventDispatcherTest, CanProcessEventsWithinSubtree) { + TestEventClient client(root_window()); + test::TestWindowDelegate d; + + ui::test::TestEventHandler nonlock_ef; + ui::test::TestEventHandler lock_ef; + client.GetNonLockWindow()->AddPreTargetHandler(&nonlock_ef); + client.GetLockWindow()->AddPreTargetHandler(&lock_ef); + + Window* w1 = test::CreateTestWindowWithBounds(gfx::Rect(10, 10, 20, 20), + client.GetNonLockWindow()); + w1->set_id(1); + Window* w2 = test::CreateTestWindowWithBounds(gfx::Rect(30, 30, 20, 20), + client.GetNonLockWindow()); + w2->set_id(2); + scoped_ptr<Window> w3( + test::CreateTestWindowWithDelegate(&d, 3, gfx::Rect(30, 30, 20, 20), + client.GetLockWindow())); + + w1->Focus(); + EXPECT_TRUE(IsFocusedWindow(w1)); + + client.Lock(); + + // Since we're locked, the attempt to focus w2 will be ignored. + w2->Focus(); + EXPECT_TRUE(IsFocusedWindow(w1)); + EXPECT_FALSE(IsFocusedWindow(w2)); + + { + // Attempting to send a key event to w1 (not in the lock container) should + // cause focus to be reset. + test::EventGenerator generator(root_window()); + generator.PressKey(ui::VKEY_SPACE, 0); + EXPECT_EQ(NULL, client::GetFocusClient(w1)->GetFocusedWindow()); + EXPECT_FALSE(IsFocusedWindow(w1)); + } + + { + // Events sent to a window not in the lock container will not be processed. + // i.e. never sent to the non-lock container's event filter. + test::EventGenerator generator(root_window(), w1); + generator.ClickLeftButton(); + EXPECT_EQ(0, nonlock_ef.num_mouse_events()); + + // Events sent to a window in the lock container will be processed. + test::EventGenerator generator3(root_window(), w3.get()); + generator3.PressLeftButton(); + EXPECT_EQ(1, lock_ef.num_mouse_events()); + } + + // Prevent w3 from being deleted by the hierarchy since its delegate is owned + // by this scope. + w3->parent()->RemoveChild(w3.get()); +} + +TEST_F(WindowEventDispatcherTest, IgnoreUnknownKeys) { + ConsumeKeyHandler handler; + root_window()->AddPreTargetHandler(&handler); + + ui::KeyEvent unknown_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 0, false); + DispatchEventUsingWindowDispatcher(&unknown_event); + EXPECT_FALSE(unknown_event.handled()); + EXPECT_EQ(0, handler.num_key_events()); + + handler.Reset(); + ui::KeyEvent known_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false); + DispatchEventUsingWindowDispatcher(&known_event); + EXPECT_TRUE(known_event.handled()); + EXPECT_EQ(1, handler.num_key_events()); + + handler.Reset(); + ui::KeyEvent ime_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, + ui::EF_IME_FABRICATED_KEY, false); + DispatchEventUsingWindowDispatcher(&ime_event); + EXPECT_TRUE(ime_event.handled()); + EXPECT_EQ(1, handler.num_key_events()); + + handler.Reset(); + ui::KeyEvent unknown_key_with_char_event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, + 0, false); + unknown_key_with_char_event.set_character(0x00e4 /* "ä" */); + DispatchEventUsingWindowDispatcher(&unknown_key_with_char_event); + EXPECT_TRUE(unknown_key_with_char_event.handled()); + EXPECT_EQ(1, handler.num_key_events()); +} + +TEST_F(WindowEventDispatcherTest, NoDelegateWindowReceivesKeyEvents) { + scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); + w1->Show(); + w1->Focus(); + + ui::test::TestEventHandler handler; + w1->AddPreTargetHandler(&handler); + ui::KeyEvent key_press(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false); + DispatchEventUsingWindowDispatcher(&key_press); + EXPECT_TRUE(key_press.handled()); + EXPECT_EQ(1, handler.num_key_events()); + + w1->RemovePreTargetHandler(&handler); +} + +// Tests that touch-events that are beyond the bounds of the root-window do get +// propagated to the event filters correctly with the root as the target. +TEST_F(WindowEventDispatcherTest, TouchEventsOutsideBounds) { + ui::test::TestEventHandler handler; + root_window()->AddPreTargetHandler(&handler); + + gfx::Point position = root_window()->bounds().origin(); + position.Offset(-10, -10); + ui::TouchEvent press( + ui::ET_TOUCH_PRESSED, position, 0, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&press); + EXPECT_EQ(1, handler.num_touch_events()); + + position = root_window()->bounds().origin(); + position.Offset(root_window()->bounds().width() + 10, + root_window()->bounds().height() + 10); + ui::TouchEvent release( + ui::ET_TOUCH_RELEASED, position, 0, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&release); + EXPECT_EQ(2, handler.num_touch_events()); +} + +// Tests that scroll events are dispatched correctly. +TEST_F(WindowEventDispatcherTest, ScrollEventDispatch) { + base::TimeDelta now = ui::EventTimeForNow(); + ui::test::TestEventHandler handler; + root_window()->AddPreTargetHandler(&handler); + + test::TestWindowDelegate delegate; + scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate)); + w1->SetBounds(gfx::Rect(20, 20, 40, 40)); + + // A scroll event on the root-window itself is dispatched. + ui::ScrollEvent scroll1(ui::ET_SCROLL, + gfx::Point(10, 10), + now, + 0, + 0, -10, + 0, -10, + 2); + DispatchEventUsingWindowDispatcher(&scroll1); + EXPECT_EQ(1, handler.num_scroll_events()); + + // Scroll event on a window should be dispatched properly. + ui::ScrollEvent scroll2(ui::ET_SCROLL, + gfx::Point(25, 30), + now, + 0, + -10, 0, + -10, 0, + 2); + DispatchEventUsingWindowDispatcher(&scroll2); + EXPECT_EQ(2, handler.num_scroll_events()); + root_window()->RemovePreTargetHandler(&handler); +} + +namespace { + +// FilterFilter that tracks the types of events it's seen. +class EventFilterRecorder : public ui::EventHandler { + public: + typedef std::vector<ui::EventType> Events; + typedef std::vector<gfx::Point> EventLocations; + typedef std::vector<int> EventFlags; + + EventFilterRecorder() + : wait_until_event_(ui::ET_UNKNOWN) { + } + + const Events& events() const { return events_; } + + const EventLocations& mouse_locations() const { return mouse_locations_; } + gfx::Point mouse_location(int i) const { return mouse_locations_[i]; } + const EventLocations& touch_locations() const { return touch_locations_; } + const EventFlags& mouse_event_flags() const { return mouse_event_flags_; } + + void WaitUntilReceivedEvent(ui::EventType type) { + wait_until_event_ = type; + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); + } + + Events GetAndResetEvents() { + Events events = events_; + Reset(); + return events; + } + + void Reset() { + events_.clear(); + mouse_locations_.clear(); + touch_locations_.clear(); + mouse_event_flags_.clear(); + } + + // ui::EventHandler overrides: + virtual void OnEvent(ui::Event* event) OVERRIDE { + ui::EventHandler::OnEvent(event); + events_.push_back(event->type()); + if (wait_until_event_ == event->type() && run_loop_) { + run_loop_->Quit(); + wait_until_event_ = ui::ET_UNKNOWN; + } + } + + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + mouse_locations_.push_back(event->location()); + mouse_event_flags_.push_back(event->flags()); + } + + virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE { + touch_locations_.push_back(event->location()); + } + + bool HasReceivedEvent(ui::EventType type) { + return std::find(events_.begin(), events_.end(), type) != events_.end(); + } + + private: + scoped_ptr<base::RunLoop> run_loop_; + ui::EventType wait_until_event_; + + Events events_; + EventLocations mouse_locations_; + EventLocations touch_locations_; + EventFlags mouse_event_flags_; + + DISALLOW_COPY_AND_ASSIGN(EventFilterRecorder); +}; + +// Converts an EventType to a string. +std::string EventTypeToString(ui::EventType type) { + switch (type) { + case ui::ET_TOUCH_RELEASED: + return "TOUCH_RELEASED"; + + case ui::ET_TOUCH_CANCELLED: + return "TOUCH_CANCELLED"; + + case ui::ET_TOUCH_PRESSED: + return "TOUCH_PRESSED"; + + case ui::ET_TOUCH_MOVED: + return "TOUCH_MOVED"; + + case ui::ET_MOUSE_PRESSED: + return "MOUSE_PRESSED"; + + case ui::ET_MOUSE_DRAGGED: + return "MOUSE_DRAGGED"; + + case ui::ET_MOUSE_RELEASED: + return "MOUSE_RELEASED"; + + case ui::ET_MOUSE_MOVED: + return "MOUSE_MOVED"; + + case ui::ET_MOUSE_ENTERED: + return "MOUSE_ENTERED"; + + case ui::ET_MOUSE_EXITED: + return "MOUSE_EXITED"; + + case ui::ET_GESTURE_SCROLL_BEGIN: + return "GESTURE_SCROLL_BEGIN"; + + case ui::ET_GESTURE_SCROLL_END: + return "GESTURE_SCROLL_END"; + + case ui::ET_GESTURE_SCROLL_UPDATE: + return "GESTURE_SCROLL_UPDATE"; + + case ui::ET_GESTURE_PINCH_BEGIN: + return "GESTURE_PINCH_BEGIN"; + + case ui::ET_GESTURE_PINCH_END: + return "GESTURE_PINCH_END"; + + case ui::ET_GESTURE_PINCH_UPDATE: + return "GESTURE_PINCH_UPDATE"; + + case ui::ET_GESTURE_TAP: + return "GESTURE_TAP"; + + case ui::ET_GESTURE_TAP_DOWN: + return "GESTURE_TAP_DOWN"; + + case ui::ET_GESTURE_TAP_CANCEL: + return "GESTURE_TAP_CANCEL"; + + case ui::ET_GESTURE_SHOW_PRESS: + return "GESTURE_SHOW_PRESS"; + + case ui::ET_GESTURE_BEGIN: + return "GESTURE_BEGIN"; + + case ui::ET_GESTURE_END: + return "GESTURE_END"; + + default: + // We should explicitly require each event type. + NOTREACHED() << "Received unexpected event: " << type; + break; + } + return ""; +} + +std::string EventTypesToString(const EventFilterRecorder::Events& events) { + std::string result; + for (size_t i = 0; i < events.size(); ++i) { + if (i != 0) + result += " "; + result += EventTypeToString(events[i]); + } + return result; +} + +} // namespace + +// Verifies a repost mouse event targets the window with capture (if there is +// one). +TEST_F(WindowEventDispatcherTest, RepostTargetsCaptureWindow) { + // Set capture on |window| generate a mouse event (that is reposted) and not + // over |window| and verify |window| gets it (|window| gets it because it has + // capture). + EXPECT_FALSE(Env::GetInstance()->IsMouseButtonDown()); + EventFilterRecorder recorder; + scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), NULL)); + window->SetBounds(gfx::Rect(20, 20, 40, 30)); + window->AddPreTargetHandler(&recorder); + window->SetCapture(); + const ui::MouseEvent press_event( + ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); + host()->dispatcher()->RepostEvent(press_event); + RunAllPendingInMessageLoop(); // Necessitated by RepostEvent(). + // Mouse moves/enters may be generated. We only care about a pressed. + EXPECT_TRUE(EventTypesToString(recorder.events()).find("MOUSE_PRESSED") != + std::string::npos) << EventTypesToString(recorder.events()); +} + +TEST_F(WindowEventDispatcherTest, MouseMovesHeld) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); + + ui::MouseEvent mouse_move_event(ui::ET_MOUSE_MOVED, gfx::Point(0, 0), + gfx::Point(0, 0), 0, 0); + DispatchEventUsingWindowDispatcher(&mouse_move_event); + // Discard MOUSE_ENTER. + recorder.Reset(); + + host()->dispatcher()->HoldPointerMoves(); + + // Check that we don't immediately dispatch the MOUSE_DRAGGED event. + ui::MouseEvent mouse_dragged_event(ui::ET_MOUSE_DRAGGED, gfx::Point(0, 0), + gfx::Point(0, 0), 0, 0); + DispatchEventUsingWindowDispatcher(&mouse_dragged_event); + EXPECT_TRUE(recorder.events().empty()); + + // Check that we do dispatch the held MOUSE_DRAGGED event before another type + // of event. + ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0), + gfx::Point(0, 0), 0, 0); + DispatchEventUsingWindowDispatcher(&mouse_pressed_event); + EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED", + EventTypesToString(recorder.events())); + recorder.Reset(); + + // Check that we coalesce held MOUSE_DRAGGED events. + ui::MouseEvent mouse_dragged_event2(ui::ET_MOUSE_DRAGGED, gfx::Point(10, 10), + gfx::Point(10, 10), 0, 0); + DispatchEventUsingWindowDispatcher(&mouse_dragged_event); + DispatchEventUsingWindowDispatcher(&mouse_dragged_event2); + EXPECT_TRUE(recorder.events().empty()); + DispatchEventUsingWindowDispatcher(&mouse_pressed_event); + EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED", + EventTypesToString(recorder.events())); + recorder.Reset(); + + // Check that on ReleasePointerMoves, held events are not dispatched + // immediately, but posted instead. + DispatchEventUsingWindowDispatcher(&mouse_dragged_event); + host()->dispatcher()->ReleasePointerMoves(); + EXPECT_TRUE(recorder.events().empty()); + RunAllPendingInMessageLoop(); + EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(recorder.events())); + recorder.Reset(); + + // However if another message comes in before the dispatch of the posted + // event, check that the posted event is dispatched before this new event. + host()->dispatcher()->HoldPointerMoves(); + DispatchEventUsingWindowDispatcher(&mouse_dragged_event); + host()->dispatcher()->ReleasePointerMoves(); + DispatchEventUsingWindowDispatcher(&mouse_pressed_event); + EXPECT_EQ("MOUSE_DRAGGED MOUSE_PRESSED", + EventTypesToString(recorder.events())); + recorder.Reset(); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(recorder.events().empty()); + + // Check that if the other message is another MOUSE_DRAGGED, we still coalesce + // them. + host()->dispatcher()->HoldPointerMoves(); + DispatchEventUsingWindowDispatcher(&mouse_dragged_event); + host()->dispatcher()->ReleasePointerMoves(); + DispatchEventUsingWindowDispatcher(&mouse_dragged_event2); + EXPECT_EQ("MOUSE_DRAGGED", EventTypesToString(recorder.events())); + recorder.Reset(); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(recorder.events().empty()); + + // Check that synthetic mouse move event has a right location when issued + // while holding pointer moves. + ui::MouseEvent mouse_dragged_event3(ui::ET_MOUSE_DRAGGED, gfx::Point(28, 28), + gfx::Point(28, 28), 0, 0); + host()->dispatcher()->HoldPointerMoves(); + DispatchEventUsingWindowDispatcher(&mouse_dragged_event); + DispatchEventUsingWindowDispatcher(&mouse_dragged_event2); + window->SetBounds(gfx::Rect(15, 15, 80, 80)); + DispatchEventUsingWindowDispatcher(&mouse_dragged_event3); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(recorder.events().empty()); + host()->dispatcher()->ReleasePointerMoves(); + RunAllPendingInMessageLoop(); + EXPECT_EQ("MOUSE_MOVED", EventTypesToString(recorder.events())); + EXPECT_EQ(gfx::Point(13, 13), recorder.mouse_location(0)); + recorder.Reset(); + root_window()->RemovePreTargetHandler(&recorder); +} + +TEST_F(WindowEventDispatcherTest, TouchMovesHeld) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window())); + + const gfx::Point touch_location(60, 60); + // Starting the touch and throwing out the first few events, since the system + // is going to generate synthetic mouse events that are not relevant to the + // test. + ui::TouchEvent touch_pressed_event( + ui::ET_TOUCH_PRESSED, touch_location, 0, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&touch_pressed_event); + recorder.WaitUntilReceivedEvent(ui::ET_GESTURE_SHOW_PRESS); + recorder.Reset(); + + host()->dispatcher()->HoldPointerMoves(); + + // Check that we don't immediately dispatch the TOUCH_MOVED event. + ui::TouchEvent touch_moved_event( + ui::ET_TOUCH_MOVED, touch_location, 0, ui::EventTimeForNow()); + ui::TouchEvent touch_moved_event2 = touch_moved_event; + ui::TouchEvent touch_moved_event3 = touch_moved_event; + + DispatchEventUsingWindowDispatcher(&touch_moved_event); + EXPECT_TRUE(recorder.events().empty()); + + // Check that on ReleasePointerMoves, held events are not dispatched + // immediately, but posted instead. + DispatchEventUsingWindowDispatcher(&touch_moved_event2); + host()->dispatcher()->ReleasePointerMoves(); + EXPECT_TRUE(recorder.events().empty()); + + RunAllPendingInMessageLoop(); + EXPECT_EQ("TOUCH_MOVED", EventTypesToString(recorder.events())); + recorder.Reset(); + + // If another touch event occurs then the held touch should be dispatched + // immediately before it. + ui::TouchEvent touch_released_event( + ui::ET_TOUCH_RELEASED, touch_location, 0, ui::EventTimeForNow()); + recorder.Reset(); + host()->dispatcher()->HoldPointerMoves(); + DispatchEventUsingWindowDispatcher(&touch_moved_event3); + DispatchEventUsingWindowDispatcher(&touch_released_event); + EXPECT_EQ("TOUCH_MOVED TOUCH_RELEASED GESTURE_TAP GESTURE_END", + EventTypesToString(recorder.events())); + recorder.Reset(); + host()->dispatcher()->ReleasePointerMoves(); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(recorder.events().empty()); +} + +// This event handler requests the dispatcher to start holding pointer-move +// events when it receives the first scroll-update gesture. +class HoldPointerOnScrollHandler : public ui::test::TestEventHandler { + public: + HoldPointerOnScrollHandler(WindowEventDispatcher* dispatcher, + EventFilterRecorder* filter) + : dispatcher_(dispatcher), + filter_(filter), + holding_moves_(false) {} + virtual ~HoldPointerOnScrollHandler() {} + + private: + // ui::test::TestEventHandler: + virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE { + if (!holding_moves_ && gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) { + holding_moves_ = true; + dispatcher_->HoldPointerMoves(); + filter_->Reset(); + } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) { + dispatcher_->ReleasePointerMoves(); + holding_moves_ = false; + } + } + + WindowEventDispatcher* dispatcher_; + EventFilterRecorder* filter_; + bool holding_moves_; + + DISALLOW_COPY_AND_ASSIGN(HoldPointerOnScrollHandler); +}; + +// Tests that touch-move events don't contribute to an in-progress scroll +// gesture if touch-move events are being held by the dispatcher. +TEST_F(WindowEventDispatcherTest, TouchMovesHeldOnScroll) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + test::TestWindowDelegate delegate; + HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window())); + window->AddPreTargetHandler(&handler); + + test::EventGenerator generator(root_window()); + generator.GestureScrollSequence( + gfx::Point(60, 60), gfx::Point(10, 60), + base::TimeDelta::FromMilliseconds(100), 25); + + // |handler| will have reset |filter| and started holding the touch-move + // events when scrolling started. At the end of the scroll (i.e. upon + // touch-release), the held touch-move event will have been dispatched first, + // along with the subsequent events (i.e. touch-release, scroll-end, and + // gesture-end). + const EventFilterRecorder::Events& events = recorder.events(); + EXPECT_EQ( + "TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED " + "GESTURE_SCROLL_END GESTURE_END", + EventTypesToString(events)); + ASSERT_EQ(2u, recorder.touch_locations().size()); + EXPECT_EQ(gfx::Point(-40, 10).ToString(), + recorder.touch_locations()[0].ToString()); + EXPECT_EQ(gfx::Point(-40, 10).ToString(), + recorder.touch_locations()[1].ToString()); +} + +// Tests that a 'held' touch-event does contribute to gesture event when it is +// dispatched. +TEST_F(WindowEventDispatcherTest, HeldTouchMoveContributesToGesture) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + + const gfx::Point location(20, 20); + ui::TouchEvent press( + ui::ET_TOUCH_PRESSED, location, 0, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&press); + EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_TOUCH_PRESSED)); + recorder.Reset(); + + host()->dispatcher()->HoldPointerMoves(); + + ui::TouchEvent move(ui::ET_TOUCH_MOVED, + location + gfx::Vector2d(100, 100), + 0, + ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&move); + EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED)); + EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_BEGIN)); + recorder.Reset(); + + host()->dispatcher()->ReleasePointerMoves(); + EXPECT_FALSE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED)); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_TOUCH_MOVED)); + EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_BEGIN)); + EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_SCROLL_UPDATE)); + + root_window()->RemovePreTargetHandler(&recorder); +} + +// Tests that synthetic mouse events are ignored when mouse +// events are disabled. +TEST_F(WindowEventDispatcherTest, DispatchSyntheticMouseEvents) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window())); + window->Show(); + window->SetCapture(); + + test::TestCursorClient cursor_client(root_window()); + + // Dispatch a non-synthetic mouse event when mouse events are enabled. + ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), + gfx::Point(10, 10), 0, 0); + DispatchEventUsingWindowDispatcher(&mouse1); + EXPECT_FALSE(recorder.events().empty()); + recorder.Reset(); + + // Dispatch a synthetic mouse event when mouse events are enabled. + ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), + gfx::Point(10, 10), ui::EF_IS_SYNTHESIZED, 0); + DispatchEventUsingWindowDispatcher(&mouse2); + EXPECT_FALSE(recorder.events().empty()); + recorder.Reset(); + + // Dispatch a synthetic mouse event when mouse events are disabled. + cursor_client.DisableMouseEvents(); + DispatchEventUsingWindowDispatcher(&mouse2); + EXPECT_TRUE(recorder.events().empty()); + root_window()->RemovePreTargetHandler(&recorder); +} + +// Tests that a mouse-move event is not synthesized when a mouse-button is down. +TEST_F(WindowEventDispatcherTest, DoNotSynthesizeWhileButtonDown) { + EventFilterRecorder recorder; + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window())); + window->Show(); + + window->AddPreTargetHandler(&recorder); + // Dispatch a non-synthetic mouse event when mouse events are enabled. + ui::MouseEvent mouse1(ui::ET_MOUSE_PRESSED, gfx::Point(10, 10), + gfx::Point(10, 10), ui::EF_LEFT_MOUSE_BUTTON, + ui::EF_LEFT_MOUSE_BUTTON); + DispatchEventUsingWindowDispatcher(&mouse1); + ASSERT_EQ(1u, recorder.events().size()); + EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.events()[0]); + window->RemovePreTargetHandler(&recorder); + recorder.Reset(); + + // Move |window| away from underneath the cursor. + root_window()->AddPreTargetHandler(&recorder); + window->SetBounds(gfx::Rect(30, 30, 100, 100)); + EXPECT_TRUE(recorder.events().empty()); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(recorder.events().empty()); + root_window()->RemovePreTargetHandler(&recorder); +} + +// Tests synthetic mouse events generated when window bounds changes such that +// the cursor previously outside the window becomes inside, or vice versa. +// Do not synthesize events if the window ignores events or is invisible. +TEST_F(WindowEventDispatcherTest, SynthesizeMouseEventsOnWindowBoundsChanged) { + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1234, gfx::Rect(5, 5, 100, 100), root_window())); + window->Show(); + window->SetCapture(); + + EventFilterRecorder recorder; + window->AddPreTargetHandler(&recorder); + + // Dispatch a non-synthetic mouse event to place cursor inside window bounds. + ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), + gfx::Point(10, 10), 0, 0); + DispatchEventUsingWindowDispatcher(&mouse); + EXPECT_FALSE(recorder.events().empty()); + recorder.Reset(); + + // Update the window bounds so that cursor is now outside the window. + // This should trigger a synthetic MOVED event. + gfx::Rect bounds1(20, 20, 100, 100); + window->SetBounds(bounds1); + RunAllPendingInMessageLoop(); + ASSERT_FALSE(recorder.events().empty()); + ASSERT_FALSE(recorder.mouse_event_flags().empty()); + EXPECT_EQ(ui::ET_MOUSE_MOVED, recorder.events().back()); + EXPECT_EQ(ui::EF_IS_SYNTHESIZED, recorder.mouse_event_flags().back()); + recorder.Reset(); + + // Set window to ignore events. + window->set_ignore_events(true); + + // Update the window bounds so that cursor is back inside the window. + // This should not trigger a synthetic event. + gfx::Rect bounds2(5, 5, 100, 100); + window->SetBounds(bounds2); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(recorder.events().empty()); + recorder.Reset(); + + // Set window to accept events but invisible. + window->set_ignore_events(false); + window->Hide(); + recorder.Reset(); + + // Update the window bounds so that cursor is outside the window. + // This should not trigger a synthetic event. + window->SetBounds(bounds1); + RunAllPendingInMessageLoop(); + EXPECT_TRUE(recorder.events().empty()); +} + +// Tests that a mouse exit is dispatched to the last known cursor location +// when the cursor becomes invisible. +TEST_F(WindowEventDispatcherTest, DispatchMouseExitWhenCursorHidden) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + + test::TestWindowDelegate delegate; + gfx::Point window_origin(7, 18); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1234, gfx::Rect(window_origin, gfx::Size(100, 100)), + root_window())); + window->Show(); + + // Dispatch a mouse move event into the window. + gfx::Point mouse_location(gfx::Point(15, 25)); + ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location, + mouse_location, 0, 0); + EXPECT_TRUE(recorder.events().empty()); + DispatchEventUsingWindowDispatcher(&mouse1); + EXPECT_FALSE(recorder.events().empty()); + recorder.Reset(); + + // Hide the cursor and verify a mouse exit was dispatched. + host()->OnCursorVisibilityChanged(false); + EXPECT_FALSE(recorder.events().empty()); + EXPECT_EQ("MOUSE_EXITED", EventTypesToString(recorder.events())); + + // Verify the mouse exit was dispatched at the correct location + // (in the correct coordinate space). + int translated_x = mouse_location.x() - window_origin.x(); + int translated_y = mouse_location.y() - window_origin.y(); + gfx::Point translated_point(translated_x, translated_y); + EXPECT_EQ(recorder.mouse_location(0).ToString(), translated_point.ToString()); + root_window()->RemovePreTargetHandler(&recorder); +} + +// Tests that a synthetic mouse exit is dispatched to the last known cursor +// location after mouse events are disabled on the cursor client. +TEST_F(WindowEventDispatcherTest, + DispatchSyntheticMouseExitAfterMouseEventsDisabled) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + + test::TestWindowDelegate delegate; + gfx::Point window_origin(7, 18); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1234, gfx::Rect(window_origin, gfx::Size(100, 100)), + root_window())); + window->Show(); + + // Dispatch a mouse move event into the window. + gfx::Point mouse_location(gfx::Point(15, 25)); + ui::MouseEvent mouse1(ui::ET_MOUSE_MOVED, mouse_location, + mouse_location, 0, 0); + EXPECT_TRUE(recorder.events().empty()); + DispatchEventUsingWindowDispatcher(&mouse1); + EXPECT_FALSE(recorder.events().empty()); + recorder.Reset(); + + test::TestCursorClient cursor_client(root_window()); + cursor_client.DisableMouseEvents(); + + gfx::Point mouse_exit_location(gfx::Point(150, 150)); + ui::MouseEvent mouse2(ui::ET_MOUSE_EXITED, gfx::Point(150, 150), + gfx::Point(150, 150), ui::EF_IS_SYNTHESIZED, 0); + DispatchEventUsingWindowDispatcher(&mouse2); + + EXPECT_FALSE(recorder.events().empty()); + // We get the mouse exited event twice in our filter. Once during the + // predispatch phase and during the actual dispatch. + EXPECT_EQ("MOUSE_EXITED MOUSE_EXITED", EventTypesToString(recorder.events())); + + // Verify the mouse exit was dispatched at the correct location + // (in the correct coordinate space). + int translated_x = mouse_exit_location.x() - window_origin.x(); + int translated_y = mouse_exit_location.y() - window_origin.y(); + gfx::Point translated_point(translated_x, translated_y); + EXPECT_EQ(recorder.mouse_location(0).ToString(), translated_point.ToString()); + root_window()->RemovePreTargetHandler(&recorder); +} + +class DeletingEventFilter : public ui::EventHandler { + public: + DeletingEventFilter() + : delete_during_pre_handle_(false) {} + virtual ~DeletingEventFilter() {} + + void Reset(bool delete_during_pre_handle) { + delete_during_pre_handle_ = delete_during_pre_handle; + } + + private: + // Overridden from ui::EventHandler: + virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { + if (delete_during_pre_handle_) + delete event->target(); + } + + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + if (delete_during_pre_handle_) + delete event->target(); + } + + bool delete_during_pre_handle_; + + DISALLOW_COPY_AND_ASSIGN(DeletingEventFilter); +}; + +class DeletingWindowDelegate : public test::TestWindowDelegate { + public: + DeletingWindowDelegate() + : window_(NULL), + delete_during_handle_(false), + got_event_(false) {} + virtual ~DeletingWindowDelegate() {} + + void Reset(Window* window, bool delete_during_handle) { + window_ = window; + delete_during_handle_ = delete_during_handle; + got_event_ = false; + } + bool got_event() const { return got_event_; } + + private: + // Overridden from WindowDelegate: + virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE { + if (delete_during_handle_) + delete window_; + got_event_ = true; + } + + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + if (delete_during_handle_) + delete window_; + got_event_ = true; + } + + Window* window_; + bool delete_during_handle_; + bool got_event_; + + DISALLOW_COPY_AND_ASSIGN(DeletingWindowDelegate); +}; + +TEST_F(WindowEventDispatcherTest, DeleteWindowDuringDispatch) { + // Verifies that we can delete a window during each phase of event handling. + // Deleting the window should not cause a crash, only prevent further + // processing from occurring. + scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); + DeletingWindowDelegate d11; + Window* w11 = CreateNormalWindow(11, w1.get(), &d11); + WindowTracker tracker; + DeletingEventFilter w1_filter; + w1->AddPreTargetHandler(&w1_filter); + client::GetFocusClient(w1.get())->FocusWindow(w11); + + test::EventGenerator generator(root_window(), w11); + + // First up, no one deletes anything. + tracker.Add(w11); + d11.Reset(w11, false); + + generator.PressLeftButton(); + EXPECT_TRUE(tracker.Contains(w11)); + EXPECT_TRUE(d11.got_event()); + generator.ReleaseLeftButton(); + + // Delegate deletes w11. This will prevent the post-handle step from applying. + w1_filter.Reset(false); + d11.Reset(w11, true); + generator.PressKey(ui::VKEY_A, 0); + EXPECT_FALSE(tracker.Contains(w11)); + EXPECT_TRUE(d11.got_event()); + + // Pre-handle step deletes w11. This will prevent the delegate and the post- + // handle steps from applying. + w11 = CreateNormalWindow(11, w1.get(), &d11); + w1_filter.Reset(true); + d11.Reset(w11, false); + generator.PressLeftButton(); + EXPECT_FALSE(tracker.Contains(w11)); + EXPECT_FALSE(d11.got_event()); +} + +namespace { + +// A window delegate that detaches the parent of the target's parent window when +// it receives a tap event. +class DetachesParentOnTapDelegate : public test::TestWindowDelegate { + public: + DetachesParentOnTapDelegate() {} + virtual ~DetachesParentOnTapDelegate() {} + + private: + virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + event->SetHandled(); + return; + } + + if (event->type() == ui::ET_GESTURE_TAP) { + Window* parent = static_cast<Window*>(event->target())->parent(); + parent->parent()->RemoveChild(parent); + event->SetHandled(); + } + } + + DISALLOW_COPY_AND_ASSIGN(DetachesParentOnTapDelegate); +}; + +} // namespace + +// Tests that the gesture recognizer is reset for all child windows when a +// window hides. No expectations, just checks that the test does not crash. +TEST_F(WindowEventDispatcherTest, + GestureRecognizerResetsTargetWhenParentHides) { + scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); + DetachesParentOnTapDelegate delegate; + scoped_ptr<Window> parent(CreateNormalWindow(22, w1.get(), NULL)); + Window* child = CreateNormalWindow(11, parent.get(), &delegate); + test::EventGenerator generator(root_window(), child); + generator.GestureTapAt(gfx::Point(40, 40)); +} + +namespace { + +// A window delegate that processes nested gestures on tap. +class NestedGestureDelegate : public test::TestWindowDelegate { + public: + NestedGestureDelegate(test::EventGenerator* generator, + const gfx::Point tap_location) + : generator_(generator), + tap_location_(tap_location), + gesture_end_count_(0) {} + virtual ~NestedGestureDelegate() {} + + int gesture_end_count() const { return gesture_end_count_; } + + private: + virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { + switch (event->type()) { + case ui::ET_GESTURE_TAP_DOWN: + event->SetHandled(); + break; + case ui::ET_GESTURE_TAP: + if (generator_) + generator_->GestureTapAt(tap_location_); + event->SetHandled(); + break; + case ui::ET_GESTURE_END: + ++gesture_end_count_; + break; + default: + break; + } + } + + test::EventGenerator* generator_; + const gfx::Point tap_location_; + int gesture_end_count_; + DISALLOW_COPY_AND_ASSIGN(NestedGestureDelegate); +}; + +} // namespace + +// Tests that gesture end is delivered after nested gesture processing. +TEST_F(WindowEventDispatcherTest, GestureEndDeliveredAfterNestedGestures) { + NestedGestureDelegate d1(NULL, gfx::Point()); + scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &d1)); + w1->SetBounds(gfx::Rect(0, 0, 100, 100)); + + test::EventGenerator nested_generator(root_window(), w1.get()); + NestedGestureDelegate d2(&nested_generator, w1->bounds().CenterPoint()); + scoped_ptr<Window> w2(CreateNormalWindow(1, root_window(), &d2)); + w2->SetBounds(gfx::Rect(100, 0, 100, 100)); + + // Tap on w2 which triggers nested gestures for w1. + test::EventGenerator generator(root_window(), w2.get()); + generator.GestureTapAt(w2->bounds().CenterPoint()); + + // Both windows should get their gesture end events. + EXPECT_EQ(1, d1.gesture_end_count()); + EXPECT_EQ(1, d2.gesture_end_count()); +} + +// Tests whether we can repost the Tap down gesture event. +TEST_F(WindowEventDispatcherTest, RepostTapdownGestureTest) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); + + ui::GestureEventDetails details(ui::ET_GESTURE_TAP_DOWN, 0.0f, 0.0f); + gfx::Point point(10, 10); + ui::GestureEvent event(ui::ET_GESTURE_TAP_DOWN, + point.x(), + point.y(), + 0, + ui::EventTimeForNow(), + details, + 0); + host()->dispatcher()->RepostEvent(event); + RunAllPendingInMessageLoop(); + // TODO(rbyers): Currently disabled - crbug.com/170987 + EXPECT_FALSE(EventTypesToString(recorder.events()).find("GESTURE_TAP_DOWN") != + std::string::npos); + recorder.Reset(); + root_window()->RemovePreTargetHandler(&recorder); +} + +// This class inherits from the EventFilterRecorder class which provides a +// facility to record events. This class additionally provides a facility to +// repost the ET_GESTURE_TAP_DOWN gesture to the target window and records +// events after that. +class RepostGestureEventRecorder : public EventFilterRecorder { + public: + RepostGestureEventRecorder(aura::Window* repost_source, + aura::Window* repost_target) + : repost_source_(repost_source), + repost_target_(repost_target), + reposted_(false), + done_cleanup_(false) {} + + virtual ~RepostGestureEventRecorder() {} + + virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE { + if (reposted_ && event->type() == ui::ET_TOUCH_PRESSED) { + done_cleanup_ = true; + Reset(); + } + EventFilterRecorder::OnTouchEvent(event); + } + + virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { + EXPECT_EQ(done_cleanup_ ? repost_target_ : repost_source_, event->target()); + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + if (!reposted_) { + EXPECT_NE(repost_target_, event->target()); + reposted_ = true; + repost_target_->GetHost()->dispatcher()->RepostEvent(*event); + // Ensure that the reposted gesture event above goes to the + // repost_target_; + repost_source_->GetRootWindow()->RemoveChild(repost_source_); + return; + } + } + EventFilterRecorder::OnGestureEvent(event); + } + + // Ignore mouse events as they don't fire at all times. This causes + // the GestureRepostEventOrder test to fail randomly. + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {} + + private: + aura::Window* repost_source_; + aura::Window* repost_target_; + // set to true if we reposted the ET_GESTURE_TAP_DOWN event. + bool reposted_; + // set true if we're done cleaning up after hiding repost_source_; + bool done_cleanup_; + DISALLOW_COPY_AND_ASSIGN(RepostGestureEventRecorder); +}; + +// Tests whether events which are generated after the reposted gesture event +// are received after that. In this case the scroll sequence events should +// be received after the reposted gesture event. +TEST_F(WindowEventDispatcherTest, GestureRepostEventOrder) { + // Expected events at the end for the repost_target window defined below. + const char kExpectedTargetEvents[] = + // TODO)(rbyers): Gesture event reposting is disabled - crbug.com/279039. + // "GESTURE_BEGIN GESTURE_TAP_DOWN " + "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " + "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE TOUCH_MOVED " + "GESTURE_SCROLL_UPDATE TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED " + "GESTURE_SCROLL_END GESTURE_END"; + // We create two windows. + // The first window (repost_source) is the one to which the initial tap + // gesture is sent. It reposts this event to the second window + // (repost_target). + // We then generate the scroll sequence for repost_target and look for two + // ET_GESTURE_TAP_DOWN events in the event list at the end. + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> repost_target(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); + + scoped_ptr<aura::Window> repost_source(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(0, 0, 50, 50), root_window())); + + RepostGestureEventRecorder repost_event_recorder(repost_source.get(), + repost_target.get()); + root_window()->AddPreTargetHandler(&repost_event_recorder); + + // Generate a tap down gesture for the repost_source. This will be reposted + // to repost_target. + test::EventGenerator repost_generator(root_window(), repost_source.get()); + repost_generator.GestureTapAt(gfx::Point(40, 40)); + RunAllPendingInMessageLoop(); + + test::EventGenerator scroll_generator(root_window(), repost_target.get()); + scroll_generator.GestureScrollSequence( + gfx::Point(80, 80), + gfx::Point(100, 100), + base::TimeDelta::FromMilliseconds(100), + 3); + RunAllPendingInMessageLoop(); + + int tap_down_count = 0; + for (size_t i = 0; i < repost_event_recorder.events().size(); ++i) { + if (repost_event_recorder.events()[i] == ui::ET_GESTURE_TAP_DOWN) + ++tap_down_count; + } + + // We expect two tap down events. One from the repost and the other one from + // the scroll sequence posted above. + // TODO(rbyers): Currently disabled - crbug.com/170987 + EXPECT_EQ(1, tap_down_count); + + EXPECT_EQ(kExpectedTargetEvents, + EventTypesToString(repost_event_recorder.events())); + root_window()->RemovePreTargetHandler(&repost_event_recorder); +} + +class OnMouseExitDeletingEventFilter : public EventFilterRecorder { + public: + OnMouseExitDeletingEventFilter() : window_to_delete_(NULL) {} + virtual ~OnMouseExitDeletingEventFilter() {} + + void set_window_to_delete(Window* window_to_delete) { + window_to_delete_ = window_to_delete; + } + + private: + // Overridden from ui::EventHandler: + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + EventFilterRecorder::OnMouseEvent(event); + if (window_to_delete_) { + delete window_to_delete_; + window_to_delete_ = NULL; + } + } + + Window* window_to_delete_; + + DISALLOW_COPY_AND_ASSIGN(OnMouseExitDeletingEventFilter); +}; + +// Tests that RootWindow drops mouse-moved event that is supposed to be sent to +// a child, but the child is destroyed because of the synthesized mouse-exit +// event generated on the previous mouse_moved_handler_. +TEST_F(WindowEventDispatcherTest, DeleteWindowDuringMouseMovedDispatch) { + // Create window 1 and set its event filter. Window 1 will take ownership of + // the event filter. + scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), NULL)); + OnMouseExitDeletingEventFilter w1_filter; + w1->AddPreTargetHandler(&w1_filter); + w1->SetBounds(gfx::Rect(20, 20, 60, 60)); + EXPECT_EQ(NULL, host()->dispatcher()->mouse_moved_handler()); + + test::EventGenerator generator(root_window(), w1.get()); + + // Move mouse over window 1 to set it as the |mouse_moved_handler_| for the + // root window. + generator.MoveMouseTo(51, 51); + EXPECT_EQ(w1.get(), host()->dispatcher()->mouse_moved_handler()); + + // Create window 2 under the mouse cursor and stack it above window 1. + Window* w2 = CreateNormalWindow(2, root_window(), NULL); + w2->SetBounds(gfx::Rect(30, 30, 40, 40)); + root_window()->StackChildAbove(w2, w1.get()); + + // Set window 2 as the window that is to be deleted when a mouse-exited event + // happens on window 1. + w1_filter.set_window_to_delete(w2); + + // Move mosue over window 2. This should generate a mouse-exited event for + // window 1 resulting in deletion of window 2. The original mouse-moved event + // that was targeted to window 2 should be dropped since window 2 is + // destroyed. This test passes if no crash happens. + generator.MoveMouseTo(52, 52); + EXPECT_EQ(NULL, host()->dispatcher()->mouse_moved_handler()); + + // Check events received by window 1. + EXPECT_EQ("MOUSE_ENTERED MOUSE_MOVED MOUSE_EXITED", + EventTypesToString(w1_filter.events())); +} + +namespace { + +// Used to track if OnWindowDestroying() is invoked and if there is a valid +// RootWindow at such time. +class ValidRootDuringDestructionWindowObserver : public aura::WindowObserver { + public: + ValidRootDuringDestructionWindowObserver(bool* got_destroying, + bool* has_valid_root) + : got_destroying_(got_destroying), + has_valid_root_(has_valid_root) { + } + + // WindowObserver: + virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { + *got_destroying_ = true; + *has_valid_root_ = (window->GetRootWindow() != NULL); + } + + private: + bool* got_destroying_; + bool* has_valid_root_; + + DISALLOW_COPY_AND_ASSIGN(ValidRootDuringDestructionWindowObserver); +}; + +} // namespace + +// Verifies GetRootWindow() from ~Window returns a valid root. +TEST_F(WindowEventDispatcherTest, ValidRootDuringDestruction) { + bool got_destroying = false; + bool has_valid_root = false; + ValidRootDuringDestructionWindowObserver observer(&got_destroying, + &has_valid_root); + { + scoped_ptr<WindowTreeHost> host( + WindowTreeHost::Create(gfx::Rect(0, 0, 100, 100))); + host->InitHost(); + // Owned by WindowEventDispatcher. + Window* w1 = CreateNormalWindow(1, host->window(), NULL); + w1->AddObserver(&observer); + } + EXPECT_TRUE(got_destroying); + EXPECT_TRUE(has_valid_root); +} + +namespace { + +// See description above DontResetHeldEvent for details. +class DontResetHeldEventWindowDelegate : public test::TestWindowDelegate { + public: + explicit DontResetHeldEventWindowDelegate(aura::Window* root) + : root_(root), + mouse_event_count_(0) {} + virtual ~DontResetHeldEventWindowDelegate() {} + + int mouse_event_count() const { return mouse_event_count_; } + + // TestWindowDelegate: + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && + mouse_event_count_++ == 0) { + ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, + gfx::Point(10, 10), gfx::Point(10, 10), + ui::EF_SHIFT_DOWN, 0); + root_->GetHost()->dispatcher()->RepostEvent(mouse_event); + } + } + + private: + Window* root_; + int mouse_event_count_; + + DISALLOW_COPY_AND_ASSIGN(DontResetHeldEventWindowDelegate); +}; + +} // namespace + +// Verifies RootWindow doesn't reset |RootWindow::held_repostable_event_| after +// dispatching. This is done by using DontResetHeldEventWindowDelegate, which +// tracks the number of events with ui::EF_SHIFT_DOWN set (all reposted events +// have EF_SHIFT_DOWN). When the first event is seen RepostEvent() is used to +// schedule another reposted event. +TEST_F(WindowEventDispatcherTest, DontResetHeldEvent) { + DontResetHeldEventWindowDelegate delegate(root_window()); + scoped_ptr<Window> w1(CreateNormalWindow(1, root_window(), &delegate)); + w1->SetBounds(gfx::Rect(0, 0, 40, 40)); + ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, + gfx::Point(10, 10), gfx::Point(10, 10), + ui::EF_SHIFT_DOWN, 0); + root_window()->GetHost()->dispatcher()->RepostEvent(pressed); + ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, + gfx::Point(10, 10), gfx::Point(10, 10), 0, 0); + // Dispatch an event to flush event scheduled by way of RepostEvent(). + DispatchEventUsingWindowDispatcher(&pressed2); + // Delegate should have seen reposted event (identified by way of + // EF_SHIFT_DOWN). Dispatch another event to flush the second + // RepostedEvent(). + EXPECT_EQ(1, delegate.mouse_event_count()); + DispatchEventUsingWindowDispatcher(&pressed2); + EXPECT_EQ(2, delegate.mouse_event_count()); +} + +namespace { + +// See description above DeleteHostFromHeldMouseEvent for details. +class DeleteHostFromHeldMouseEventDelegate + : public test::TestWindowDelegate { + public: + explicit DeleteHostFromHeldMouseEventDelegate(WindowTreeHost* host) + : host_(host), + got_mouse_event_(false), + got_destroy_(false) { + } + virtual ~DeleteHostFromHeldMouseEventDelegate() {} + + bool got_mouse_event() const { return got_mouse_event_; } + bool got_destroy() const { return got_destroy_; } + + // TestWindowDelegate: + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + if ((event->flags() & ui::EF_SHIFT_DOWN) != 0) { + got_mouse_event_ = true; + delete host_; + } + } + virtual void OnWindowDestroyed(Window* window) OVERRIDE { + got_destroy_ = true; + } + + private: + WindowTreeHost* host_; + bool got_mouse_event_; + bool got_destroy_; + + DISALLOW_COPY_AND_ASSIGN(DeleteHostFromHeldMouseEventDelegate); +}; + +} // namespace + +// Verifies if a WindowTreeHost is deleted from dispatching a held mouse event +// we don't crash. +TEST_F(WindowEventDispatcherTest, DeleteHostFromHeldMouseEvent) { + // Should be deleted by |delegate|. + WindowTreeHost* h2 = WindowTreeHost::Create(gfx::Rect(0, 0, 100, 100)); + h2->InitHost(); + DeleteHostFromHeldMouseEventDelegate delegate(h2); + // Owned by |h2|. + Window* w1 = CreateNormalWindow(1, h2->window(), &delegate); + w1->SetBounds(gfx::Rect(0, 0, 40, 40)); + ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, + gfx::Point(10, 10), gfx::Point(10, 10), + ui::EF_SHIFT_DOWN, 0); + h2->dispatcher()->RepostEvent(pressed); + // RunAllPendingInMessageLoop() to make sure the |pressed| is run. + RunAllPendingInMessageLoop(); + EXPECT_TRUE(delegate.got_mouse_event()); + EXPECT_TRUE(delegate.got_destroy()); +} + +TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveTouches) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); + + gfx::Point position1 = root_window()->bounds().origin(); + ui::TouchEvent press( + ui::ET_TOUCH_PRESSED, position1, 0, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&press); + + EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN", + EventTypesToString(recorder.GetAndResetEvents())); + + window->Hide(); + + EXPECT_EQ(ui::ET_TOUCH_CANCELLED, recorder.events()[0]); + EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_TAP_CANCEL)); + EXPECT_TRUE(recorder.HasReceivedEvent(ui::ET_GESTURE_END)); + EXPECT_EQ(3U, recorder.events().size()); + root_window()->RemovePreTargetHandler(&recorder); +} + +TEST_F(WindowEventDispatcherTest, WindowHideCancelsActiveGestures) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window())); + + gfx::Point position1 = root_window()->bounds().origin(); + gfx::Point position2 = root_window()->bounds().CenterPoint(); + ui::TouchEvent press( + ui::ET_TOUCH_PRESSED, position1, 0, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&press); + + ui::TouchEvent move( + ui::ET_TOUCH_MOVED, position2, 0, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&move); + + ui::TouchEvent press2( + ui::ET_TOUCH_PRESSED, position1, 1, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&press2); + + // TODO(tdresser): once the unified Gesture Recognizer has stuck, remove the + // special casing here. See crbug.com/332418 for details. + std::string expected = + "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " + "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE " + "TOUCH_PRESSED GESTURE_BEGIN GESTURE_PINCH_BEGIN"; + + std::string expected_ugr = + "TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " + "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE " + "TOUCH_PRESSED GESTURE_BEGIN"; + + std::string events_string = EventTypesToString(recorder.GetAndResetEvents()); + EXPECT_TRUE((expected == events_string) || (expected_ugr == events_string)); + + window->Hide(); + + expected = + "TOUCH_CANCELLED GESTURE_PINCH_END GESTURE_END TOUCH_CANCELLED " + "GESTURE_SCROLL_END GESTURE_END"; + expected_ugr = + "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END GESTURE_END " + "TOUCH_CANCELLED"; + + events_string = EventTypesToString(recorder.GetAndResetEvents()); + EXPECT_TRUE((expected == events_string) || (expected_ugr == events_string)); + + root_window()->RemovePreTargetHandler(&recorder); +} + +// Places two windows side by side. Presses down on one window, and starts a +// scroll. Sets capture on the other window and ensures that the "ending" events +// aren't sent to the window which gained capture. +TEST_F(WindowEventDispatcherTest, EndingEventDoesntRetarget) { + EventFilterRecorder recorder1; + EventFilterRecorder recorder2; + scoped_ptr<Window> window1(CreateNormalWindow(1, root_window(), NULL)); + window1->SetBounds(gfx::Rect(0, 0, 40, 40)); + + scoped_ptr<Window> window2(CreateNormalWindow(2, root_window(), NULL)); + window2->SetBounds(gfx::Rect(40, 0, 40, 40)); + + window1->AddPreTargetHandler(&recorder1); + window2->AddPreTargetHandler(&recorder2); + + gfx::Point position = window1->bounds().origin(); + ui::TouchEvent press( + ui::ET_TOUCH_PRESSED, position, 0, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&press); + + gfx::Point position2 = window1->bounds().CenterPoint(); + ui::TouchEvent move( + ui::ET_TOUCH_MOVED, position2, 0, ui::EventTimeForNow()); + DispatchEventUsingWindowDispatcher(&move); + + window2->SetCapture(); + + EXPECT_EQ("TOUCH_PRESSED GESTURE_BEGIN GESTURE_TAP_DOWN TOUCH_MOVED " + "GESTURE_TAP_CANCEL GESTURE_SCROLL_BEGIN GESTURE_SCROLL_UPDATE " + "TOUCH_CANCELLED GESTURE_SCROLL_END GESTURE_END", + EventTypesToString(recorder1.events())); + + EXPECT_TRUE(recorder2.events().empty()); +} + +namespace { + +// This class creates and manages a window which is destroyed as soon as +// capture is lost. This is the case for the drag and drop capture window. +class CaptureWindowTracker : public test::TestWindowDelegate { + public: + CaptureWindowTracker() {} + virtual ~CaptureWindowTracker() {} + + void CreateCaptureWindow(aura::Window* root_window) { + capture_window_.reset(test::CreateTestWindowWithDelegate( + this, -1234, gfx::Rect(20, 20, 20, 20), root_window)); + capture_window_->SetCapture(); + } + + void reset() { + capture_window_.reset(); + } + + virtual void OnCaptureLost() OVERRIDE { + capture_window_.reset(); + } + + virtual void OnWindowDestroyed(Window* window) OVERRIDE { + TestWindowDelegate::OnWindowDestroyed(window); + capture_window_.reset(); + } + + aura::Window* capture_window() { return capture_window_.get(); } + + private: + scoped_ptr<aura::Window> capture_window_; + + DISALLOW_COPY_AND_ASSIGN(CaptureWindowTracker); +}; + +} + +// Verifies handling loss of capture by the capture window being hidden. +TEST_F(WindowEventDispatcherTest, CaptureWindowHidden) { + CaptureWindowTracker capture_window_tracker; + capture_window_tracker.CreateCaptureWindow(root_window()); + capture_window_tracker.capture_window()->Hide(); + EXPECT_EQ(NULL, capture_window_tracker.capture_window()); +} + +// Verifies handling loss of capture by the capture window being destroyed. +TEST_F(WindowEventDispatcherTest, CaptureWindowDestroyed) { + CaptureWindowTracker capture_window_tracker; + capture_window_tracker.CreateCaptureWindow(root_window()); + capture_window_tracker.reset(); + EXPECT_EQ(NULL, capture_window_tracker.capture_window()); +} + +class ExitMessageLoopOnMousePress : public ui::test::TestEventHandler { + public: + ExitMessageLoopOnMousePress() {} + virtual ~ExitMessageLoopOnMousePress() {} + + protected: + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + ui::test::TestEventHandler::OnMouseEvent(event); + if (event->type() == ui::ET_MOUSE_PRESSED) + base::MessageLoopForUI::current()->Quit(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ExitMessageLoopOnMousePress); +}; + +class WindowEventDispatcherTestWithMessageLoop + : public WindowEventDispatcherTest { + public: + WindowEventDispatcherTestWithMessageLoop() {} + virtual ~WindowEventDispatcherTestWithMessageLoop() {} + + void RunTest() { + // Reset any event the window may have received when bringing up the window + // (e.g. mouse-move events if the mouse cursor is over the window). + handler_.Reset(); + + // Start a nested message-loop, post an event to be dispatched, and then + // terminate the message-loop. When the message-loop unwinds and gets back, + // the reposted event should not have fired. + scoped_ptr<ui::MouseEvent> mouse(new ui::MouseEvent(ui::ET_MOUSE_PRESSED, + gfx::Point(10, 10), + gfx::Point(10, 10), + ui::EF_NONE, + ui::EF_NONE)); + message_loop()->PostTask( + FROM_HERE, + base::Bind(&WindowEventDispatcherTestWithMessageLoop::RepostEventHelper, + host()->dispatcher(), + base::Passed(&mouse))); + message_loop()->PostTask(FROM_HERE, message_loop()->QuitClosure()); + + base::MessageLoop::ScopedNestableTaskAllower allow(message_loop()); + base::RunLoop loop; + loop.Run(); + EXPECT_EQ(0, handler_.num_mouse_events()); + + // Let the current message-loop run. The event-handler will terminate the + // message-loop when it receives the reposted event. + } + + base::MessageLoop* message_loop() { + return base::MessageLoopForUI::current(); + } + + protected: + virtual void SetUp() OVERRIDE { + WindowEventDispatcherTest::SetUp(); + window_.reset(CreateNormalWindow(1, root_window(), NULL)); + window_->AddPreTargetHandler(&handler_); + } + + virtual void TearDown() OVERRIDE { + window_.reset(); + WindowEventDispatcherTest::TearDown(); + } + + private: + // Used to avoid a copying |event| when binding to a closure. + static void RepostEventHelper(WindowEventDispatcher* dispatcher, + scoped_ptr<ui::MouseEvent> event) { + dispatcher->RepostEvent(*event); + } + + scoped_ptr<Window> window_; + ExitMessageLoopOnMousePress handler_; + + DISALLOW_COPY_AND_ASSIGN(WindowEventDispatcherTestWithMessageLoop); +}; + +TEST_F(WindowEventDispatcherTestWithMessageLoop, EventRepostedInNonNestedLoop) { + CHECK(!message_loop()->is_running()); + // Perform the test in a callback, so that it runs after the message-loop + // starts. + message_loop()->PostTask( + FROM_HERE, base::Bind( + &WindowEventDispatcherTestWithMessageLoop::RunTest, + base::Unretained(this))); + message_loop()->Run(); +} + +class WindowEventDispatcherTestInHighDPI : public WindowEventDispatcherTest { + public: + WindowEventDispatcherTestInHighDPI() {} + virtual ~WindowEventDispatcherTestInHighDPI() {} + + protected: + virtual void SetUp() OVERRIDE { + WindowEventDispatcherTest::SetUp(); + test_screen()->SetDeviceScaleFactor(2.f); + } +}; + +TEST_F(WindowEventDispatcherTestInHighDPI, EventLocationTransform) { + test::TestWindowDelegate delegate; + scoped_ptr<aura::Window> child(test::CreateTestWindowWithDelegate(&delegate, + 1234, gfx::Rect(20, 20, 100, 100), root_window())); + child->Show(); + + ui::test::TestEventHandler handler_child; + ui::test::TestEventHandler handler_root; + root_window()->AddPreTargetHandler(&handler_root); + child->AddPreTargetHandler(&handler_child); + + { + ui::MouseEvent move(ui::ET_MOUSE_MOVED, + gfx::Point(30, 30), gfx::Point(30, 30), + ui::EF_NONE, ui::EF_NONE); + DispatchEventUsingWindowDispatcher(&move); + EXPECT_EQ(0, handler_child.num_mouse_events()); + EXPECT_EQ(1, handler_root.num_mouse_events()); + } + + { + ui::MouseEvent move(ui::ET_MOUSE_MOVED, + gfx::Point(50, 50), gfx::Point(50, 50), + ui::EF_NONE, ui::EF_NONE); + DispatchEventUsingWindowDispatcher(&move); + // The child receives an ENTER, and a MOVED event. + EXPECT_EQ(2, handler_child.num_mouse_events()); + // The root receives both the ENTER and the MOVED events dispatched to + // |child|, as well as an EXIT event. + EXPECT_EQ(3, handler_root.num_mouse_events()); + } + + child->RemovePreTargetHandler(&handler_child); + root_window()->RemovePreTargetHandler(&handler_root); +} + +TEST_F(WindowEventDispatcherTestInHighDPI, TouchMovesHeldOnScroll) { + EventFilterRecorder recorder; + root_window()->AddPreTargetHandler(&recorder); + test::TestWindowDelegate delegate; + HoldPointerOnScrollHandler handler(host()->dispatcher(), &recorder); + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window())); + window->AddPreTargetHandler(&handler); + + test::EventGenerator generator(root_window()); + generator.GestureScrollSequence( + gfx::Point(120, 120), gfx::Point(20, 120), + base::TimeDelta::FromMilliseconds(100), 25); + + // |handler| will have reset |filter| and started holding the touch-move + // events when scrolling started. At the end of the scroll (i.e. upon + // touch-release), the held touch-move event will have been dispatched first, + // along with the subsequent events (i.e. touch-release, scroll-end, and + // gesture-end). + const EventFilterRecorder::Events& events = recorder.events(); + EXPECT_EQ( + "TOUCH_MOVED GESTURE_SCROLL_UPDATE TOUCH_RELEASED " + "GESTURE_SCROLL_END GESTURE_END", + EventTypesToString(events)); + ASSERT_EQ(2u, recorder.touch_locations().size()); + EXPECT_EQ(gfx::Point(-40, 10).ToString(), + recorder.touch_locations()[0].ToString()); + EXPECT_EQ(gfx::Point(-40, 10).ToString(), + recorder.touch_locations()[1].ToString()); +} + +class SelfDestructDelegate : public test::TestWindowDelegate { + public: + SelfDestructDelegate() {} + virtual ~SelfDestructDelegate() {} + + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + window_.reset(); + } + + void set_window(scoped_ptr<aura::Window> window) { + window_ = window.Pass(); + } + bool has_window() const { return !!window_.get(); } + + private: + scoped_ptr<aura::Window> window_; + DISALLOW_COPY_AND_ASSIGN(SelfDestructDelegate); +}; + +TEST_F(WindowEventDispatcherTest, SynthesizedLocatedEvent) { + test::EventGenerator generator(root_window()); + generator.MoveMouseTo(10, 10); + EXPECT_EQ("10,10", + Env::GetInstance()->last_mouse_location().ToString()); + + // Synthesized event should not update the mouse location. + ui::MouseEvent mouseev(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), + ui::EF_IS_SYNTHESIZED, 0); + generator.Dispatch(&mouseev); + EXPECT_EQ("10,10", + Env::GetInstance()->last_mouse_location().ToString()); + + generator.MoveMouseTo(0, 0); + EXPECT_EQ("0,0", + Env::GetInstance()->last_mouse_location().ToString()); + + // Make sure the location gets updated when a syntheiszed enter + // event destroyed the window. + SelfDestructDelegate delegate; + scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( + &delegate, 1, gfx::Rect(50, 50, 100, 100), root_window())); + delegate.set_window(window.Pass()); + EXPECT_TRUE(delegate.has_window()); + + generator.MoveMouseTo(100, 100); + EXPECT_FALSE(delegate.has_window()); + EXPECT_EQ("100,100", + Env::GetInstance()->last_mouse_location().ToString()); +} + +class StaticFocusClient : public client::FocusClient { + public: + explicit StaticFocusClient(Window* focused) + : focused_(focused) {} + virtual ~StaticFocusClient() {} + + private: + // client::FocusClient: + virtual void AddObserver(client::FocusChangeObserver* observer) OVERRIDE {} + virtual void RemoveObserver(client::FocusChangeObserver* observer) OVERRIDE {} + virtual void FocusWindow(Window* window) OVERRIDE {} + virtual void ResetFocusWithinActiveWindow(Window* window) OVERRIDE {} + virtual Window* GetFocusedWindow() OVERRIDE { return focused_; } + + Window* focused_; + + DISALLOW_COPY_AND_ASSIGN(StaticFocusClient); +}; + +// Tests that host-cancel-mode event can be dispatched to a dispatcher safely +// when the focused window does not live in the dispatcher's tree. +TEST_F(WindowEventDispatcherTest, HostCancelModeWithFocusedWindowOutside) { + test::TestWindowDelegate delegate; + scoped_ptr<Window> focused(CreateTestWindowWithDelegate(&delegate, 123, + gfx::Rect(20, 30, 100, 50), NULL)); + StaticFocusClient focus_client(focused.get()); + client::SetFocusClient(root_window(), &focus_client); + EXPECT_FALSE(root_window()->Contains(focused.get())); + EXPECT_EQ(focused.get(), + client::GetFocusClient(root_window())->GetFocusedWindow()); + host()->dispatcher()->DispatchCancelModeEvent(); + EXPECT_EQ(focused.get(), + client::GetFocusClient(root_window())->GetFocusedWindow()); +} + +// Dispatches a mouse-move event to |target| when it receives a mouse-move +// event. +class DispatchEventHandler : public ui::EventHandler { + public: + explicit DispatchEventHandler(Window* target) + : target_(target), + dispatched_(false) {} + virtual ~DispatchEventHandler() {} + + bool dispatched() const { return dispatched_; } + private: + // ui::EventHandler: + virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { + if (mouse->type() == ui::ET_MOUSE_MOVED) { + ui::MouseEvent move(ui::ET_MOUSE_MOVED, target_->bounds().CenterPoint(), + target_->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE); + ui::EventDispatchDetails details = + target_->GetHost()->dispatcher()->OnEventFromSource(&move); + ASSERT_FALSE(details.dispatcher_destroyed); + EXPECT_FALSE(details.target_destroyed); + EXPECT_EQ(target_, move.target()); + dispatched_ = true; + } + ui::EventHandler::OnMouseEvent(mouse); + } + + Window* target_; + bool dispatched_; + + DISALLOW_COPY_AND_ASSIGN(DispatchEventHandler); +}; + +// Moves |window| to |root_window| when it receives a mouse-move event. +class MoveWindowHandler : public ui::EventHandler { + public: + MoveWindowHandler(Window* window, Window* root_window) + : window_to_move_(window), + root_window_to_move_to_(root_window) {} + virtual ~MoveWindowHandler() {} + + private: + // ui::EventHandler: + virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { + if (mouse->type() == ui::ET_MOUSE_MOVED) { + root_window_to_move_to_->AddChild(window_to_move_); + } + ui::EventHandler::OnMouseEvent(mouse); + } + + Window* window_to_move_; + Window* root_window_to_move_to_; + + DISALLOW_COPY_AND_ASSIGN(MoveWindowHandler); +}; + +// Tests that nested event dispatch works correctly if the target of the older +// event being dispatched is moved to a different dispatcher in response to an +// event in the inner loop. +TEST_F(WindowEventDispatcherTest, NestedEventDispatchTargetMoved) { + scoped_ptr<WindowTreeHost> second_host( + WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50))); + second_host->InitHost(); + Window* second_root = second_host->window(); + + // Create two windows parented to |root_window()|. + test::TestWindowDelegate delegate; + scoped_ptr<Window> first(CreateTestWindowWithDelegate(&delegate, 123, + gfx::Rect(20, 10, 10, 20), root_window())); + scoped_ptr<Window> second(CreateTestWindowWithDelegate(&delegate, 234, + gfx::Rect(40, 10, 50, 20), root_window())); + + // Setup a handler on |first| so that it dispatches an event to |second| when + // |first| receives an event. + DispatchEventHandler dispatch_event(second.get()); + first->AddPreTargetHandler(&dispatch_event); + + // Setup a handler on |second| so that it moves |first| into |second_root| + // when |second| receives an event. + MoveWindowHandler move_window(first.get(), second_root); + second->AddPreTargetHandler(&move_window); + + // Some sanity checks: |first| is inside |root_window()|'s tree. + EXPECT_EQ(root_window(), first->GetRootWindow()); + // The two root windows are different. + EXPECT_NE(root_window(), second_root); + + // Dispatch an event to |first|. + ui::MouseEvent move(ui::ET_MOUSE_MOVED, first->bounds().CenterPoint(), + first->bounds().CenterPoint(), ui::EF_NONE, ui::EF_NONE); + ui::EventDispatchDetails details = + host()->dispatcher()->OnEventFromSource(&move); + ASSERT_FALSE(details.dispatcher_destroyed); + EXPECT_TRUE(details.target_destroyed); + EXPECT_EQ(first.get(), move.target()); + EXPECT_TRUE(dispatch_event.dispatched()); + EXPECT_EQ(second_root, first->GetRootWindow()); + + first->RemovePreTargetHandler(&dispatch_event); + second->RemovePreTargetHandler(&move_window); +} + +class AlwaysMouseDownInputStateLookup : public InputStateLookup { + public: + AlwaysMouseDownInputStateLookup() {} + virtual ~AlwaysMouseDownInputStateLookup() {} + + private: + // InputStateLookup: + virtual bool IsMouseButtonDown() const OVERRIDE { return true; } + + DISALLOW_COPY_AND_ASSIGN(AlwaysMouseDownInputStateLookup); +}; + +TEST_F(WindowEventDispatcherTest, + CursorVisibilityChangedWhileCaptureWindowInAnotherDispatcher) { + test::EventCountDelegate delegate; + scoped_ptr<Window> window(CreateTestWindowWithDelegate(&delegate, 123, + gfx::Rect(20, 10, 10, 20), root_window())); + window->Show(); + + scoped_ptr<WindowTreeHost> second_host( + WindowTreeHost::Create(gfx::Rect(20, 30, 100, 50))); + second_host->InitHost(); + WindowEventDispatcher* second_dispatcher = second_host->dispatcher(); + + // Install an InputStateLookup on the Env that always claims that a + // mouse-button is down. + test::EnvTestHelper(Env::GetInstance()).SetInputStateLookup( + scoped_ptr<InputStateLookup>(new AlwaysMouseDownInputStateLookup())); + + window->SetCapture(); + + // Because the mouse button is down, setting the capture on |window| will set + // it as the mouse-move handler for |root_window()|. + EXPECT_EQ(window.get(), host()->dispatcher()->mouse_moved_handler()); + + // This does not set |window| as the mouse-move handler for the second + // dispatcher. + EXPECT_EQ(NULL, second_dispatcher->mouse_moved_handler()); + + // However, some capture-client updates the capture in each root-window on a + // capture. Emulate that here. Because of this, the second dispatcher also has + // |window| as the mouse-move handler. + client::CaptureDelegate* second_capture_delegate = second_dispatcher; + second_capture_delegate->UpdateCapture(NULL, window.get()); + EXPECT_EQ(window.get(), second_dispatcher->mouse_moved_handler()); + + // Reset the mouse-event counts for |window|. + delegate.GetMouseMotionCountsAndReset(); + + // Notify both hosts that the cursor is now hidden. This should send a single + // mouse-exit event to |window|. + host()->OnCursorVisibilityChanged(false); + second_host->OnCursorVisibilityChanged(false); + EXPECT_EQ("0 0 1", delegate.GetMouseMotionCountsAndReset()); +} + +} // namespace aura diff --git a/chromium/ui/aura/window_observer.cc b/chromium/ui/aura/window_observer.cc new file mode 100644 index 00000000000..24d51d47df0 --- /dev/null +++ b/chromium/ui/aura/window_observer.cc @@ -0,0 +1,31 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura/window_observer.h" + +#include "base/logging.h" +#include "ui/aura/window.h" + +namespace aura { + +WindowObserver::WindowObserver() : observing_(0) { +} + +WindowObserver::~WindowObserver() { + // TODO(flackr): Remove this check and observing_ counter when the cause of + // http://crbug.com/365364 is discovered. + CHECK_EQ(0, observing_); +} + +void WindowObserver::OnObservingWindow(aura::Window* window) { + if (!window->HasObserver(this)) + observing_++; +} + +void WindowObserver::OnUnobservingWindow(aura::Window* window) { + if (window->HasObserver(this)) + observing_--; +} + +} // namespace aura diff --git a/chromium/ui/aura/window_observer.h b/chromium/ui/aura/window_observer.h index 9408ee831dd..ef1259a234d 100644 --- a/chromium/ui/aura/window_observer.h +++ b/chromium/ui/aura/window_observer.h @@ -31,6 +31,8 @@ class AURA_EXPORT WindowObserver { Window* receiver; // The window receiving the notification. }; + WindowObserver(); + // Called when a window is added or removed. Notifications are sent to the // following hierarchies in this order: // 1. |target|. @@ -75,6 +77,10 @@ class AURA_EXPORT WindowObserver { const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) {} + // Invoked when SetTransform() is invoked on |window|. + virtual void OnWindowTransforming(Window* window) {} + virtual void OnWindowTransformed(Window* window) {} + // Invoked when |window|'s position among its siblings in the stacking order // has changed. virtual void OnWindowStackingChanged(Window* window) {} @@ -100,17 +106,29 @@ class AURA_EXPORT WindowObserver { // Called when a Window has been added to a RootWindow. virtual void OnWindowAddedToRootWindow(Window* window) {} - // Called when a Window is about to be removed from a RootWindow. - virtual void OnWindowRemovingFromRootWindow(Window* window) {} + // Called when a Window is about to be removed from a root Window. + // |new_root| contains the new root Window if it is being added to one + // atomically. + virtual void OnWindowRemovingFromRootWindow(Window* window, + Window* new_root) {} - // Called when a transient child is added to |window|. - virtual void OnAddTransientChild(Window* window, Window* transient) {} + protected: + virtual ~WindowObserver(); - // Called when a transient child is removed from |window|. - virtual void OnRemoveTransientChild(Window* window, Window* transient) {} + private: + friend class Window; - protected: - virtual ~WindowObserver() {} + // Called when this is added as an observer on |window|. + void OnObservingWindow(Window* window); + + // Called when this is removed from the observers on |window|. + void OnUnobservingWindow(Window* window); + + // Tracks the number of windows being observed to track down + // http://crbug.com/365364. + int observing_; + + DISALLOW_COPY_AND_ASSIGN(WindowObserver); }; } // namespace aura diff --git a/chromium/ui/aura/window_targeter.cc b/chromium/ui/aura/window_targeter.cc index 586392bcdc8..601321525e8 100644 --- a/chromium/ui/aura/window_targeter.cc +++ b/chromium/ui/aura/window_targeter.cc @@ -7,9 +7,10 @@ #include "ui/aura/client/capture_client.h" #include "ui/aura/client/event_client.h" #include "ui/aura/client/focus_client.h" -#include "ui/aura/root_window.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" +#include "ui/aura/window_event_dispatcher.h" +#include "ui/aura/window_tree_host.h" #include "ui/events/event_target.h" namespace aura { @@ -19,29 +20,28 @@ WindowTargeter::~WindowTargeter() {} ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root, ui::Event* event) { - if (event->IsKeyEvent()) { - Window* window = static_cast<Window*>(root); - Window* root_window = window->GetRootWindow(); - const ui::KeyEvent& key = static_cast<const ui::KeyEvent&>(*event); - if (key.key_code() == ui::VKEY_UNKNOWN) - return NULL; - client::EventClient* event_client = client::GetEventClient(root_window); - client::FocusClient* focus_client = client::GetFocusClient(root_window); - Window* focused_window = focus_client->GetFocusedWindow(); - if (event_client && - !event_client->CanProcessEventsWithinSubtree(focused_window)) { - focus_client->FocusWindow(NULL); - return NULL; + Window* window = static_cast<Window*>(root); + Window* target = event->IsKeyEvent() ? + FindTargetForKeyEvent(window, *static_cast<ui::KeyEvent*>(event)) : + static_cast<Window*>(EventTargeter::FindTargetForEvent(root, event)); + if (target && !window->parent()) { + // |window| is the root window. + if (!window->Contains(target)) { + // |target| is not a descendent of |window|. So do not allow dispatching + // from here. Instead, dispatch the event through the + // WindowEventDispatcher that owns |target|. + ui::EventDispatchDetails details ALLOW_UNUSED = + target->GetHost()->event_processor()->OnEventFromSource(event); + target = NULL; } - return focused_window ? focused_window : window; } - return EventTargeter::FindTargetForEvent(root, event); + return target; } -bool WindowTargeter::SubtreeShouldBeExploredForEvent( - ui::EventTarget* root, - const ui::LocatedEvent& event) { - Window* window = static_cast<Window*>(root); +bool WindowTargeter::SubtreeCanAcceptEvent( + ui::EventTarget* target, + const ui::LocatedEvent& event) const { + aura::Window* window = static_cast<aura::Window*>(target); if (!window->IsVisible()) return false; if (window->ignore_events()) @@ -55,7 +55,17 @@ bool WindowTargeter::SubtreeShouldBeExploredForEvent( ShouldDescendIntoChildForEventHandling(window, event.location())) { return false; } - return window->bounds().Contains(event.location()); + return true; +} + +bool WindowTargeter::EventLocationInsideBounds( + ui::EventTarget* target, + const ui::LocatedEvent& event) const { + aura::Window* window = static_cast<aura::Window*>(target); + gfx::Point point = event.location(); + if (window->parent()) + aura::Window::ConvertPointToTarget(window->parent(), window, &point); + return gfx::Rect(window->bounds().size()).Contains(point); } ui::EventTarget* WindowTargeter::FindTargetForLocatedEvent( @@ -72,6 +82,27 @@ ui::EventTarget* WindowTargeter::FindTargetForLocatedEvent( return EventTargeter::FindTargetForLocatedEvent(root, event); } +Window* WindowTargeter::FindTargetForKeyEvent(Window* window, + const ui::KeyEvent& key) { + Window* root_window = window->GetRootWindow(); + if (key.key_code() == ui::VKEY_UNKNOWN && + (key.flags() & ui::EF_IME_FABRICATED_KEY) == 0 && + key.GetCharacter() == 0) + return NULL; + client::FocusClient* focus_client = client::GetFocusClient(root_window); + Window* focused_window = focus_client->GetFocusedWindow(); + if (!focused_window) + return window; + + client::EventClient* event_client = client::GetEventClient(root_window); + if (event_client && + !event_client->CanProcessEventsWithinSubtree(focused_window)) { + focus_client->FocusWindow(NULL); + return NULL; + } + return focused_window ? focused_window : window; +} + Window* WindowTargeter::FindTargetInRootWindow(Window* root_window, const ui::LocatedEvent& event) { DCHECK_EQ(root_window, root_window->GetRootWindow()); @@ -79,7 +110,7 @@ Window* WindowTargeter::FindTargetInRootWindow(Window* root_window, // Mouse events should be dispatched to the window that processed the // mouse-press events (if any). if (event.IsScrollEvent() || event.IsMouseEvent()) { - WindowEventDispatcher* dispatcher = root_window->GetDispatcher(); + WindowEventDispatcher* dispatcher = root_window->GetHost()->dispatcher(); if (dispatcher->mouse_pressed_handler()) return dispatcher->mouse_pressed_handler(); } @@ -89,6 +120,24 @@ Window* WindowTargeter::FindTargetInRootWindow(Window* root_window, if (capture_window) return capture_window; + if (event.IsTouchEvent()) { + // Query the gesture-recognizer to find targets for touch events. + const ui::TouchEvent& touch = static_cast<const ui::TouchEvent&>(event); + ui::GestureConsumer* consumer = + ui::GestureRecognizer::Get()->GetTouchLockedTarget(touch); + if (consumer) + return static_cast<Window*>(consumer); + consumer = + ui::GestureRecognizer::Get()->GetTargetForLocation( + event.location(), touch.source_device_id()); + if (consumer) + return static_cast<Window*>(consumer); + + // If the initial touch is outside the root window, target the root. + if (!root_window->bounds().Contains(event.location())) + return root_window; + } + return NULL; } diff --git a/chromium/ui/aura/window_targeter.h b/chromium/ui/aura/window_targeter.h index 4457f77c371..e64ef75f807 100644 --- a/chromium/ui/aura/window_targeter.h +++ b/chromium/ui/aura/window_targeter.h @@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef UI_AURA_WINDOW_TARGETER_H_ +#define UI_AURA_WINDOW_TARGETER_H_ + +#include "ui/aura/aura_export.h" #include "ui/events/event_targeter.h" namespace aura { class Window; -class WindowTargeter : public ui::EventTargeter { +class AURA_EXPORT WindowTargeter : public ui::EventTargeter { public: WindowTargeter(); virtual ~WindowTargeter(); @@ -20,11 +24,16 @@ class WindowTargeter : public ui::EventTargeter { virtual ui::EventTarget* FindTargetForLocatedEvent( ui::EventTarget* root, ui::LocatedEvent* event) OVERRIDE; - virtual bool SubtreeShouldBeExploredForEvent( + virtual bool SubtreeCanAcceptEvent( + ui::EventTarget* target, + const ui::LocatedEvent& event) const OVERRIDE; + virtual bool EventLocationInsideBounds( ui::EventTarget* target, - const ui::LocatedEvent& event) OVERRIDE; + const ui::LocatedEvent& event) const OVERRIDE; private: + Window* FindTargetForKeyEvent(Window* root_window, + const ui::KeyEvent& event); Window* FindTargetInRootWindow(Window* root_window, const ui::LocatedEvent& event); @@ -32,3 +41,5 @@ class WindowTargeter : public ui::EventTargeter { }; } // namespace aura + +#endif // UI_AURA_WINDOW_TARGETER_H_ diff --git a/chromium/ui/aura/window_targeter_unittest.cc b/chromium/ui/aura/window_targeter_unittest.cc index 396c805353f..f14d3379ea3 100644 --- a/chromium/ui/aura/window_targeter_unittest.cc +++ b/chromium/ui/aura/window_targeter_unittest.cc @@ -4,13 +4,34 @@ #include "ui/aura/window_targeter.h" +#include "ui/aura/scoped_window_targeter.h" #include "ui/aura/test/aura_test_base.h" -#include "ui/aura/test/test_event_handler.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" +#include "ui/events/test/test_event_handler.h" namespace aura { +// Always returns the same window. +class StaticWindowTargeter : public ui::EventTargeter { + public: + explicit StaticWindowTargeter(aura::Window* window) + : window_(window) {} + virtual ~StaticWindowTargeter() {} + + private: + // ui::EventTargeter: + virtual ui::EventTarget* FindTargetForLocatedEvent( + ui::EventTarget* root, + ui::LocatedEvent* event) OVERRIDE { + return window_; + } + + Window* window_; + + DISALLOW_COPY_AND_ASSIGN(StaticWindowTargeter); +}; + class WindowTargeterTest : public test::AuraTestBase { public: WindowTargeterTest() {} @@ -19,6 +40,18 @@ class WindowTargeterTest : public test::AuraTestBase { Window* root_window() { return AuraTestBase::root_window(); } }; +gfx::RectF GetEffectiveVisibleBoundsInRootWindow(Window* window) { + gfx::RectF bounds = gfx::Rect(window->bounds().size()); + Window* root = window->GetRootWindow(); + CHECK(window->layer()); + CHECK(root->layer()); + gfx::Transform transform; + if (!window->layer()->GetTargetTransformRelativeTo(root->layer(), &transform)) + return gfx::RectF(); + transform.TransformRect(&bounds); + return bounds; +} + TEST_F(WindowTargeterTest, Basic) { test::TestWindowDelegate delegate; scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate)); @@ -31,24 +64,102 @@ TEST_F(WindowTargeterTest, Basic) { root_window()->Show(); - test::TestEventHandler handler; + ui::test::TestEventHandler handler; one->AddPreTargetHandler(&handler); ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(20, 20), gfx::Point(20, 20), + ui::EF_NONE, ui::EF_NONE); - root_window()->GetDispatcher()->AsRootWindowHostDelegate()-> - OnHostMouseEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_EQ(1, handler.num_mouse_events()); handler.Reset(); - ui::EventDispatchDetails details = - root_window()->GetDispatcher()->OnEventFromSource(&press); - EXPECT_FALSE(details.dispatcher_destroyed); + DispatchEventUsingWindowDispatcher(&press); EXPECT_EQ(1, handler.num_mouse_events()); one->RemovePreTargetHandler(&handler); } +TEST_F(WindowTargeterTest, ScopedWindowTargeter) { + test::TestWindowDelegate delegate; + scoped_ptr<Window> window(CreateNormalWindow(1, root_window(), &delegate)); + Window* child = CreateNormalWindow(2, window.get(), &delegate); + + window->SetBounds(gfx::Rect(30, 30, 100, 100)); + child->SetBounds(gfx::Rect(20, 20, 50, 50)); + root_window()->Show(); + + ui::EventTarget* root = root_window(); + ui::EventTargeter* targeter = root->GetEventTargeter(); + + gfx::Point event_location(60, 60); + { + ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, + ui::EF_NONE, ui::EF_NONE); + EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse)); + } + + // Install a targeter on |window| so that the events never reach the child. + scoped_ptr<ScopedWindowTargeter> scoped_targeter( + new ScopedWindowTargeter(window.get(), scoped_ptr<ui::EventTargeter>( + new StaticWindowTargeter(window.get())))); + { + ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, + ui::EF_NONE, ui::EF_NONE); + EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root, &mouse)); + } + scoped_targeter.reset(); + { + ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, + ui::EF_NONE, ui::EF_NONE); + EXPECT_EQ(child, targeter->FindTargetForEvent(root, &mouse)); + } +} + +TEST_F(WindowTargeterTest, TargetTransformedWindow) { + root_window()->Show(); + + test::TestWindowDelegate delegate; + scoped_ptr<Window> window(CreateNormalWindow(2, root_window(), &delegate)); + + const gfx::Rect window_bounds(100, 20, 400, 80); + window->SetBounds(window_bounds); + + ui::EventTarget* root_target = root_window(); + ui::EventTargeter* targeter = root_target->GetEventTargeter(); + gfx::Point event_location(490, 50); + { + ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, + ui::EF_NONE, ui::EF_NONE); + EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse)); + } + + // Scale |window| by 50%. This should move it away from underneath + // |event_location|, so an event in that location will not be targeted to it. + gfx::Transform transform; + transform.Scale(0.5, 0.5); + window->SetTransform(transform); + EXPECT_EQ(gfx::RectF(100, 20, 200, 40).ToString(), + GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString()); + { + ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, + ui::EF_NONE, ui::EF_NONE); + EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_target, &mouse)); + } + + transform = gfx::Transform(); + transform.Translate(200, 10); + transform.Scale(0.5, 0.5); + window->SetTransform(transform); + EXPECT_EQ(gfx::RectF(300, 30, 200, 40).ToString(), + GetEffectiveVisibleBoundsInRootWindow(window.get()).ToString()); + { + ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, + ui::EF_NONE, ui::EF_NONE); + EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &mouse)); + } +} + } // namespace aura diff --git a/chromium/ui/aura/window_tree_host.cc b/chromium/ui/aura/window_tree_host.cc index 1bee9231a0a..9ac7cf7ab01 100644 --- a/chromium/ui/aura/window_tree_host.cc +++ b/chromium/ui/aura/window_tree_host.cc @@ -4,36 +4,270 @@ #include "ui/aura/window_tree_host.h" -#include "ui/aura/root_window.h" -#include "ui/aura/window_tree_host_delegate.h" +#include "base/debug/trace_event.h" +#include "ui/aura/client/capture_client.h" +#include "ui/aura/client/cursor_client.h" +#include "ui/aura/env.h" +#include "ui/aura/window.h" +#include "ui/aura/window_event_dispatcher.h" +#include "ui/aura/window_targeter.h" +#include "ui/aura/window_tree_host_observer.h" +#include "ui/base/view_prop.h" +#include "ui/compositor/dip_util.h" +#include "ui/compositor/layer.h" +#include "ui/gfx/display.h" +#include "ui/gfx/insets.h" #include "ui/gfx/point.h" +#include "ui/gfx/point3_f.h" +#include "ui/gfx/point_conversions.h" +#include "ui/gfx/screen.h" +#include "ui/gfx/size_conversions.h" namespace aura { +const char kWindowTreeHostForAcceleratedWidget[] = + "__AURA_WINDOW_TREE_HOST_ACCELERATED_WIDGET__"; + +float GetDeviceScaleFactorFromDisplay(Window* window) { + gfx::Display display = gfx::Screen::GetScreenFor(window)-> + GetDisplayNearestWindow(window); + DCHECK(display.is_valid()); + return display.device_scale_factor(); +} + //////////////////////////////////////////////////////////////////////////////// -// RootWindowHost, public: +// WindowTreeHost, public: + +WindowTreeHost::~WindowTreeHost() { + DCHECK(!compositor_) << "compositor must be destroyed before root window"; +} + +#if defined(OS_ANDROID) +// static +WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) { + // This is only hit for tests and ash, right now these aren't an issue so + // adding the CHECK. + // TODO(sky): decide if we want a factory. + CHECK(false); + return NULL; +} +#endif + +// static +WindowTreeHost* WindowTreeHost::GetForAcceleratedWidget( + gfx::AcceleratedWidget widget) { + return reinterpret_cast<WindowTreeHost*>( + ui::ViewProp::GetValue(widget, kWindowTreeHostForAcceleratedWidget)); +} + +void WindowTreeHost::InitHost() { + InitCompositor(); + UpdateRootWindowSize(GetBounds().size()); + Env::GetInstance()->NotifyHostInitialized(this); + window()->Show(); +} + +void WindowTreeHost::InitCompositor() { + compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()), + GetBounds().size()); + compositor_->SetRootLayer(window()->layer()); +} + +void WindowTreeHost::AddObserver(WindowTreeHostObserver* observer) { + observers_.AddObserver(observer); +} -RootWindowHost::~RootWindowHost() { +void WindowTreeHost::RemoveObserver(WindowTreeHostObserver* observer) { + observers_.RemoveObserver(observer); } -void RootWindowHost::ConvertPointToNativeScreen(gfx::Point* point) const { - delegate_->AsRootWindow()->ConvertPointToHost(point); +ui::EventProcessor* WindowTreeHost::event_processor() { + return dispatcher(); +} + +gfx::Transform WindowTreeHost::GetRootTransform() const { + float scale = ui::GetDeviceScaleFactor(window()->layer()); + gfx::Transform transform; + transform.Scale(scale, scale); + transform *= window()->layer()->transform(); + return transform; +} + +void WindowTreeHost::SetRootTransform(const gfx::Transform& transform) { + window()->SetTransform(transform); + UpdateRootWindowSize(GetBounds().size()); +} + +gfx::Transform WindowTreeHost::GetInverseRootTransform() const { + gfx::Transform invert; + gfx::Transform transform = GetRootTransform(); + if (!transform.GetInverse(&invert)) + return transform; + return invert; +} + +void WindowTreeHost::UpdateRootWindowSize(const gfx::Size& host_size) { + gfx::Rect bounds(host_size); + gfx::RectF new_bounds(ui::ConvertRectToDIP(window()->layer(), bounds)); + window()->layer()->transform().TransformRect(&new_bounds); + window()->SetBounds(gfx::Rect(gfx::ToFlooredSize(new_bounds.size()))); +} + +void WindowTreeHost::ConvertPointToNativeScreen(gfx::Point* point) const { + ConvertPointToHost(point); gfx::Point location = GetLocationOnNativeScreen(); point->Offset(location.x(), location.y()); } -void RootWindowHost::ConvertPointFromNativeScreen(gfx::Point* point) const { +void WindowTreeHost::ConvertPointFromNativeScreen(gfx::Point* point) const { gfx::Point location = GetLocationOnNativeScreen(); point->Offset(-location.x(), -location.y()); - delegate_->AsRootWindow()->ConvertPointFromHost(point); + ConvertPointFromHost(point); +} + +void WindowTreeHost::ConvertPointToHost(gfx::Point* point) const { + gfx::Point3F point_3f(*point); + GetRootTransform().TransformPoint(&point_3f); + *point = gfx::ToFlooredPoint(point_3f.AsPointF()); +} + +void WindowTreeHost::ConvertPointFromHost(gfx::Point* point) const { + gfx::Point3F point_3f(*point); + GetInverseRootTransform().TransformPoint(&point_3f); + *point = gfx::ToFlooredPoint(point_3f.AsPointF()); +} + +void WindowTreeHost::SetCursor(gfx::NativeCursor cursor) { + last_cursor_ = cursor; + // A lot of code seems to depend on NULL cursors actually showing an arrow, + // so just pass everything along to the host. + SetCursorNative(cursor); +} + +void WindowTreeHost::OnCursorVisibilityChanged(bool show) { + // Clear any existing mouse hover effects when the cursor becomes invisible. + // Note we do not need to dispatch a mouse enter when the cursor becomes + // visible because that can only happen in response to a mouse event, which + // will trigger its own mouse enter. + if (!show) { + dispatcher()->DispatchMouseExitAtPoint( + dispatcher()->GetLastMouseLocationInRoot()); + } + + OnCursorVisibilityChangedNative(show); +} + +void WindowTreeHost::MoveCursorTo(const gfx::Point& location_in_dip) { + gfx::Point host_location(location_in_dip); + ConvertPointToHost(&host_location); + MoveCursorToInternal(location_in_dip, host_location); +} + +void WindowTreeHost::MoveCursorToHostLocation(const gfx::Point& host_location) { + gfx::Point root_location(host_location); + ConvertPointFromHost(&root_location); + MoveCursorToInternal(root_location, host_location); } //////////////////////////////////////////////////////////////////////////////// -// RootWindowHost, protected: +// WindowTreeHost, protected: + +WindowTreeHost::WindowTreeHost() + : window_(new Window(NULL)), + last_cursor_(ui::kCursorNull) { +} + +void WindowTreeHost::DestroyCompositor() { + compositor_.reset(); +} + +void WindowTreeHost::DestroyDispatcher() { + delete window_; + window_ = NULL; + dispatcher_.reset(); + + // TODO(beng): this comment is no longer quite valid since this function + // isn't called from WED, and WED isn't a subclass of Window. So it seems + // like we could just rely on ~Window now. + // Destroy child windows while we're still valid. This is also done by + // ~Window, but by that time any calls to virtual methods overriden here (such + // as GetRootWindow()) result in Window's implementation. By destroying here + // we ensure GetRootWindow() still returns this. + //window()->RemoveOrDestroyChildren(); +} -RootWindowHost::RootWindowHost() - : delegate_(NULL) { +void WindowTreeHost::CreateCompositor( + gfx::AcceleratedWidget accelerated_widget) { + DCHECK(Env::GetInstance()); + ui::ContextFactory* context_factory = Env::GetInstance()->context_factory(); + DCHECK(context_factory); + compositor_.reset( + new ui::Compositor(GetAcceleratedWidget(), context_factory)); + // TODO(beng): I think this setup should probably all move to a "accelerated + // widget available" function. + if (!dispatcher()) { + window()->Init(WINDOW_LAYER_NOT_DRAWN); + window()->set_host(this); + window()->SetName("RootWindow"); + window()->SetEventTargeter( + scoped_ptr<ui::EventTargeter>(new WindowTargeter())); + prop_.reset(new ui::ViewProp(GetAcceleratedWidget(), + kWindowTreeHostForAcceleratedWidget, + this)); + dispatcher_.reset(new WindowEventDispatcher(this)); + } } +void WindowTreeHost::OnHostMoved(const gfx::Point& new_location) { + TRACE_EVENT1("ui", "WindowTreeHost::OnHostMoved", + "origin", new_location.ToString()); + + FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_, + OnHostMoved(this, new_location)); +} + +void WindowTreeHost::OnHostResized(const gfx::Size& new_size) { + // The compositor should have the same size as the native root window host. + // Get the latest scale from display because it might have been changed. + compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()), + new_size); + + gfx::Size layer_size = GetBounds().size(); + // The layer, and the observers should be notified of the + // transformed size of the root window. + UpdateRootWindowSize(layer_size); + FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_, OnHostResized(this)); +} + +void WindowTreeHost::OnHostCloseRequested() { + FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_, + OnHostCloseRequested(this)); +} + +void WindowTreeHost::OnHostActivated() { + Env::GetInstance()->NotifyHostActivated(this); +} + +void WindowTreeHost::OnHostLostWindowCapture() { + Window* capture_window = client::GetCaptureWindow(window()); + if (capture_window && capture_window->GetRootWindow() == window()) + capture_window->ReleaseCapture(); +} + +//////////////////////////////////////////////////////////////////////////////// +// WindowTreeHost, private: + +void WindowTreeHost::MoveCursorToInternal(const gfx::Point& root_location, + const gfx::Point& host_location) { + last_cursor_request_position_in_host_ = host_location; + MoveCursorToNative(host_location); + client::CursorClient* cursor_client = client::GetCursorClient(window()); + if (cursor_client) { + const gfx::Display& display = + gfx::Screen::GetScreenFor(window())->GetDisplayNearestWindow(window()); + cursor_client->SetDisplay(display); + } + dispatcher()->OnCursorMovedToRootLocation(root_location); +} } // namespace aura diff --git a/chromium/ui/aura/window_tree_host.h b/chromium/ui/aura/window_tree_host.h index 5aaa65c3116..9d54944777f 100644 --- a/chromium/ui/aura/window_tree_host.h +++ b/chromium/ui/aura/window_tree_host.h @@ -2,14 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_AURA_ROOT_WINDOW_HOST_H_ -#define UI_AURA_ROOT_WINDOW_HOST_H_ +#ifndef UI_AURA_WINDOW_TREE_HOST_H_ +#define UI_AURA_WINDOW_TREE_HOST_H_ #include <vector> +#include "base/event_types.h" #include "base/message_loop/message_loop.h" #include "ui/aura/aura_export.h" #include "ui/base/cursor/cursor.h" +#include "ui/events/event_source.h" #include "ui/gfx/native_widget_types.h" namespace gfx { @@ -17,53 +19,69 @@ class Insets; class Point; class Rect; class Size; +class Transform; +} + +namespace ui { +class Compositor; +class EventProcessor; +class ViewProp; } namespace aura { +namespace test { +class WindowTreeHostTestApi; +} -class RootWindow; -class RootWindowHostDelegate; +class WindowEventDispatcher; +class WindowTreeHostObserver; -// RootWindowHost bridges between a native window and the embedded RootWindow. +// WindowTreeHost bridges between a native window and the embedded RootWindow. // It provides the accelerated widget and maps events from the native os to // aura. -class AURA_EXPORT RootWindowHost { +class AURA_EXPORT WindowTreeHost { public: - virtual ~RootWindowHost(); + virtual ~WindowTreeHost(); - // Creates a new RootWindowHost. The caller owns the returned value. - static RootWindowHost* Create(const gfx::Rect& bounds); + // Creates a new WindowTreeHost. The caller owns the returned value. + static WindowTreeHost* Create(const gfx::Rect& bounds); - // Returns the actual size of the screen. - // (gfx::Screen only reports on the virtual desktop exposed by Aura.) - static gfx::Size GetNativeScreenSize(); + // Returns the WindowTreeHost for the specified accelerated widget, or NULL + // if there is none associated. + static WindowTreeHost* GetForAcceleratedWidget(gfx::AcceleratedWidget widget); - void set_delegate(RootWindowHostDelegate* delegate) { - delegate_ = delegate; - } + void InitHost(); - virtual RootWindow* GetRootWindow() = 0; + void InitCompositor(); - // Returns the accelerated widget. - virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; + void AddObserver(WindowTreeHostObserver* observer); + void RemoveObserver(WindowTreeHostObserver* observer); - // Shows the RootWindowHost. - virtual void Show() = 0; + Window* window() { return window_; } + const Window* window() const { return window_; } - // Hides the RootWindowHost. - virtual void Hide() = 0; + ui::EventProcessor* event_processor(); - // Toggles the host's full screen state. - virtual void ToggleFullScreen() = 0; + WindowEventDispatcher* dispatcher() { + return const_cast<WindowEventDispatcher*>( + const_cast<const WindowTreeHost*>(this)->dispatcher()); + } + const WindowEventDispatcher* dispatcher() const { return dispatcher_.get(); } - // Gets/Sets the size of the RootWindowHost. - virtual gfx::Rect GetBounds() const = 0; - virtual void SetBounds(const gfx::Rect& bounds) = 0; + ui::Compositor* compositor() { return compositor_.get(); } + + // Gets/Sets the root window's transform. + virtual gfx::Transform GetRootTransform() const; + virtual void SetRootTransform(const gfx::Transform& transform); + virtual gfx::Transform GetInverseRootTransform() const; - // Sets/Gets the insets that specifies the effective root window area - // in the host window. - virtual gfx::Insets GetInsets() const = 0; - virtual void SetInsets(const gfx::Insets& insets) = 0; + // Updates the root window's size using |host_size|, current + // transform and insets. + virtual void UpdateRootWindowSize(const gfx::Size& host_size); + + // Returns the actual size of the screen. + // (gfx::Screen only reports on the virtual desktop exposed by Aura.) + static gfx::Size GetNativeScreenSize(); // Converts |point| from the root window's coordinate system to native // screen's. @@ -72,58 +90,117 @@ class AURA_EXPORT RootWindowHost { // Converts |point| from native screen coordinate system to the root window's. void ConvertPointFromNativeScreen(gfx::Point* point) const; + // Converts |point| from the root window's coordinate system to the + // host window's. + void ConvertPointToHost(gfx::Point* point) const; + + // Converts |point| from the host window's coordinate system to the + // root window's. + void ConvertPointFromHost(gfx::Point* point) const; + + // Cursor. + // Sets the currently-displayed cursor. If the cursor was previously hidden + // via ShowCursor(false), it will remain hidden until ShowCursor(true) is + // called, at which point the cursor that was last set via SetCursor() will be + // used. + void SetCursor(gfx::NativeCursor cursor); + + // Invoked when the cursor's visibility has changed. + void OnCursorVisibilityChanged(bool visible); + + // Moves the cursor to the specified location relative to the root window. + void MoveCursorTo(const gfx::Point& location); + + // Moves the cursor to the |host_location| given in host coordinates. + void MoveCursorToHostLocation(const gfx::Point& host_location); + + gfx::NativeCursor last_cursor() const { return last_cursor_; } + + // Returns the EventSource responsible for dispatching events to the window + // tree. + virtual ui::EventSource* GetEventSource() = 0; + + // Returns the accelerated widget. + virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; + + // Shows the WindowTreeHost. + virtual void Show() = 0; + + // Hides the WindowTreeHost. + virtual void Hide() = 0; + + // Gets/Sets the size of the WindowTreeHost. + virtual gfx::Rect GetBounds() const = 0; + virtual void SetBounds(const gfx::Rect& bounds) = 0; + // Sets the OS capture to the root window. virtual void SetCapture() = 0; // Releases OS capture of the root window. virtual void ReleaseCapture() = 0; - // Sets the currently displayed cursor. - virtual void SetCursor(gfx::NativeCursor cursor) = 0; - - // Queries the mouse's current position relative to the host window and sets - // it in |location_return|. Returns true if the cursor is within the host - // window. The position set to |location_return| is constrained within the - // host window. If the cursor is disabled, returns false and (0, 0) is set to - // |location_return|. - // This method is expensive, instead use gfx::Screen::GetCursorScreenPoint(). - virtual bool QueryMouseLocation(gfx::Point* location_return) = 0; - - // Clips the cursor to the bounds of the root window until UnConfineCursor(). - // We would like to be able to confine the cursor to that window. However, - // currently, we do not have such functionality in X. So we just confine - // to the root window. This is ok because this option is currently only - // being used in fullscreen mode, so root_window bounds = window bounds. - virtual bool ConfineCursorToRootWindow() = 0; - virtual void UnConfineCursor() = 0; - - // Called when the cursor visibility has changed. - virtual void OnCursorVisibilityChanged(bool show) = 0; - - // Moves the cursor to the specified location relative to the root window. - virtual void MoveCursorTo(const gfx::Point& location) = 0; - // Posts |native_event| to the platform's event queue. virtual void PostNativeEvent(const base::NativeEvent& native_event) = 0; // Called when the device scale factor of the root window has chagned. virtual void OnDeviceScaleFactorChanged(float device_scale_factor) = 0; - // Stop listening events in preparation for shutdown. - virtual void PrepareForShutdown() = 0; - protected: - RootWindowHost(); + friend class TestScreen; // TODO(beng): see if we can remove/consolidate. + + WindowTreeHost(); + void DestroyCompositor(); + void DestroyDispatcher(); + + void CreateCompositor(gfx::AcceleratedWidget accelerated_widget); // Returns the location of the RootWindow on native screen. virtual gfx::Point GetLocationOnNativeScreen() const = 0; - RootWindowHostDelegate* delegate_; + void OnHostMoved(const gfx::Point& new_location); + void OnHostResized(const gfx::Size& new_size); + void OnHostCloseRequested(); + void OnHostActivated(); + void OnHostLostWindowCapture(); + + // Sets the currently displayed cursor. + virtual void SetCursorNative(gfx::NativeCursor cursor) = 0; + + // Moves the cursor to the specified location relative to the root window. + virtual void MoveCursorToNative(const gfx::Point& location) = 0; + + // kCalled when the cursor visibility has changed. + virtual void OnCursorVisibilityChangedNative(bool show) = 0; private: - DISALLOW_COPY_AND_ASSIGN(RootWindowHost); + friend class test::WindowTreeHostTestApi; + + // Moves the cursor to the specified location. This method is internally used + // by MoveCursorTo() and MoveCursorToHostLocation(). + void MoveCursorToInternal(const gfx::Point& root_location, + const gfx::Point& host_location); + + // We don't use a scoped_ptr for |window_| since we need this ptr to be valid + // during its deletion. (Window's dtor notifies observers that may attempt to + // reach back up to access this object which will be valid until the end of + // the dtor). + Window* window_; // Owning. + + ObserverList<WindowTreeHostObserver> observers_; + + scoped_ptr<WindowEventDispatcher> dispatcher_; + + scoped_ptr<ui::Compositor> compositor_; + + // Last cursor set. Used for testing. + gfx::NativeCursor last_cursor_; + gfx::Point last_cursor_request_position_in_host_; + + scoped_ptr<ui::ViewProp> prop_; + + DISALLOW_COPY_AND_ASSIGN(WindowTreeHost); }; } // namespace aura -#endif // UI_AURA_ROOT_WINDOW_HOST_H_ +#endif // UI_AURA_WINDOW_TREE_HOST_H_ diff --git a/chromium/ui/aura/window_tree_host_delegate.h b/chromium/ui/aura/window_tree_host_delegate.h deleted file mode 100644 index ad08039d627..00000000000 --- a/chromium/ui/aura/window_tree_host_delegate.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_AURA_ROOT_WINDOW_HOST_DELEGATE_H_ -#define UI_AURA_ROOT_WINDOW_HOST_DELEGATE_H_ - -#include "ui/aura/aura_export.h" - -namespace gfx { -class Point; -class Rect; -class Size; -} - -namespace ui { -class Event; -class EventProcessor; -class KeyEvent; -class MouseEvent; -class ScrollEvent; -class TouchEvent; -} - -namespace aura { - -class RootWindow; - -// A private interface used by RootWindowHost implementations to communicate -// with their owning RootWindow. -class AURA_EXPORT RootWindowHostDelegate { - public: - virtual bool OnHostKeyEvent(ui::KeyEvent* event) = 0; - virtual bool OnHostMouseEvent(ui::MouseEvent* event) = 0; - virtual bool OnHostScrollEvent(ui::ScrollEvent* event) = 0; - virtual bool OnHostTouchEvent(ui::TouchEvent* event) = 0; - virtual void OnHostCancelMode() = 0; - - // Called when the windowing system activates the window. - virtual void OnHostActivated() = 0; - - // Called when system focus is changed to another window. - virtual void OnHostLostWindowCapture() = 0; - - // Called when the windowing system has mouse grab because it's performing a - // window move on our behalf, but we should still paint as if we're active. - virtual void OnHostLostMouseGrab() = 0; - - virtual void OnHostPaint(const gfx::Rect& damage_rect) = 0; - - virtual void OnHostMoved(const gfx::Point& origin) = 0; - virtual void OnHostResized(const gfx::Size& size) = 0; - - virtual float GetDeviceScaleFactor() = 0; - - virtual RootWindow* AsRootWindow() = 0; - virtual const RootWindow* AsRootWindow() const = 0; - - virtual ui::EventProcessor* GetEventProcessor() = 0; - - protected: - virtual ~RootWindowHostDelegate() {} -}; - -} // namespace aura - -#endif // UI_AURA_ROOT_WINDOW_HOST_DELEGATE_H_ diff --git a/chromium/ui/aura/window_tree_host_mac.h b/chromium/ui/aura/window_tree_host_mac.h new file mode 100644 index 00000000000..8fbf4ec81bb --- /dev/null +++ b/chromium/ui/aura/window_tree_host_mac.h @@ -0,0 +1,61 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_WINDOW_TREE_HOST_MAC_H_ +#define UI_AURA_WINDOW_TREE_HOST_MAC_H_ + +#include <vector> + +#include "base/mac/scoped_nsobject.h" +#include "ui/aura/aura_export.h" +#include "ui/aura/window_tree_host.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/rect.h" + +namespace ui { +class MouseEvent; +} + +namespace aura { + +namespace internal { +class TouchEventCalibrate; +} + +class AURA_EXPORT WindowTreeHostMac : public WindowTreeHost { + public: + explicit WindowTreeHostMac(const gfx::Rect& bounds); + virtual ~WindowTreeHostMac(); + + private: + // WindowTreeHost Overrides. + virtual ui::EventSource* GetEventSource() OVERRIDE; + virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; + virtual void ToggleFullScreen() OVERRIDE; + virtual gfx::Rect GetBounds() const OVERRIDE; + virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; + virtual gfx::Insets GetInsets() const OVERRIDE; + virtual void SetInsets(const gfx::Insets& insets) OVERRIDE; + virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE; + virtual void SetCapture() OVERRIDE; + virtual void ReleaseCapture() OVERRIDE; + virtual bool ConfineCursorToRootWindow() OVERRIDE; + virtual void UnConfineCursor() OVERRIDE; + virtual void SetCursorNative(gfx::NativeCursor cursor_type) OVERRIDE; + virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE; + virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE; + virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE; + virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; + + private: + base::scoped_nsobject<NSWindow> window_; + + DISALLOW_COPY_AND_ASSIGN(WindowTreeHostMac); +}; + +} // namespace aura + +#endif // UI_AURA_WINDOW_TREE_HOST_MAC_H_ diff --git a/chromium/ui/aura/window_tree_host_mac.mm b/chromium/ui/aura/window_tree_host_mac.mm new file mode 100644 index 00000000000..7fb3f82a2ec --- /dev/null +++ b/chromium/ui/aura/window_tree_host_mac.mm @@ -0,0 +1,114 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <Cocoa/Cocoa.h> + +#include "ui/aura/window_tree_host_mac.h" +#include "ui/aura/window_tree_host.h" + +namespace aura { + +WindowTreeHostMac::WindowTreeHostMac(const gfx::Rect& bounds) { + window_.reset( + [[NSWindow alloc] + initWithContentRect:NSRectFromCGRect(bounds.ToCGRect()) + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]); + CreateCompositor(GetAcceleratedWidget()); +} + +WindowTreeHostMac::~WindowTreeHostMac() { + DestroyDispatcher(); +} + +EventSource* WindowTreeHostMac::GetEventSource() { + NOTIMPLEMENTED(); + return nil; +} + +gfx::AcceleratedWidget WindowTreeHostMac::GetAcceleratedWidget() { + return [window_ contentView]; +} +void WindowTreeHostMac::Show() { + [window_ makeKeyAndOrderFront:nil]; +} + +void WindowTreeHostMac::Hide() { + [window_ orderOut:nil]; +} + +void WindowTreeHostMac::ToggleFullScreen() { +} + +gfx::Rect WindowTreeHostMac::GetBounds() const { + return gfx::Rect(NSRectToCGRect([window_ frame])); +} + +void WindowTreeHostMac::SetBounds(const gfx::Rect& bounds) { + [window_ setFrame:NSRectFromCGRect(bounds.ToCGRect()) display:YES animate:NO]; +} + +gfx::Insets WindowTreeHostMac::GetInsets() const { + NOTIMPLEMENTED(); + return gfx::Insets(); +} + +void WindowTreeHostMac::SetInsets(const gfx::Insets& insets) { + NOTIMPLEMENTED(); +} + +gfx::Point WindowTreeHostMac::GetLocationOnNativeScreen() const { + NOTIMPLEMENTED(); + return gfx::Point(0, 0); +} + +void WindowTreeHostMac::SetCapture() { + NOTIMPLEMENTED(); +} + +void WindowTreeHostMac::ReleaseCapture() { + NOTIMPLEMENTED(); +} + +bool WindowTreeHostMac::ConfineCursorToRootWindow() { + return false; +} + +void WindowTreeHostMac::UnConfineCursor() { + NOTIMPLEMENTED(); +} + +void WindowTreeHostMac::SetCursorNative(gfx::NativeCursor cursor_type) { + NOTIMPLEMENTED(); +} + +void WindowTreeHostMac::MoveCursorToNative(const gfx::Point& location) { + NOTIMPLEMENTED(); +} + +void WindowTreeHostMac::OnCursorVisibilityChangedNative(bool show) { + NOTIMPLEMENTED(); +} + +void WindowTreeHostMac::PostNativeEvent(const base::NativeEvent& event) { + NOTIMPLEMENTED(); +} + +void WindowTreeHostMac::OnDeviceScaleFactorChanged(float device_scale_factor) { + NOTIMPLEMENTED(); +} + +// static +WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) { + return new WindowTreeHostMac(bounds); +} + +// static +gfx::Size WindowTreeHost::GetNativeScreenSize() { + NOTIMPLEMENTED(); + return gfx::Size(1024, 768); +} + +} // namespace aura diff --git a/chromium/ui/aura/window_tree_host_observer.h b/chromium/ui/aura/window_tree_host_observer.h new file mode 100644 index 00000000000..d96e9d3b24d --- /dev/null +++ b/chromium/ui/aura/window_tree_host_observer.h @@ -0,0 +1,36 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_WINDOW_TREE_HOST_OBSERVER_H_ +#define UI_AURA_WINDOW_TREE_HOST_OBSERVER_H_ + +#include "ui/aura/aura_export.h" + +namespace gfx { +class Point; +} + +namespace aura { +class Window; +class WindowTreeHost; + +class AURA_EXPORT WindowTreeHostObserver { + public: + // Called when the host's client size has changed. + virtual void OnHostResized(const WindowTreeHost* host) {} + + // Called when the host is moved on screen. + virtual void OnHostMoved(const WindowTreeHost* host, + const gfx::Point& new_origin) {} + + // Called when the native window system sends the host request to close. + virtual void OnHostCloseRequested(const WindowTreeHost* host) {} + + protected: + virtual ~WindowTreeHostObserver() {} +}; + +} // namespace aura + +#endif // UI_AURA_WINDOW_TREE_HOST_OBSERVER_H_ diff --git a/chromium/ui/aura/window_tree_host_ozone.cc b/chromium/ui/aura/window_tree_host_ozone.cc new file mode 100644 index 00000000000..d247734940e --- /dev/null +++ b/chromium/ui/aura/window_tree_host_ozone.cc @@ -0,0 +1,118 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura/window_tree_host_ozone.h" + +#include "ui/aura/window_event_dispatcher.h" +#include "ui/events/platform/platform_event_source.h" +#include "ui/ozone/public/cursor_factory_ozone.h" +#include "ui/ozone/public/event_factory_ozone.h" +#include "ui/ozone/public/surface_factory_ozone.h" + +namespace aura { + +WindowTreeHostOzone::WindowTreeHostOzone(const gfx::Rect& bounds) + : widget_(0), + bounds_(bounds) { + ui::SurfaceFactoryOzone* surface_factory = + ui::SurfaceFactoryOzone::GetInstance(); + widget_ = surface_factory->GetAcceleratedWidget(); + + ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); + CreateCompositor(GetAcceleratedWidget()); +} + +WindowTreeHostOzone::~WindowTreeHostOzone() { + ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); + DestroyCompositor(); + DestroyDispatcher(); +} + +bool WindowTreeHostOzone::CanDispatchEvent(const ui::PlatformEvent& ne) { + CHECK(ne); + ui::Event* event = static_cast<ui::Event*>(ne); + if (event->IsMouseEvent() || event->IsScrollEvent()) + return ui::CursorFactoryOzone::GetInstance()->GetCursorWindow() == widget_; + + return true; +} + +uint32_t WindowTreeHostOzone::DispatchEvent(const ui::PlatformEvent& ne) { + ui::Event* event = static_cast<ui::Event*>(ne); + ui::EventDispatchDetails details ALLOW_UNUSED = SendEventToProcessor(event); + return ui::POST_DISPATCH_STOP_PROPAGATION; +} + +ui::EventSource* WindowTreeHostOzone::GetEventSource() { + return this; +} + +gfx::AcceleratedWidget WindowTreeHostOzone::GetAcceleratedWidget() { + return widget_; +} + +void WindowTreeHostOzone::Show() { NOTIMPLEMENTED(); } + +void WindowTreeHostOzone::Hide() { NOTIMPLEMENTED(); } + +gfx::Rect WindowTreeHostOzone::GetBounds() const { return bounds_; } + +void WindowTreeHostOzone::SetBounds(const gfx::Rect& bounds) { + bool origin_changed = bounds_.origin() != bounds.origin(); + bool size_changed = bounds_.size() != bounds.size(); + bounds_ = bounds; + if (size_changed) + OnHostResized(bounds_.size()); + if (origin_changed) + OnHostMoved(bounds_.origin()); +} + +gfx::Point WindowTreeHostOzone::GetLocationOnNativeScreen() const { + return bounds_.origin(); +} + +void WindowTreeHostOzone::SetCapture() { NOTIMPLEMENTED(); } + +void WindowTreeHostOzone::ReleaseCapture() { NOTIMPLEMENTED(); } + +void WindowTreeHostOzone::PostNativeEvent( + const base::NativeEvent& native_event) { + NOTIMPLEMENTED(); +} + +void WindowTreeHostOzone::OnDeviceScaleFactorChanged( + float device_scale_factor) { + NOTIMPLEMENTED(); +} + +void WindowTreeHostOzone::SetCursorNative(gfx::NativeCursor cursor) { + ui::CursorFactoryOzone::GetInstance()->SetCursor(GetAcceleratedWidget(), + cursor.platform()); +} + +void WindowTreeHostOzone::MoveCursorToNative(const gfx::Point& location) { + ui::EventFactoryOzone::GetInstance()->WarpCursorTo(GetAcceleratedWidget(), + location); +} + +void WindowTreeHostOzone::OnCursorVisibilityChangedNative(bool show) { + NOTIMPLEMENTED(); +} + +ui::EventProcessor* WindowTreeHostOzone::GetEventProcessor() { + return dispatcher(); +} + +// static +WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) { + return new WindowTreeHostOzone(bounds); +} + +// static +gfx::Size WindowTreeHost::GetNativeScreenSize() { + NOTIMPLEMENTED(); + return gfx::Size(); +} + +} // namespace aura diff --git a/chromium/ui/aura/window_tree_host_ozone.h b/chromium/ui/aura/window_tree_host_ozone.h new file mode 100644 index 00000000000..f7ea6227996 --- /dev/null +++ b/chromium/ui/aura/window_tree_host_ozone.h @@ -0,0 +1,58 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_WINDOW_TREE_HOST_OZONE_H_ +#define UI_AURA_WINDOW_TREE_HOST_OZONE_H_ + +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "ui/aura/window_tree_host.h" +#include "ui/events/event_source.h" +#include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/rect.h" + +namespace aura { + +class AURA_EXPORT WindowTreeHostOzone : public WindowTreeHost, + public ui::EventSource, + public ui::PlatformEventDispatcher { + public: + explicit WindowTreeHostOzone(const gfx::Rect& bounds); + virtual ~WindowTreeHostOzone(); + + private: + // ui::PlatformEventDispatcher: + virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE; + virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE; + + // WindowTreeHost: + virtual ui::EventSource* GetEventSource() OVERRIDE; + virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; + virtual gfx::Rect GetBounds() const OVERRIDE; + virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; + virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE; + virtual void SetCapture() OVERRIDE; + virtual void ReleaseCapture() OVERRIDE; + virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE; + virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; + virtual void SetCursorNative(gfx::NativeCursor cursor_type) OVERRIDE; + virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE; + virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE; + + // ui::EventSource overrides. + virtual ui::EventProcessor* GetEventProcessor() OVERRIDE; + + gfx::AcceleratedWidget widget_; + gfx::Rect bounds_; + + DISALLOW_COPY_AND_ASSIGN(WindowTreeHostOzone); +}; + +} // namespace aura + +#endif // UI_AURA_WINDOW_TREE_HOST_OZONE_H_ diff --git a/chromium/ui/aura/window_tree_host_win.cc b/chromium/ui/aura/window_tree_host_win.cc new file mode 100644 index 00000000000..adf56e91ac7 --- /dev/null +++ b/chromium/ui/aura/window_tree_host_win.cc @@ -0,0 +1,238 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura/window_tree_host_win.h" + +#include <windows.h> + +#include <algorithm> + +#include "base/message_loop/message_loop.h" +#include "ui/aura/client/cursor_client.h" +#include "ui/aura/window_event_dispatcher.h" +#include "ui/base/cursor/cursor_loader_win.h" +#include "ui/base/view_prop.h" +#include "ui/compositor/compositor.h" +#include "ui/events/event.h" +#include "ui/gfx/display.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/screen.h" + +using std::max; +using std::min; + +namespace aura { +namespace { + +bool use_popup_as_root_window_for_test = false; + +} // namespace + +// static +WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) { + return new WindowTreeHostWin(bounds); +} + +// static +gfx::Size WindowTreeHost::GetNativeScreenSize() { + return gfx::Size(GetSystemMetrics(SM_CXSCREEN), + GetSystemMetrics(SM_CYSCREEN)); +} + +WindowTreeHostWin::WindowTreeHostWin(const gfx::Rect& bounds) + : has_capture_(false) { + if (use_popup_as_root_window_for_test) + set_window_style(WS_POPUP); + Init(NULL, bounds); + SetWindowText(hwnd(), L"aura::RootWindow!"); + CreateCompositor(GetAcceleratedWidget()); +} + +WindowTreeHostWin::~WindowTreeHostWin() { + DestroyCompositor(); + DestroyDispatcher(); + DestroyWindow(hwnd()); +} + +ui::EventSource* WindowTreeHostWin::GetEventSource() { + return this; +} + +gfx::AcceleratedWidget WindowTreeHostWin::GetAcceleratedWidget() { + return hwnd(); +} + +void WindowTreeHostWin::Show() { + ShowWindow(hwnd(), SW_SHOWNORMAL); +} + +void WindowTreeHostWin::Hide() { + NOTIMPLEMENTED(); +} + +gfx::Rect WindowTreeHostWin::GetBounds() const { + RECT r; + GetClientRect(hwnd(), &r); + return gfx::Rect(r); +} + +void WindowTreeHostWin::SetBounds(const gfx::Rect& bounds) { + RECT window_rect; + window_rect.left = bounds.x(); + window_rect.top = bounds.y(); + window_rect.right = bounds.right() ; + window_rect.bottom = bounds.bottom(); + AdjustWindowRectEx(&window_rect, + GetWindowLong(hwnd(), GWL_STYLE), + FALSE, + GetWindowLong(hwnd(), GWL_EXSTYLE)); + SetWindowPos( + hwnd(), + NULL, + window_rect.left, + window_rect.top, + window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top, + SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOREPOSITION); + + // Explicity call OnHostResized when the scale has changed because + // the window size may not have changed. + float current_scale = compositor()->device_scale_factor(); + float new_scale = gfx::Screen::GetScreenFor(window())-> + GetDisplayNearestWindow(window()).device_scale_factor(); + if (current_scale != new_scale) + OnHostResized(bounds.size()); +} + +gfx::Point WindowTreeHostWin::GetLocationOnNativeScreen() const { + RECT r; + GetClientRect(hwnd(), &r); + return gfx::Point(r.left, r.top); +} + + +void WindowTreeHostWin::SetCapture() { + if (!has_capture_) { + has_capture_ = true; + ::SetCapture(hwnd()); + } +} + +void WindowTreeHostWin::ReleaseCapture() { + if (has_capture_) { + has_capture_ = false; + ::ReleaseCapture(); + } +} + +void WindowTreeHostWin::SetCursorNative(gfx::NativeCursor native_cursor) { + // Custom web cursors are handled directly. + if (native_cursor == ui::kCursorCustom) + return; + + ui::CursorLoaderWin cursor_loader; + cursor_loader.SetPlatformCursor(&native_cursor); + ::SetCursor(native_cursor.platform()); +} + +void WindowTreeHostWin::MoveCursorToNative(const gfx::Point& location) { + // Deliberately not implemented. +} + +void WindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) { + NOTIMPLEMENTED(); +} + +void WindowTreeHostWin::PostNativeEvent(const base::NativeEvent& native_event) { + ::PostMessage( + hwnd(), native_event.message, native_event.wParam, native_event.lParam); +} + +void WindowTreeHostWin::OnDeviceScaleFactorChanged( + float device_scale_factor) { + NOTIMPLEMENTED(); +} + +ui::EventProcessor* WindowTreeHostWin::GetEventProcessor() { + return dispatcher(); +} + +void WindowTreeHostWin::OnClose() { + // TODO: this obviously shouldn't be here. + base::MessageLoopForUI::current()->Quit(); +} + +LRESULT WindowTreeHostWin::OnKeyEvent(UINT message, + WPARAM w_param, + LPARAM l_param) { + MSG msg = { hwnd(), message, w_param, l_param }; + ui::KeyEvent keyev(msg, message == WM_CHAR); + ui::EventDispatchDetails details = SendEventToProcessor(&keyev); + SetMsgHandled(keyev.handled() || details.dispatcher_destroyed); + return 0; +} + +LRESULT WindowTreeHostWin::OnMouseRange(UINT message, + WPARAM w_param, + LPARAM l_param) { + MSG msg = { hwnd(), message, w_param, l_param, 0, + { CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param) } }; + ui::MouseEvent event(msg); + bool handled = false; + if (!(event.flags() & ui::EF_IS_NON_CLIENT)) { + ui::EventDispatchDetails details = SendEventToProcessor(&event); + handled = event.handled() || details.dispatcher_destroyed; + } + SetMsgHandled(handled); + return 0; +} + +LRESULT WindowTreeHostWin::OnCaptureChanged(UINT message, + WPARAM w_param, + LPARAM l_param) { + if (has_capture_) { + has_capture_ = false; + OnHostLostWindowCapture(); + } + return 0; +} + +LRESULT WindowTreeHostWin::OnNCActivate(UINT message, + WPARAM w_param, + LPARAM l_param) { + if (!!w_param) + OnHostActivated(); + return DefWindowProc(hwnd(), message, w_param, l_param); +} + +void WindowTreeHostWin::OnMove(const gfx::Point& point) { + OnHostMoved(point); +} + +void WindowTreeHostWin::OnPaint(HDC dc) { + gfx::Rect damage_rect; + RECT update_rect = {0}; + if (GetUpdateRect(hwnd(), &update_rect, FALSE)) + damage_rect = gfx::Rect(update_rect); + compositor()->ScheduleRedrawRect(damage_rect); + ValidateRect(hwnd(), NULL); +} + +void WindowTreeHostWin::OnSize(UINT param, const gfx::Size& size) { + // Minimizing resizes the window to 0x0 which causes our layout to go all + // screwy, so we just ignore it. + if (dispatcher() && param != SIZE_MINIMIZED) + OnHostResized(size); +} + +namespace test { + +// static +void SetUsePopupAsRootWindowForTest(bool use) { + use_popup_as_root_window_for_test = use; +} + +} // namespace test + +} // namespace aura diff --git a/chromium/ui/aura/window_tree_host_win.h b/chromium/ui/aura/window_tree_host_win.h new file mode 100644 index 00000000000..64648510927 --- /dev/null +++ b/chromium/ui/aura/window_tree_host_win.h @@ -0,0 +1,93 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_WINDOW_TREE_HOST_WIN_H_ +#define UI_AURA_WINDOW_TREE_HOST_WIN_H_ + +#include "base/compiler_specific.h" +#include "ui/aura/aura_export.h" +#include "ui/aura/window_tree_host.h" +#include "ui/events/event_source.h" +#include "ui/gfx/win/window_impl.h" + +namespace aura { + +class AURA_EXPORT WindowTreeHostWin : public WindowTreeHost, + public ui::EventSource, + public gfx::WindowImpl { + public: + explicit WindowTreeHostWin(const gfx::Rect& bounds); + virtual ~WindowTreeHostWin(); + // WindowTreeHost: + virtual ui::EventSource* GetEventSource() OVERRIDE; + virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; + virtual gfx::Rect GetBounds() const OVERRIDE; + virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; + virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE; + virtual void SetCapture() OVERRIDE; + virtual void ReleaseCapture() OVERRIDE; + virtual void SetCursorNative(gfx::NativeCursor cursor) OVERRIDE; + virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE; + virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE; + virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE; + virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; + + // ui::EventSource: + virtual ui::EventProcessor* GetEventProcessor() OVERRIDE; + + private: + CR_BEGIN_MSG_MAP_EX(WindowTreeHostWin) + // Range handlers must go first! + CR_MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange) + CR_MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, + WM_NCXBUTTONDBLCLK, + OnMouseRange) + + // Mouse capture events. + CR_MESSAGE_HANDLER_EX(WM_CAPTURECHANGED, OnCaptureChanged) + + // Key events. + CR_MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent) + CR_MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent) + CR_MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyEvent) + CR_MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyEvent) + CR_MESSAGE_HANDLER_EX(WM_CHAR, OnKeyEvent) + CR_MESSAGE_HANDLER_EX(WM_SYSCHAR, OnKeyEvent) + CR_MESSAGE_HANDLER_EX(WM_IME_CHAR, OnKeyEvent) + CR_MESSAGE_HANDLER_EX(WM_NCACTIVATE, OnNCActivate) + + CR_MSG_WM_CLOSE(OnClose) + CR_MSG_WM_MOVE(OnMove) + CR_MSG_WM_PAINT(OnPaint) + CR_MSG_WM_SIZE(OnSize) + CR_END_MSG_MAP() + + void OnClose(); + LRESULT OnKeyEvent(UINT message, WPARAM w_param, LPARAM l_param); + LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param); + LRESULT OnCaptureChanged(UINT message, WPARAM w_param, LPARAM l_param); + LRESULT OnNCActivate(UINT message, WPARAM w_param, LPARAM l_param); + void OnMove(const gfx::Point& point); + void OnPaint(HDC dc); + void OnSize(UINT param, const gfx::Size& size); + + bool has_capture_; + + DISALLOW_COPY_AND_ASSIGN(WindowTreeHostWin); +}; + +namespace test { + +// Set true to let WindowTreeHostWin use a popup window +// with no frame/title so that the window size and test's +// expectations matches. +AURA_EXPORT void SetUsePopupAsRootWindowForTest(bool use); + +} // namespace + +} // namespace aura + +#endif // UI_AURA_WINDOW_TREE_HOST_WIN_H_ diff --git a/chromium/ui/aura/root_window_host_x11.cc b/chromium/ui/aura/window_tree_host_x11.cc index 4fb00471332..c3dcb19f151 100644 --- a/chromium/ui/aura/root_window_host_x11.cc +++ b/chromium/ui/aura/window_tree_host_x11.cc @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/aura/root_window_host_x11.h" +#include "ui/aura/window_tree_host_x11.h" #include <strings.h> #include <X11/cursorfont.h> -#include <X11/extensions/Xfixes.h> #include <X11/extensions/XInput2.h> #include <X11/extensions/Xrandr.h> #include <X11/Xatom.h> @@ -20,27 +19,28 @@ #include "base/basictypes.h" #include "base/command_line.h" #include "base/debug/trace_event.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_pump_x11.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/sys_info.h" #include "ui/aura/client/cursor_client.h" -#include "ui/aura/client/screen_position_client.h" -#include "ui/aura/client/user_action_client.h" #include "ui/aura/env.h" -#include "ui/aura/root_window.h" +#include "ui/aura/window.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/base/cursor/cursor.h" #include "ui/base/ui_base_switches.h" #include "ui/base/view_prop.h" #include "ui/base/x/x11_util.h" +#include "ui/compositor/compositor.h" #include "ui/compositor/dip_util.h" #include "ui/compositor/layer.h" #include "ui/events/event.h" +#include "ui/events/event_switches.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/keyboard_codes.h" +#include "ui/events/platform/platform_event_observer.h" +#include "ui/events/platform/x11/x11_event_source.h" #include "ui/events/x/device_data_manager.h" #include "ui/events/x/device_list_cache_x.h" #include "ui/events/x/touch_factory_x11.h" @@ -53,18 +53,10 @@ namespace aura { namespace { -// Standard Linux mouse buttons for going back and forward. -const int kBackMouseButton = 8; -const int kForwardMouseButton = 9; - const char* kAtomsToCache[] = { "WM_DELETE_WINDOW", "_NET_WM_PING", "_NET_WM_PID", - "WM_S0", -#if defined(OS_CHROMEOS) - "Tap Paused", // Defined in the gestures library. -#endif NULL }; @@ -75,15 +67,6 @@ const char* kAtomsToCache[] = { return target; } -#if defined(USE_XI2_MT) -bool IsSideBezelsEnabled() { - static bool side_bezels_enabled = - CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kTouchSideBezels) != "0"; - return side_bezels_enabled; -} -#endif - void SelectXInput2EventsForRootWindow(XDisplay* display, ::Window root_window) { CHECK(ui::IsXInput2Available()); unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {}; @@ -122,24 +105,24 @@ bool default_override_redirect = false; namespace internal { +// TODO(miletus) : Move this into DeviceDataManager. // Accomplishes 2 tasks concerning touch event calibration: // 1. Being a message-pump observer, // routes all the touch events to the X root window, // where they can be calibrated later. // 2. Has the Calibrate method that does the actual bezel calibration, // when invoked from X root window's event dispatcher. -class TouchEventCalibrate : public base::MessagePumpObserver { +class TouchEventCalibrate : public ui::PlatformEventObserver { public: - TouchEventCalibrate() - : left_(0), - right_(0), - top_(0), - bottom_(0) { - base::MessageLoopForUI::current()->AddObserver(this); + TouchEventCalibrate() : left_(0), right_(0), top_(0), bottom_(0) { + if (ui::PlatformEventSource::GetInstance()) + ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this); #if defined(USE_XI2_MT) std::vector<std::string> parts; if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kTouchCalibration), ",", &parts) >= 4) { + switches::kTouchCalibration), + ",", + &parts) >= 4) { if (!base::StringToInt(parts[0], &left_)) DLOG(ERROR) << "Incorrect left border calibration value passed."; if (!base::StringToInt(parts[1], &right_)) @@ -153,22 +136,10 @@ class TouchEventCalibrate : public base::MessagePumpObserver { } virtual ~TouchEventCalibrate() { - base::MessageLoopForUI::current()->RemoveObserver(this); + if (ui::PlatformEventSource::GetInstance()) + ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this); } -#if defined(USE_XI2_MT) - bool IsEventOnSideBezels( - const base::NativeEvent& xev, - const gfx::Rect& bounds) { - if (!left_ && !right_) - return false; - - gfx::Point location = ui::EventLocationFromNative(xev); - int x = location.x(); - return x < left_ || x > bounds.width() - right_; - } -#endif // defined(USE_XI2_MT) - // Modify the location of the |event|, // expanding it from |bounds| to (|bounds| + bezels). // Required when touchscreen is bigger than screen (i.e. has bezels), @@ -232,9 +203,8 @@ class TouchEventCalibrate : public base::MessagePumpObserver { } private: - // Overridden from base::MessagePumpObserver: - virtual base::EventStatus WillProcessEvent( - const base::NativeEvent& event) OVERRIDE { + // ui::PlatformEventObserver: + virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE { #if defined(USE_XI2_MT) if (event->type == GenericEvent && (event->xgeneric.evtype == XI_TouchBegin || @@ -246,11 +216,9 @@ class TouchEventCalibrate : public base::MessagePumpObserver { xievent->event_y = xievent->root_y; } #endif // defined(USE_XI2_MT) - return base::EVENT_CONTINUE; } - virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE { - } + virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE {} // The difference in screen's native resolution pixels between // the border of the touchscreen and the border of the screen, @@ -266,61 +234,17 @@ class TouchEventCalibrate : public base::MessagePumpObserver { } // namespace internal //////////////////////////////////////////////////////////////////////////////// -// RootWindowHostX11::MouseMoveFilter filters out the move events that -// jump back and forth between two points. This happens when sub pixel mouse -// move is enabled and mouse move events could be jumping between two neighbor -// pixels, e.g. move(0,0), move(1,0), move(0,0), move(1,0) and on and on. -// The filtering is done by keeping track of the last two event locations and -// provides a Filter method to find out whether a mouse event is in a different -// location and should be processed. - -class RootWindowHostX11::MouseMoveFilter { - public: - MouseMoveFilter() : insert_index_(0) { - for (size_t i = 0; i < kMaxEvents; ++i) { - const int int_max = std::numeric_limits<int>::max(); - recent_locations_[i] = gfx::Point(int_max, int_max); - } - } - ~MouseMoveFilter() {} - - // Returns true if |event| is known and should be ignored. - bool Filter(const base::NativeEvent& event) { - const gfx::Point& location = ui::EventLocationFromNative(event); - for (size_t i = 0; i < kMaxEvents; ++i) { - if (location == recent_locations_[i]) - return true; - } - - recent_locations_[insert_index_] = location; - insert_index_ = (insert_index_ + 1) % kMaxEvents; - return false; - } - - private: - static const size_t kMaxEvents = 2; - - gfx::Point recent_locations_[kMaxEvents]; - size_t insert_index_; - - DISALLOW_COPY_AND_ASSIGN(MouseMoveFilter); -}; - -//////////////////////////////////////////////////////////////////////////////// -// RootWindowHostX11 +// WindowTreeHostX11 -RootWindowHostX11::RootWindowHostX11(const gfx::Rect& bounds) +WindowTreeHostX11::WindowTreeHostX11(const gfx::Rect& bounds) : xdisplay_(gfx::GetXDisplay()), xwindow_(0), x_root_window_(DefaultRootWindow(xdisplay_)), current_cursor_(ui::kCursorNull), window_mapped_(false), bounds_(bounds), - is_internal_display_(false), touch_calibrate_(new internal::TouchEventCalibrate), - mouse_move_filter_(new MouseMoveFilter), - atom_cache_(xdisplay_, kAtomsToCache), - bezel_tracking_ids_(0) { + atom_cache_(xdisplay_, kAtomsToCache) { XSetWindowAttributes swa; memset(&swa, 0, sizeof(swa)); swa.background_pixmap = None; @@ -334,8 +258,8 @@ RootWindowHostX11::RootWindowHostX11(const gfx::Rect& bounds) CopyFromParent, // visual CWBackPixmap | CWOverrideRedirect, &swa); - base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_); - base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this); + if (ui::PlatformEventSource::GetInstance()) + ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | KeyPressMask | KeyReleaseMask | @@ -376,30 +300,46 @@ RootWindowHostX11::RootWindowHostX11(const gfx::Rect& bounds) PropModeReplace, reinterpret_cast<unsigned char*>(&pid), 1); + // Allow subclasses to create and cache additional atoms. + atom_cache_.allow_uncached_atoms(); + XRRSelectInput(xdisplay_, x_root_window_, RRScreenChangeNotifyMask | RROutputChangeNotifyMask); - Env::GetInstance()->AddObserver(this); + CreateCompositor(GetAcceleratedWidget()); } -RootWindowHostX11::~RootWindowHostX11() { - Env::GetInstance()->RemoveObserver(this); - base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this); - base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_); - - UnConfineCursor(); +WindowTreeHostX11::~WindowTreeHostX11() { + if (ui::PlatformEventSource::GetInstance()) + ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); + DestroyCompositor(); + DestroyDispatcher(); XDestroyWindow(xdisplay_, xwindow_); } -bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) { - XEvent* xev = event; +bool WindowTreeHostX11::CanDispatchEvent(const ui::PlatformEvent& event) { + ::Window target = FindEventTarget(event); + return target == xwindow_ || target == x_root_window_; +} - if (FindEventTarget(event) == x_root_window_) - return DispatchEventForRootWindow(event); +uint32_t WindowTreeHostX11::DispatchEvent(const ui::PlatformEvent& event) { + XEvent* xev = event; + if (FindEventTarget(xev) == x_root_window_) { + if (xev->type == GenericEvent) + DispatchXI2Event(xev); + return ui::POST_DISPATCH_NONE; + } switch (xev->type) { case EnterNotify: { - aura::Window* root_window = GetRootWindow()->window(); + // Ignore EventNotify events from children of |xwindow_|. + // NativeViewGLSurfaceGLX adds a child to |xwindow_|. + // TODO(pkotwicz|tdanderson): Figure out whether the suppression is + // necessary. crbug.com/385716 + if (xev->xcrossing.detail == NotifyInferior) + break; + + aura::Window* root_window = window(); client::CursorClient* cursor_client = client::GetCursorClient(root_window); if (cursor_client) { @@ -411,55 +351,49 @@ bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) { // EnterNotify creates ET_MOUSE_MOVE. Mark as synthesized as this is not // real mouse move event. mouse_event.set_flags(mouse_event.flags() | ui::EF_IS_SYNTHESIZED); - TranslateAndDispatchMouseEvent(&mouse_event); + TranslateAndDispatchLocatedEvent(&mouse_event); break; } case LeaveNotify: { + // Ignore LeaveNotify events from children of |xwindow_|. + // NativeViewGLSurfaceGLX adds a child to |xwindow_|. + // TODO(pkotwicz|tdanderson): Figure out whether the suppression is + // necessary. crbug.com/385716 + if (xev->xcrossing.detail == NotifyInferior) + break; + ui::MouseEvent mouse_event(xev); - TranslateAndDispatchMouseEvent(&mouse_event); + TranslateAndDispatchLocatedEvent(&mouse_event); break; } case Expose: { gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y, xev->xexpose.width, xev->xexpose.height); - delegate_->AsRootWindow()->ScheduleRedrawRect(damage_rect); + compositor()->ScheduleRedrawRect(damage_rect); break; } case KeyPress: { ui::KeyEvent keydown_event(xev, false); - delegate_->OnHostKeyEvent(&keydown_event); + SendEventToProcessor(&keydown_event); break; } case KeyRelease: { ui::KeyEvent keyup_event(xev, false); - delegate_->OnHostKeyEvent(&keyup_event); + SendEventToProcessor(&keyup_event); break; } - case ButtonPress: { - if (static_cast<int>(xev->xbutton.button) == kBackMouseButton || - static_cast<int>(xev->xbutton.button) == kForwardMouseButton) { - client::UserActionClient* gesture_client = - client::GetUserActionClient(delegate_->AsRootWindow()->window()); - if (gesture_client) { - gesture_client->OnUserAction( - static_cast<int>(xev->xbutton.button) == kBackMouseButton ? - client::UserActionClient::BACK : - client::UserActionClient::FORWARD); - } - break; - } - } // fallthrough + case ButtonPress: case ButtonRelease: { switch (ui::EventTypeFromNative(xev)) { case ui::ET_MOUSEWHEEL: { ui::MouseWheelEvent mouseev(xev); - TranslateAndDispatchMouseEvent(&mouseev); + TranslateAndDispatchLocatedEvent(&mouseev); break; } case ui::ET_MOUSE_PRESSED: case ui::ET_MOUSE_RELEASED: { ui::MouseEvent mouseev(xev); - TranslateAndDispatchMouseEvent(&mouseev); + TranslateAndDispatchLocatedEvent(&mouseev); break; } case ui::ET_UNKNOWN: @@ -472,7 +406,7 @@ bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) { } case FocusOut: if (xev->xfocus.mode != NotifyGrab) - delegate_->OnHostLostWindowCapture(); + OnHostLostWindowCapture(); break; case ConfigureNotify: { DCHECK_EQ(xwindow_, xev->xconfigure.event); @@ -485,27 +419,21 @@ bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) { bool size_changed = bounds_.size() != bounds.size(); bool origin_changed = bounds_.origin() != bounds.origin(); bounds_ = bounds; - UpdateIsInternalDisplay(); - // Always update barrier and mouse location because |bounds_| might - // have already been updated in |SetBounds|. - if (pointer_barriers_) { - UnConfineCursor(); - ConfineCursorToRootWindow(); - } + OnConfigureNotify(); if (size_changed) - delegate_->OnHostResized(bounds.size()); + OnHostResized(bounds.size()); if (origin_changed) - delegate_->OnHostMoved(bounds_.origin()); + OnHostMoved(bounds_.origin()); break; } case GenericEvent: - DispatchXI2Event(event); + DispatchXI2Event(xev); break; case ClientMessage: { Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]); if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { // We have received a close message from the window manager. - delegate_->AsRootWindow()->OnRootWindowHostCloseRequested(); + OnHostCloseRequested(); } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) { XEvent reply_event = *xev; reply_event.xclient.window = x_root_window_; @@ -515,6 +443,7 @@ bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) { False, SubstructureRedirectMask | SubstructureNotifyMask, &reply_event); + XFlush(xdisplay_); } break; } @@ -523,7 +452,6 @@ bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) { case MappingModifier: case MappingKeyboard: XRefreshKeyboardMapping(&xev->xmapping); - delegate_->AsRootWindow()->OnKeyboardMappingChanged(); break; case MappingPointer: ui::DeviceDataManager::GetInstance()->UpdateButtonMap(); @@ -553,22 +481,22 @@ bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) { } ui::MouseEvent mouseev(xev); - TranslateAndDispatchMouseEvent(&mouseev); + TranslateAndDispatchLocatedEvent(&mouseev); break; } } - return true; + return ui::POST_DISPATCH_STOP_PROPAGATION; } -RootWindow* RootWindowHostX11::GetRootWindow() { - return delegate_->AsRootWindow(); +ui::EventSource* WindowTreeHostX11::GetEventSource() { + return this; } -gfx::AcceleratedWidget RootWindowHostX11::GetAcceleratedWidget() { +gfx::AcceleratedWidget WindowTreeHostX11::GetAcceleratedWidget() { return xwindow_; } -void RootWindowHostX11::Show() { +void WindowTreeHostX11::Show() { if (!window_mapped_) { // Before we map the window, set size hints. Otherwise, some window managers // will ignore toplevel XMoveWindow commands. @@ -586,33 +514,29 @@ void RootWindowHostX11::Show() { // We now block until our window is mapped. Some X11 APIs will crash and // burn if passed |xwindow_| before the window is mapped, and XMapWindow is // asynchronous. - base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_); + if (ui::X11EventSource::GetInstance()) + ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_); window_mapped_ = true; } } -void RootWindowHostX11::Hide() { +void WindowTreeHostX11::Hide() { if (window_mapped_) { XWithdrawWindow(xdisplay_, xwindow_, 0); window_mapped_ = false; } } -void RootWindowHostX11::ToggleFullScreen() { - NOTIMPLEMENTED(); -} - -gfx::Rect RootWindowHostX11::GetBounds() const { +gfx::Rect WindowTreeHostX11::GetBounds() const { return bounds_; } -void RootWindowHostX11::SetBounds(const gfx::Rect& bounds) { +void WindowTreeHostX11::SetBounds(const gfx::Rect& bounds) { // Even if the host window's size doesn't change, aura's root window // size, which is in DIP, changes when the scale changes. - float current_scale = delegate_->GetDeviceScaleFactor(); - float new_scale = gfx::Screen::GetScreenFor( - delegate_->AsRootWindow()->window())->GetDisplayNearestWindow( - delegate_->AsRootWindow()->window()).device_scale_factor(); + float current_scale = compositor()->device_scale_factor(); + float new_scale = gfx::Screen::GetScreenFor(window())-> + GetDisplayNearestWindow(window()).device_scale_factor(); bool origin_changed = bounds_.origin() != bounds.origin(); bool size_changed = bounds_.size() != bounds.size(); XWindowChanges changes = {0}; @@ -638,131 +562,28 @@ void RootWindowHostX11::SetBounds(const gfx::Rect& bounds) { // (possibly synthetic) ConfigureNotify about the actual size and correct // |bounds_| later. bounds_ = bounds; - UpdateIsInternalDisplay(); if (origin_changed) - delegate_->OnHostMoved(bounds.origin()); + OnHostMoved(bounds.origin()); if (size_changed || current_scale != new_scale) { - delegate_->OnHostResized(bounds.size()); + OnHostResized(bounds.size()); } else { - delegate_->AsRootWindow()->window()->SchedulePaintInRect( - delegate_->AsRootWindow()->window()->bounds()); + window()->SchedulePaintInRect(window()->bounds()); } } -gfx::Insets RootWindowHostX11::GetInsets() const { - return insets_; -} - -void RootWindowHostX11::SetInsets(const gfx::Insets& insets) { - insets_ = insets; - if (pointer_barriers_) { - UnConfineCursor(); - ConfineCursorToRootWindow(); - } -} - -gfx::Point RootWindowHostX11::GetLocationOnNativeScreen() const { +gfx::Point WindowTreeHostX11::GetLocationOnNativeScreen() const { return bounds_.origin(); } -void RootWindowHostX11::SetCapture() { +void WindowTreeHostX11::SetCapture() { // TODO(oshima): Grab x input. } -void RootWindowHostX11::ReleaseCapture() { +void WindowTreeHostX11::ReleaseCapture() { // TODO(oshima): Release x input. } -void RootWindowHostX11::SetCursor(gfx::NativeCursor cursor) { - if (cursor == current_cursor_) - return; - current_cursor_ = cursor; - SetCursorInternal(cursor); -} - -bool RootWindowHostX11::QueryMouseLocation(gfx::Point* location_return) { - client::CursorClient* cursor_client = - client::GetCursorClient(GetRootWindow()->window()); - if (cursor_client && !cursor_client->IsMouseEventsEnabled()) { - *location_return = gfx::Point(0, 0); - return false; - } - - ::Window root_return, child_return; - int root_x_return, root_y_return, win_x_return, win_y_return; - unsigned int mask_return; - XQueryPointer(xdisplay_, - xwindow_, - &root_return, - &child_return, - &root_x_return, &root_y_return, - &win_x_return, &win_y_return, - &mask_return); - *location_return = gfx::Point(max(0, min(bounds_.width(), win_x_return)), - max(0, min(bounds_.height(), win_y_return))); - return (win_x_return >= 0 && win_x_return < bounds_.width() && - win_y_return >= 0 && win_y_return < bounds_.height()); -} - -bool RootWindowHostX11::ConfineCursorToRootWindow() { -#if XFIXES_MAJOR >= 5 - DCHECK(!pointer_barriers_.get()); - if (pointer_barriers_) - return false; - pointer_barriers_.reset(new XID[4]); - gfx::Rect bounds(bounds_); - bounds.Inset(insets_); - // Horizontal, top barriers. - pointer_barriers_[0] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, - bounds.x(), bounds.y(), bounds.right(), bounds.y(), - BarrierPositiveY, - 0, XIAllDevices); - // Horizontal, bottom barriers. - pointer_barriers_[1] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, - bounds.x(), bounds.bottom(), bounds.right(), bounds.bottom(), - BarrierNegativeY, - 0, XIAllDevices); - // Vertical, left barriers. - pointer_barriers_[2] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, - bounds.x(), bounds.y(), bounds.x(), bounds.bottom(), - BarrierPositiveX, - 0, XIAllDevices); - // Vertical, right barriers. - pointer_barriers_[3] = XFixesCreatePointerBarrier( - xdisplay_, x_root_window_, - bounds.right(), bounds.y(), bounds.right(), bounds.bottom(), - BarrierNegativeX, - 0, XIAllDevices); -#endif - return true; -} - -void RootWindowHostX11::UnConfineCursor() { -#if XFIXES_MAJOR >= 5 - if (pointer_barriers_) { - XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[0]); - XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[1]); - XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[2]); - XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[3]); - pointer_barriers_.reset(); - } -#endif -} - -void RootWindowHostX11::OnCursorVisibilityChanged(bool show) { - SetCrOSTapPaused(!show); -} - -void RootWindowHostX11::MoveCursorTo(const gfx::Point& location) { - XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0, - bounds_.x() + location.x(), - bounds_.y() + location.y()); -} - -void RootWindowHostX11::PostNativeEvent( +void WindowTreeHostX11::PostNativeEvent( const base::NativeEvent& native_event) { DCHECK(xwindow_); DCHECK(xdisplay_); @@ -785,7 +606,7 @@ void RootWindowHostX11::PostNativeEvent( xevent.xmotion.time = CurrentTime; gfx::Point point(xevent.xmotion.x, xevent.xmotion.y); - delegate_->AsRootWindow()->host()->ConvertPointToNativeScreen(&point); + ConvertPointToNativeScreen(&point); xevent.xmotion.x_root = point.x(); xevent.xmotion.y_root = point.y(); } @@ -793,57 +614,41 @@ void RootWindowHostX11::PostNativeEvent( break; } XSendEvent(xdisplay_, xwindow_, False, 0, &xevent); + XFlush(xdisplay_); } -void RootWindowHostX11::OnDeviceScaleFactorChanged( +void WindowTreeHostX11::OnDeviceScaleFactorChanged( float device_scale_factor) { } -void RootWindowHostX11::PrepareForShutdown() { - base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_); -} - -void RootWindowHostX11::OnWindowInitialized(Window* window) { -} - -void RootWindowHostX11::OnRootWindowInitialized(RootWindow* root_window) { - // UpdateIsInternalDisplay relies on: - // 1. delegate_ pointing to RootWindow - available after SetDelegate. - // 2. RootWindow's kDisplayIdKey property set - available by the time - // RootWindow::Init is called. - // (set in DisplayManager::CreateRootWindowForDisplay) - // Ready when NotifyRootWindowInitialized is called from RootWindow::Init. - if (!delegate_ || root_window != GetRootWindow()) +void WindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) { + if (cursor == current_cursor_) return; - UpdateIsInternalDisplay(); - - // We have to enable Tap-to-click by default because the cursor is set to - // visible in Shell::InitRootWindowController. - SetCrOSTapPaused(false); + current_cursor_ = cursor; + SetCursorInternal(cursor); } -ui::EventProcessor* RootWindowHostX11::GetEventProcessor() { - return delegate_->GetEventProcessor(); +void WindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) { + XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0, + bounds_.x() + location.x(), + bounds_.y() + location.y()); } -bool RootWindowHostX11::DispatchEventForRootWindow( - const base::NativeEvent& event) { - switch (event->type) { - case GenericEvent: - DispatchXI2Event(event); - break; - } +void WindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) { +} - return true; +ui::EventProcessor* WindowTreeHostX11::GetEventProcessor() { + return dispatcher(); } -void RootWindowHostX11::DispatchXI2Event(const base::NativeEvent& event) { +void WindowTreeHostX11::DispatchXI2Event(const base::NativeEvent& event) { ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); XEvent* xev = event; + XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data); if (!factory->ShouldProcessXI2Event(xev)) return; - TRACE_EVENT1("input", "RootWindowHostX11::DispatchXI2Event", + TRACE_EVENT1("input", "WindowTreeHostX11::DispatchXI2Event", "event_latency_us", (ui::EventTimeForNow() - ui::EventTimeFromNative(event)). InMicroseconds()); @@ -857,50 +662,12 @@ void RootWindowHostX11::DispatchXI2Event(const base::NativeEvent& event) { case ui::ET_TOUCH_PRESSED: case ui::ET_TOUCH_CANCELLED: case ui::ET_TOUCH_RELEASED: { -#if defined(OS_CHROMEOS) - // Bail out early before generating a ui::TouchEvent if this event - // is not within the range of this RootWindow. Converting an xevent - // to ui::TouchEvent might change the state of the global touch tracking - // state, e.g. touch release event can remove the touch id from the - // record, and doing this multiple time when there are multiple - // RootWindow will cause problem. So only generate the ui::TouchEvent - // when we are sure it belongs to this RootWindow. - if (base::SysInfo::IsRunningOnChromeOS() && - !bounds_.Contains(ui::EventLocationFromNative(xev))) - break; -#endif // defined(OS_CHROMEOS) ui::TouchEvent touchev(xev); -#if defined(USE_XI2_MT) - // Ignore touch events with touch press happening on the side bezel. - if (!IsSideBezelsEnabled()) { - uint32 tracking_id = (1 << touchev.touch_id()); - if (type == ui::ET_TOUCH_PRESSED && - touch_calibrate_->IsEventOnSideBezels(xev, bounds_)) - bezel_tracking_ids_ |= tracking_id; - if (bezel_tracking_ids_ & tracking_id) { - if (type == ui::ET_TOUCH_CANCELLED || type == ui::ET_TOUCH_RELEASED) - bezel_tracking_ids_ = - (bezel_tracking_ids_ | tracking_id) ^ tracking_id; - return; - } + if (ui::DeviceDataManager::GetInstance()->TouchEventNeedsCalibrate( + xiev->deviceid)) { + touch_calibrate_->Calibrate(&touchev, bounds_); } -#endif // defined(USE_XI2_MT) -#if defined(OS_CHROMEOS) - if (base::SysInfo::IsRunningOnChromeOS()) { - // X maps the touch-surface to the size of the X root-window. - // In multi-monitor setup, Coordinate Transformation Matrix - // repositions the touch-surface onto part of X root-window - // containing aura root-window corresponding to the touchscreen. - // However, if aura root-window has non-zero origin, - // we need to relocate the event into aura root-window coordinates. - touchev.Relocate(bounds_.origin()); -#if defined(USE_XI2_MT) - if (is_internal_display_) - touch_calibrate_->Calibrate(&touchev, bounds_); -#endif // defined(USE_XI2_MT) - } -#endif // defined(OS_CHROMEOS) - delegate_->OnHostTouchEvent(&touchev); + TranslateAndDispatchLocatedEvent(&touchev); break; } case ui::ET_MOUSE_MOVED: @@ -915,45 +682,21 @@ void RootWindowHostX11::DispatchXI2Event(const base::NativeEvent& event) { num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event); if (num_coalesced > 0) xev = &last_event; - - if (mouse_move_filter_ && mouse_move_filter_->Filter(xev)) - break; - } else if (type == ui::ET_MOUSE_PRESSED || - type == ui::ET_MOUSE_RELEASED) { - XIDeviceEvent* xievent = - static_cast<XIDeviceEvent*>(xev->xcookie.data); - int button = xievent->detail; - if (button == kBackMouseButton || button == kForwardMouseButton) { - if (type == ui::ET_MOUSE_RELEASED) - break; - client::UserActionClient* gesture_client = - client::GetUserActionClient(delegate_->AsRootWindow()->window()); - if (gesture_client) { - bool reverse_direction = - ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled(); - gesture_client->OnUserAction( - (button == kBackMouseButton && !reverse_direction) || - (button == kForwardMouseButton && reverse_direction) ? - client::UserActionClient::BACK : - client::UserActionClient::FORWARD); - } - break; - } } ui::MouseEvent mouseev(xev); - TranslateAndDispatchMouseEvent(&mouseev); + TranslateAndDispatchLocatedEvent(&mouseev); break; } case ui::ET_MOUSEWHEEL: { ui::MouseWheelEvent mouseev(xev); - TranslateAndDispatchMouseEvent(&mouseev); + TranslateAndDispatchLocatedEvent(&mouseev); break; } case ui::ET_SCROLL_FLING_START: case ui::ET_SCROLL_FLING_CANCEL: case ui::ET_SCROLL: { ui::ScrollEvent scrollev(xev); - delegate_->OnHostScrollEvent(&scrollev); + SendEventToProcessor(&scrollev); break; } case ui::ET_UMA_DATA: @@ -969,83 +712,24 @@ void RootWindowHostX11::DispatchXI2Event(const base::NativeEvent& event) { XFreeEventData(xev->xgeneric.display, &last_event.xcookie); } -bool RootWindowHostX11::IsWindowManagerPresent() { - // Per ICCCM 2.8, "Manager Selections", window managers should take ownership - // of WM_Sn selections (where n is a screen number). - return XGetSelectionOwner( - xdisplay_, atom_cache_.GetAtom("WM_S0")) != None; -} - -void RootWindowHostX11::SetCursorInternal(gfx::NativeCursor cursor) { +void WindowTreeHostX11::SetCursorInternal(gfx::NativeCursor cursor) { XDefineCursor(xdisplay_, xwindow_, cursor.platform()); } -void RootWindowHostX11::TranslateAndDispatchMouseEvent( - ui::MouseEvent* event) { - Window* root_window = GetRootWindow()->window(); - client::ScreenPositionClient* screen_position_client = - client::GetScreenPositionClient(root_window); - gfx::Rect local(bounds_.size()); - - if (screen_position_client && !local.Contains(event->location())) { - gfx::Point location(event->location()); - // In order to get the correct point in screen coordinates - // during passive grab, we first need to find on which host window - // the mouse is on, and find out the screen coordinates on that - // host window, then convert it back to this host window's coordinate. - screen_position_client->ConvertHostPointToScreen(root_window, &location); - screen_position_client->ConvertPointFromScreen(root_window, &location); - root_window->GetDispatcher()->ConvertPointToHost(&location); - event->set_location(location); - event->set_root_location(location); - } - delegate_->OnHostMouseEvent(event); -} - -void RootWindowHostX11::UpdateIsInternalDisplay() { - Window* root_window = GetRootWindow()->window(); - gfx::Screen* screen = gfx::Screen::GetScreenFor(root_window); - gfx::Display display = screen->GetDisplayNearestWindow(root_window); - is_internal_display_ = display.IsInternal(); -} +void WindowTreeHostX11::OnConfigureNotify() {} -void RootWindowHostX11::SetCrOSTapPaused(bool state) { -#if defined(OS_CHROMEOS) - if (!ui::IsXInput2Available()) - return; - // Temporarily pause tap-to-click when the cursor is hidden. - Atom prop = atom_cache_.GetAtom("Tap Paused"); - unsigned char value = state; - XIDeviceList dev_list = - ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(xdisplay_); - - // Only slave pointer devices could possibly have tap-paused property. - for (int i = 0; i < dev_list.count; i++) { - if (dev_list[i].use == XISlavePointer) { - Atom old_type; - int old_format; - unsigned long old_nvalues, bytes; - unsigned char* data; - int result = XIGetProperty(xdisplay_, dev_list[i].deviceid, prop, 0, 0, - False, AnyPropertyType, &old_type, &old_format, - &old_nvalues, &bytes, &data); - if (result != Success) - continue; - XFree(data); - XIChangeProperty(xdisplay_, dev_list[i].deviceid, prop, XA_INTEGER, 8, - PropModeReplace, &value, 1); - } - } -#endif +void WindowTreeHostX11::TranslateAndDispatchLocatedEvent( + ui::LocatedEvent* event) { + SendEventToProcessor(event); } // static -RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) { - return new RootWindowHostX11(bounds); +WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) { + return new WindowTreeHostX11(bounds); } // static -gfx::Size RootWindowHost::GetNativeScreenSize() { +gfx::Size WindowTreeHost::GetNativeScreenSize() { ::XDisplay* xdisplay = gfx::GetXDisplay(); return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0)); } diff --git a/chromium/ui/aura/window_tree_host_x11.h b/chromium/ui/aura/window_tree_host_x11.h new file mode 100644 index 00000000000..1db9f675684 --- /dev/null +++ b/chromium/ui/aura/window_tree_host_x11.h @@ -0,0 +1,118 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_WINDOW_TREE_HOST_X11_H_ +#define UI_AURA_WINDOW_TREE_HOST_X11_H_ + +#include "base/memory/scoped_ptr.h" +#include "ui/aura/aura_export.h" +#include "ui/aura/window_tree_host.h" +#include "ui/events/event_source.h" +#include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/x/x11_atom_cache.h" + +// X forward decls to avoid including Xlib.h in a header file. +typedef struct _XDisplay XDisplay; +typedef unsigned long XID; +typedef XID Window; + +namespace ui { +class MouseEvent; +} + +namespace aura { + +namespace internal { +class TouchEventCalibrate; +} + +class AURA_EXPORT WindowTreeHostX11 : public WindowTreeHost, + public ui::EventSource, + public ui::PlatformEventDispatcher { + + public: + explicit WindowTreeHostX11(const gfx::Rect& bounds); + virtual ~WindowTreeHostX11(); + + // ui::PlatformEventDispatcher: + virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE; + virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE; + + // WindowTreeHost: + virtual ui::EventSource* GetEventSource() OVERRIDE; + virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; + virtual gfx::Rect GetBounds() const OVERRIDE; + virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; + virtual gfx::Point GetLocationOnNativeScreen() const OVERRIDE; + virtual void SetCapture() OVERRIDE; + virtual void ReleaseCapture() OVERRIDE; + virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE; + virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; + virtual void SetCursorNative(gfx::NativeCursor cursor_type) OVERRIDE; + virtual void MoveCursorToNative(const gfx::Point& location) OVERRIDE; + virtual void OnCursorVisibilityChangedNative(bool show) OVERRIDE; + + // ui::EventSource overrides. + virtual ui::EventProcessor* GetEventProcessor() OVERRIDE; + + protected: + // Called when X Configure Notify event is recevied. + virtual void OnConfigureNotify(); + + // Translates the native mouse location into screen coordinates and + // dispatches the event via WindowEventDispatcher. + virtual void TranslateAndDispatchLocatedEvent(ui::LocatedEvent* event); + + ::Window x_root_window() { return x_root_window_; } + XDisplay* xdisplay() { return xdisplay_; } + const gfx::Rect bounds() const { return bounds_; } + ui::X11AtomCache* atom_cache() { return &atom_cache_; } + + private: + // Dispatches XI2 events. Note that some events targetted for the X root + // window are dispatched to the aura root window (e.g. touch events after + // calibration). + void DispatchXI2Event(const base::NativeEvent& event); + + // Sets the cursor on |xwindow_| to |cursor|. Does not check or update + // |current_cursor_|. + void SetCursorInternal(gfx::NativeCursor cursor); + + // The display and the native X window hosting the root window. + XDisplay* xdisplay_; + ::Window xwindow_; + + // The native root window. + ::Window x_root_window_; + + // Current Aura cursor. + gfx::NativeCursor current_cursor_; + + // Is the window mapped to the screen? + bool window_mapped_; + + // The bounds of |xwindow_|. + gfx::Rect bounds_; + + scoped_ptr<internal::TouchEventCalibrate> touch_calibrate_; + + ui::X11AtomCache atom_cache_; + + DISALLOW_COPY_AND_ASSIGN(WindowTreeHostX11); +}; + +namespace test { + +// Set the default value of the override redirect flag used to +// create a X window for WindowTreeHostX11. +AURA_EXPORT void SetUseOverrideRedirectWindowByDefault(bool override_redirect); + +} // namespace test +} // namespace aura + +#endif // UI_AURA_WINDOW_TREE_HOST_X11_H_ diff --git a/chromium/ui/aura/window_unittest.cc b/chromium/ui/aura/window_unittest.cc index b79143113b7..37cf5edca78 100644 --- a/chromium/ui/aura/window_unittest.cc +++ b/chromium/ui/aura/window_unittest.cc @@ -18,20 +18,20 @@ #include "ui/aura/client/focus_change_observer.h" #include "ui/aura/client/visibility_client.h" #include "ui/aura/client/window_tree_client.h" -#include "ui/aura/layout_manager.h" -#include "ui/aura/root_window.h" -#include "ui/aura/root_window_observer.h" #include "ui/aura/test/aura_test_base.h" +#include "ui/aura/test/aura_test_utils.h" #include "ui/aura/test/event_generator.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/test/window_test_api.h" #include "ui/aura/window_delegate.h" +#include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_observer.h" #include "ui/aura/window_property.h" #include "ui/aura/window_tree_host.h" #include "ui/base/hit_test.h" #include "ui/compositor/layer.h" +#include "ui/compositor/layer_animation_observer.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/compositor/test/test_layers.h" @@ -94,13 +94,13 @@ class DestroyTrackingDelegateImpl : public TestWindowDelegate { bool in_destroying() const { return in_destroying_; } - virtual void OnWindowDestroying() OVERRIDE { + virtual void OnWindowDestroying(Window* window) OVERRIDE { EXPECT_FALSE(in_destroying_); in_destroying_ = true; destroying_count_++; } - virtual void OnWindowDestroyed() OVERRIDE { + virtual void OnWindowDestroyed(Window* window) OVERRIDE { EXPECT_TRUE(in_destroying_); in_destroying_ = false; destroyed_count_++; @@ -123,9 +123,9 @@ class ChildWindowDelegateImpl : public DestroyTrackingDelegateImpl { : parent_delegate_(parent_delegate) { } - virtual void OnWindowDestroying() OVERRIDE { + virtual void OnWindowDestroying(Window* window) OVERRIDE { EXPECT_TRUE(parent_delegate_->in_destroying()); - DestroyTrackingDelegateImpl::OnWindowDestroying(); + DestroyTrackingDelegateImpl::OnWindowDestroying(window); } private: @@ -143,7 +143,7 @@ class DestroyOrphanDelegate : public TestWindowDelegate { void set_window(Window* window) { window_ = window; } - virtual void OnWindowDestroyed() OVERRIDE { + virtual void OnWindowDestroyed(Window* window) OVERRIDE { EXPECT_FALSE(window_->parent()); } @@ -245,7 +245,7 @@ class DestroyWindowDelegate : public TestWindowDelegate { virtual ~DestroyWindowDelegate() {} // Overridden from WindowDelegate. - virtual void OnWindowDestroyed() OVERRIDE { + virtual void OnWindowDestroyed(Window* window) OVERRIDE { delete this; } @@ -269,11 +269,11 @@ TEST_F(WindowTest, GetChildById) { // and not containing NULL or parents. TEST_F(WindowTest, Contains) { Window parent(NULL); - parent.Init(ui::LAYER_NOT_DRAWN); + parent.Init(aura::WINDOW_LAYER_NOT_DRAWN); Window child1(NULL); - child1.Init(ui::LAYER_NOT_DRAWN); + child1.Init(aura::WINDOW_LAYER_NOT_DRAWN); Window child2(NULL); - child2.Init(ui::LAYER_NOT_DRAWN); + child2.Init(aura::WINDOW_LAYER_NOT_DRAWN); parent.AddChild(&child1); child1.AddChild(&child2); @@ -372,13 +372,11 @@ TEST_F(WindowTest, MoveCursorToWithTransformRootWindow) { transform.Translate(100.0, 100.0); transform.Rotate(90.0); transform.Scale(2.0, 5.0); - dispatcher()->SetTransform(transform); - dispatcher()->MoveCursorTo(gfx::Point(10, 10)); + host()->SetRootTransform(transform); + host()->MoveCursorTo(gfx::Point(10, 10)); #if !defined(OS_WIN) - gfx::Point mouse_location; - EXPECT_TRUE(dispatcher()->host()->QueryMouseLocation(&mouse_location)); // TODO(yoshiki): fix this to build on Windows. See crbug.com/133413.OD - EXPECT_EQ("50,120", mouse_location.ToString()); + EXPECT_EQ("50,120", QueryLatestMousePositionRequestInHost(host()).ToString()); #endif EXPECT_EQ("10,10", gfx::Screen::GetScreenFor( root_window())->GetCursorScreenPoint().ToString()); @@ -453,7 +451,7 @@ TEST_F(WindowTest, MoveCursorToWithComplexTransform) { transform.Translate(10.0, 20.0); transform.Rotate(10.0); transform.Scale(0.3f, 0.5f); - dispatcher()->SetTransform(root_transform); + host()->SetRootTransform(root_transform); w1->SetTransform(transform); w11->SetTransform(transform); w111->SetTransform(transform); @@ -463,67 +461,12 @@ TEST_F(WindowTest, MoveCursorToWithComplexTransform) { #if !defined(OS_WIN) // TODO(yoshiki): fix this to build on Windows. See crbug.com/133413. - gfx::Point mouse_location; - EXPECT_TRUE(dispatcher()->host()->QueryMouseLocation(&mouse_location)); - EXPECT_EQ("169,80", mouse_location.ToString()); + EXPECT_EQ("169,80", QueryLatestMousePositionRequestInHost(host()).ToString()); #endif EXPECT_EQ("20,53", gfx::Screen::GetScreenFor(root)->GetCursorScreenPoint().ToString()); } -TEST_F(WindowTest, HitTest) { - Window w1(new ColorTestWindowDelegate(SK_ColorWHITE)); - w1.set_id(1); - w1.Init(ui::LAYER_TEXTURED); - w1.SetBounds(gfx::Rect(10, 20, 50, 60)); - w1.Show(); - ParentWindow(&w1); - - // Points are in the Window's coordinates. - EXPECT_TRUE(w1.HitTest(gfx::Point(1, 1))); - EXPECT_FALSE(w1.HitTest(gfx::Point(-1, -1))); - - // We can expand the bounds slightly to track events outside our border. - w1.SetHitTestBoundsOverrideOuter(gfx::Insets(-1, -1, -1, -1), - gfx::Insets(-5, -5, -5, -5)); - EXPECT_TRUE(w1.HitTest(gfx::Point(-1, -1))); - EXPECT_FALSE(w1.HitTest(gfx::Point(-2, -2))); - - ui::TouchEvent pressed( - ui::ET_TOUCH_PRESSED, gfx::Point(50, 50), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&pressed); - EXPECT_TRUE(w1.HitTest(gfx::Point(-2, -2))); - EXPECT_TRUE(w1.HitTest(gfx::Point(-5, -5))); - EXPECT_FALSE(w1.HitTest(gfx::Point(-5, -6))); - ui::TouchEvent released( - ui::ET_TOUCH_RELEASED, gfx::Point(50, 50), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&released); - EXPECT_FALSE(w1.HitTest(gfx::Point(-2, -2))); - - // TODO(beng): clip Window to parent. -} - -TEST_F(WindowTest, HitTestMask) { - MaskedWindowDelegate d1(gfx::Rect(5, 6, 20, 30)); - Window w1(&d1); - w1.Init(ui::LAYER_NOT_DRAWN); - w1.SetBounds(gfx::Rect(10, 20, 50, 60)); - w1.Show(); - ParentWindow(&w1); - - // Points inside the mask. - EXPECT_TRUE(w1.HitTest(gfx::Point(5, 6))); // top-left - EXPECT_TRUE(w1.HitTest(gfx::Point(15, 21))); // center - EXPECT_TRUE(w1.HitTest(gfx::Point(24, 35))); // bottom-right - - // Points outside the mask. - EXPECT_FALSE(w1.HitTest(gfx::Point(0, 0))); - EXPECT_FALSE(w1.HitTest(gfx::Point(60, 80))); - EXPECT_FALSE(w1.HitTest(gfx::Point(4, 6))); - EXPECT_FALSE(w1.HitTest(gfx::Point(5, 5))); - EXPECT_FALSE(w1.HitTest(gfx::Point(25, 36))); -} - TEST_F(WindowTest, GetEventHandlerForPoint) { scoped_ptr<Window> w1( CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(10, 10, 500, 500), @@ -660,7 +603,7 @@ TEST_F(WindowTest, WindowAddedToRootWindowShouldNotifyChildAndNotParent) { AddedToRootWindowObserver child_observer; scoped_ptr<Window> parent_window(CreateTestWindowWithId(1, root_window())); scoped_ptr<Window> child_window(new Window(NULL)); - child_window->Init(ui::LAYER_TEXTURED); + child_window->Init(aura::WINDOW_LAYER_TEXTURED); child_window->Show(); parent_window->AddObserver(&parent_observer); @@ -709,11 +652,11 @@ TEST_F(WindowTest, OrphanedBeforeOnDestroyed) { // Make sure StackChildAtTop moves both the window and layer to the front. TEST_F(WindowTest, StackChildAtTop) { Window parent(NULL); - parent.Init(ui::LAYER_NOT_DRAWN); + parent.Init(aura::WINDOW_LAYER_NOT_DRAWN); Window child1(NULL); - child1.Init(ui::LAYER_NOT_DRAWN); + child1.Init(aura::WINDOW_LAYER_NOT_DRAWN); Window child2(NULL); - child2.Init(ui::LAYER_NOT_DRAWN); + child2.Init(aura::WINDOW_LAYER_NOT_DRAWN); parent.AddChild(&child1); parent.AddChild(&child2); @@ -736,15 +679,15 @@ TEST_F(WindowTest, StackChildAtTop) { // Make sure StackChildBelow works. TEST_F(WindowTest, StackChildBelow) { Window parent(NULL); - parent.Init(ui::LAYER_NOT_DRAWN); + parent.Init(aura::WINDOW_LAYER_NOT_DRAWN); Window child1(NULL); - child1.Init(ui::LAYER_NOT_DRAWN); + child1.Init(aura::WINDOW_LAYER_NOT_DRAWN); child1.set_id(1); Window child2(NULL); - child2.Init(ui::LAYER_NOT_DRAWN); + child2.Init(aura::WINDOW_LAYER_NOT_DRAWN); child2.set_id(2); Window child3(NULL); - child3.Init(ui::LAYER_NOT_DRAWN); + child3.Init(aura::WINDOW_LAYER_NOT_DRAWN); child3.set_id(3); parent.AddChild(&child1); @@ -768,13 +711,13 @@ TEST_F(WindowTest, StackChildBelow) { // Various assertions for StackChildAbove. TEST_F(WindowTest, StackChildAbove) { Window parent(NULL); - parent.Init(ui::LAYER_NOT_DRAWN); + parent.Init(aura::WINDOW_LAYER_NOT_DRAWN); Window child1(NULL); - child1.Init(ui::LAYER_NOT_DRAWN); + child1.Init(aura::WINDOW_LAYER_NOT_DRAWN); Window child2(NULL); - child2.Init(ui::LAYER_NOT_DRAWN); + child2.Init(aura::WINDOW_LAYER_NOT_DRAWN); Window child3(NULL); - child3.Init(ui::LAYER_NOT_DRAWN); + child3.Init(aura::WINDOW_LAYER_NOT_DRAWN); parent.AddChild(&child1); parent.AddChild(&child2); @@ -848,7 +791,7 @@ TEST_F(WindowTest, CaptureTests) { ui::TouchEvent touchev( ui::ET_TOUCH_PRESSED, gfx::Point(50, 50), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev); + DispatchEventUsingWindowDispatcher(&touchev); EXPECT_EQ(1, delegate.touch_event_count()); delegate.ResetCounts(); @@ -864,7 +807,7 @@ TEST_F(WindowTest, CaptureTests) { ui::TouchEvent touchev2( ui::ET_TOUCH_PRESSED, gfx::Point(250, 250), 1, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&touchev2); + DispatchEventUsingWindowDispatcher(&touchev2); EXPECT_EQ(0, delegate.touch_event_count()); // Removing the capture window from parent should reset the capture window @@ -887,7 +830,7 @@ TEST_F(WindowTest, TouchCaptureCancelsOtherTouches) { // Press on w1. ui::TouchEvent press( ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN. EXPECT_EQ(2, delegate1.gesture_event_count()); delegate1.ResetCounts(); @@ -901,7 +844,7 @@ TEST_F(WindowTest, TouchCaptureCancelsOtherTouches) { // Events now go to w2. ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + DispatchEventUsingWindowDispatcher(&move); EXPECT_EQ(0, delegate1.gesture_event_count()); EXPECT_EQ(0, delegate1.touch_event_count()); EXPECT_EQ(0, delegate2.gesture_event_count()); @@ -909,14 +852,14 @@ TEST_F(WindowTest, TouchCaptureCancelsOtherTouches) { ui::TouchEvent release( ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_EQ(0, delegate1.gesture_event_count()); EXPECT_EQ(0, delegate2.gesture_event_count()); // A new press is captured by w2. ui::TouchEvent press2( ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press2); + DispatchEventUsingWindowDispatcher(&press2); EXPECT_EQ(0, delegate1.gesture_event_count()); // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN. EXPECT_EQ(2, delegate2.gesture_event_count()); @@ -938,7 +881,7 @@ TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) { ui::TouchEvent press( ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN. EXPECT_EQ(2, delegate.gesture_event_count()); @@ -953,7 +896,7 @@ TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) { // On move We will get TOUCH_MOVED, GESTURE_TAP_CANCEL, // GESTURE_SCROLL_START and GESTURE_SCROLL_UPDATE. ui::TouchEvent move(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move); + DispatchEventUsingWindowDispatcher(&move); EXPECT_EQ(1, delegate.touch_event_count()); EXPECT_EQ(3, delegate.gesture_event_count()); delegate.ResetCounts(); @@ -966,7 +909,7 @@ TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) { // On move we still get TOUCH_MOVED and GESTURE_SCROLL_UPDATE. ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(10, 30), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&move2); + DispatchEventUsingWindowDispatcher(&move2); EXPECT_EQ(1, delegate.touch_event_count()); EXPECT_EQ(1, delegate.gesture_event_count()); delegate.ResetCounts(); @@ -974,7 +917,7 @@ TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) { // And on release we get TOUCH_RELEASED, GESTURE_SCROLL_END, GESTURE_END ui::TouchEvent release( ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&release); + DispatchEventUsingWindowDispatcher(&release); EXPECT_EQ(1, delegate.touch_event_count()); EXPECT_EQ(2, delegate.gesture_event_count()); } @@ -987,7 +930,7 @@ TEST_F(WindowTest, TransferCaptureTouchEvents) { scoped_ptr<Window> w1(CreateTestWindowWithDelegate( &d1, 0, gfx::Rect(0, 0, 20, 20), root_window())); ui::TouchEvent p1(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&p1); + DispatchEventUsingWindowDispatcher(&p1); // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN. EXPECT_EQ(1, d1.touch_event_count()); EXPECT_EQ(2, d1.gesture_event_count()); @@ -998,7 +941,7 @@ TEST_F(WindowTest, TransferCaptureTouchEvents) { scoped_ptr<Window> w2(CreateTestWindowWithDelegate( &d2, 0, gfx::Rect(40, 0, 40, 20), root_window())); ui::TouchEvent p2(ui::ET_TOUCH_PRESSED, gfx::Point(41, 10), 1, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&p2); + DispatchEventUsingWindowDispatcher(&p2); EXPECT_EQ(0, d1.touch_event_count()); EXPECT_EQ(0, d1.gesture_event_count()); // We will get both GESTURE_BEGIN and GESTURE_TAP_DOWN for new target window. @@ -1034,7 +977,7 @@ TEST_F(WindowTest, TransferCaptureTouchEvents) { // Move touch id originally associated with |w2|. Since capture was transfered // from 2 to 3 only |w3| should get the event. ui::TouchEvent m3(ui::ET_TOUCH_MOVED, gfx::Point(110, 105), 1, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&m3); + DispatchEventUsingWindowDispatcher(&m3); EXPECT_EQ(0, d1.touch_event_count()); EXPECT_EQ(0, d1.gesture_event_count()); EXPECT_EQ(0, d2.touch_event_count()); @@ -1057,7 +1000,7 @@ TEST_F(WindowTest, TransferCaptureTouchEvents) { // And when we move the touch again, |w3| still gets the events. ui::TouchEvent m4(ui::ET_TOUCH_MOVED, gfx::Point(120, 105), 1, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&m4); + DispatchEventUsingWindowDispatcher(&m4); EXPECT_EQ(0, d1.touch_event_count()); EXPECT_EQ(0, d1.gesture_event_count()); EXPECT_EQ(0, d2.touch_event_count()); @@ -1123,7 +1066,7 @@ TEST_F(WindowTest, ReleaseCaptureOnDestroy) { window.reset(); // Make sure the root window doesn't reference the window anymore. - EXPECT_EQ(NULL, dispatcher()->mouse_pressed_handler()); + EXPECT_EQ(NULL, host()->dispatcher()->mouse_pressed_handler()); EXPECT_EQ(NULL, aura::client::GetCaptureWindow(root_window())); } @@ -1208,7 +1151,7 @@ TEST_F(WindowTest, MouseEnterExit) { } // Verifies that the WindowDelegate receives MouseExit from ET_MOUSE_EXITED. -TEST_F(WindowTest, RootWindowHostExit) { +TEST_F(WindowTest, WindowTreeHostExit) { MouseEnterExitWindowDelegate d1; scoped_ptr<Window> w1( CreateTestWindowWithDelegate(&d1, 1, gfx::Rect(10, 10, 50, 50), @@ -1221,8 +1164,8 @@ TEST_F(WindowTest, RootWindowHostExit) { d1.ResetExpectations(); ui::MouseEvent exit_event( - ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(), 0); - dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&exit_event); + ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(), 0, 0); + DispatchEventUsingWindowDispatcher(&exit_event); EXPECT_FALSE(d1.entered()); EXPECT_TRUE(d1.exited()); } @@ -1298,21 +1241,23 @@ TEST_F(WindowTest, MouseEnterExitWithDelete) { generator.MoveMouseToCenterOf(w1.get()); EXPECT_TRUE(d1.entered()); EXPECT_FALSE(d1.exited()); + d1.ResetExpectations(); MouseEnterExitWindowDelegate d2; { scoped_ptr<Window> w2( CreateTestWindowWithDelegate(&d2, 2, gfx::Rect(10, 10, 50, 50), root_window())); - // Enters / exits can be send asynchronously. + // Enters / exits can be sent asynchronously. RunAllPendingInMessageLoop(); - EXPECT_TRUE(d1.entered()); + EXPECT_FALSE(d1.entered()); EXPECT_TRUE(d1.exited()); EXPECT_TRUE(d2.entered()); EXPECT_FALSE(d2.exited()); d1.ResetExpectations(); + d2.ResetExpectations(); } - // Enters / exits can be send asynchronously. + // Enters / exits can be sent asynchronously. RunAllPendingInMessageLoop(); EXPECT_TRUE(d2.exited()); EXPECT_TRUE(d1.entered()); @@ -1538,7 +1483,7 @@ TEST_F(WindowTest, IgnoreEventsTest) { // Tests transformation on the root window. TEST_F(WindowTest, Transform) { - gfx::Size size = dispatcher()->host()->GetBounds().size(); + gfx::Size size = host()->GetBounds().size(); EXPECT_EQ(gfx::Rect(size), gfx::Screen::GetScreenFor(root_window())->GetDisplayNearestPoint( gfx::Point()).bounds()); @@ -1547,7 +1492,7 @@ TEST_F(WindowTest, Transform) { gfx::Transform transform; transform.Translate(size.height(), 0); transform.Rotate(90.0); - dispatcher()->SetTransform(transform); + host()->SetRootTransform(transform); // The size should be the transformed size. gfx::Size transformed_size(size.height(), size.width()); @@ -1559,12 +1504,11 @@ TEST_F(WindowTest, Transform) { gfx::Point()).bounds().ToString()); // Host size shouldn't change. - EXPECT_EQ(size.ToString(), - dispatcher()->host()->GetBounds().size().ToString()); + EXPECT_EQ(size.ToString(), host()->GetBounds().size().ToString()); } TEST_F(WindowTest, TransformGesture) { - gfx::Size size = dispatcher()->host()->GetBounds().size(); + gfx::Size size = host()->GetBounds().size(); scoped_ptr<GestureTrackPositionDelegate> delegate( new GestureTrackPositionDelegate); @@ -1575,49 +1519,14 @@ TEST_F(WindowTest, TransformGesture) { gfx::Transform transform; transform.Translate(size.height(), 0.0); transform.Rotate(90.0); - dispatcher()->SetTransform(transform); + host()->SetRootTransform(transform); ui::TouchEvent press( ui::ET_TOUCH_PRESSED, gfx::Point(size.height() - 10, 10), 0, getTime()); - dispatcher()->AsRootWindowHostDelegate()->OnHostTouchEvent(&press); + DispatchEventUsingWindowDispatcher(&press); EXPECT_EQ(gfx::Point(10, 10).ToString(), delegate->position().ToString()); } -// Various assertions for transient children. -TEST_F(WindowTest, TransientChildren) { - scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window())); - scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get())); - scoped_ptr<Window> w3(CreateTestWindowWithId(3, parent.get())); - Window* w2 = CreateTestWindowWithId(2, parent.get()); - w1->AddTransientChild(w2); // w2 is now owned by w1. - // Stack w1 at the top (end), this should force w2 to be last (on top of w1). - parent->StackChildAtTop(w1.get()); - ASSERT_EQ(3u, parent->children().size()); - EXPECT_EQ(w2, parent->children().back()); - - // Destroy w1, which should also destroy w3 (since it's a transient child). - w1.reset(); - w2 = NULL; - ASSERT_EQ(1u, parent->children().size()); - EXPECT_EQ(w3.get(), parent->children()[0]); - - w1.reset(CreateTestWindowWithId(4, parent.get())); - w2 = CreateTestWindowWithId(5, w3.get()); - w1->AddTransientChild(w2); - parent->StackChildAtTop(w3.get()); - // Stack w1 at the top (end), this shouldn't affect w2 since it has a - // different parent. - parent->StackChildAtTop(w1.get()); - ASSERT_EQ(2u, parent->children().size()); - EXPECT_EQ(w3.get(), parent->children()[0]); - EXPECT_EQ(w1.get(), parent->children()[1]); - - // Hiding parent should hide transient children. - EXPECT_TRUE(w2->IsVisible()); - w1->Hide(); - EXPECT_FALSE(w2->IsVisible()); -} - namespace { DEFINE_WINDOW_PROPERTY_KEY(int, kIntKey, -2); DEFINE_WINDOW_PROPERTY_KEY(const char*, kStringKey, "squeamish"); @@ -1717,7 +1626,7 @@ TEST_F(WindowTest, SetBoundsInternalShouldCheckTargetBounds) { EXPECT_FALSE(!w1->layer()); w1->layer()->GetAnimator()->set_disable_timer_for_test(true); - gfx::AnimationContainerElement* element = w1->layer()->GetAnimator(); + ui::LayerAnimator* animator = w1->layer()->GetAnimator(); EXPECT_EQ("0,0 100x100", w1->bounds().ToString()); EXPECT_EQ("0,0 100x100", w1->layer()->GetTargetBounds().ToString()); @@ -1747,7 +1656,7 @@ TEST_F(WindowTest, SetBoundsInternalShouldCheckTargetBounds) { base::TimeTicks start_time = w1->layer()->GetAnimator()->last_step_time(); - element->Step(start_time + base::TimeDelta::FromMilliseconds(1000)); + animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000)); EXPECT_EQ("0,0 100x100", w1->bounds().ToString()); } @@ -1971,6 +1880,12 @@ TEST_F(WindowTest, AcquireLayer) { EXPECT_FALSE(window1_test_api.OwnsLayer()); EXPECT_TRUE(window1_layer.get() == window1->layer()); + // The acquired layer's owner should be set NULL and re-acquring + // should return NULL. + EXPECT_FALSE(window1_layer->owner()); + scoped_ptr<ui::Layer> window1_layer_reacquired(window1->AcquireLayer()); + EXPECT_FALSE(window1_layer_reacquired.get()); + // Upon destruction, window1's layer should still be valid, and in the layer // hierarchy, but window2's should be gone, and no longer in the hierarchy. window1.reset(); @@ -1987,11 +1902,10 @@ TEST_F(WindowTest, RecreateLayer) { // Set properties to non default values. Window w(new ColorTestWindowDelegate(SK_ColorWHITE)); w.set_id(1); - w.Init(ui::LAYER_SOLID_COLOR); + w.Init(aura::WINDOW_LAYER_SOLID_COLOR); w.SetBounds(gfx::Rect(0, 0, 100, 100)); ui::Layer* layer = w.layer(); - layer->set_scale_content(false); layer->SetVisible(false); layer->SetMasksToBounds(true); @@ -2001,10 +1915,11 @@ TEST_F(WindowTest, RecreateLayer) { scoped_ptr<ui::Layer> old_layer(w.RecreateLayer()); layer = w.layer(); EXPECT_EQ(ui::LAYER_SOLID_COLOR, layer->type()); - EXPECT_FALSE(layer->scale_content()); EXPECT_FALSE(layer->visible()); EXPECT_EQ(1u, layer->children().size()); EXPECT_TRUE(layer->GetMasksToBounds()); + EXPECT_EQ("0,0 100x100", w.bounds().ToString()); + EXPECT_EQ("0,0 100x100", layer->bounds().ToString()); } // Verify that RecreateLayer() stacks the old layer above the newly creatd @@ -2028,8 +1943,8 @@ TEST_F(WindowTest, AcquireThenRecreateLayer) { scoped_ptr<Window> w( CreateTestWindow(SK_ColorWHITE, 1, gfx::Rect(0, 0, 100, 100), root_window())); - scoped_ptr<ui::Layer>acquired_layer(w->AcquireLayer()); - scoped_ptr<ui::Layer>doubly_acquired_layer(w->RecreateLayer()); + scoped_ptr<ui::Layer> acquired_layer(w->AcquireLayer()); + scoped_ptr<ui::Layer> doubly_acquired_layer(w->RecreateLayer()); EXPECT_EQ(NULL, doubly_acquired_layer.get()); // Destroy window before layer gets destroyed. @@ -2056,66 +1971,6 @@ TEST_F(WindowTest, StackWindowAtBottomBelowWindowWhoseLayerHasNoDelegate) { ui::test::ChildLayerNamesAsString(*root_window()->layer())); } -TEST_F(WindowTest, StackWindowsWhoseLayersHaveNoDelegate) { - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - window1->layer()->set_name("1"); - scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window())); - window2->layer()->set_name("2"); - scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window())); - window3->layer()->set_name("3"); - - // This brings |window1| (and its layer) to the front. - root_window()->StackChildAbove(window1.get(), window3.get()); - EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("2 3 1", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); - - // Since |window1| does not have a delegate, |window2| should not move in - // front of it, nor should its layer. - window1->layer()->set_delegate(NULL); - root_window()->StackChildAbove(window2.get(), window1.get()); - EXPECT_EQ("3 2 1", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("3 2 1", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); - - // It should still be possible to stack |window3| immediately below |window1|. - root_window()->StackChildBelow(window3.get(), window1.get()); - EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("2 3 1", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); - - // Since neither |window3| nor |window1| have a delegate, |window2| should - // not move in front of either. - window3->layer()->set_delegate(NULL); - root_window()->StackChildBelow(window2.get(), window1.get()); - EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("2 3 1", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); -} - -TEST_F(WindowTest, StackTransientsWhoseLayersHaveNoDelegate) { - // Create a window with several transients, then a couple windows on top. - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - scoped_ptr<Window> window11(CreateTransientChild(11, window1.get())); - scoped_ptr<Window> window12(CreateTransientChild(12, window1.get())); - scoped_ptr<Window> window13(CreateTransientChild(13, window1.get())); - scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window())); - scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window())); - - EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window())); - - // Remove the delegates of a couple of transients, as if they are closing - // and animating out. - window11->layer()->set_delegate(NULL); - window13->layer()->set_delegate(NULL); - - // Move window1 to the front. All transients should move with it, and their - // order should be preserved. - root_window()->StackChildAtTop(window1.get()); - - EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window())); -} - class TestVisibilityClient : public client::VisibilityClient { public: explicit TestVisibilityClient(Window* root_window) @@ -2161,7 +2016,7 @@ TEST_F(WindowTest, VisibilityClientIsVisible) { // Tests mouse events on window change. TEST_F(WindowTest, MouseEventsOnWindowChange) { - gfx::Size size = dispatcher()->host()->GetBounds().size(); + gfx::Size size = host()->GetBounds().size(); EventGenerator generator(root_window()); generator.MoveMouseTo(50, 50); @@ -2253,240 +2108,6 @@ TEST_F(WindowTest, MouseEventsOnWindowChange) { EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset()); } -class StackingMadrigalLayoutManager : public LayoutManager { - public: - explicit StackingMadrigalLayoutManager(Window* root_window) - : root_window_(root_window) { - root_window_->SetLayoutManager(this); - } - virtual ~StackingMadrigalLayoutManager() { - } - - private: - // Overridden from LayoutManager: - virtual void OnWindowResized() OVERRIDE {} - virtual void OnWindowAddedToLayout(Window* child) OVERRIDE {} - virtual void OnWillRemoveWindowFromLayout(Window* child) OVERRIDE {} - virtual void OnWindowRemovedFromLayout(Window* child) OVERRIDE {} - virtual void OnChildWindowVisibilityChanged(Window* child, - bool visible) OVERRIDE { - Window::Windows::const_iterator it = root_window_->children().begin(); - Window* last_window = NULL; - for (; it != root_window_->children().end(); ++it) { - if (*it == child && last_window) { - if (!visible) - root_window_->StackChildAbove(last_window, *it); - else - root_window_->StackChildAbove(*it, last_window); - break; - } - last_window = *it; - } - } - virtual void SetChildBounds(Window* child, - const gfx::Rect& requested_bounds) OVERRIDE { - SetChildBoundsDirect(child, requested_bounds); - } - - Window* root_window_; - - DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager); -}; - -class StackingMadrigalVisibilityClient : public client::VisibilityClient { - public: - explicit StackingMadrigalVisibilityClient(Window* root_window) - : ignored_window_(NULL) { - client::SetVisibilityClient(root_window, this); - } - virtual ~StackingMadrigalVisibilityClient() { - } - - void set_ignored_window(Window* ignored_window) { - ignored_window_ = ignored_window; - } - - private: - // Overridden from client::VisibilityClient: - virtual void UpdateLayerVisibility(Window* window, bool visible) OVERRIDE { - if (!visible) { - if (window == ignored_window_) - window->layer()->set_delegate(NULL); - else - window->layer()->SetVisible(visible); - } else { - window->layer()->SetVisible(visible); - } - } - - Window* ignored_window_; - - DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient); -}; - -// This test attempts to reconstruct a circumstance that can happen when the -// aura client attempts to manipulate the visibility and delegate of a layer -// independent of window visibility. -// A use case is where the client attempts to keep a window visible onscreen -// even after code has called Hide() on the window. The use case for this would -// be that window hides are animated (e.g. the window fades out). To prevent -// spurious updating the client code may also clear window's layer's delegate, -// so that the window cannot attempt to paint or update it further. The window -// uses the presence of a NULL layer delegate as a signal in stacking to note -// that the window is being manipulated by such a use case and its stacking -// should not be adjusted. -// One issue that can arise when a window opens two transient children, and the -// first is hidden. Subsequent attempts to activate the transient parent can -// result in the transient parent being stacked above the second transient -// child. A fix is made to Window::StackAbove to prevent this, and this test -// verifies this fix. -TEST_F(WindowTest, StackingMadrigal) { - new StackingMadrigalLayoutManager(root_window()); - StackingMadrigalVisibilityClient visibility_client(root_window()); - - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - scoped_ptr<Window> window11(CreateTransientChild(11, window1.get())); - - visibility_client.set_ignored_window(window11.get()); - - window11->Show(); - window11->Hide(); - - // As a transient, window11 should still be stacked above window1, even when - // hidden. - EXPECT_TRUE(WindowIsAbove(window11.get(), window1.get())); - EXPECT_TRUE(LayerIsAbove(window11.get(), window1.get())); - - // A new transient should still be above window1. It will appear behind - // window11 because we don't stack windows on top of targets with NULL - // delegates. - scoped_ptr<Window> window12(CreateTransientChild(12, window1.get())); - window12->Show(); - - EXPECT_TRUE(WindowIsAbove(window12.get(), window1.get())); - EXPECT_TRUE(LayerIsAbove(window12.get(), window1.get())); - - // In earlier versions of the StackChildAbove() method, attempting to stack - // window1 above window12 at this point would actually restack the layers - // resulting in window12's layer being below window1's layer (though the - // windows themselves would still be correctly stacked, so events would pass - // through.) - root_window()->StackChildAbove(window1.get(), window12.get()); - - // Both window12 and its layer should be stacked above window1. - EXPECT_TRUE(WindowIsAbove(window12.get(), window1.get())); - EXPECT_TRUE(LayerIsAbove(window12.get(), window1.get())); -} - -// Test for an issue where attempting to stack a primary window on top of a -// transient with a NULL layer delegate causes that primary window to be moved, -// but the layer order not changed to match. http://crbug.com/112562 -TEST_F(WindowTest, StackOverClosingTransient) { - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - scoped_ptr<Window> transient1(CreateTransientChild(11, window1.get())); - scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window())); - scoped_ptr<Window> transient2(CreateTransientChild(21, window2.get())); - - // Both windows and layers are stacked in creation order. - Window* root = root_window(); - ASSERT_EQ(4u, root->children().size()); - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], transient1.get()); - EXPECT_EQ(root->children()[2], window2.get()); - EXPECT_EQ(root->children()[3], transient2.get()); - ASSERT_EQ(4u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], transient1->layer()); - EXPECT_EQ(root->layer()->children()[2], window2->layer()); - EXPECT_EQ(root->layer()->children()[3], transient2->layer()); - EXPECT_EQ("1 11 2 21", ChildWindowIDsAsString(root_window())); - - // This brings window1 and its transient to the front. - root->StackChildAtTop(window1.get()); - EXPECT_EQ("2 21 1 11", ChildWindowIDsAsString(root_window())); - - EXPECT_EQ(root->children()[0], window2.get()); - EXPECT_EQ(root->children()[1], transient2.get()); - EXPECT_EQ(root->children()[2], window1.get()); - EXPECT_EQ(root->children()[3], transient1.get()); - EXPECT_EQ(root->layer()->children()[0], window2->layer()); - EXPECT_EQ(root->layer()->children()[1], transient2->layer()); - EXPECT_EQ(root->layer()->children()[2], window1->layer()); - EXPECT_EQ(root->layer()->children()[3], transient1->layer()); - - // Pretend we're closing the top-most transient, then bring window2 to the - // front. This mimics activating a browser window while the status bubble - // is fading out. The transient should stay topmost. - transient1->layer()->set_delegate(NULL); - root->StackChildAtTop(window2.get()); - - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], window2.get()); - EXPECT_EQ(root->children()[2], transient2.get()); - EXPECT_EQ(root->children()[3], transient1.get()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], window2->layer()); - EXPECT_EQ(root->layer()->children()[2], transient2->layer()); - EXPECT_EQ(root->layer()->children()[3], transient1->layer()); - - // Close the transient. Remaining windows are stable. - transient1.reset(); - - ASSERT_EQ(3u, root->children().size()); - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], window2.get()); - EXPECT_EQ(root->children()[2], transient2.get()); - ASSERT_EQ(3u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], window2->layer()); - EXPECT_EQ(root->layer()->children()[2], transient2->layer()); - - // Open another window on top. - scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window())); - - ASSERT_EQ(4u, root->children().size()); - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], window2.get()); - EXPECT_EQ(root->children()[2], transient2.get()); - EXPECT_EQ(root->children()[3], window3.get()); - ASSERT_EQ(4u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], window2->layer()); - EXPECT_EQ(root->layer()->children()[2], transient2->layer()); - EXPECT_EQ(root->layer()->children()[3], window3->layer()); - - // Pretend we're closing the topmost non-transient window, then bring - // window2 to the top. It should not move. - window3->layer()->set_delegate(NULL); - root->StackChildAtTop(window2.get()); - - ASSERT_EQ(4u, root->children().size()); - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], window2.get()); - EXPECT_EQ(root->children()[2], transient2.get()); - EXPECT_EQ(root->children()[3], window3.get()); - ASSERT_EQ(4u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], window2->layer()); - EXPECT_EQ(root->layer()->children()[2], transient2->layer()); - EXPECT_EQ(root->layer()->children()[3], window3->layer()); - - // Bring window1 to the top. It should move ahead of window2, but not - // ahead of window3 (with NULL delegate). - root->StackChildAtTop(window1.get()); - - ASSERT_EQ(4u, root->children().size()); - EXPECT_EQ(root->children()[0], window2.get()); - EXPECT_EQ(root->children()[1], transient2.get()); - EXPECT_EQ(root->children()[2], window1.get()); - EXPECT_EQ(root->children()[3], window3.get()); - ASSERT_EQ(4u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window2->layer()); - EXPECT_EQ(root->layer()->children()[1], transient2->layer()); - EXPECT_EQ(root->layer()->children()[2], window1->layer()); - EXPECT_EQ(root->layer()->children()[3], window3->layer()); -} - class RootWindowAttachmentObserver : public WindowObserver { public: RootWindowAttachmentObserver() : added_count_(0), removed_count_(0) {} @@ -2504,7 +2125,8 @@ class RootWindowAttachmentObserver : public WindowObserver { virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE { ++added_count_; } - virtual void OnWindowRemovingFromRootWindow(Window* window) OVERRIDE { + virtual void OnWindowRemovingFromRootWindow(Window* window, + Window* new_root) OVERRIDE { ++removed_count_; } @@ -2520,7 +2142,7 @@ TEST_F(WindowTest, RootWindowAttachment) { // Test a direct add/remove from the RootWindow. scoped_ptr<Window> w1(new Window(NULL)); - w1->Init(ui::LAYER_NOT_DRAWN); + w1->Init(aura::WINDOW_LAYER_NOT_DRAWN); w1->AddObserver(&observer); ParentWindow(w1.get()); @@ -2535,9 +2157,9 @@ TEST_F(WindowTest, RootWindowAttachment) { // Test an indirect add/remove from the RootWindow. w1.reset(new Window(NULL)); - w1->Init(ui::LAYER_NOT_DRAWN); + w1->Init(aura::WINDOW_LAYER_NOT_DRAWN); Window* w11 = new Window(NULL); - w11->Init(ui::LAYER_NOT_DRAWN); + w11->Init(aura::WINDOW_LAYER_NOT_DRAWN); w11->AddObserver(&observer); w1->AddChild(w11); EXPECT_EQ(0, observer.added_count()); @@ -2556,13 +2178,13 @@ TEST_F(WindowTest, RootWindowAttachment) { // Test an indirect add/remove with nested observers. w1.reset(new Window(NULL)); - w1->Init(ui::LAYER_NOT_DRAWN); + w1->Init(aura::WINDOW_LAYER_NOT_DRAWN); w11 = new Window(NULL); - w11->Init(ui::LAYER_NOT_DRAWN); + w11->Init(aura::WINDOW_LAYER_NOT_DRAWN); w11->AddObserver(&observer); w1->AddChild(w11); Window* w111 = new Window(NULL); - w111->Init(ui::LAYER_NOT_DRAWN); + w111->Init(aura::WINDOW_LAYER_NOT_DRAWN); w111->AddObserver(&observer); w11->AddChild(w111); @@ -2580,15 +2202,71 @@ TEST_F(WindowTest, RootWindowAttachment) { EXPECT_EQ(2, observer.removed_count()); } +class BoundsChangedWindowObserver : public WindowObserver { + public: + BoundsChangedWindowObserver() : root_set_(false) {} + + virtual void OnWindowBoundsChanged(Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) OVERRIDE { + root_set_ = window->GetRootWindow() != NULL; + } + + bool root_set() const { return root_set_; } + + private: + bool root_set_; + + DISALLOW_COPY_AND_ASSIGN(BoundsChangedWindowObserver); +}; + +TEST_F(WindowTest, RootWindowSetWhenReparenting) { + Window parent1(NULL); + parent1.Init(aura::WINDOW_LAYER_NOT_DRAWN); + Window parent2(NULL); + parent2.Init(aura::WINDOW_LAYER_NOT_DRAWN); + ParentWindow(&parent1); + ParentWindow(&parent2); + parent1.SetBounds(gfx::Rect(10, 10, 300, 300)); + parent2.SetBounds(gfx::Rect(20, 20, 300, 300)); + + BoundsChangedWindowObserver observer; + Window child(NULL); + child.Init(aura::WINDOW_LAYER_NOT_DRAWN); + child.SetBounds(gfx::Rect(5, 5, 100, 100)); + parent1.AddChild(&child); + + // We need animations to start in order to observe the bounds changes. + ui::ScopedAnimationDurationScaleMode animation_duration_mode( + ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); + ui::ScopedLayerAnimationSettings settings1(child.layer()->GetAnimator()); + settings1.SetTransitionDuration(base::TimeDelta::FromMilliseconds(100)); + gfx::Rect new_bounds(gfx::Rect(35, 35, 50, 50)); + child.SetBounds(new_bounds); + + child.AddObserver(&observer); + + // Reparenting the |child| will cause it to get moved. During this move + // the window should still have root window set. + parent2.AddChild(&child); + EXPECT_TRUE(observer.root_set()); + + // Animations should stop and the bounds should be as set before the |child| + // got reparented. + EXPECT_EQ(new_bounds.ToString(), child.GetTargetBounds().ToString()); + EXPECT_EQ(new_bounds.ToString(), child.bounds().ToString()); + EXPECT_EQ("55,55 50x50", child.GetBoundsInRootWindow().ToString()); +} + TEST_F(WindowTest, OwnedByParentFalse) { // By default, a window is owned by its parent. If this is set to false, the // window will not be destroyed when its parent is. scoped_ptr<Window> w1(new Window(NULL)); - w1->Init(ui::LAYER_NOT_DRAWN); + w1->Init(aura::WINDOW_LAYER_NOT_DRAWN); scoped_ptr<Window> w2(new Window(NULL)); w2->set_owned_by_parent(false); - w2->Init(ui::LAYER_NOT_DRAWN); + w2->Init(aura::WINDOW_LAYER_NOT_DRAWN); w1->AddChild(w2.get()); w1.reset(); @@ -2609,7 +2287,7 @@ class OwningWindowDelegate : public TestWindowDelegate { owned_window_.reset(window); } - virtual void OnWindowDestroyed() OVERRIDE { + virtual void OnWindowDestroyed(Window* window) OVERRIDE { owned_window_.reset(NULL); } @@ -2628,13 +2306,13 @@ class OwningWindowDelegate : public TestWindowDelegate { // bubble. TEST_F(WindowTest, DeleteWindowFromOnWindowDestroyed) { scoped_ptr<Window> parent(new Window(NULL)); - parent->Init(ui::LAYER_NOT_DRAWN); + parent->Init(aura::WINDOW_LAYER_NOT_DRAWN); OwningWindowDelegate delegate; Window* c1 = new Window(&delegate); - c1->Init(ui::LAYER_NOT_DRAWN); + c1->Init(aura::WINDOW_LAYER_NOT_DRAWN); parent->AddChild(c1); Window* c2 = new Window(NULL); - c2->Init(ui::LAYER_NOT_DRAWN); + c2->Init(aura::WINDOW_LAYER_NOT_DRAWN); parent->AddChild(c2); delegate.SetOwnedWindow(c2); parent.reset(); @@ -2697,8 +2375,8 @@ TEST_F(WindowTest, DelegateNotifiedAsBoundsChange) { // Animate to the end, which should notify of the change. base::TimeTicks start_time = window->layer()->GetAnimator()->last_step_time(); - gfx::AnimationContainerElement* element = window->layer()->GetAnimator(); - element->Step(start_time + base::TimeDelta::FromMilliseconds(1000)); + ui::LayerAnimator* animator = window->layer()->GetAnimator(); + animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000)); EXPECT_TRUE(delegate.bounds_changed()); EXPECT_NE("0,0 100x100", window->bounds().ToString()); } @@ -2739,8 +2417,8 @@ TEST_F(WindowTest, DelegateNotifiedAsBoundsChangeInHiddenLayer) { // Animate to the end: will *not* notify of the change since we are hidden. base::TimeTicks start_time = window->layer()->GetAnimator()->last_step_time(); - gfx::AnimationContainerElement* element = window->layer()->GetAnimator(); - element->Step(start_time + base::TimeDelta::FromMilliseconds(1000)); + ui::LayerAnimator* animator = window->layer()->GetAnimator(); + animator->Step(start_time + base::TimeDelta::FromMilliseconds(1000)); // No bounds changed notification at the end of animation since layer // delegate is NULL. @@ -2766,7 +2444,8 @@ class AddChildNotificationsObserver : public WindowObserver { virtual void OnWindowAddedToRootWindow(Window* window) OVERRIDE { added_count_++; } - virtual void OnWindowRemovingFromRootWindow(Window* window) OVERRIDE { + virtual void OnWindowRemovingFromRootWindow(Window* window, + Window* new_root) OVERRIDE { removed_count_++; } @@ -3007,59 +2686,15 @@ TEST_F(WindowTest, OnWindowHierarchyChange) { } -namespace { - -// Used by NotifyDelegateAfterDeletingTransients. Adds a string to a vector when -// OnWindowDestroyed() is invoked so that destruction order can be verified. -class DestroyedTrackingDelegate : public TestWindowDelegate { - public: - explicit DestroyedTrackingDelegate(const std::string& name, - std::vector<std::string>* results) - : name_(name), - results_(results) {} - - virtual void OnWindowDestroyed() OVERRIDE { - results_->push_back(name_); - } - - private: - const std::string name_; - std::vector<std::string>* results_; - - DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingDelegate); -}; - -} // namespace - -// Verifies the delegate is notified of destruction after transients are -// destroyed. -TEST_F(WindowTest, NotifyDelegateAfterDeletingTransients) { - std::vector<std::string> destruction_order; - - DestroyedTrackingDelegate parent_delegate("parent", &destruction_order); - scoped_ptr<Window> parent(new Window(&parent_delegate)); - parent->Init(ui::LAYER_NOT_DRAWN); - - DestroyedTrackingDelegate transient_delegate("transient", &destruction_order); - Window* transient = new Window(&transient_delegate); // Owned by |parent|. - transient->Init(ui::LAYER_NOT_DRAWN); - parent->AddTransientChild(transient); - parent.reset(); - - ASSERT_EQ(2u, destruction_order.size()); - EXPECT_EQ("transient", destruction_order[0]); - EXPECT_EQ("parent", destruction_order[1]); -} - // Verifies SchedulePaint() on a layerless window results in damaging the right // thing. TEST_F(WindowTest, LayerlessWindowSchedulePaint) { Window root(NULL); - root.Init(ui::LAYER_NOT_DRAWN); + root.Init(aura::WINDOW_LAYER_NOT_DRAWN); root.SetBounds(gfx::Rect(0, 0, 100, 100)); Window* layerless_window = new Window(NULL); // Owned by |root|. - layerless_window->InitWithWindowLayerType(WINDOW_LAYER_NONE); + layerless_window->Init(WINDOW_LAYER_NONE); layerless_window->SetBounds(gfx::Rect(10, 11, 12, 13)); root.AddChild(layerless_window); @@ -3071,7 +2706,7 @@ TEST_F(WindowTest, LayerlessWindowSchedulePaint) { ToString()); Window* layerless_window2 = new Window(NULL); // Owned by |layerless_window|. - layerless_window2->InitWithWindowLayerType(WINDOW_LAYER_NONE); + layerless_window2->Init(WINDOW_LAYER_NONE); layerless_window2->SetBounds(gfx::Rect(1, 2, 3, 4)); layerless_window->AddChild(layerless_window2); @@ -3097,30 +2732,30 @@ TEST_F(WindowTest, NestedLayerlessWindowsBoundsOnAddRemove) { // // ll: layer less, eg no layer Window root(NULL); - root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + root.Init(WINDOW_LAYER_NOT_DRAWN); root.SetBounds(gfx::Rect(0, 0, 100, 100)); Window* w1ll = new Window(NULL); - w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE); + w1ll->Init(WINDOW_LAYER_NONE); w1ll->SetBounds(gfx::Rect(1, 2, 100, 100)); Window* w11ll = new Window(NULL); - w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE); + w11ll->Init(WINDOW_LAYER_NONE); w11ll->SetBounds(gfx::Rect(3, 4, 100, 100)); w1ll->AddChild(w11ll); Window* w111 = new Window(NULL); - w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w111->Init(WINDOW_LAYER_NOT_DRAWN); w111->SetBounds(gfx::Rect(5, 6, 100, 100)); w11ll->AddChild(w111); Window* w12 = new Window(NULL); - w12->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w12->Init(WINDOW_LAYER_NOT_DRAWN); w12->SetBounds(gfx::Rect(7, 8, 100, 100)); w1ll->AddChild(w12); Window* w121 = new Window(NULL); - w121->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w121->Init(WINDOW_LAYER_NOT_DRAWN); w121->SetBounds(gfx::Rect(9, 10, 100, 100)); w12->AddChild(w121); @@ -3177,30 +2812,30 @@ TEST_F(WindowTest, NestedLayerlessWindowsBoundsOnSetBounds) { // // ll: layer less, eg no layer Window root(NULL); - root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + root.Init(WINDOW_LAYER_NOT_DRAWN); root.SetBounds(gfx::Rect(0, 0, 100, 100)); Window* w1ll = new Window(NULL); - w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE); + w1ll->Init(WINDOW_LAYER_NONE); w1ll->SetBounds(gfx::Rect(1, 2, 100, 100)); Window* w11ll = new Window(NULL); - w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE); + w11ll->Init(WINDOW_LAYER_NONE); w11ll->SetBounds(gfx::Rect(3, 4, 100, 100)); w1ll->AddChild(w11ll); Window* w111 = new Window(NULL); - w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w111->Init(WINDOW_LAYER_NOT_DRAWN); w111->SetBounds(gfx::Rect(5, 6, 100, 100)); w11ll->AddChild(w111); Window* w12 = new Window(NULL); - w12->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w12->Init(WINDOW_LAYER_NOT_DRAWN); w12->SetBounds(gfx::Rect(7, 8, 100, 100)); w1ll->AddChild(w12); Window* w121 = new Window(NULL); - w121->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w121->Init(WINDOW_LAYER_NOT_DRAWN); w121->SetBounds(gfx::Rect(9, 10, 100, 100)); w12->AddChild(w121); @@ -3291,23 +2926,23 @@ TEST_F(WindowTest, PaintLayerless) { PaintWindowDelegate w111_delegate; Window root(NULL); - root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + root.Init(WINDOW_LAYER_NOT_DRAWN); root.SetBounds(gfx::Rect(0, 0, 100, 100)); Window* w1ll = new Window(&w1ll_delegate); - w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE); + w1ll->Init(WINDOW_LAYER_NONE); w1ll->SetBounds(gfx::Rect(1, 2, 40, 50)); w1ll->Show(); root.AddChild(w1ll); Window* w11ll = new Window(&w11ll_delegate); - w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE); + w11ll->Init(WINDOW_LAYER_NONE); w11ll->SetBounds(gfx::Rect(3, 4, 11, 12)); w11ll->Show(); w1ll->AddChild(w11ll); Window* w111 = new Window(&w111_delegate); - w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w111->Init(WINDOW_LAYER_NOT_DRAWN); w111->SetBounds(gfx::Rect(5, 6, 100, 100)); w111->Show(); w11ll->AddChild(w111); @@ -3359,30 +2994,30 @@ TEST_F(WindowTest, ConvertPointToTargetLayerless) { // // ll: layer less, eg no layer Window root(NULL); - root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + root.Init(WINDOW_LAYER_NOT_DRAWN); root.SetBounds(gfx::Rect(0, 0, 100, 100)); Window* w1ll = new Window(NULL); - w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE); + w1ll->Init(WINDOW_LAYER_NONE); w1ll->SetBounds(gfx::Rect(1, 2, 100, 100)); Window* w11ll = new Window(NULL); - w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE); + w11ll->Init(WINDOW_LAYER_NONE); w11ll->SetBounds(gfx::Rect(3, 4, 100, 100)); w1ll->AddChild(w11ll); Window* w111 = new Window(NULL); - w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w111->Init(WINDOW_LAYER_NOT_DRAWN); w111->SetBounds(gfx::Rect(5, 6, 100, 100)); w11ll->AddChild(w111); Window* w12 = new Window(NULL); - w12->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w12->Init(WINDOW_LAYER_NOT_DRAWN); w12->SetBounds(gfx::Rect(7, 8, 100, 100)); w1ll->AddChild(w12); Window* w121 = new Window(NULL); - w121->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + w121->Init(WINDOW_LAYER_NOT_DRAWN); w121->SetBounds(gfx::Rect(9, 10, 100, 100)); w12->AddChild(w121); @@ -3420,7 +3055,7 @@ TEST_F(WindowTest, ConvertPointToTargetLayerless) { // Verifies PrintWindowHierarchy() doesn't crash with a layerless window. TEST_F(WindowTest, PrintWindowHierarchyNotCrashLayerless) { Window root(NULL); - root.InitWithWindowLayerType(WINDOW_LAYER_NONE); + root.Init(WINDOW_LAYER_NONE); root.SetBounds(gfx::Rect(0, 0, 100, 100)); root.PrintWindowHierarchy(0); } @@ -3446,7 +3081,7 @@ aura::Window* CreateWindowFromDescription(const std::string& description, << description; } Window* window = new Window(delegate); - window->InitWithWindowLayerType(window_type); + window->Init(window_type); window->SetName(name); // Window name is only propagated to layer in debug builds. if (window->layer()) @@ -3676,7 +3311,7 @@ TEST_F(WindowTest, StackChildAtLayerless) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { test::TestWindowDelegate delegate; Window root(NULL); - root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN); + root.Init(WINDOW_LAYER_NOT_DRAWN); root.SetBounds(gfx::Rect(0, 0, 100, 100)); AddWindowsFromString( &root, @@ -3713,5 +3348,95 @@ TEST_F(WindowTest, StackChildAtLayerless) { } } +namespace { + +class TestLayerAnimationObserver : public ui::LayerAnimationObserver { + public: + TestLayerAnimationObserver() + : animation_completed_(false), + animation_aborted_(false) {} + virtual ~TestLayerAnimationObserver() {} + + bool animation_completed() const { return animation_completed_; } + bool animation_aborted() const { return animation_aborted_; } + + void Reset() { + animation_completed_ = false; + animation_aborted_ = false; + } + + private: + // ui::LayerAnimationObserver: + virtual void OnLayerAnimationEnded( + ui::LayerAnimationSequence* sequence) OVERRIDE { + animation_completed_ = true; + } + + virtual void OnLayerAnimationAborted( + ui::LayerAnimationSequence* sequence) OVERRIDE { + animation_aborted_ = true; + } + + virtual void OnLayerAnimationScheduled( + ui::LayerAnimationSequence* sequence) OVERRIDE { + } + + bool animation_completed_; + bool animation_aborted_; + + DISALLOW_COPY_AND_ASSIGN(TestLayerAnimationObserver); +}; + +} + +TEST_F(WindowTest, WindowDestroyCompletesAnimations) { + ui::ScopedAnimationDurationScaleMode normal_duration_mode( + ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); + scoped_refptr<ui::LayerAnimator> animator = + ui::LayerAnimator::CreateImplicitAnimator(); + TestLayerAnimationObserver observer; + animator->AddObserver(&observer); + // Make sure destroying a Window completes the animation. + { + scoped_ptr<Window> window(CreateTestWindowWithId(1, root_window())); + window->layer()->SetAnimator(animator); + + gfx::Transform transform; + transform.Scale(0.5f, 0.5f); + window->SetTransform(transform); + + EXPECT_TRUE(animator->is_animating()); + EXPECT_FALSE(observer.animation_completed()); + } + EXPECT_TRUE(animator); + EXPECT_FALSE(animator->is_animating()); + EXPECT_TRUE(observer.animation_completed()); + EXPECT_FALSE(observer.animation_aborted()); + animator->RemoveObserver(&observer); + observer.Reset(); + + animator = ui::LayerAnimator::CreateImplicitAnimator(); + animator->AddObserver(&observer); + ui::Layer layer; + layer.SetAnimator(animator); + { + scoped_ptr<Window> window(CreateTestWindowWithId(1, root_window())); + window->layer()->Add(&layer); + + gfx::Transform transform; + transform.Scale(0.5f, 0.5f); + layer.SetTransform(transform); + + EXPECT_TRUE(animator->is_animating()); + EXPECT_FALSE(observer.animation_completed()); + } + + EXPECT_TRUE(animator); + EXPECT_FALSE(animator->is_animating()); + EXPECT_TRUE(observer.animation_completed()); + EXPECT_FALSE(observer.animation_aborted()); + animator->RemoveObserver(&observer); +} + } // namespace test } // namespace aura |