summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-23 22:40:52 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-23 22:40:52 +0000
commit2f74428eee5f226ccdba805b91bd7e45a0f7a4e4 (patch)
tree7bba8d381a8f4f46f487f92cd5ce81e978d0114a /ash
parenteb929d6e96d746d808f1083dd54d7514e4c45e85 (diff)
downloadchromium_src-2f74428eee5f226ccdba805b91bd7e45a0f7a4e4.zip
chromium_src-2f74428eee5f226ccdba805b91bd7e45a0f7a4e4.tar.gz
chromium_src-2f74428eee5f226ccdba805b91bd7e45a0f7a4e4.tar.bz2
More stuff -> ash
http://crbug.com/108457 TEST=none TBR=sky Review URL: http://codereview.chromium.org/9033006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@115741 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/OWNERS3
-rw-r--r--ash/PRESUBMIT.py12
-rw-r--r--ash/accelerators/accelerator_controller.cc206
-rw-r--r--ash/accelerators/accelerator_controller.h76
-rw-r--r--ash/accelerators/accelerator_controller_unittest.cc333
-rw-r--r--ash/accelerators/accelerator_filter.cc58
-rw-r--r--ash/accelerators/accelerator_filter.h39
-rw-r--r--ash/desktop_background/desktop_background_view.cc67
-rw-r--r--ash/desktop_background/desktop_background_view.h35
-rw-r--r--ash/drag_drop/drag_drop_controller.cc176
-rw-r--r--ash/drag_drop/drag_drop_controller.h83
-rw-r--r--ash/drag_drop/drag_drop_controller_unittest.cc432
-rw-r--r--ash/drag_drop/drag_image_view.cc60
-rw-r--r--ash/drag_drop/drag_image_view.h41
-rw-r--r--ash/launcher/launcher_unittest.cc2
-rw-r--r--ash/status_area/status_area_view.cc53
-rw-r--r--ash/status_area/status_area_view.h34
-rw-r--r--ash/test/aura_shell_test_base.cc37
-rw-r--r--ash/test/aura_shell_test_base.h31
-rw-r--r--ash/test/test_activation_delegate.cc53
-rw-r--r--ash/test/test_activation_delegate.h59
-rw-r--r--ash/test/test_shell_delegate.cc43
-rw-r--r--ash/test/test_shell_delegate.h35
-rw-r--r--ash/test/test_suite.cc52
-rw-r--r--ash/test/test_suite.h28
-rw-r--r--ash/tooltips/tooltip_controller.cc296
-rw-r--r--ash/tooltips/tooltip_controller.h80
-rw-r--r--ash/tooltips/tooltip_controller_unittest.cc179
-rw-r--r--ash/wm/activation_controller_unittest.cc4
-rw-r--r--ash/wm/image_grid_unittest.cc2
-rw-r--r--ash/wm/modal_container_layout_manager_unittest.cc2
-rw-r--r--ash/wm/root_window_event_filter_unittest.cc2
-rw-r--r--ash/wm/shadow_controller_unittest.cc2
-rw-r--r--ash/wm/shelf_layout_manager_unittest.cc2
34 files changed, 2609 insertions, 8 deletions
diff --git a/ash/OWNERS b/ash/OWNERS
new file mode 100644
index 0000000..ec790c4
--- /dev/null
+++ b/ash/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+ben@chromium.org
+sky@chromium.org
diff --git a/ash/PRESUBMIT.py b/ash/PRESUBMIT.py
new file mode 100644
index 0000000..12f1918
--- /dev/null
+++ b/ash/PRESUBMIT.py
@@ -0,0 +1,12 @@
+# Copyright (c) 2011 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.
+
+"""Chromium presubmit script for src/ash
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details on the presubmit API built into gcl.
+"""
+
+def GetPreferredTrySlaves():
+ return ['linux_aura:compile']
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
new file mode 100644
index 0000000..e2aaeda
--- /dev/null
+++ b/ash/accelerators/accelerator_controller.cc
@@ -0,0 +1,206 @@
+// Copyright (c) 2011 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 "ash/accelerators/accelerator_controller.h"
+
+#include "ash/launcher/launcher.h"
+#include "ash/launcher/launcher_model.h"
+#include "ash/wm/window_util.h"
+#include "ui/aura/event.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura_shell/screenshot_delegate.h"
+#include "ui/aura_shell/shell.h"
+#include "ui/aura_shell/shell_window_ids.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/accelerators/accelerator_manager.h"
+#include "ui/gfx/compositor/debug_utils.h"
+#include "ui/gfx/compositor/layer_animation_sequence.h"
+#include "ui/gfx/compositor/layer_animator.h"
+#include "ui/gfx/compositor/screen_rotation.h"
+
+namespace {
+
+enum AcceleratorAction {
+ CYCLE_BACKWARD,
+ CYCLE_FORWARD,
+ TAKE_SCREENSHOT,
+#if !defined(NDEBUG)
+ ROTATE_SCREEN,
+ PRINT_LAYER_HIERARCHY,
+ TOGGLE_ROOT_WINDOW_FULL_SCREEN,
+#endif
+};
+
+// Accelerators handled by AcceleratorController.
+struct AcceleratorData {
+ ui::KeyboardCode keycode;
+ bool shift;
+ bool ctrl;
+ bool alt;
+ AcceleratorAction action;
+} kAcceleratorData[] = {
+ { ui::VKEY_TAB, true, false, true, CYCLE_BACKWARD },
+ { ui::VKEY_TAB, false, false, true, CYCLE_FORWARD },
+ { ui::VKEY_F5, false, false, false, CYCLE_FORWARD },
+ { ui::VKEY_F5, false, true, false, TAKE_SCREENSHOT },
+ { ui::VKEY_PRINT, false, false, false, TAKE_SCREENSHOT },
+#if !defined(NDEBUG)
+ { ui::VKEY_HOME, false, true, false, ROTATE_SCREEN },
+ { ui::VKEY_F11, false, true, false, TOGGLE_ROOT_WINDOW_FULL_SCREEN },
+ { ui::VKEY_L, false, false, true, PRINT_LAYER_HIERARCHY },
+#endif
+};
+
+bool HandleCycleWindow(bool forward) {
+ if (aura_shell::Shell::GetInstance()->IsScreenLocked())
+ return false;
+
+ // Use the same order of the windows in LauncherModel to cycle windows.
+ aura_shell::LauncherModel* model =
+ aura_shell::Shell::GetInstance()->launcher()->model();
+ aura::Window* active_window = aura_shell::GetActiveWindow();
+ if (!active_window) {
+ LOG(ERROR) << "No active window";
+ return false;
+ }
+ int active_index = model->ItemIndexByWindow(active_window);
+ if (active_index < 0) {
+ VLOG(2) << "Active window not found in the launcher model";
+ return false;
+ }
+ int next_index = (active_index + (forward ? 1 : -1) + model->item_count()) %
+ model->item_count();
+ aura_shell::ActivateWindow(model->items()[next_index].window);
+ return true;
+}
+
+#if !defined(NDEBUG)
+// Rotates the screen.
+bool HandleRotateScreen() {
+ static int i = 0;
+ int delta = 0;
+ switch (i) {
+ case 0: delta = 90; break;
+ case 1: delta = 90; break;
+ case 2: delta = 90; break;
+ case 3: delta = 90; break;
+ case 4: delta = -90; break;
+ case 5: delta = -90; break;
+ case 6: delta = -90; break;
+ case 7: delta = -90; break;
+ case 8: delta = -90; break;
+ case 9: delta = 180; break;
+ case 10: delta = 180; break;
+ case 11: delta = 90; break;
+ case 12: delta = 180; break;
+ case 13: delta = 180; break;
+ }
+ i = (i + 1) % 14;
+ aura::RootWindow::GetInstance()->layer()->GetAnimator()->
+ set_preemption_strategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
+ scoped_ptr<ui::LayerAnimationSequence> screen_rotation(
+ new ui::LayerAnimationSequence(new ui::ScreenRotation(delta)));
+ screen_rotation->AddObserver(aura::RootWindow::GetInstance());
+ aura::RootWindow::GetInstance()->layer()->GetAnimator()->StartAnimation(
+ screen_rotation.release());
+ return true;
+}
+
+bool HandleToggleRootWindowFullScreen() {
+ aura::RootWindow::GetInstance()->ToggleFullScreen();
+ return true;
+}
+
+bool HandlePrintLayerHierarchy() {
+ ui::PrintLayerHierarchy(aura::RootWindow::GetInstance()->layer());
+ return true;
+}
+#endif
+
+} // namespace
+
+namespace aura_shell {
+
+////////////////////////////////////////////////////////////////////////////////
+// AcceleratorController, public:
+
+AcceleratorController::AcceleratorController()
+ : accelerator_manager_(new ui::AcceleratorManager) {
+ Init();
+}
+
+AcceleratorController::~AcceleratorController() {
+}
+
+void AcceleratorController::Init() {
+ for (size_t i = 0; i < arraysize(kAcceleratorData); ++i) {
+ ui::Accelerator accelerator(kAcceleratorData[i].keycode,
+ kAcceleratorData[i].shift,
+ kAcceleratorData[i].ctrl,
+ kAcceleratorData[i].alt);
+ Register(accelerator, this);
+ accelerators_.insert(std::make_pair(accelerator,
+ kAcceleratorData[i].action));
+ }
+}
+
+void AcceleratorController::Register(
+ const ui::Accelerator& accelerator,
+ ui::AcceleratorTarget* target) {
+ accelerator_manager_->Register(accelerator, target);
+}
+
+void AcceleratorController::Unregister(
+ const ui::Accelerator& accelerator,
+ ui::AcceleratorTarget* target) {
+ accelerator_manager_->Unregister(accelerator, target);
+}
+
+void AcceleratorController::UnregisterAll(
+ ui::AcceleratorTarget* target) {
+ accelerator_manager_->UnregisterAll(target);
+}
+
+bool AcceleratorController::Process(const ui::Accelerator& accelerator) {
+ return accelerator_manager_->Process(accelerator);
+}
+
+void AcceleratorController::SetScreenshotDelegate(
+ ScreenshotDelegate* screenshot_delegate) {
+ screenshot_delegate_.reset(screenshot_delegate);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AcceleratorController, ui::AcceleratorTarget implementation:
+
+bool AcceleratorController::AcceleratorPressed(
+ const ui::Accelerator& accelerator) {
+ std::map<ui::Accelerator, int>::const_iterator it =
+ accelerators_.find(accelerator);
+ DCHECK(it != accelerators_.end());
+ switch (static_cast<AcceleratorAction>(it->second)) {
+ case CYCLE_BACKWARD:
+ return HandleCycleWindow(false);
+ case CYCLE_FORWARD:
+ return HandleCycleWindow(true);
+ case TAKE_SCREENSHOT:
+ if (screenshot_delegate_.get())
+ screenshot_delegate_->HandleTakeScreenshot();
+ // Return true to prevent propagation of the key event.
+ return true;
+#if !defined(NDEBUG)
+ case ROTATE_SCREEN:
+ return HandleRotateScreen();
+ case TOGGLE_ROOT_WINDOW_FULL_SCREEN:
+ return HandleToggleRootWindowFullScreen();
+ case PRINT_LAYER_HIERARCHY:
+ return HandlePrintLayerHierarchy();
+#endif
+ default:
+ NOTREACHED() << "Unhandled action " << it->second;;
+ }
+ return false;
+}
+
+} // namespace aura_shell
diff --git a/ash/accelerators/accelerator_controller.h b/ash/accelerators/accelerator_controller.h
new file mode 100644
index 0000000..e6a0946
--- /dev/null
+++ b/ash/accelerators/accelerator_controller.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 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 ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_H_
+#define ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_H_
+#pragma once
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/base/accelerators/accelerator.h"
+
+namespace ui {
+class AcceleratorManager;
+}
+
+namespace aura_shell {
+
+class ScreenshotDelegate;
+
+// AcceleratorController provides functions for registering or unregistering
+// global keyboard accelerators, which are handled earlier than any windows. It
+// also implements several handlers as an accelerator target.
+class AURA_SHELL_EXPORT AcceleratorController : public ui::AcceleratorTarget {
+ public:
+ AcceleratorController();
+ virtual ~AcceleratorController();
+
+ // Register a global keyboard accelerator for the specified target. If
+ // multiple targets are registered for an accelerator, a target registered
+ // later has higher priority.
+ void Register(const ui::Accelerator& accelerator,
+ ui::AcceleratorTarget* target);
+
+ // Unregister the specified keyboard accelerator for the specified target.
+ void Unregister(const ui::Accelerator& accelerator,
+ ui::AcceleratorTarget* target);
+
+ // Unregister all keyboard accelerators for the specified target.
+ void UnregisterAll(ui::AcceleratorTarget* target);
+
+ // Activate the target associated with the specified accelerator.
+ // First, AcceleratorPressed handler of the most recently registered target
+ // is called, and if that handler processes the event (i.e. returns true),
+ // this method immediately returns. If not, we do the same thing on the next
+ // target, and so on.
+ // Returns true if an accelerator was activated.
+ bool Process(const ui::Accelerator& accelerator);
+
+ // Overridden from ui::AcceleratorTarget:
+ virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
+
+ void SetScreenshotDelegate(ScreenshotDelegate* screenshot_delegate);
+
+ private:
+ // Initialize the accelerators this class handles as a target.
+ void Init();
+
+ scoped_ptr<ui::AcceleratorManager> accelerator_manager_;
+
+ scoped_ptr<ScreenshotDelegate> screenshot_delegate_;
+
+ // A map from accelerators to the AcceleratorAction values, which are used in
+ // the implementation.
+ std::map<ui::Accelerator, int> accelerators_;
+
+ DISALLOW_COPY_AND_ASSIGN(AcceleratorController);
+};
+
+} // namespace aura_shell
+
+#endif // ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_H_
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
new file mode 100644
index 0000000..f4de2e2
--- /dev/null
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -0,0 +1,333 @@
+// Copyright (c) 2011 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 "ash/accelerators/accelerator_controller.h"
+#include "ash/test/aura_shell_test_base.h"
+#include "ash/wm/window_util.h"
+#include "ui/aura/event.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/aura_shell/shell.h"
+#include "ui/aura_shell/shell_window_ids.h"
+
+#if defined(USE_X11)
+#include <X11/Xlib.h>
+#include "ui/base/x/x11_util.h"
+#endif
+
+namespace aura_shell {
+namespace test {
+
+namespace {
+class TestTarget : public ui::AcceleratorTarget {
+ public:
+ TestTarget() : accelerator_pressed_count_(0) {};
+ virtual ~TestTarget() {};
+
+ int accelerator_pressed_count() const {
+ return accelerator_pressed_count_;
+ }
+
+ void set_accelerator_pressed_count(int accelerator_pressed_count) {
+ accelerator_pressed_count_ = accelerator_pressed_count;
+ }
+
+ // Overridden from ui::AcceleratorTarget:
+ virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
+
+ private:
+ int accelerator_pressed_count_;
+};
+
+bool TestTarget::AcceleratorPressed(const ui::Accelerator& accelerator) {
+ ++accelerator_pressed_count_;
+ return true;
+}
+
+} // namespace
+
+class AcceleratorControllerTest : public AuraShellTestBase {
+ public:
+ AcceleratorControllerTest() {};
+ virtual ~AcceleratorControllerTest() {};
+
+ static AcceleratorController* GetController();
+};
+
+AcceleratorController* AcceleratorControllerTest::GetController() {
+ return Shell::GetInstance()->accelerator_controller();
+}
+
+TEST_F(AcceleratorControllerTest, Register) {
+ const ui::Accelerator accelerator_a(ui::VKEY_A, false, false, false);
+ TestTarget target;
+ GetController()->Register(accelerator_a, &target);
+
+ // The registered accelerator is processed.
+ EXPECT_TRUE(GetController()->Process(accelerator_a));
+ EXPECT_EQ(1, target.accelerator_pressed_count());
+}
+
+TEST_F(AcceleratorControllerTest, RegisterMultipleTarget) {
+ const ui::Accelerator accelerator_a(ui::VKEY_A, false, false, false);
+ TestTarget target1;
+ GetController()->Register(accelerator_a, &target1);
+ TestTarget target2;
+ GetController()->Register(accelerator_a, &target2);
+
+ // If multiple targets are registered with the same accelerator, the target
+ // registered later processes the accelerator.
+ EXPECT_TRUE(GetController()->Process(accelerator_a));
+ EXPECT_EQ(0, target1.accelerator_pressed_count());
+ EXPECT_EQ(1, target2.accelerator_pressed_count());
+}
+
+TEST_F(AcceleratorControllerTest, Unregister) {
+ const ui::Accelerator accelerator_a(ui::VKEY_A, false, false, false);
+ TestTarget target;
+ GetController()->Register(accelerator_a, &target);
+ const ui::Accelerator accelerator_b(ui::VKEY_B, false, false, false);
+ GetController()->Register(accelerator_b, &target);
+
+ // Unregistering a different accelerator does not affect the other
+ // accelerator.
+ GetController()->Unregister(accelerator_b, &target);
+ EXPECT_TRUE(GetController()->Process(accelerator_a));
+ EXPECT_EQ(1, target.accelerator_pressed_count());
+
+ // The unregistered accelerator is no longer processed.
+ target.set_accelerator_pressed_count(0);
+ GetController()->Unregister(accelerator_a, &target);
+ EXPECT_FALSE(GetController()->Process(accelerator_a));
+ EXPECT_EQ(0, target.accelerator_pressed_count());
+}
+
+TEST_F(AcceleratorControllerTest, UnregisterAll) {
+ const ui::Accelerator accelerator_a(ui::VKEY_A, false, false, false);
+ TestTarget target1;
+ GetController()->Register(accelerator_a, &target1);
+ const ui::Accelerator accelerator_b(ui::VKEY_B, false, false, false);
+ GetController()->Register(accelerator_b, &target1);
+ const ui::Accelerator accelerator_c(ui::VKEY_C, false, false, false);
+ TestTarget target2;
+ GetController()->Register(accelerator_c, &target2);
+ GetController()->UnregisterAll(&target1);
+
+ // All the accelerators registered for |target1| are no longer processed.
+ EXPECT_FALSE(GetController()->Process(accelerator_a));
+ EXPECT_FALSE(GetController()->Process(accelerator_b));
+ EXPECT_EQ(0, target1.accelerator_pressed_count());
+
+ // UnregisterAll with a different target does not affect the other target.
+ EXPECT_TRUE(GetController()->Process(accelerator_c));
+ EXPECT_EQ(1, target2.accelerator_pressed_count());
+}
+
+TEST_F(AcceleratorControllerTest, Process) {
+ const ui::Accelerator accelerator_a(ui::VKEY_A, false, false, false);
+ TestTarget target1;
+ GetController()->Register(accelerator_a, &target1);
+
+ // The registered accelerator is processed.
+ EXPECT_TRUE(GetController()->Process(accelerator_a));
+ EXPECT_EQ(1, target1.accelerator_pressed_count());
+
+ // The non-registered accelerator is not processed.
+ const ui::Accelerator accelerator_b(ui::VKEY_B, false, false, false);
+ EXPECT_FALSE(GetController()->Process(accelerator_b));
+}
+
+#if defined(OS_WIN) || defined(USE_X11)
+TEST_F(AcceleratorControllerTest, ProcessOnce) {
+ // A focused window must exist for accelerators to be processed.
+ aura::Window* default_container =
+ aura_shell::Shell::GetInstance()->GetContainer(
+ internal::kShellWindowId_DefaultContainer);
+ aura::Window* window = aura::test::CreateTestWindowWithDelegate(
+ new aura::test::TestWindowDelegate,
+ -1,
+ gfx::Rect(),
+ default_container);
+ ActivateWindow(window);
+
+ const ui::Accelerator accelerator_a(ui::VKEY_A, false, false, false);
+ TestTarget target;
+ GetController()->Register(accelerator_a, &target);
+
+ // The accelerator is processed only once.
+#if defined(OS_WIN)
+ MSG msg1 = { NULL, WM_KEYDOWN, ui::VKEY_A, 0 };
+ aura::KeyEvent key_event1(msg1, false);
+ EXPECT_TRUE(aura::RootWindow::GetInstance()->DispatchKeyEvent(&key_event1));
+
+ MSG msg2 = { NULL, WM_CHAR, L'A', 0 };
+ aura::KeyEvent key_event2(msg2, true);
+ EXPECT_FALSE(aura::RootWindow::GetInstance()->DispatchKeyEvent(&key_event2));
+
+ MSG msg3 = { NULL, WM_KEYUP, ui::VKEY_A, 0 };
+ aura::KeyEvent key_event3(msg3, false);
+ EXPECT_FALSE(aura::RootWindow::GetInstance()->DispatchKeyEvent(&key_event3));
+#elif defined(USE_X11)
+ XEvent key_event;
+ ui::InitXKeyEventForTesting(ui::ET_KEY_PRESSED,
+ ui::VKEY_A,
+ 0,
+ &key_event);
+ EXPECT_TRUE(aura::RootWindow::GetInstance()->GetDispatcher()->Dispatch(
+ &key_event));
+#endif
+ EXPECT_EQ(1, target.accelerator_pressed_count());
+}
+#endif
+
+TEST_F(AcceleratorControllerTest, GlobalAccelerators) {
+ // A focused window must exist for accelerators to be processed.
+ aura::Window* default_container =
+ aura_shell::Shell::GetInstance()->GetContainer(
+ internal::kShellWindowId_DefaultContainer);
+ aura::Window* window = aura::test::CreateTestWindowWithDelegate(
+ new aura::test::TestWindowDelegate,
+ -1,
+ gfx::Rect(),
+ default_container);
+ ActivateWindow(window);
+
+ // CycleBackward
+ EXPECT_TRUE(GetController()->Process(
+ ui::Accelerator(ui::VKEY_TAB, true, false, true)));
+ // CycleForwrard
+ EXPECT_TRUE(GetController()->Process(
+ ui::Accelerator(ui::VKEY_F5, false, false, false)));
+ EXPECT_TRUE(GetController()->Process(
+ ui::Accelerator(ui::VKEY_TAB, false, false, true)));
+ // TakeScreenshot
+ // EXPECT_TRUE(GetController()->Process(
+ // ui::Accelerator(ui::VKEY_F5, false, true, false)));
+ // EXPECT_TRUE(GetController()->Process(
+ // ui::Accelerator(ui::VKEY_PRINT, false, false, false)));
+#if !defined(NDEBUG)
+ // RotateScreen
+ EXPECT_TRUE(GetController()->Process(
+ ui::Accelerator(ui::VKEY_HOME, false, true, false)));
+#if !defined(OS_LINUX)
+ // ToggleDesktopFullScreen (not implemented yet on Linux)
+ EXPECT_TRUE(GetController()->Process(
+ ui::Accelerator(ui::VKEY_F11, false, true, false)));
+#endif
+#endif
+}
+
+TEST_F(AcceleratorControllerTest, HandleCycleWindow) {
+ aura::Window* default_container =
+ aura_shell::Shell::GetInstance()->GetContainer(
+ internal::kShellWindowId_DefaultContainer);
+ aura::Window* window0 = aura::test::CreateTestWindowWithDelegate(
+ new aura::test::TestWindowDelegate,
+ -1,
+ gfx::Rect(),
+ default_container);
+ aura::Window* window1 = aura::test::CreateTestWindowWithDelegate(
+ new aura::test::TestWindowDelegate,
+ -1,
+ gfx::Rect(),
+ default_container);
+ aura::Window* window2 = aura::test::CreateTestWindowWithDelegate(
+ new aura::test::TestWindowDelegate,
+ -1,
+ gfx::Rect(),
+ default_container);
+ ActivateWindow(window0);
+ EXPECT_TRUE(IsActiveWindow(window0));
+
+ ui::Accelerator cycle_forward(ui::VKEY_TAB, false, false, true);
+ EXPECT_TRUE(GetController()->Process(cycle_forward));
+ EXPECT_TRUE(IsActiveWindow(window1));
+ EXPECT_TRUE(GetController()->Process(cycle_forward));
+ EXPECT_TRUE(IsActiveWindow(window2));
+ EXPECT_TRUE(GetController()->Process(cycle_forward));
+ EXPECT_TRUE(IsActiveWindow(window0));
+
+ ui::Accelerator cycle_backward(ui::VKEY_TAB, true, false, true);
+ EXPECT_TRUE(GetController()->Process(cycle_backward));
+ EXPECT_TRUE(IsActiveWindow(window2));
+ EXPECT_TRUE(GetController()->Process(cycle_backward));
+ EXPECT_TRUE(IsActiveWindow(window1));
+ EXPECT_TRUE(GetController()->Process(cycle_backward));
+ EXPECT_TRUE(IsActiveWindow(window0));
+
+ aura::Window* modal_container =
+ aura_shell::Shell::GetInstance()->GetContainer(
+ internal::kShellWindowId_AlwaysOnTopContainer);
+ aura::Window* modal_window = aura::test::CreateTestWindowWithDelegate(
+ new aura::test::TestWindowDelegate,
+ -1,
+ gfx::Rect(),
+ modal_container);
+
+ // When the modal window is active, cycling window does not take effect.
+ ActivateWindow(modal_window);
+ EXPECT_TRUE(IsActiveWindow(modal_window));
+ EXPECT_FALSE(GetController()->Process(cycle_forward));
+ EXPECT_TRUE(IsActiveWindow(modal_window));
+ EXPECT_FALSE(IsActiveWindow(window0));
+ EXPECT_FALSE(IsActiveWindow(window1));
+ EXPECT_FALSE(IsActiveWindow(window2));
+ EXPECT_FALSE(GetController()->Process(cycle_backward));
+ EXPECT_TRUE(IsActiveWindow(modal_window));
+ EXPECT_FALSE(IsActiveWindow(window0));
+ EXPECT_FALSE(IsActiveWindow(window1));
+ EXPECT_FALSE(IsActiveWindow(window2));
+
+ // The modal window is not activated by cycling window.
+ ActivateWindow(window0);
+ EXPECT_TRUE(GetController()->Process(cycle_forward));
+ EXPECT_FALSE(IsActiveWindow(modal_window));
+ EXPECT_TRUE(GetController()->Process(cycle_forward));
+ EXPECT_FALSE(IsActiveWindow(modal_window));
+ EXPECT_TRUE(GetController()->Process(cycle_forward));
+ EXPECT_FALSE(IsActiveWindow(modal_window));
+ EXPECT_TRUE(GetController()->Process(cycle_backward));
+ EXPECT_FALSE(IsActiveWindow(modal_window));
+ EXPECT_TRUE(GetController()->Process(cycle_backward));
+ EXPECT_FALSE(IsActiveWindow(modal_window));
+ EXPECT_TRUE(GetController()->Process(cycle_backward));
+ EXPECT_FALSE(IsActiveWindow(modal_window));
+
+ // When a screen lock window is visible, cycling window does not take effect.
+ aura::Window* lock_screen_container =
+ aura_shell::Shell::GetInstance()->GetContainer(
+ internal::kShellWindowId_LockScreenContainer);
+ aura::Window* lock_screen_window = aura::test::CreateTestWindowWithDelegate(
+ new aura::test::TestWindowDelegate,
+ -1,
+ gfx::Rect(),
+ lock_screen_container);
+
+ lock_screen_window->Show();
+ EXPECT_FALSE(GetController()->Process(cycle_forward));
+ EXPECT_FALSE(GetController()->Process(cycle_backward));
+
+ // When a screen lock window is visible, cycling window does not take effect.
+ // But otherwise, cycling window does take effect.
+ aura::Window* lock_modal_container =
+ aura_shell::Shell::GetInstance()->GetContainer(
+ internal::kShellWindowId_LockModalContainer);
+ aura::Window* lock_modal_window = aura::test::CreateTestWindowWithDelegate(
+ new aura::test::TestWindowDelegate,
+ -1,
+ gfx::Rect(),
+ lock_modal_container);
+
+ lock_modal_window->Show();
+ EXPECT_FALSE(GetController()->Process(cycle_forward));
+ EXPECT_FALSE(GetController()->Process(cycle_backward));
+ lock_screen_window->Hide();
+ EXPECT_TRUE(GetController()->Process(cycle_forward));
+ EXPECT_TRUE(GetController()->Process(cycle_backward));
+}
+
+} // namespace test
+} // namespace aura_shell
diff --git a/ash/accelerators/accelerator_filter.cc b/ash/accelerators/accelerator_filter.cc
new file mode 100644
index 0000000..fbeaaa0
--- /dev/null
+++ b/ash/accelerators/accelerator_filter.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2011 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 "ash/accelerators/accelerator_filter.h"
+
+#include "ash/accelerators/accelerator_controller.h"
+#include "ui/aura/event.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura_shell/shell.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/accelerators/accelerator_manager.h"
+
+namespace {
+const int kModifierFlagMask = (ui::EF_SHIFT_DOWN |
+ ui::EF_CONTROL_DOWN |
+ ui::EF_ALT_DOWN);
+} // namespace
+
+namespace aura_shell {
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// AcceleratorFilter, public:
+
+AcceleratorFilter::AcceleratorFilter()
+ : EventFilter(aura::RootWindow::GetInstance()) {
+}
+
+AcceleratorFilter::~AcceleratorFilter() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AcceleratorFilter, EventFilter implementation:
+
+bool AcceleratorFilter::PreHandleKeyEvent(aura::Window* target,
+ aura::KeyEvent* event) {
+ if (event->type() == ui::ET_KEY_PRESSED && !event->is_char()) {
+ return Shell::GetInstance()->accelerator_controller()->Process(
+ ui::Accelerator(event->key_code(),
+ event->flags() & kModifierFlagMask));
+ }
+ return false;
+}
+
+bool AcceleratorFilter::PreHandleMouseEvent(aura::Window* target,
+ aura::MouseEvent* event) {
+ return false;
+}
+
+ui::TouchStatus AcceleratorFilter::PreHandleTouchEvent(
+ aura::Window* target,
+ aura::TouchEvent* event) {
+ return ui::TOUCH_STATUS_UNKNOWN;
+}
+
+} // namespace internal
+} // namespace aura_shell
diff --git a/ash/accelerators/accelerator_filter.h b/ash/accelerators/accelerator_filter.h
new file mode 100644
index 0000000..11c2fdd
--- /dev/null
+++ b/ash/accelerators/accelerator_filter.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 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 ASH_ACCELERATORS_ACCELERATOR_FILTER_H_
+#define ASH_ACCELERATORS_ACCELERATOR_FILTER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/aura/event_filter.h"
+#include "ui/aura_shell/aura_shell_export.h"
+
+namespace aura_shell {
+namespace internal {
+
+// AcceleratorFilter filters key events for AcceleratorControler handling global
+// keyboard accelerators.
+class AURA_SHELL_EXPORT AcceleratorFilter : public aura::EventFilter {
+ public:
+ AcceleratorFilter();
+ virtual ~AcceleratorFilter();
+
+ // Overridden from aura::EventFilter:
+ virtual bool PreHandleKeyEvent(aura::Window* target,
+ aura::KeyEvent* event) OVERRIDE;
+ virtual bool PreHandleMouseEvent(aura::Window* target,
+ aura::MouseEvent* event) OVERRIDE;
+ virtual ui::TouchStatus PreHandleTouchEvent(aura::Window* target,
+ aura::TouchEvent* event) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AcceleratorFilter);
+};
+
+} // namespace internal
+} // namespace aura_shell
+
+#endif // ASH_ACCELERATORS_ACCELERATOR_FILTER_H_
diff --git a/ash/desktop_background/desktop_background_view.cc b/ash/desktop_background/desktop_background_view.cc
new file mode 100644
index 0000000..e046a8b
--- /dev/null
+++ b/ash/desktop_background/desktop_background_view.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2011 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 "ash/desktop_background/desktop_background_view.h"
+
+#include "base/utf_string_conversions.h"
+#include "grit/ui_resources.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/aura_shell/shell.h"
+#include "ui/aura_shell/shell_window_ids.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/views/widget/widget.h"
+
+namespace aura_shell {
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopBackgroundView, public:
+
+DesktopBackgroundView::DesktopBackgroundView() {
+ wallpaper_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_AURA_WALLPAPER);
+ wallpaper_.buildMipMap(false);
+}
+
+DesktopBackgroundView::~DesktopBackgroundView() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DesktopBackgroundView, views::View overrides:
+
+void DesktopBackgroundView::OnPaint(gfx::Canvas* canvas) {
+ canvas->DrawBitmapInt(wallpaper_,
+ 0, 0, wallpaper_.width(), wallpaper_.height(),
+ 0, 0, width(), height(),
+ true);
+}
+
+bool DesktopBackgroundView::OnMousePressed(const views::MouseEvent& event) {
+ return true;
+}
+
+void DesktopBackgroundView::OnMouseReleased(const views::MouseEvent& event) {
+ Shell::GetInstance()->ToggleOverview();
+}
+
+views::Widget* CreateDesktopBackground() {
+ views::Widget* desktop_widget = new views::Widget;
+ views::Widget::InitParams params(
+ views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ DesktopBackgroundView* view = new DesktopBackgroundView;
+ params.delegate = view;
+ desktop_widget->Init(params);
+ Shell::GetInstance()->GetContainer(
+ aura_shell::internal::kShellWindowId_DesktopBackgroundContainer)->
+ AddChild(desktop_widget->GetNativeView());
+ desktop_widget->SetContentsView(view);
+ desktop_widget->Show();
+ desktop_widget->GetNativeView()->SetName("DesktopBackgroundView");
+ return desktop_widget;
+}
+
+} // namespace internal
+} // namespace aura_shell
diff --git a/ash/desktop_background/desktop_background_view.h b/ash/desktop_background/desktop_background_view.h
new file mode 100644
index 0000000..8f8912b
--- /dev/null
+++ b/ash/desktop_background/desktop_background_view.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 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 ASH_DESKTOP_BACKGROUND_DESKTOP_BACKGROUND_VIEW_H_
+#define ASH_DESKTOP_BACKGROUND_DESKTOP_BACKGROUND_VIEW_H_
+#pragma once
+
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace aura_shell {
+namespace internal {
+
+class DesktopBackgroundView : public views::WidgetDelegateView {
+ public:
+ DesktopBackgroundView();
+ virtual ~DesktopBackgroundView();
+
+ private:
+ // Overridden from views::View:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE;
+
+ SkBitmap wallpaper_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopBackgroundView);
+};
+
+} // namespace internal
+} // namespace aura_shell
+
+#endif // ASH_DESKTOP_BACKGROUND_DESKTOP_BACKGROUND_VIEW_H_
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
new file mode 100644
index 0000000..b316d14
--- /dev/null
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2011 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 "ash/drag_drop/drag_drop_controller.h"
+
+#include "ash/drag_drop/drag_image_view.h"
+#include "base/message_loop.h"
+#include "ui/aura/client/drag_drop_delegate.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/aura_shell/shell.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_aura.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/rect.h"
+#include "ui/views/widget/native_widget_aura.h"
+
+namespace aura_shell {
+namespace internal {
+
+using aura::RootWindow;
+
+namespace {
+const gfx::Point kDragDropWidgetOffset(0, 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DragDropController, public:
+
+DragDropController::DragDropController()
+ : aura::EventFilter(RootWindow::GetInstance()),
+ drag_image_(NULL),
+ drag_data_(NULL),
+ drag_operation_(0),
+ dragged_window_(NULL),
+ drag_drop_in_progress_(false),
+ should_block_during_drag_drop_(true) {
+ Shell::GetInstance()->AddRootWindowEventFilter(this);
+ aura::client::SetDragDropClient(this);
+}
+
+DragDropController::~DragDropController() {
+ Shell::GetInstance()->RemoveRootWindowEventFilter(this);
+ Cleanup();
+}
+
+int DragDropController::StartDragAndDrop(const ui::OSExchangeData& data,
+ int operation) {
+ DCHECK(!drag_drop_in_progress_);
+ aura::Window* capture_window = RootWindow::GetInstance()->capture_window();
+ if (capture_window)
+ RootWindow::GetInstance()->ReleaseCapture(capture_window);
+ drag_drop_in_progress_ = true;
+
+ drag_data_ = &data;
+ drag_operation_ = operation;
+ gfx::Point location = RootWindow::GetInstance()->last_mouse_location();
+ const ui::OSExchangeDataProviderAura& provider =
+ static_cast<const ui::OSExchangeDataProviderAura&>(data.provider());
+
+ drag_image_.reset(new DragImageView);
+ drag_image_->SetImage(provider.drag_image());
+ drag_image_->SetScreenBounds(gfx::Rect(location.Add(kDragDropWidgetOffset),
+ drag_image_->GetPreferredSize()));
+ drag_image_->SetWidgetVisible(true);
+
+ dragged_window_ = NULL;
+
+ if (should_block_during_drag_drop_) {
+ MessageLoopForUI::current()->RunWithDispatcher(
+ RootWindow::GetInstance()->GetDispatcher());
+ }
+ return drag_operation_;
+}
+
+void DragDropController::DragUpdate(aura::Window* target,
+ const aura::MouseEvent& event) {
+ aura::client::DragDropDelegate* delegate = NULL;
+ if (target != dragged_window_) {
+ if (dragged_window_ &&
+ (delegate = aura::client::GetDragDropDelegate(dragged_window_))) {
+ delegate->OnDragExited();
+ }
+ dragged_window_ = target;
+ if ((delegate = aura::client::GetDragDropDelegate(dragged_window_))) {
+ aura::DropTargetEvent e(*drag_data_, event.location(), drag_operation_);
+ delegate->OnDragEntered(e);
+ }
+ } else {
+ if ((delegate = aura::client::GetDragDropDelegate(dragged_window_))) {
+ aura::DropTargetEvent e(*drag_data_, event.location(), drag_operation_);
+ int op = delegate->OnDragUpdated(e);
+ gfx::NativeCursor cursor = (op == ui::DragDropTypes::DRAG_NONE)?
+ aura::kCursorMove : aura::kCursorHand;
+ RootWindow::GetInstance()->SetCursor(cursor);
+ }
+ }
+
+ DCHECK(drag_image_.get());
+ if (drag_image_->visible()) {
+ drag_image_->SetScreenPosition(RootWindow::GetInstance()->
+ last_mouse_location().Add(kDragDropWidgetOffset));
+ }
+}
+
+void DragDropController::Drop(aura::Window* target,
+ const aura::MouseEvent& event) {
+ aura::client::DragDropDelegate* delegate = NULL;
+ DCHECK(target == dragged_window_);
+ if ((delegate = aura::client::GetDragDropDelegate(dragged_window_))) {
+ aura::DropTargetEvent e(*drag_data_, event.location(), drag_operation_);
+ drag_operation_ = delegate->OnPerformDrop(e);
+ // TODO(varunjain): if drag_op is 0, do drag widget flying back animation
+ }
+
+ Cleanup();
+ if (should_block_during_drag_drop_)
+ MessageLoop::current()->Quit();
+}
+
+void DragDropController::DragCancel() {
+ // TODO(varunjain): Do drag widget flying back animation
+ Cleanup();
+ drag_operation_ = 0;
+ if (should_block_during_drag_drop_)
+ MessageLoop::current()->Quit();
+}
+
+bool DragDropController::IsDragDropInProgress() {
+ return drag_drop_in_progress_;
+}
+
+bool DragDropController::PreHandleKeyEvent(aura::Window* target,
+ aura::KeyEvent* event) {
+ return false;
+}
+
+bool DragDropController::PreHandleMouseEvent(aura::Window* target,
+ aura::MouseEvent* event) {
+ if (!drag_drop_in_progress_)
+ return false;
+ switch (event->type()) {
+ case ui::ET_MOUSE_DRAGGED:
+ DragUpdate(target, *event);
+ break;
+ case ui::ET_MOUSE_RELEASED:
+ Drop(target, *event);
+ break;
+ case ui::ET_MOUSE_EXITED:
+ DragCancel();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return true;
+}
+
+ui::TouchStatus DragDropController::PreHandleTouchEvent(
+ aura::Window* target,
+ aura::TouchEvent* event) {
+ return ui::TOUCH_STATUS_UNKNOWN;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DragDropController, private:
+
+void DragDropController::Cleanup() {
+ drag_image_.reset();
+ drag_data_ = NULL;
+ drag_drop_in_progress_ = false;
+}
+
+} // namespace internal
+} // namespace aura_shell
diff --git a/ash/drag_drop/drag_drop_controller.h b/ash/drag_drop/drag_drop_controller.h
new file mode 100644
index 0000000..b1aabf8
--- /dev/null
+++ b/ash/drag_drop/drag_drop_controller.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 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 ASH_DRAG_DROP_DRAG_DROP_CONTROLLER_H_
+#define ASH_DRAG_DROP_DRAG_DROP_CONTROLLER_H_
+#pragma once
+
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/event.h"
+#include "ui/aura/event_filter.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/events.h"
+#include "ui/gfx/point.h"
+
+namespace aura {
+class Window;
+}
+
+namespace aura_shell {
+
+namespace test {
+class DragDropControllerTest;
+}
+
+namespace internal {
+
+class DragImageView;
+
+class AURA_SHELL_EXPORT DragDropController
+ : public aura::client::DragDropClient,
+ public aura::EventFilter {
+ public:
+ DragDropController();
+ virtual ~DragDropController();
+
+ void set_should_block_during_drag_drop(bool should_block_during_drag_drop) {
+ should_block_during_drag_drop_ = should_block_during_drag_drop;
+ }
+
+ // Overridden from aura::client::DragDropClient:
+ virtual int StartDragAndDrop(const ui::OSExchangeData& data,
+ int operation) OVERRIDE;
+ virtual void DragUpdate(aura::Window* target,
+ const aura::MouseEvent& event) OVERRIDE;
+ virtual void Drop(aura::Window* target,
+ const aura::MouseEvent& event) OVERRIDE;
+ virtual void DragCancel() OVERRIDE;
+ virtual bool IsDragDropInProgress() OVERRIDE;
+
+ // Overridden from aura::EventFilter:
+ virtual bool PreHandleKeyEvent(aura::Window* target,
+ aura::KeyEvent* event) OVERRIDE;
+ virtual bool PreHandleMouseEvent(aura::Window* target,
+ aura::MouseEvent* event) OVERRIDE;
+ virtual ui::TouchStatus PreHandleTouchEvent(aura::Window* target,
+ aura::TouchEvent* event) OVERRIDE;
+
+ private:
+ friend class aura_shell::test::DragDropControllerTest;
+
+ // Helper method to reset everything.
+ void Cleanup();
+
+ scoped_ptr<DragImageView> drag_image_;
+ const ui::OSExchangeData* drag_data_;
+ int drag_operation_;
+ aura::Window* dragged_window_;
+
+ bool drag_drop_in_progress_;
+
+ // Indicates whether the caller should be blocked on a drag/drop session.
+ // Only be used for tests.
+ bool should_block_during_drag_drop_;
+
+ DISALLOW_COPY_AND_ASSIGN(DragDropController);
+};
+
+} // namespace internal
+} // namespace aura_shell
+
+#endif // ASH_DRAG_DROP_DRAG_DROP_CONTROLLER_H_
diff --git a/ash/drag_drop/drag_drop_controller_unittest.cc b/ash/drag_drop/drag_drop_controller_unittest.cc
new file mode 100644
index 0000000..db4ae5e
--- /dev/null
+++ b/ash/drag_drop/drag_drop_controller_unittest.cc
@@ -0,0 +1,432 @@
+// Copyright (c) 2011 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 "ash/drag_drop/drag_drop_controller.h"
+
+#include "ash/test/aura_shell_test_base.h"
+#include "ash/wm/root_window_event_filter.h"
+#include "base/location.h"
+#include "base/utf_string_conversions.h"
+#include "ui/aura/event.h"
+#include "ui/aura/root_window.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/views/events/event.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace aura_shell {
+namespace test {
+
+namespace {
+
+// A simple view that makes sure RunShellDrag is invoked on mouse drag.
+class DragTestView : public views::View {
+ public:
+ DragTestView() : views::View() {
+ Reset();
+ }
+
+ void Reset() {
+ num_drag_enters_ = 0;
+ num_drag_exits_ = 0;
+ num_drag_updates_ = 0;
+ num_drops_ = 0;
+ drag_done_received_ = false;
+ }
+
+ int VerticalDragThreshold() {
+ return views::View::GetVerticalDragThreshold();
+ }
+
+ int HorizontalDragThreshold() {
+ return views::View::GetHorizontalDragThreshold();
+ }
+
+ int num_drag_enters_;
+ int num_drag_exits_;
+ int num_drag_updates_;
+ int num_drops_;
+ bool drag_done_received_;
+
+ private:
+ // View overrides:
+ int GetDragOperations(const gfx::Point& press_pt) OVERRIDE {
+ return ui::DragDropTypes::DRAG_COPY;
+ }
+
+ void WriteDragData(const gfx::Point& p, OSExchangeData* data) OVERRIDE {
+ data->SetString(UTF8ToUTF16("I am being dragged"));
+ }
+
+ bool OnMousePressed(const views::MouseEvent& event) OVERRIDE {
+ return true;
+ }
+
+ bool GetDropFormats(int* formats,
+ std::set<OSExchangeData::CustomFormat>* custom_formats) {
+ *formats = ui::OSExchangeData::STRING;
+ return true;
+ }
+
+ bool CanDrop(const OSExchangeData& data) OVERRIDE {
+ return true;
+ }
+
+ void OnDragEntered(const views::DropTargetEvent& event) OVERRIDE {
+ num_drag_enters_++;
+ }
+
+ int OnDragUpdated(const views::DropTargetEvent& event) OVERRIDE {
+ num_drag_updates_++;
+ return ui::DragDropTypes::DRAG_COPY;
+ }
+
+ void OnDragExited() OVERRIDE {
+ num_drag_exits_++;
+ }
+
+ int OnPerformDrop(const views::DropTargetEvent& event) OVERRIDE {
+ num_drops_++;
+ return ui::DragDropTypes::DRAG_COPY;
+ }
+
+ void OnDragDone() OVERRIDE {
+ drag_done_received_ = true;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(DragTestView);
+};
+
+class TestDragDropController : public internal::DragDropController {
+ public:
+ TestDragDropController() : internal::DragDropController() {
+ Reset();
+ }
+
+ void Reset() {
+ drag_start_received_ = false;
+ num_drag_updates_ = 0;
+ drop_received_ = false;
+ drag_string_.clear();
+ }
+
+ bool drag_start_received_;
+ int num_drag_updates_;
+ bool drop_received_;
+ string16 drag_string_;
+
+ private:
+ int StartDragAndDrop(const ui::OSExchangeData& data,
+ int operation) OVERRIDE {
+ drag_start_received_ = true;
+ data.GetString(&drag_string_);
+ return DragDropController::StartDragAndDrop(data, operation);
+ }
+
+ void DragUpdate(aura::Window* target,
+ const aura::MouseEvent& event) OVERRIDE {
+ DragDropController::DragUpdate(target, event);
+ num_drag_updates_++;
+ }
+
+ void Drop(aura::Window* target, const aura::MouseEvent& event) OVERRIDE {
+ DragDropController::Drop(target, event);
+ drop_received_ = true;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(TestDragDropController);
+};
+
+views::Widget* CreateNewWidget() {
+ views::Widget* widget = new views::Widget;
+ views::Widget::InitParams params;
+ params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
+ params.accept_events = true;
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.parent = aura::RootWindow::GetInstance();
+ params.child = true;
+ widget->Init(params);
+ widget->Show();
+ return widget;
+}
+
+void AddViewToWidgetAndResize(views::Widget* widget, views::View* view) {
+ if (!widget->GetContentsView()) {
+ views::View* contents_view = new views::View;
+ widget->SetContentsView(contents_view);
+ }
+
+ views::View* contents_view = widget->GetContentsView();
+ contents_view->AddChildView(view);
+ view->SetBounds(contents_view->width(), 0, 100, 100);
+ gfx::Rect contents_view_bounds = contents_view->bounds();
+ contents_view_bounds = contents_view_bounds.Union(view->bounds());
+ contents_view->SetBoundsRect(contents_view_bounds);
+ widget->SetBounds(contents_view_bounds);
+}
+
+} // namespace
+
+class DragDropControllerTest : public AuraShellTestBase {
+ public:
+ DragDropControllerTest() : AuraShellTestBase() {}
+ virtual ~DragDropControllerTest() {}
+
+ void SetUp() OVERRIDE {
+ AuraShellTestBase::SetUp();
+ drag_drop_controller_.reset(new TestDragDropController);
+ drag_drop_controller_->set_should_block_during_drag_drop(false);
+ aura::client::SetDragDropClient(drag_drop_controller_.get());
+ }
+
+ void TearDown() OVERRIDE {
+ aura::client::SetDragDropClient(NULL);
+ drag_drop_controller_.reset();
+ AuraShellTestBase::TearDown();
+ }
+
+ void UpdateDragData(ui::OSExchangeData* data) {
+ drag_drop_controller_->drag_data_ = data;
+ }
+
+ protected:
+ scoped_ptr<TestDragDropController> drag_drop_controller_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DragDropControllerTest);
+};
+
+TEST_F(DragDropControllerTest, DragDropInSingleViewTest) {
+ views::Widget* widget = CreateNewWidget();
+ DragTestView* drag_view = new DragTestView;
+ AddViewToWidgetAndResize(widget, drag_view);
+ gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
+ ui::OSExchangeData data;
+ data.SetString(UTF8ToUTF16("I am being dragged"));
+
+ aura::MouseEvent event1(ui::ET_MOUSE_PRESSED,
+ point,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&event1);
+
+ int num_drags = 17;
+ for (int i = 0; i < num_drags; ++i) {
+ // Because we are not doing a blocking drag and drop, the original
+ // OSDragExchangeData object is lost as soon as we return from the drag
+ // initiation in DragDropController::StartDragAndDrop(). Hence we set the
+ // drag_data_ to a fake drag data object that we created.
+ if (i > 0)
+ UpdateDragData(&data);
+ point.Offset(0, 1);
+ aura::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
+ point,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&drag_event);
+ }
+
+ aura::MouseEvent event2(ui::ET_MOUSE_RELEASED, point, 0);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&event2);
+
+ EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
+ EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
+ drag_drop_controller_->num_drag_updates_);
+ EXPECT_TRUE(drag_drop_controller_->drop_received_);
+ EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
+ drag_drop_controller_->drag_string_);
+
+ EXPECT_EQ(1, drag_view->num_drag_enters_);
+ EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
+ drag_view->num_drag_updates_);
+ EXPECT_EQ(1, drag_view->num_drops_);
+ EXPECT_EQ(0, drag_view->num_drag_exits_);
+ EXPECT_TRUE(drag_view->drag_done_received_);
+ delete widget;
+}
+
+TEST_F(DragDropControllerTest, DragDropInMultipleViewsSingleWidgetTest) {
+ views::Widget* widget = CreateNewWidget();
+ DragTestView* drag_view1 = new DragTestView;
+ AddViewToWidgetAndResize(widget, drag_view1);
+ gfx::Point point = drag_view1->bounds().CenterPoint();
+ DragTestView* drag_view2 = new DragTestView;
+ AddViewToWidgetAndResize(widget, drag_view2);
+
+ ui::OSExchangeData data;
+ data.SetString(UTF8ToUTF16("I am being dragged"));
+
+ aura::MouseEvent event1(ui::ET_MOUSE_PRESSED,
+ point,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&event1);
+
+ int num_drags = drag_view1->width();
+ for (int i = 0; i < num_drags; ++i) {
+ // Because we are not doing a blocking drag and drop, the original
+ // OSDragExchangeData object is lost as soon as we return from the drag
+ // initiation in DragDropController::StartDragAndDrop(). Hence we set the
+ // drag_data_ to a fake drag data object that we created.
+ if (i > 0)
+ UpdateDragData(&data);
+ point.Offset(1, 0);
+ aura::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
+ point,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&drag_event);
+ }
+
+ aura::MouseEvent event2(ui::ET_MOUSE_RELEASED, point, 0);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&event2);
+
+ EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
+ EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
+ drag_drop_controller_->num_drag_updates_);
+ EXPECT_TRUE(drag_drop_controller_->drop_received_);
+ EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
+ drag_drop_controller_->drag_string_);
+
+ EXPECT_EQ(1, drag_view1->num_drag_enters_);
+ int num_expected_updates = drag_view1->bounds().width() -
+ drag_view1->bounds().CenterPoint().x() - 2;
+ EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
+ drag_view1->num_drag_updates_);
+ EXPECT_EQ(0, drag_view1->num_drops_);
+ EXPECT_EQ(1, drag_view1->num_drag_exits_);
+ EXPECT_TRUE(drag_view1->drag_done_received_);
+
+ EXPECT_EQ(1, drag_view2->num_drag_enters_);
+ num_expected_updates = num_drags - num_expected_updates - 1;
+ EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
+ EXPECT_EQ(1, drag_view2->num_drops_);
+ EXPECT_EQ(0, drag_view2->num_drag_exits_);
+ EXPECT_FALSE(drag_view2->drag_done_received_);
+ delete widget;
+}
+
+TEST_F(DragDropControllerTest, DragDropInMultipleViewsMultipleWidgetsTest) {
+ views::Widget* widget1 = CreateNewWidget();
+ DragTestView* drag_view1 = new DragTestView;
+ AddViewToWidgetAndResize(widget1, drag_view1);
+ gfx::Point point = drag_view1->bounds().CenterPoint();
+ views::Widget* widget2 = CreateNewWidget();
+ DragTestView* drag_view2 = new DragTestView;
+ AddViewToWidgetAndResize(widget2, drag_view2);
+ gfx::Rect widget1_bounds = widget1->GetClientAreaScreenBounds();
+ gfx::Rect widget2_bounds = widget2->GetClientAreaScreenBounds();
+ widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0,
+ widget2_bounds.width(), widget2_bounds.height()));
+
+ ui::OSExchangeData data;
+ data.SetString(UTF8ToUTF16("I am being dragged"));
+
+ aura::MouseEvent event1(ui::ET_MOUSE_PRESSED,
+ point,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&event1);
+
+ int num_drags = drag_view1->width();
+ for (int i = 0; i < num_drags; ++i) {
+ // Because we are not doing a blocking drag and drop, the original
+ // OSDragExchangeData object is lost as soon as we return from the drag
+ // initiation in DragDropController::StartDragAndDrop(). Hence we set the
+ // drag_data_ to a fake drag data object that we created.
+ if (i > 0)
+ UpdateDragData(&data);
+ point.Offset(1, 0);
+ aura::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
+ point,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&drag_event);
+ }
+
+ aura::MouseEvent event2(ui::ET_MOUSE_RELEASED, point, 0);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&event2);
+
+ EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
+ EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
+ drag_drop_controller_->num_drag_updates_);
+ EXPECT_TRUE(drag_drop_controller_->drop_received_);
+ EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
+ drag_drop_controller_->drag_string_);
+
+ EXPECT_EQ(1, drag_view1->num_drag_enters_);
+ int num_expected_updates = drag_view1->bounds().width() -
+ drag_view1->bounds().CenterPoint().x() - 2;
+ EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
+ drag_view1->num_drag_updates_);
+ EXPECT_EQ(0, drag_view1->num_drops_);
+ EXPECT_EQ(1, drag_view1->num_drag_exits_);
+ EXPECT_TRUE(drag_view1->drag_done_received_);
+
+ EXPECT_EQ(1, drag_view2->num_drag_enters_);
+ num_expected_updates = num_drags - num_expected_updates - 1;
+ EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
+ EXPECT_EQ(1, drag_view2->num_drops_);
+ EXPECT_EQ(0, drag_view2->num_drag_exits_);
+ EXPECT_FALSE(drag_view2->drag_done_received_);
+ delete widget1;
+ delete widget2;
+}
+
+TEST_F(DragDropControllerTest, ViewRemovedWhileInDragDropTest) {
+ views::Widget* widget = CreateNewWidget();
+ DragTestView* drag_view = new DragTestView;
+ AddViewToWidgetAndResize(widget, drag_view);
+ gfx::Point point = gfx::Rect(drag_view->bounds()).CenterPoint();
+ ui::OSExchangeData data;
+ data.SetString(UTF8ToUTF16("I am being dragged"));
+
+ aura::MouseEvent event1(ui::ET_MOUSE_PRESSED,
+ point,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&event1);
+
+ int num_drags_1 = 17;
+ for (int i = 0; i < num_drags_1; ++i) {
+ // Because we are not doing a blocking drag and drop, the original
+ // OSDragExchangeData object is lost as soon as we return from the drag
+ // initiation in DragDropController::StartDragAndDrop(). Hence we set the
+ // drag_data_ to a fake drag data object that we created.
+ if (i > 0)
+ UpdateDragData(&data);
+ point.Offset(0, 1);
+ aura::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
+ point,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&drag_event);
+ }
+
+ drag_view->parent()->RemoveChildView(drag_view);
+ // View has been removed. We will not get any of the following drag updates.
+ int num_drags_2 = 23;
+ for (int i = 0; i < num_drags_2; ++i) {
+ UpdateDragData(&data);
+ point.Offset(0, 1);
+ aura::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED,
+ point,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&drag_event);
+ }
+
+ aura::MouseEvent event2(ui::ET_MOUSE_RELEASED, point, 0);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&event2);
+
+ EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
+ EXPECT_EQ(num_drags_1 + num_drags_2 - 1 - drag_view->VerticalDragThreshold(),
+ drag_drop_controller_->num_drag_updates_);
+ EXPECT_TRUE(drag_drop_controller_->drop_received_);
+ EXPECT_EQ(UTF8ToUTF16("I am being dragged"),
+ drag_drop_controller_->drag_string_);
+
+ EXPECT_EQ(1, drag_view->num_drag_enters_);
+ EXPECT_EQ(num_drags_1 - 1 - drag_view->VerticalDragThreshold(),
+ drag_view->num_drag_updates_);
+ EXPECT_EQ(0, drag_view->num_drops_);
+ EXPECT_EQ(0, drag_view->num_drag_exits_);
+ EXPECT_TRUE(drag_view->drag_done_received_);
+ delete widget;
+}
+
+} // namespace test
+} // namespace aura
diff --git a/ash/drag_drop/drag_image_view.cc b/ash/drag_drop/drag_image_view.cc
new file mode 100644
index 0000000..13e4193
--- /dev/null
+++ b/ash/drag_drop/drag_image_view.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 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 "ash/drag_drop/drag_image_view.h"
+
+#include "ui/views/widget/widget.h"
+
+namespace aura_shell {
+namespace internal {
+
+namespace {
+using views::Widget;
+
+Widget* CreateDragWidget() {
+ Widget* drag_widget = new Widget;
+ Widget::InitParams params;
+ params.type = Widget::InitParams::TYPE_TOOLTIP;
+ params.keep_on_top = true;
+ params.accept_events = false;
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.transparent = true;
+ drag_widget->Init(params);
+ drag_widget->SetOpacity(0xFF);
+ return drag_widget;
+}
+}
+
+DragImageView::DragImageView() : views::ImageView() {
+ widget_.reset(CreateDragWidget());
+ widget_->SetContentsView(this);
+ widget_->SetAlwaysOnTop(true);
+
+ // We are owned by the DragDropController.
+ set_parent_owned(false);
+}
+
+DragImageView::~DragImageView() {
+ widget_->Hide();
+}
+
+void DragImageView::SetScreenBounds(const gfx::Rect& bounds) {
+ widget_->SetBounds(bounds);
+}
+
+void DragImageView::SetScreenPosition(const gfx::Point& position) {
+ widget_->SetBounds(gfx::Rect(position, GetPreferredSize()));
+}
+
+void DragImageView::SetWidgetVisible(bool visible) {
+ if (visible != widget_->IsVisible()) {
+ if (visible)
+ widget_->Show();
+ else
+ widget_->Hide();
+ }
+}
+
+} // namespace internal
+} // namespace aura_shell
diff --git a/ash/drag_drop/drag_image_view.h b/ash/drag_drop/drag_image_view.h
new file mode 100644
index 0000000..2e75034
--- /dev/null
+++ b/ash/drag_drop/drag_image_view.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 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 ASH_DRAG_DROP_DRAG_IMAGE_VIEW_H_
+#define ASH_DRAG_DROP_DRAG_IMAGE_VIEW_H_
+#pragma once
+
+#include "ui/views/controls/image_view.h"
+
+namespace views {
+class Widget;
+}
+
+namespace aura_shell {
+namespace internal {
+
+class DragImageView : public views::ImageView {
+ public:
+ DragImageView();
+ virtual ~DragImageView();
+
+ // Sets the bounds of the native widget.
+ void SetScreenBounds(const gfx::Rect& bounds);
+
+ // Sets the position of the native widget.
+ void SetScreenPosition(const gfx::Point& position);
+
+ // Sets the visibility of the native widget.
+ void SetWidgetVisible(bool visible);
+
+ private:
+ scoped_ptr<views::Widget> widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(DragImageView);
+};
+
+} // namespace internal
+} // namespace aura_shell
+
+#endif // ASH_DRAG_DROP_DRAG_IMAGE_VIEW_H_
diff --git a/ash/launcher/launcher_unittest.cc b/ash/launcher/launcher_unittest.cc
index de65658..69ac021 100644
--- a/ash/launcher/launcher_unittest.cc
+++ b/ash/launcher/launcher_unittest.cc
@@ -4,8 +4,8 @@
#include "ash/launcher/launcher.h"
+#include "ash/test/aura_shell_test_base.h"
#include "ui/aura_shell/shell.h"
-#include "ui/aura_shell/test/aura_shell_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
diff --git a/ash/status_area/status_area_view.cc b/ash/status_area/status_area_view.cc
new file mode 100644
index 0000000..5f9fb01
--- /dev/null
+++ b/ash/status_area/status_area_view.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 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 "ash/status_area/status_area_view.h"
+
+#include "base/utf_string_conversions.h"
+#include "grit/ui_resources.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/aura_shell/shell.h"
+#include "ui/aura_shell/shell_window_ids.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/views/widget/widget.h"
+
+namespace aura_shell {
+namespace internal {
+
+StatusAreaView::StatusAreaView()
+ : status_mock_(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_AURA_STATUS_MOCK)) {
+}
+StatusAreaView::~StatusAreaView() {
+}
+
+gfx::Size StatusAreaView::GetPreferredSize() {
+ return gfx::Size(status_mock_.width(), status_mock_.height());
+}
+
+void StatusAreaView::OnPaint(gfx::Canvas* canvas) {
+ canvas->DrawBitmapInt(status_mock_, 0, 0);
+}
+
+AURA_SHELL_EXPORT views::Widget* CreateStatusArea() {
+ StatusAreaView* status_area_view = new StatusAreaView;
+ views::Widget* widget = new views::Widget;
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
+ gfx::Size ps = status_area_view->GetPreferredSize();
+ params.bounds = gfx::Rect(0, 0, ps.width(), ps.height());
+ params.parent = Shell::GetInstance()->GetContainer(
+ aura_shell::internal::kShellWindowId_StatusContainer);
+ params.delegate = status_area_view;
+ params.transparent = true;
+ widget->Init(params);
+ widget->SetContentsView(status_area_view);
+ widget->Show();
+ widget->GetNativeView()->SetName("StatusAreaView");
+ return widget;
+}
+
+} // namespace internal
+} // namespace aura_shell
diff --git a/ash/status_area/status_area_view.h b/ash/status_area/status_area_view.h
new file mode 100644
index 0000000..7e7f8dc
--- /dev/null
+++ b/ash/status_area/status_area_view.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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 ASH_STATUS_AREA_STATUS_AREA_VIEW_H_
+#define ASH_STATUS_AREA_STATUS_AREA_VIEW_H_
+#pragma once
+
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace aura_shell {
+namespace internal {
+
+class StatusAreaView : public views::WidgetDelegateView {
+ public:
+ StatusAreaView();
+ virtual ~StatusAreaView();
+
+ // Overridden from views::View:
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+ private:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
+ SkBitmap status_mock_;
+
+ DISALLOW_COPY_AND_ASSIGN(StatusAreaView);
+};
+
+} // namespace internal
+} // namespace aura_shell
+
+#endif // ASH_STATUS_AREA_STATUS_AREA_VIEW_H_
diff --git a/ash/test/aura_shell_test_base.cc b/ash/test/aura_shell_test_base.cc
new file mode 100644
index 0000000..608f76a
--- /dev/null
+++ b/ash/test/aura_shell_test_base.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2011 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 "ash/test/aura_shell_test_base.h"
+
+#include "ash/test/test_shell_delegate.h"
+#include "ui/aura_shell/shell.h"
+
+namespace aura_shell {
+namespace test {
+
+AuraShellTestBase::AuraShellTestBase() {
+}
+
+AuraShellTestBase::~AuraShellTestBase() {
+}
+
+void AuraShellTestBase::SetUp() {
+ aura::test::AuraTestBase::SetUp();
+
+ // Creates Shell and hook with Desktop.
+ aura_shell::Shell::CreateInstance(new TestShellDelegate);
+}
+
+void AuraShellTestBase::TearDown() {
+ // Flush the message loop to finish pending release tasks.
+ RunAllPendingInMessageLoop();
+
+ // Tear down the shell.
+ aura_shell::Shell::DeleteInstance();
+
+ aura::test::AuraTestBase::TearDown();
+}
+
+} // namespace test
+} // namespace aura_shell
diff --git a/ash/test/aura_shell_test_base.h b/ash/test/aura_shell_test_base.h
new file mode 100644
index 0000000..92cb9ca
--- /dev/null
+++ b/ash/test/aura_shell_test_base.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 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 ASH_TEST_AURA_SHELL_TEST_BASE_H_
+#define ASH_TEST_AURA_SHELL_TEST_BASE_H_
+#pragma once
+
+#include "base/compiler_specific.h"
+#include "ui/aura/test/aura_test_base.h"
+
+namespace aura_shell {
+namespace test {
+
+class AuraShellTestBase : public aura::test::AuraTestBase {
+ public:
+ AuraShellTestBase();
+ virtual ~AuraShellTestBase();
+
+ // testing::Test:
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AuraShellTestBase);
+};
+
+} // namespace test
+} // namespace aura_shell
+
+#endif // ASH_TEST_AURA_SHELL_TEST_BASE_H_
diff --git a/ash/test/test_activation_delegate.cc b/ash/test/test_activation_delegate.cc
new file mode 100644
index 0000000..e92223a
--- /dev/null
+++ b/ash/test/test_activation_delegate.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 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 "ash/test/test_activation_delegate.h"
+
+#include "ash/wm/window_util.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+
+namespace aura_shell {
+namespace test {
+
+////////////////////////////////////////////////////////////////////////////////
+// TestActivationDelegate
+
+TestActivationDelegate::TestActivationDelegate()
+ : window_(NULL),
+ window_was_active_(false),
+ activate_(true),
+ activated_count_(0),
+ lost_active_count_(0),
+ should_activate_count_(0) {
+}
+
+TestActivationDelegate::TestActivationDelegate(bool activate)
+ : window_(NULL),
+ window_was_active_(false),
+ activate_(activate),
+ activated_count_(0),
+ lost_active_count_(0),
+ should_activate_count_(0) {
+}
+
+void TestActivationDelegate::SetWindow(aura::Window* window) {
+ window_ = window;
+ aura::client::SetActivationDelegate(window, this);
+}
+
+bool TestActivationDelegate::ShouldActivate(aura::Event* event) {
+ should_activate_count_++;
+ return activate_;
+}
+void TestActivationDelegate::OnActivated() {
+ activated_count_++;
+}
+void TestActivationDelegate::OnLostActive() {
+ if (lost_active_count_++ == 0)
+ window_was_active_ = IsActiveWindow(window_);
+}
+
+} // namespace test
+} // namespace aura_shell
diff --git a/ash/test/test_activation_delegate.h b/ash/test/test_activation_delegate.h
new file mode 100644
index 0000000..d799745
--- /dev/null
+++ b/ash/test/test_activation_delegate.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2011 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 ASH_TEST_TEST_ACTIVATION_DELEGATE_H_
+#define ASH_TEST_TEST_ACTIVATION_DELEGATE_H_
+#pragma once
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "ui/aura/client/activation_delegate.h"
+
+namespace aura {
+class Window;
+}
+
+namespace aura_shell {
+namespace test {
+
+// A test ActivationDelegate that can be used to track activation changes for
+// an aura::Window.
+class TestActivationDelegate : public aura::client::ActivationDelegate {
+ public:
+ TestActivationDelegate();
+ explicit TestActivationDelegate(bool activate);
+
+ // Associates this delegate with a Window.
+ void SetWindow(aura::Window* window);
+
+ bool window_was_active() const { return window_was_active_; }
+ void set_activate(bool v) { activate_ = v; }
+ int activated_count() const { return activated_count_; }
+ int lost_active_count() const { return lost_active_count_; }
+ int should_activate_count() const { return should_activate_count_; }
+ void Clear() {
+ activated_count_ = lost_active_count_ = should_activate_count_ = 0;
+ window_was_active_ = false;
+ }
+
+ // Overridden from client::ActivationDelegate:
+ virtual bool ShouldActivate(aura::Event* event) OVERRIDE;
+ virtual void OnActivated() OVERRIDE;
+ virtual void OnLostActive() OVERRIDE;
+
+ private:
+ aura::Window* window_;
+ bool window_was_active_;
+ bool activate_;
+ int activated_count_;
+ int lost_active_count_;
+ int should_activate_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestActivationDelegate);
+};
+
+} // namespace test
+} // namespace aura_shell
+
+#endif // ASH_TEST_TEST_ACTIVATION_DELEGATE_H_
diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc
new file mode 100644
index 0000000..eb289f4
--- /dev/null
+++ b/ash/test/test_shell_delegate.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 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 "ash/test/test_shell_delegate.h"
+
+namespace aura_shell {
+namespace test {
+
+TestShellDelegate::TestShellDelegate() {
+}
+
+TestShellDelegate::~TestShellDelegate() {
+}
+
+void TestShellDelegate::CreateNewWindow() {
+}
+
+views::Widget* TestShellDelegate::CreateStatusArea() {
+ return NULL;
+}
+
+void TestShellDelegate::RequestAppListWidget(
+ const gfx::Rect& bounds,
+ const SetWidgetCallback& callback) {
+}
+
+void TestShellDelegate::BuildAppListModel(AppListModel* model) {
+}
+
+AppListViewDelegate* TestShellDelegate::CreateAppListViewDelegate() {
+ return NULL;
+}
+
+void TestShellDelegate::LauncherItemClicked(const LauncherItem& item) {
+}
+
+bool TestShellDelegate::ConfigureLauncherItem(LauncherItem* item) {
+ return true;
+}
+
+} // namespace test
+} // namespace aura_shell
diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h
new file mode 100644
index 0000000..6d922ca
--- /dev/null
+++ b/ash/test/test_shell_delegate.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 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 ASH_TEST_TEST_SHELL_DELEGATE_H_
+#define ASH_TEST_TEST_SHELL_DELEGATE_H_
+#pragma once
+
+#include "base/compiler_specific.h"
+#include "ui/aura_shell/shell_delegate.h"
+
+namespace aura_shell {
+namespace test {
+
+class TestShellDelegate : public ShellDelegate {
+ public:
+ TestShellDelegate();
+ virtual ~TestShellDelegate();
+
+ // Overridden from ShellDelegate:
+ virtual void CreateNewWindow() OVERRIDE;
+ virtual views::Widget* CreateStatusArea() OVERRIDE;
+ virtual void RequestAppListWidget(
+ const gfx::Rect& bounds,
+ const SetWidgetCallback& callback) OVERRIDE;
+ virtual void BuildAppListModel(AppListModel* model) OVERRIDE;
+ virtual AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE;
+ virtual void LauncherItemClicked(const LauncherItem& item) OVERRIDE;
+ virtual bool ConfigureLauncherItem(LauncherItem* item) OVERRIDE;
+};
+
+} // namespace test
+} // namespace aura_shell
+
+#endif // ASH_TEST_TEST_SHELL_DELEGATE_H_
diff --git a/ash/test/test_suite.cc b/ash/test/test_suite.cc
new file mode 100644
index 0000000..eb22a6b
--- /dev/null
+++ b/ash/test/test_suite.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 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 "ash/test/test_suite.h"
+
+#include "base/file_path.h"
+#include "base/path_service.h"
+#include "build/build_config.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_paths.h"
+#include "ui/gfx/compositor/test/compositor_test_support.h"
+#include "ui/gfx/gfx_paths.h"
+
+#if defined(USE_WEBKIT_COMPOSITOR)
+#include "ui/gfx/compositor/compositor_setup.h"
+#else
+#include "ui/gfx/test/gfx_test_utils.h"
+#endif
+
+namespace aura_shell {
+namespace test {
+
+AuraShellTestSuite::AuraShellTestSuite(int argc, char** argv)
+ : TestSuite(argc, argv) {}
+
+void AuraShellTestSuite::Initialize() {
+ base::TestSuite::Initialize();
+
+ gfx::RegisterPathProvider();
+ ui::RegisterPathProvider();
+
+ // Force unittests to run using en-US so if we test against string
+ // output, it'll pass regardless of the system language.
+ ui::ResourceBundle::InitSharedInstance("en-US");
+ ui::CompositorTestSupport::Initialize();
+#if defined(USE_WEBKIT_COMPOSITOR)
+ ui::SetupTestCompositor();
+#else
+ ui::gfx_test_utils::SetupTestCompositor();
+#endif
+}
+
+void AuraShellTestSuite::Shutdown() {
+ ui::CompositorTestSupport::Terminate();
+ ui::ResourceBundle::CleanupSharedInstance();
+
+ base::TestSuite::Shutdown();
+}
+
+} // namespace test
+} // namespace aura_shell
diff --git a/ash/test/test_suite.h b/ash/test/test_suite.h
new file mode 100644
index 0000000..5a32b69
--- /dev/null
+++ b/ash/test/test_suite.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 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 ASH_TEST_TEST_SUITE_H_
+#define ASH_TEST_TEST_SUITE_H_
+#pragma once
+
+#include "base/compiler_specific.h"
+#include "base/test/test_suite.h"
+
+namespace aura_shell {
+namespace test {
+
+class AuraShellTestSuite : public base::TestSuite {
+ public:
+ AuraShellTestSuite(int argc, char** argv);
+
+ protected:
+ // base::TestSuite:
+ virtual void Initialize() OVERRIDE;
+ virtual void Shutdown() OVERRIDE;
+};
+
+} // namespace test
+} // namespace aura_shell
+
+#endif // ASH_TEST_TEST_SUITE_H_
diff --git a/ash/tooltips/tooltip_controller.cc b/ash/tooltips/tooltip_controller.cc
new file mode 100644
index 0000000..20e1097
--- /dev/null
+++ b/ash/tooltips/tooltip_controller.cc
@@ -0,0 +1,296 @@
+// Copyright (c) 2011 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 "ash/tooltips/tooltip_controller.h"
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/location.h"
+#include "base/string_split.h"
+#include "base/time.h"
+#include "ui/aura_shell/aura_shell_switches.h"
+#include "ui/aura/event.h"
+#include "ui/aura/window.h"
+#include "ui/aura_shell/shell.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/text/text_elider.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/widget/widget.h"
+
+namespace {
+
+const SkColor kTooltipBackground = 0xFFFFFFCC;
+const SkColor kTooltipBorder = 0xFF646450;
+const int kTooltipBorderWidth = 1;
+const int kTooltipHorizontalPadding = 3;
+// TODO(derat): This padding is needed on Chrome OS devices but seems excessive
+// when running the same binary on a Linux workstation; presumably there's a
+// difference in font metrics. Rationalize this.
+const int kTooltipVerticalPadding = 2;
+const int kTooltipTimeoutMs = 500;
+
+// FIXME: get cursor offset from actual cursor size.
+const int kCursorOffsetX = 10;
+const int kCursorOffsetY = 15;
+
+// Maximum number of characters we allow in a tooltip.
+const size_t kMaxTooltipLength = 1024;
+
+// Maximum number of lines we allow in the tooltip.
+const size_t kMaxLines = 6;
+
+gfx::Font GetDefaultFont() {
+ // TODO(varunjain): implementation duplicated in tooltip_manager_aura. Figure
+ // out a way to merge.
+ return ui::ResourceBundle::GetSharedInstance().GetFont(
+ ui::ResourceBundle::BaseFont);
+}
+
+int GetMaxWidth(int x, int y) {
+ // TODO(varunjain): implementation duplicated in tooltip_manager_aura. Figure
+ // out a way to merge.
+ gfx::Rect monitor_bounds =
+ gfx::Screen::GetMonitorAreaNearestPoint(gfx::Point(x, y));
+ return (monitor_bounds.width() + 1) / 2;
+}
+
+// Trims the tooltip to fit, setting |text| to the clipped result,
+// |max_width| to the width (in pixels) of the clipped text and |line_count|
+// to the number of lines of text in the tooltip. |x| and |y| give the
+// location of the tooltip in screen coordinates.
+void TrimTooltipToFit(string16* text,
+ int* max_width,
+ int* line_count,
+ int x,
+ int y) {
+ *max_width = 0;
+ *line_count = 0;
+
+ // Clamp the tooltip length to kMaxTooltipLength so that we don't
+ // accidentally DOS the user with a mega tooltip.
+ if (text->length() > kMaxTooltipLength)
+ *text = text->substr(0, kMaxTooltipLength);
+
+ // Determine the available width for the tooltip.
+ int available_width = GetMaxWidth(x, y);
+
+ // Split the string into at most kMaxLines lines.
+ std::vector<string16> lines;
+ base::SplitString(*text, '\n', &lines);
+ if (lines.size() > kMaxLines)
+ lines.resize(kMaxLines);
+ *line_count = static_cast<int>(lines.size());
+
+ // Format each line to fit.
+ gfx::Font font = GetDefaultFont();
+ string16 result;
+ for (std::vector<string16>::iterator i = lines.begin(); i != lines.end();
+ ++i) {
+ string16 elided_text =
+ ui::ElideText(*i, font, available_width, ui::ELIDE_AT_END);
+ *max_width = std::max(*max_width, font.GetStringWidth(elided_text));
+ if (!result.empty())
+ result.push_back('\n');
+ result.append(elided_text);
+ }
+ *text = result;
+}
+
+// Creates a widget of type TYPE_TOOLTIP
+views::Widget* CreateTooltip() {
+ views::Widget* widget = new views::Widget;
+ views::Widget::InitParams params;
+ // For aura, since we set the type to TOOLTIP_TYPE, the widget will get
+ // auto-parented to the MenuAndTooltipsContainer.
+ params.type = views::Widget::InitParams::TYPE_TOOLTIP;
+ params.keep_on_top = true;
+ params.accept_events = false;
+ params.transparent = true;
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget->Init(params);
+ return widget;
+}
+
+} // namespace
+
+namespace aura_shell {
+namespace internal {
+
+// Displays a widget with tooltip using a views::Label.
+class TooltipController::Tooltip {
+ public:
+ Tooltip() {
+ label_.set_background(
+ views::Background::CreateSolidBackground(kTooltipBackground));
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAuraNoShadows)) {
+ label_.set_border(
+ views::Border::CreateSolidBorder(kTooltipBorderWidth,
+ kTooltipBorder));
+ }
+ label_.set_parent_owned(false);
+ widget_.reset(CreateTooltip());
+ widget_->SetContentsView(&label_);
+ widget_->Activate();
+ }
+
+ ~Tooltip() {
+ widget_->Close();
+ }
+
+ // Updates the text on the tooltip and resizes to fit.
+ void SetText(string16 tooltip_text, gfx::Point location) {
+ int max_width, line_count;
+ TrimTooltipToFit(&tooltip_text, &max_width, &line_count,
+ location.x(), location.y());
+ label_.SetText(tooltip_text);
+
+ int width = max_width + 2 * kTooltipHorizontalPadding;
+ int height = label_.GetPreferredSize().height() +
+ 2 * kTooltipVerticalPadding;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAuraNoShadows)) {
+ width += 2 * kTooltipBorderWidth;
+ height += 2 * kTooltipBorderWidth;
+ }
+ SetTooltipBounds(location, width, height);
+ }
+
+ // Shows the tooltip.
+ void Show() {
+ widget_->Show();
+ }
+
+ // Hides the tooltip.
+ void Hide() {
+ widget_->Hide();
+ }
+
+ bool IsVisible() {
+ return widget_->IsVisible();
+ }
+
+ private:
+ views::Label label_;
+ scoped_ptr<views::Widget> widget_;
+
+ // Adjusts the bounds given by the arguments to fit inside the desktop
+ // and applies the adjusted bounds to the label_.
+ void SetTooltipBounds(gfx::Point mouse_pos,
+ int tooltip_width,
+ int tooltip_height) {
+ gfx::Rect tooltip_rect(mouse_pos.x(), mouse_pos.y(), tooltip_width,
+ tooltip_height);
+
+ tooltip_rect.Offset(kCursorOffsetX, kCursorOffsetY);
+ gfx::Rect monitor_bounds =
+ gfx::Screen::GetMonitorAreaNearestPoint(tooltip_rect.origin());
+ widget_->SetBounds(tooltip_rect.AdjustToFit(monitor_bounds));
+ }
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// TooltipController public:
+
+TooltipController::TooltipController()
+ : aura::EventFilter(NULL),
+ tooltip_window_(NULL),
+ tooltip_(new Tooltip) {
+ tooltip_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kTooltipTimeoutMs),
+ this, &TooltipController::TooltipTimerFired);
+}
+
+TooltipController::~TooltipController() {
+ if (tooltip_window_)
+ tooltip_window_->RemoveObserver(this);
+}
+
+void TooltipController::UpdateTooltip(aura::Window* target) {
+ // If tooltip is visible, we may want to hide it. If it is not, we are ok.
+ if (tooltip_window_ == target && tooltip_->IsVisible())
+ UpdateIfRequired();
+}
+
+bool TooltipController::PreHandleKeyEvent(aura::Window* target,
+ aura::KeyEvent* event) {
+ return false;
+}
+
+bool TooltipController::PreHandleMouseEvent(aura::Window* target,
+ aura::MouseEvent* event) {
+ switch (event->type()) {
+ case ui::ET_MOUSE_MOVED:
+ if (tooltip_window_ != target) {
+ if (tooltip_window_)
+ tooltip_window_->RemoveObserver(this);
+ tooltip_window_ = target;
+ tooltip_window_->AddObserver(this);
+ }
+ curr_mouse_loc_ = event->location();
+ if (tooltip_timer_.IsRunning())
+ tooltip_timer_.Reset();
+
+ if (tooltip_->IsVisible())
+ UpdateIfRequired();
+ break;
+ case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_RELEASED:
+ case ui::ET_MOUSE_DRAGGED:
+ case ui::ET_MOUSEWHEEL:
+ // Hide the tooltip for click, release, drag, wheel events.
+ if (tooltip_->IsVisible())
+ tooltip_->Hide();
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+ui::TouchStatus TooltipController::PreHandleTouchEvent(
+ aura::Window* target,
+ aura::TouchEvent* event) {
+ return ui::TOUCH_STATUS_UNKNOWN;
+}
+
+void TooltipController::OnWindowDestroyed(aura::Window* window) {
+ if (tooltip_window_ == window) {
+ tooltip_window_->RemoveObserver(this);
+ tooltip_window_ = NULL;
+ }
+}
+
+void TooltipController::TooltipTimerFired() {
+ UpdateIfRequired();
+}
+
+void TooltipController::UpdateIfRequired() {
+ string16 tooltip_text;
+ if (tooltip_window_)
+ tooltip_text = *aura::client::GetTooltipText(tooltip_window_);
+
+ if (tooltip_text_ != tooltip_text) {
+ tooltip_text_ = tooltip_text;
+ if (tooltip_text_.empty()) {
+ tooltip_->Hide();
+ } else {
+ string16 tooltip_text(tooltip_text_);
+ gfx::Point widget_loc = curr_mouse_loc_;
+ widget_loc = widget_loc.Add(tooltip_window_->GetScreenBounds().origin());
+ tooltip_->SetText(tooltip_text, widget_loc);
+ tooltip_->Show();
+ }
+ }
+}
+
+} // namespace internal
+} // namespace aura_shell
diff --git a/ash/tooltips/tooltip_controller.h b/ash/tooltips/tooltip_controller.h
new file mode 100644
index 0000000..41daaa22
--- /dev/null
+++ b/ash/tooltips/tooltip_controller.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 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 ASH_TOOLTIPS_TOOLTIP_CONTROLLER_H_
+#define ASH_TOOLTIPS_TOOLTIP_CONTROLLER_H_
+#pragma once
+
+#include "base/memory/scoped_ptr.h"
+#include "base/string16.h"
+#include "base/timer.h"
+#include "ui/aura/client/tooltip_client.h"
+#include "ui/aura/event_filter.h"
+#include "ui/aura/window_observer.h"
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/gfx/point.h"
+
+namespace aura {
+class KeyEvent;
+class MouseEvent;
+class TouchEvent;
+class Window;
+}
+
+namespace aura_shell {
+
+namespace test {
+class TooltipControllerTest;
+} // namespace test
+
+namespace internal {
+
+// TooltipController provides tooltip functionality for aura shell.
+class AURA_SHELL_EXPORT TooltipController : public aura::client::TooltipClient,
+ public aura::EventFilter,
+ public aura::WindowObserver {
+ public:
+ TooltipController();
+ virtual ~TooltipController();
+
+ // Overridden from aura::client::TooltipClient.
+ void UpdateTooltip(aura::Window* target);
+
+ // Overridden from aura::EventFilter.
+ virtual bool PreHandleKeyEvent(aura::Window* target,
+ aura::KeyEvent* event) OVERRIDE;
+ virtual bool PreHandleMouseEvent(aura::Window* target,
+ aura::MouseEvent* event) OVERRIDE;
+ virtual ui::TouchStatus PreHandleTouchEvent(aura::Window* target,
+ aura::TouchEvent* event) OVERRIDE;
+
+ // Overridden from aura::WindowObserver.
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
+ private:
+ friend class aura_shell::test::TooltipControllerTest;
+
+ class Tooltip;
+
+ void TooltipTimerFired();
+
+ // Updates the tooltip if required (if there is any change in the tooltip
+ // text or the aura::Window.
+ void UpdateIfRequired();
+
+ aura::Window* tooltip_window_;
+ string16 tooltip_text_;
+ scoped_ptr<Tooltip> tooltip_;
+
+ base::RepeatingTimer<TooltipController> tooltip_timer_;
+
+ gfx::Point curr_mouse_loc_;
+
+ DISALLOW_COPY_AND_ASSIGN(TooltipController);
+};
+
+} // namespace internal
+} // namespace aura_shell
+
+#endif // ASH_TOOLTIPS_TOOLTIP_CONTROLLER_H_
diff --git a/ash/tooltips/tooltip_controller_unittest.cc b/ash/tooltips/tooltip_controller_unittest.cc
new file mode 100644
index 0000000..8ac5937
--- /dev/null
+++ b/ash/tooltips/tooltip_controller_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2011 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 "ash/test/aura_shell_test_base.h"
+#include "ash/tooltips/tooltip_controller.h"
+#include "base/utf_string_conversions.h"
+#include "ui/aura/client/tooltip_client.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/gfx/point.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace aura_shell {
+namespace test {
+
+namespace {
+
+class TooltipTestView : public views::View {
+ public:
+ TooltipTestView() : views::View() {
+ }
+
+ void set_tooltip_text(string16 tooltip_text) { tooltip_text_ = tooltip_text; }
+
+ // Overridden from views::View
+ bool GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+ *tooltip = tooltip_text_;
+ return true;
+ }
+
+ private:
+ string16 tooltip_text_;
+
+ DISALLOW_COPY_AND_ASSIGN(TooltipTestView);
+};
+
+views::Widget* CreateNewWidget() {
+ views::Widget* widget = new views::Widget;
+ views::Widget::InitParams params;
+ params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
+ params.accept_events = true;
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.parent = aura::RootWindow::GetInstance();
+ params.child = true;
+ widget->Init(params);
+ widget->Show();
+ return widget;
+}
+
+void AddViewToWidgetAndResize(views::Widget* widget, views::View* view) {
+ if (!widget->GetContentsView()) {
+ views::View* contents_view = new views::View;
+ widget->SetContentsView(contents_view);
+ }
+
+ views::View* contents_view = widget->GetContentsView();
+ contents_view->AddChildView(view);
+ view->SetBounds(contents_view->width(), 0, 100, 100);
+ gfx::Rect contents_view_bounds = contents_view->bounds();
+ contents_view_bounds = contents_view_bounds.Union(view->bounds());
+ contents_view->SetBoundsRect(contents_view_bounds);
+ widget->SetBounds(contents_view_bounds);
+}
+
+aura_shell::internal::TooltipController* GetController() {
+ return static_cast<aura_shell::internal::TooltipController*>(
+ aura::client::GetTooltipClient());
+}
+
+void SimulateMouseMoveAtPoint(const gfx::Point& point) {
+ aura::MouseEvent event(ui::ET_MOUSE_MOVED, point, 0);
+ aura::RootWindow::GetInstance()->DispatchMouseEvent(&event);
+}
+
+} // namespace
+
+class TooltipControllerTest : public AuraShellTestBase {
+ public:
+ TooltipControllerTest() {}
+ virtual ~TooltipControllerTest() {}
+
+ string16 GetTooltipText() {
+ return GetController()->tooltip_text_;
+ }
+
+ aura::Window* GetTooltipWindow() {
+ return GetController()->tooltip_window_;
+ }
+
+ void FireTooltipTimer() {
+ GetController()->TooltipTimerFired();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest);
+};
+
+TEST_F(TooltipControllerTest, NonNullTooltipClient) {
+ EXPECT_TRUE(aura::client::GetTooltipClient() != NULL);
+ EXPECT_EQ(ASCIIToUTF16(""), GetTooltipText());
+ EXPECT_EQ(NULL, GetTooltipWindow());
+}
+
+TEST_F(TooltipControllerTest, ViewTooltip) {
+ views::Widget* widget = CreateNewWidget();
+ TooltipTestView* view = new TooltipTestView;
+ AddViewToWidgetAndResize(widget, view);
+ view->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
+ EXPECT_EQ(ASCIIToUTF16(""), GetTooltipText());
+ EXPECT_EQ(NULL, GetTooltipWindow());
+
+ gfx::Point point = gfx::Rect(view->bounds()).CenterPoint();
+ SimulateMouseMoveAtPoint(point);
+ aura::Window* window = widget->GetNativeView();
+ EXPECT_EQ(window,
+ aura::RootWindow::GetInstance()->GetEventHandlerForPoint(point));
+ EXPECT_TRUE(aura::client::GetTooltipText(window) != NULL);
+ string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
+ EXPECT_EQ(expected_tooltip, *aura::client::GetTooltipText(window));
+ EXPECT_EQ(ASCIIToUTF16(""), GetTooltipText());
+ EXPECT_EQ(window, GetTooltipWindow());
+
+ // Fire tooltip timer so tooltip becomes visible.
+ FireTooltipTimer();
+
+ point.Offset(1, 0);
+ SimulateMouseMoveAtPoint(point);
+
+ EXPECT_TRUE(aura::client::GetTooltipText(window) != NULL);
+ EXPECT_EQ(expected_tooltip, *aura::client::GetTooltipText(window));
+ EXPECT_EQ(expected_tooltip, GetTooltipText());
+ EXPECT_EQ(window, GetTooltipWindow());
+}
+
+TEST_F(TooltipControllerTest, TooltipsInMultipleViews) {
+ views::Widget* widget = CreateNewWidget();
+ TooltipTestView* view1 = new TooltipTestView;
+ AddViewToWidgetAndResize(widget, view1);
+ view1->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
+ EXPECT_EQ(ASCIIToUTF16(""), GetTooltipText());
+ EXPECT_EQ(NULL, GetTooltipWindow());
+
+ TooltipTestView* view2 = new TooltipTestView;
+ AddViewToWidgetAndResize(widget, view2);
+
+ aura::Window* window = widget->GetNativeView();
+ gfx::Point point = gfx::Rect(view1->bounds()).CenterPoint();
+
+ // Fire tooltip timer so tooltip becomes visible.
+ SimulateMouseMoveAtPoint(point);
+ FireTooltipTimer();
+ for (int i = 0; i < 50; i++) {
+ point.Offset(1, 0);
+ SimulateMouseMoveAtPoint(point);
+ EXPECT_EQ(window,
+ aura::RootWindow::GetInstance()->GetEventHandlerForPoint(point));
+ EXPECT_TRUE(aura::client::GetTooltipText(window) != NULL);
+ string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
+ EXPECT_EQ(expected_tooltip, *aura::client::GetTooltipText(window));
+ EXPECT_EQ(expected_tooltip, GetTooltipText());
+ EXPECT_EQ(window, GetTooltipWindow());
+ }
+ for (int i = 0; i < 50; i++) {
+ point.Offset(1, 0);
+ SimulateMouseMoveAtPoint(point);
+ EXPECT_EQ(window,
+ aura::RootWindow::GetInstance()->GetEventHandlerForPoint(point));
+ EXPECT_TRUE(aura::client::GetTooltipText(window) != NULL);
+ string16 expected_tooltip = ASCIIToUTF16("");
+ EXPECT_EQ(expected_tooltip, *aura::client::GetTooltipText(window));
+ EXPECT_EQ(expected_tooltip, GetTooltipText());
+ EXPECT_EQ(window, GetTooltipWindow());
+ }
+}
+
+} // namespace test
+} // namespace aura_shell
diff --git a/ash/wm/activation_controller_unittest.cc b/ash/wm/activation_controller_unittest.cc
index e2b1470..1d3ad2d 100644
--- a/ash/wm/activation_controller_unittest.cc
+++ b/ash/wm/activation_controller_unittest.cc
@@ -4,14 +4,14 @@
#include "ash/wm/activation_controller.h"
+#include "ash/test/aura_shell_test_base.h"
+#include "ash/test/test_activation_delegate.h"
#include "ash/wm/window_util.h"
#include "ui/aura/focus_manager.h"
#include "ui/aura/root_window.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura_shell/test/aura_shell_test_base.h"
-#include "ui/aura_shell/test/test_activation_delegate.h"
#if defined(OS_WIN)
// Windows headers define macros for these function names which screw with us.
diff --git a/ash/wm/image_grid_unittest.cc b/ash/wm/image_grid_unittest.cc
index cc7b260..3bb8714 100644
--- a/ash/wm/image_grid_unittest.cc
+++ b/ash/wm/image_grid_unittest.cc
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ash/test/aura_shell_test_base.h"
#include "ash/wm/image_grid.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/aura_shell/test/aura_shell_test_base.h"
#include "ui/gfx/image/image.h"
using aura_shell::internal::ImageGrid;
diff --git a/ash/wm/modal_container_layout_manager_unittest.cc b/ash/wm/modal_container_layout_manager_unittest.cc
index b55bc94..4264a86 100644
--- a/ash/wm/modal_container_layout_manager_unittest.cc
+++ b/ash/wm/modal_container_layout_manager_unittest.cc
@@ -4,6 +4,7 @@
#include "ash/wm/modal_container_layout_manager.h"
+#include "ash/test/aura_shell_test_base.h"
#include "ash/wm/window_util.h"
#include "base/compiler_specific.h"
#include "ui/aura/root_window.h"
@@ -11,7 +12,6 @@
#include "ui/aura/window.h"
#include "ui/aura_shell/shell.h"
#include "ui/aura_shell/shell_window_ids.h"
-#include "ui/aura_shell/test/aura_shell_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
diff --git a/ash/wm/root_window_event_filter_unittest.cc b/ash/wm/root_window_event_filter_unittest.cc
index c3b8392..7b1a2b4 100644
--- a/ash/wm/root_window_event_filter_unittest.cc
+++ b/ash/wm/root_window_event_filter_unittest.cc
@@ -4,6 +4,7 @@
#include "ash/wm/root_window_event_filter.h"
+#include "ash/test/test_activation_delegate.h"
#include "ash/wm/activation_controller.h"
#include "ash/wm/window_util.h"
#include "ui/aura/client/activation_delegate.h"
@@ -16,7 +17,6 @@
#include "ui/aura/test/test_event_filter.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura_shell/shell_window_ids.h"
-#include "ui/aura_shell/test/test_activation_delegate.h"
#include "ui/base/hit_test.h"
#include "ui/gfx/screen.h"
diff --git a/ash/wm/shadow_controller_unittest.cc b/ash/wm/shadow_controller_unittest.cc
index 5bc57ce..6f8efe4 100644
--- a/ash/wm/shadow_controller_unittest.cc
+++ b/ash/wm/shadow_controller_unittest.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <vector>
+#include "ash/test/aura_shell_test_base.h"
#include "ash/wm/shadow.h"
#include "ash/wm/shadow_types.h"
#include "ash/wm/window_properties.h"
@@ -14,7 +15,6 @@
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/aura_shell/shell.h"
-#include "ui/aura_shell/test/aura_shell_test_base.h"
#include "ui/gfx/compositor/layer.h"
namespace aura_shell {
diff --git a/ash/wm/shelf_layout_manager_unittest.cc b/ash/wm/shelf_layout_manager_unittest.cc
index 77974b1..c1daf9a 100644
--- a/ash/wm/shelf_layout_manager_unittest.cc
+++ b/ash/wm/shelf_layout_manager_unittest.cc
@@ -5,12 +5,12 @@
#include "ash/wm/shelf_layout_manager.h"
#include "ash/launcher/launcher.h"
+#include "ash/test/aura_shell_test_base.h"
#include "ui/aura/root_window.h"
#include "ui/aura/screen_aura.h"
#include "ui/aura/window.h"
#include "ui/aura_shell/shell.h"
#include "ui/aura_shell/shell_window_ids.h"
-#include "ui/aura_shell/test/aura_shell_test_base.h"
#include "ui/base/animation/animation_container_element.h"
#include "ui/gfx/compositor/layer_animator.h"
#include "ui/gfx/compositor/layer.h"