diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-23 19:08:04 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-23 19:08:04 +0000 |
commit | a1b7a82fbb37bce916ef205bf862cb940b5307df (patch) | |
tree | 91be529daf93c6b1d3186876b042ac3e2adcfa58 | |
parent | 4447016b31992cea934c3f83fb5d0ddd4147f56e (diff) | |
download | chromium_src-a1b7a82fbb37bce916ef205bf862cb940b5307df.zip chromium_src-a1b7a82fbb37bce916ef205bf862cb940b5307df.tar.gz chromium_src-a1b7a82fbb37bce916ef205bf862cb940b5307df.tar.bz2 |
Gets tooltips to work for desktop aura. This constrains the tooltips
to the bounds of the Widget. We'll see how well that works.
BUG=175441
TEST=make sure tooltips work for win-aura.
R=varunjain@chromium.org
Review URL: https://chromiumcodereview.appspot.com/12334017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@184324 0039d316-1c4b-4281-b951-d872f2087c98
24 files changed, 813 insertions, 520 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index e7f1b7e..6336f08 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -291,8 +291,6 @@ 'system/user/user_observer.h', 'system/web_notification/web_notification_tray.cc', 'system/web_notification/web_notification_tray.h', - 'tooltips/tooltip_controller.cc', - 'tooltips/tooltip_controller.h', 'touch/touch_observer_hud.cc', 'touch/touch_observer_hud.h', 'touch/touch_uma.cc', diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc index 13636d8..bc0877d 100644 --- a/ash/ash_switches.cc +++ b/ash/ash_switches.cc @@ -108,9 +108,6 @@ const char kAshTouchHud[] = "ash-touch-hud"; // instead of displaying an interactive animation. const char kAuraLegacyPowerButton[] = "aura-legacy-power-button"; -// Avoid drawing drop shadows under windows. -const char kAuraNoShadows[] = "aura-no-shadows"; - // Overrides all displays' orientation. The value should be one of 0 // (normal), 1 (90 degrees clockwise), 2 (180 degrees) or 3 (270 // degrees clockwise). diff --git a/ash/ash_switches.h b/ash/ash_switches.h index 233bfbd..0a65d77 100644 --- a/ash/ash_switches.h +++ b/ash/ash_switches.h @@ -44,7 +44,6 @@ ASH_EXPORT extern const char kAshImmersiveHideTabIndicators[]; ASH_EXPORT extern const char kAshSecondaryDisplayLayout[]; ASH_EXPORT extern const char kAshTouchHud[]; ASH_EXPORT extern const char kAuraLegacyPowerButton[]; -ASH_EXPORT extern const char kAuraNoShadows[]; ASH_EXPORT extern const char kAshOverrideDisplayOrientation[]; } // namespace switches diff --git a/ash/shell.cc b/ash/shell.cc index 1a386ea..e44c477 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -34,7 +34,6 @@ #include "ash/system/status_area_widget.h" #include "ash/system/tray/system_tray_delegate.h" #include "ash/system/tray/system_tray_notifier.h" -#include "ash/tooltips/tooltip_controller.h" #include "ash/touch/touch_observer_hud.h" #include "ash/wm/activation_controller.h" #include "ash/wm/always_on_top_controller.h" @@ -89,6 +88,7 @@ #include "ui/views/corewm/focus_controller.h" #include "ui/views/corewm/input_method_event_filter.h" #include "ui/views/corewm/shadow_controller.h" +#include "ui/views/corewm/tooltip_controller.h" #include "ui/views/corewm/visibility_controller.h" #include "ui/views/corewm/window_modality_controller.h" #include "ui/views/focus/focus_manager_factory.h" @@ -536,8 +536,8 @@ void Shell::Init() { video_detector_.reset(new VideoDetector); window_cycle_controller_.reset(new WindowCycleController(activation_client_)); - tooltip_controller_.reset(new internal::TooltipController( - drag_drop_controller_.get())); + tooltip_controller_.reset(new views::corewm::TooltipController( + gfx::SCREEN_TYPE_ALTERNATE)); AddPreTargetHandler(tooltip_controller_.get()); event_client_.reset(new internal::EventClientImpl); @@ -553,7 +553,7 @@ void Shell::Init() { // StatusAreaWidget uses Shell's CapsLockDelegate. caps_lock_delegate_.reset(delegate_->CreateCapsLockDelegate()); - if (!command_line->HasSwitch(switches::kAuraNoShadows)) { + if (!command_line->HasSwitch(views::corewm::switches::kNoDropShadows)) { resize_shadow_controller_.reset(new internal::ResizeShadowController()); shadow_controller_.reset( new views::corewm::ShadowController(GetPrimaryRootWindow())); diff --git a/ash/shell.h b/ash/shell.h index d57f519..168854f 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -58,6 +58,7 @@ namespace corewm { class CompoundEventFilter; class InputMethodEventFilter; class ShadowController; +class TooltipController; class VisibilityController; class WindowModalityController; } @@ -118,7 +119,6 @@ class SlowAnimationEventFilter; class StatusAreaWidget; class SystemGestureEventFilter; class SystemModalContainerEventFilter; -class TooltipController; class TouchObserverHUD; class WorkspaceController; } @@ -285,7 +285,7 @@ class ASH_EXPORT Shell views::corewm::CompoundEventFilter* env_filter() { return env_filter_.get(); } - internal::TooltipController* tooltip_controller() { + views::corewm::TooltipController* tooltip_controller() { return tooltip_controller_.get(); } internal::TouchObserverHUD* touch_observer_hud() { @@ -526,7 +526,7 @@ class ASH_EXPORT Shell scoped_ptr<views::corewm::VisibilityController> visibility_controller_; scoped_ptr<views::corewm::WindowModalityController> window_modality_controller_; - scoped_ptr<internal::TooltipController> tooltip_controller_; + scoped_ptr<views::corewm::TooltipController> tooltip_controller_; scoped_ptr<DesktopBackgroundController> desktop_background_controller_; scoped_ptr<PowerButtonController> power_button_controller_; scoped_ptr<SessionStateController> session_state_controller_; diff --git a/ash/shell/lock_view.cc b/ash/shell/lock_view.cc index 56c0f27..16895c6 100644 --- a/ash/shell/lock_view.cc +++ b/ash/shell/lock_view.cc @@ -6,13 +6,13 @@ #include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/shell/example_factory.h" -#include "ash/tooltips/tooltip_controller.h" #include "base/utf_string_conversions.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font.h" #include "ui/views/controls/button/text_button.h" +#include "ui/views/corewm/tooltip_controller.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -100,6 +100,7 @@ void CreateLockScreen() { widget->GetNativeView()->SetName("LockView"); widget->GetNativeView()->Focus(); + // TODO: it shouldn't be necessary to invoke UpdateTooltip() here. Shell::GetInstance()->tooltip_controller()->UpdateTooltip( widget->GetNativeView()); } diff --git a/ash/tooltips/tooltip_controller_unittest.cc b/ash/tooltips/tooltip_controller_unittest.cc index f594de4..85ded1e 100644 --- a/ash/tooltips/tooltip_controller_unittest.cc +++ b/ash/tooltips/tooltip_controller_unittest.cc @@ -5,7 +5,6 @@ #include "ash/display/display_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/tooltips/tooltip_controller.h" #include "ash/wm/cursor_manager.h" #include "base/utf_string_conversions.h" #include "ui/aura/client/tooltip_client.h" @@ -14,37 +13,26 @@ #include "ui/aura/test/event_generator.h" #include "ui/aura/window.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/views/corewm/tooltip_controller.h" +#include "ui/views/corewm/tooltip_controller_test_helper.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" +using views::corewm::TooltipController; +using views::corewm::test::TooltipTestView; +using views::corewm::test::TooltipControllerTestHelper; + +// The tests in this file exercise bits of TooltipController that are hard to +// test outside of ash. Meaning these tests require the shell and related things +// to be installed. + namespace ash { 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 - virtual bool GetTooltipText(const gfx::Point& p, - string16* tooltip) const OVERRIDE { - *tooltip = tooltip_text_; - return true; - } - - private: - string16 tooltip_text_; - - DISALLOW_COPY_AND_ASSIGN(TooltipTestView); -}; - views::Widget* CreateNewWidgetWithBoundsOn(int display, const gfx::Rect& bounds) { views::Widget* widget = new views::Widget; @@ -80,8 +68,8 @@ void AddViewToWidgetAndResize(views::Widget* widget, views::View* view) { contents_view_bounds.size())); } -ash::internal::TooltipController* GetController() { - return static_cast<ash::internal::TooltipController*>( +TooltipController* GetController() { + return static_cast<TooltipController*>( aura::client::GetTooltipClient(Shell::GetPrimaryRootWindow())); } @@ -97,43 +85,13 @@ class TooltipControllerTest : public AshTestBase { TooltipControllerTest() {} virtual ~TooltipControllerTest() {} - string16 GetTooltipText() { - return GetController()->tooltip_text_; - } - - aura::Window* GetTooltipWindow() { - return GetController()->tooltip_window_; + virtual void SetUp() OVERRIDE { + AshTestBase::SetUp(); + helper_.reset(new TooltipControllerTestHelper(GetController())); } - void FireTooltipTimer() { - GetController()->TooltipTimerFired(); - } - - bool IsTooltipTimerRunning() { - return GetController()->tooltip_timer_.IsRunning(); - } - - void FireTooltipShownTimer() { - GetController()->tooltip_shown_timer_.Stop(); - GetController()->TooltipShownTimerFired(); - } - - bool IsTooltipShownTimerRunning() { - return GetController()->tooltip_shown_timer_.IsRunning(); - } - - bool IsTooltipVisible() { - return GetController()->IsTooltipVisible(); - } - - void TrimTooltipToFit(string16* text, - int* max_width, - int* line_count, - int x, - int y) { - ash::internal::TooltipController::TrimTooltipToFit(text, max_width, - line_count, x, y); - } + protected: + scoped_ptr<TooltipControllerTestHelper> helper_; private: DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest); @@ -142,112 +100,9 @@ class TooltipControllerTest : public AshTestBase { TEST_F(TooltipControllerTest, NonNullTooltipClient) { EXPECT_TRUE(aura::client::GetTooltipClient(Shell::GetPrimaryRootWindow()) != NULL); - EXPECT_EQ(string16(), GetTooltipText()); - EXPECT_EQ(NULL, GetTooltipWindow()); - EXPECT_FALSE(IsTooltipVisible()); -} - -TEST_F(TooltipControllerTest, ViewTooltip) { - scoped_ptr<views::Widget> widget(CreateNewWidgetOn(0)); - TooltipTestView* view = new TooltipTestView; - AddViewToWidgetAndResize(widget.get(), view); - view->set_tooltip_text(ASCIIToUTF16("Tooltip Text")); - EXPECT_EQ(string16(), GetTooltipText()); - EXPECT_EQ(NULL, GetTooltipWindow()); - aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); - generator.MoveMouseToCenterOf(widget->GetNativeView()); - - aura::Window* window = widget->GetNativeView(); - EXPECT_EQ(window, Shell::GetPrimaryRootWindow()->GetEventHandlerForPoint( - generator.current_location())); - string16 expected_tooltip = ASCIIToUTF16("Tooltip Text"); - EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); - EXPECT_EQ(string16(), GetTooltipText()); - EXPECT_EQ(window, GetTooltipWindow()); - - // Fire tooltip timer so tooltip becomes visible. - FireTooltipTimer(); - - EXPECT_TRUE(IsTooltipVisible()); - generator.MoveMouseBy(1, 0); - - EXPECT_TRUE(IsTooltipVisible()); - EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); - EXPECT_EQ(expected_tooltip, GetTooltipText()); - EXPECT_EQ(window, GetTooltipWindow()); -} - -TEST_F(TooltipControllerTest, TooltipsInMultipleViews) { - scoped_ptr<views::Widget> widget(CreateNewWidgetOn(0)); - TooltipTestView* view1 = new TooltipTestView; - AddViewToWidgetAndResize(widget.get(), view1); - view1->set_tooltip_text(ASCIIToUTF16("Tooltip Text")); - EXPECT_EQ(string16(), GetTooltipText()); - EXPECT_EQ(NULL, GetTooltipWindow()); - - TooltipTestView* view2 = new TooltipTestView; - AddViewToWidgetAndResize(widget.get(), view2); - - aura::Window* window = widget->GetNativeView(); - - // Fire tooltip timer so tooltip becomes visible. - aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); - generator.MoveMouseRelativeTo(window, - view1->bounds().CenterPoint()); - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); - for (int i = 0; i < 49; ++i) { - generator.MoveMouseBy(1, 0); - EXPECT_TRUE(IsTooltipVisible()); - EXPECT_EQ(window, - Shell::GetPrimaryRootWindow()->GetEventHandlerForPoint( - generator.current_location())); - 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 < 49; ++i) { - generator.MoveMouseBy(1, 0); - EXPECT_FALSE(IsTooltipVisible()); - EXPECT_EQ(window, - Shell::GetPrimaryRootWindow()->GetEventHandlerForPoint( - generator.current_location())); - string16 expected_tooltip; // = "" - EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); - EXPECT_EQ(expected_tooltip, GetTooltipText()); - EXPECT_EQ(window, GetTooltipWindow()); - } -} - -TEST_F(TooltipControllerTest, EnableOrDisableTooltips) { - scoped_ptr<views::Widget> widget(CreateNewWidgetOn(0)); - TooltipTestView* view = new TooltipTestView; - AddViewToWidgetAndResize(widget.get(), view); - view->set_tooltip_text(ASCIIToUTF16("Tooltip Text")); - EXPECT_EQ(string16(), GetTooltipText()); - EXPECT_EQ(NULL, GetTooltipWindow()); - - aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); - generator.MoveMouseRelativeTo(widget->GetNativeView(), - view->bounds().CenterPoint()); - string16 expected_tooltip = ASCIIToUTF16("Tooltip Text"); - - // Fire tooltip timer so tooltip becomes visible. - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); - - // Diable tooltips and check again. - GetController()->SetTooltipsEnabled(false); - EXPECT_FALSE(IsTooltipVisible()); - FireTooltipTimer(); - EXPECT_FALSE(IsTooltipVisible()); - - // Enable tooltips back and check again. - GetController()->SetTooltipsEnabled(true); - EXPECT_FALSE(IsTooltipVisible()); - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); + EXPECT_EQ(string16(), helper_->GetTooltipText()); + EXPECT_EQ(NULL, helper_->GetTooltipWindow()); + EXPECT_FALSE(helper_->IsTooltipVisible()); } TEST_F(TooltipControllerTest, HideTooltipWhenCursorHidden) { @@ -255,8 +110,8 @@ TEST_F(TooltipControllerTest, HideTooltipWhenCursorHidden) { TooltipTestView* view = new TooltipTestView; AddViewToWidgetAndResize(widget.get(), view); view->set_tooltip_text(ASCIIToUTF16("Tooltip Text")); - EXPECT_EQ(string16(), GetTooltipText()); - EXPECT_EQ(NULL, GetTooltipWindow()); + EXPECT_EQ(string16(), helper_->GetTooltipText()); + EXPECT_EQ(NULL, helper_->GetTooltipWindow()); aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); generator.MoveMouseRelativeTo(widget->GetNativeView(), @@ -264,220 +119,18 @@ TEST_F(TooltipControllerTest, HideTooltipWhenCursorHidden) { string16 expected_tooltip = ASCIIToUTF16("Tooltip Text"); // Fire tooltip timer so tooltip becomes visible. - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); // Hide the cursor and check again. ash::Shell::GetInstance()->cursor_manager()->DisableMouseEvents(); - FireTooltipTimer(); - EXPECT_FALSE(IsTooltipVisible()); + helper_->FireTooltipTimer(); + EXPECT_FALSE(helper_->IsTooltipVisible()); // Show the cursor and re-check. ash::Shell::GetInstance()->cursor_manager()->EnableMouseEvents(); - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); -} - -TEST_F(TooltipControllerTest, TrimTooltipToFitTests) { - string16 tooltip; - int max_width, line_count, expect_lines; - int max_pixel_width = 400; // copied from constants in tooltip_controller.cc - int max_lines = 10; // copied from constants in tooltip_controller.cc - gfx::Font font = GetDefaultFont(); - size_t tooltip_len; - - // Error in computed size vs. expected size should not be greater than the - // size of the longest word. - int error_in_pixel_width = font.GetStringWidth(ASCIIToUTF16("tooltip")); - - // Long tooltips should wrap to next line - tooltip.clear(); - max_width = line_count = -1; - expect_lines = 3; - for (; font.GetStringWidth(tooltip) <= (expect_lines - 1) * max_pixel_width;) - tooltip.append(ASCIIToUTF16("This is part of the tooltip")); - tooltip_len = tooltip.length(); - TrimTooltipToFit(&tooltip, &max_width, &line_count, 0, 0); - EXPECT_NEAR(max_pixel_width, max_width, error_in_pixel_width); - EXPECT_EQ(expect_lines, line_count); - EXPECT_EQ(tooltip_len + expect_lines - 1, tooltip.length()); - - // More than |max_lines| lines should get truncated at 10 lines. - tooltip.clear(); - max_width = line_count = -1; - expect_lines = 13; - for (; font.GetStringWidth(tooltip) <= (expect_lines - 1) * max_pixel_width;) - tooltip.append(ASCIIToUTF16("This is part of the tooltip")); - TrimTooltipToFit(&tooltip, &max_width, &line_count, 0, 0); - EXPECT_NEAR(max_pixel_width, max_width, error_in_pixel_width); - EXPECT_EQ(max_lines, line_count); - - // Long multi line tooltips should wrap individual lines. - tooltip.clear(); - max_width = line_count = -1; - expect_lines = 4; - for (; font.GetStringWidth(tooltip) <= (expect_lines - 2) * max_pixel_width;) - tooltip.append(ASCIIToUTF16("This is part of the tooltip")); - tooltip.insert(tooltip.length() / 2, ASCIIToUTF16("\n")); - tooltip_len = tooltip.length(); - TrimTooltipToFit(&tooltip, &max_width, &line_count, 0, 0); - EXPECT_NEAR(max_pixel_width, max_width, error_in_pixel_width); - EXPECT_EQ(expect_lines, line_count); - // We may have inserted the line break above near a space which will get - // trimmed. Hence we may be off by 1 in the final tooltip length calculation. - EXPECT_NEAR(tooltip_len + expect_lines - 2, tooltip.length(), 1); - -#if !defined(OS_WIN) - // Tooltip with really long word gets elided. - tooltip.clear(); - max_width = line_count = -1; - tooltip = UTF8ToUTF16(std::string('a', max_pixel_width)); - TrimTooltipToFit(&tooltip, &max_width, &line_count, 0, 0); - EXPECT_NEAR(max_pixel_width, max_width, 5); - EXPECT_EQ(1, line_count); - EXPECT_EQ(ui::ElideText(UTF8ToUTF16(std::string('a', max_pixel_width)), font, - max_pixel_width, ui::ELIDE_AT_END), tooltip); -#endif - - // Normal small tooltip should stay as is. - tooltip.clear(); - max_width = line_count = -1; - tooltip = ASCIIToUTF16("Small Tooltip"); - TrimTooltipToFit(&tooltip, &max_width, &line_count, 0, 0); - EXPECT_EQ(font.GetStringWidth(ASCIIToUTF16("Small Tooltip")), max_width); - EXPECT_EQ(1, line_count); - EXPECT_EQ(ASCIIToUTF16("Small Tooltip"), tooltip); - - // Normal small multi-line tooltip should stay as is. - tooltip.clear(); - max_width = line_count = -1; - tooltip = ASCIIToUTF16("Multi line\nTooltip"); - TrimTooltipToFit(&tooltip, &max_width, &line_count, 0, 0); - int expected_width = font.GetStringWidth(ASCIIToUTF16("Multi line")); - expected_width = std::max(expected_width, - font.GetStringWidth(ASCIIToUTF16("Tooltip"))); - EXPECT_EQ(expected_width, max_width); - EXPECT_EQ(2, line_count); - EXPECT_EQ(ASCIIToUTF16("Multi line\nTooltip"), tooltip); - - // Whitespaces in tooltips are preserved. - tooltip.clear(); - max_width = line_count = -1; - tooltip = ASCIIToUTF16("Small Tool t\tip"); - TrimTooltipToFit(&tooltip, &max_width, &line_count, 0, 0); - EXPECT_EQ(font.GetStringWidth(ASCIIToUTF16("Small Tool t\tip")), max_width); - EXPECT_EQ(1, line_count); - EXPECT_EQ(ASCIIToUTF16("Small Tool t\tip"), tooltip); -} - -TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) { - scoped_ptr<views::Widget> widget(CreateNewWidgetOn(0)); - TooltipTestView* view1 = new TooltipTestView; - AddViewToWidgetAndResize(widget.get(), view1); - view1->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1")); - EXPECT_EQ(string16(), GetTooltipText()); - EXPECT_EQ(NULL, GetTooltipWindow()); - - TooltipTestView* view2 = new TooltipTestView; - AddViewToWidgetAndResize(widget.get(), view2); - view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2")); - - aura::Window* window = widget->GetNativeView(); - - // Fire tooltip timer so tooltip becomes visible. - aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); - generator.MoveMouseRelativeTo(window, - view1->bounds().CenterPoint()); - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); - EXPECT_TRUE(IsTooltipShownTimerRunning()); - - generator.PressKey(ui::VKEY_1, 0); - EXPECT_FALSE(IsTooltipVisible()); - EXPECT_FALSE(IsTooltipTimerRunning()); - EXPECT_FALSE(IsTooltipShownTimerRunning()); - - // Moving the mouse inside |view1| should not change the state of the tooltip - // or the timers. - for (int i = 0; i < 49; i++) { - generator.MoveMouseBy(1, 0); - EXPECT_FALSE(IsTooltipVisible()); - EXPECT_FALSE(IsTooltipTimerRunning()); - EXPECT_FALSE(IsTooltipShownTimerRunning()); - EXPECT_EQ(window, - Shell::GetPrimaryRootWindow()->GetEventHandlerForPoint( - generator.current_location())); - string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1"); - EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); - EXPECT_EQ(expected_tooltip, GetTooltipText()); - EXPECT_EQ(window, GetTooltipWindow()); - } - - // Now we move the mouse on to |view2|. It should re-start the tooltip timer. - generator.MoveMouseBy(1, 0); - EXPECT_TRUE(IsTooltipTimerRunning()); - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); - EXPECT_TRUE(IsTooltipShownTimerRunning()); - string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 2"); - EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); - EXPECT_EQ(expected_tooltip, GetTooltipText()); - EXPECT_EQ(window, GetTooltipWindow()); -} - -TEST_F(TooltipControllerTest, TooltipHidesOnTimeoutAndStaysHiddenUntilChange) { - scoped_ptr<views::Widget> widget(CreateNewWidgetOn(0)); - TooltipTestView* view1 = new TooltipTestView; - AddViewToWidgetAndResize(widget.get(), view1); - view1->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1")); - EXPECT_EQ(string16(), GetTooltipText()); - EXPECT_EQ(NULL, GetTooltipWindow()); - - TooltipTestView* view2 = new TooltipTestView; - AddViewToWidgetAndResize(widget.get(), view2); - view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2")); - - aura::Window* window = widget->GetNativeView(); - - // Fire tooltip timer so tooltip becomes visible. - aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); - generator.MoveMouseRelativeTo(window, - view1->bounds().CenterPoint()); - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); - EXPECT_TRUE(IsTooltipShownTimerRunning()); - - FireTooltipShownTimer(); - EXPECT_FALSE(IsTooltipVisible()); - EXPECT_FALSE(IsTooltipTimerRunning()); - EXPECT_FALSE(IsTooltipShownTimerRunning()); - - // Moving the mouse inside |view1| should not change the state of the tooltip - // or the timers. - for (int i = 0; i < 49; ++i) { - generator.MoveMouseBy(1, 0); - EXPECT_FALSE(IsTooltipVisible()); - EXPECT_FALSE(IsTooltipTimerRunning()); - EXPECT_FALSE(IsTooltipShownTimerRunning()); - EXPECT_EQ(window, - Shell::GetPrimaryRootWindow()->GetEventHandlerForPoint( - generator.current_location())); - string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1"); - EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); - EXPECT_EQ(expected_tooltip, GetTooltipText()); - EXPECT_EQ(window, GetTooltipWindow()); - } - - // Now we move the mouse on to |view2|. It should re-start the tooltip timer. - generator.MoveMouseBy(1, 0); - EXPECT_TRUE(IsTooltipTimerRunning()); - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); - EXPECT_TRUE(IsTooltipShownTimerRunning()); - string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 2"); - EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); - EXPECT_EQ(expected_tooltip, GetTooltipText()); - EXPECT_EQ(window, GetTooltipWindow()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); } #if defined(OS_WIN) @@ -510,8 +163,8 @@ TEST_F(TooltipControllerTest, MAYBE_TooltipsOnMultiDisplayShouldNotCrash) { aura::test::EventGenerator generator(root_windows[1]); generator.MoveMouseRelativeTo(widget2->GetNativeView(), view2->bounds().CenterPoint()); - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); // Get rid of secondary display. This destroy's the tooltip's aura window. If // we have handled this case, we will not crash in the following statement. @@ -520,7 +173,7 @@ TEST_F(TooltipControllerTest, MAYBE_TooltipsOnMultiDisplayShouldNotCrash) { // TODO(cpu): Detangle the window destruction notification. Currently // the TooltipController::OnWindowDestroyed is not being called then the // display is torn down so the tooltip is is still there. - EXPECT_FALSE(IsTooltipVisible()); + EXPECT_FALSE(helper_->IsTooltipVisible()); #endif EXPECT_EQ(widget2->GetNativeView()->GetRootWindow(), root_windows[0]); @@ -529,8 +182,8 @@ TEST_F(TooltipControllerTest, MAYBE_TooltipsOnMultiDisplayShouldNotCrash) { aura::test::EventGenerator generator1(root_windows[0]); generator1.MoveMouseRelativeTo(widget1->GetNativeView(), view1->bounds().CenterPoint()); - FireTooltipTimer(); - EXPECT_TRUE(IsTooltipVisible()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); } } // namespace test diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc index 6ddbdcf9..77976f5 100644 --- a/chrome/browser/chromeos/login/login_utils.cc +++ b/chrome/browser/chromeos/login/login_utils.cc @@ -798,13 +798,13 @@ std::string LoginUtilsImpl::GetOffTheRecordCommandLine( ::switches::kUseExynosVda, ash::switches::kAshTouchHud, ash::switches::kAuraLegacyPowerButton, - ash::switches::kAuraNoShadows, ash::switches::kAshEnableNewNetworkStatusArea, cc::switches::kDisableThreadedAnimation, cc::switches::kEnablePartialSwap, chromeos::switches::kDbusStub, gfx::switches::kEnableBrowserTextSubpixelPositioning, gfx::switches::kEnableWebkitTextSubpixelPositioning, + views::corewm::switches::kNoDropShadows, views::corewm::switches::kWindowAnimationsDisabled, }; command_line->CopySwitchesFrom(base_command_line, diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc index 824c138..60c16e7 100644 --- a/chrome/browser/ui/views/chrome_views_delegate.cc +++ b/chrome/browser/ui/views/chrome_views_delegate.cc @@ -217,7 +217,7 @@ void ChromeViewsDelegate::OnBeforeWidgetInit( } else if (params->parent && params->type != views::Widget::InitParams::TYPE_MENU) { params->native_widget = new views::NativeWidgetAura(delegate); - } else { + } else if (params->type != views::Widget::InitParams::TYPE_TOOLTIP) { // TODO(erg): Once we've threaded context to everywhere that needs it, we // should remove this check here. gfx::NativeView to_check = diff --git a/ui/views/corewm/corewm_switches.cc b/ui/views/corewm/corewm_switches.cc index ac0ffab..450738e 100644 --- a/ui/views/corewm/corewm_switches.cc +++ b/ui/views/corewm/corewm_switches.cc @@ -18,6 +18,8 @@ const char kDisableFocusController[] = "disable-focus-controller"; const char kDisableFocusControllerOnDesktop[] = "disable-focus-controller-on-desktop"; +const char kNoDropShadows[] = "aura-no-shadows"; + // If present animations are disabled. const char kWindowAnimationsDisabled[] = "views-corewm-window-animations-disabled"; diff --git a/ui/views/corewm/corewm_switches.h b/ui/views/corewm/corewm_switches.h index a9f452d..a78088c 100644 --- a/ui/views/corewm/corewm_switches.h +++ b/ui/views/corewm/corewm_switches.h @@ -17,6 +17,7 @@ namespace switches { // see chromeos::LoginUtil::GetOffTheRecordCommandLine().) // Please keep alphabetized. +VIEWS_EXPORT extern const char kNoDropShadows[]; VIEWS_EXPORT extern const char kWindowAnimationsDisabled[]; } // namespace switches diff --git a/ash/tooltips/tooltip_controller.cc b/ui/views/corewm/tooltip_controller.cc index c8bde19..0f63063 100644 --- a/ash/tooltips/tooltip_controller.cc +++ b/ui/views/corewm/tooltip_controller.cc @@ -2,18 +2,15 @@ // 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 "ui/views/corewm/tooltip_controller.h" #include <vector> -#include "ash/ash_switches.h" -#include "ash/shell.h" -#include "ash/wm/coordinate_conversion.h" -#include "ash/wm/cursor_manager.h" #include "base/command_line.h" #include "base/location.h" #include "base/string_split.h" #include "base/time.h" +#include "ui/aura/client/cursor_client.h" #include "ui/aura/client/drag_drop_client.h" #include "ui/aura/env.h" #include "ui/aura/root_window.h" @@ -28,6 +25,7 @@ #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" +#include "ui/views/corewm/corewm_switches.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_observer.h" @@ -66,22 +64,14 @@ gfx::Font GetDefaultFont() { 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 display_bounds = ash::Shell::GetScreen()->GetDisplayNearestPoint( - gfx::Point(x, y)).bounds(); - return (display_bounds.width() + 1) / 2; -} - // Creates a widget of type TYPE_TOOLTIP -views::Widget* CreateTooltip(const gfx::Point location) { +views::Widget* CreateTooltip(aura::Window* tooltip_window) { 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.context = ash::wm::GetRootWindowAt(location); + params.context = tooltip_window; DCHECK(params.context); params.keep_on_top = true; params.accept_events = false; @@ -91,17 +81,18 @@ views::Widget* CreateTooltip(const gfx::Point location) { } // namespace -namespace ash { -namespace internal { +namespace views { +namespace corewm { // Displays a widget with tooltip using a views::Label. class TooltipController::Tooltip : public views::WidgetObserver { public: Tooltip(TooltipController* controller) - : controller_(controller), widget_(NULL) { + : controller_(controller), + widget_(NULL) { label_.set_background( views::Background::CreateSolidBackground(kTooltipBackground)); - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAuraNoShadows)) { + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoDropShadows)) { label_.set_border( views::Border::CreateSolidBorder(kTooltipBorderWidth, kTooltipBorder)); @@ -117,26 +108,31 @@ class TooltipController::Tooltip : public views::WidgetObserver { } // Updates the text on the tooltip and resizes to fit. - void SetText(string16 tooltip_text, gfx::Point location) { + void SetText(aura::Window* window, + const string16& tooltip_text, + const gfx::Point& location) { int max_width, line_count; - TrimTooltipToFit(&tooltip_text, &max_width, &line_count, - location.x(), location.y()); - label_.SetText(tooltip_text); + string16 trimmed_text(tooltip_text); + controller_->TrimTooltipToFit( + controller_->GetMaxWidth(location), &trimmed_text, &max_width, + &line_count); + label_.SetText(trimmed_text); int width = max_width + 2 * kTooltipHorizontalPadding; int height = label_.GetPreferredSize().height() + 2 * kTooltipVerticalPadding; - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAuraNoShadows)) { + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoDropShadows)) { width += 2 * kTooltipBorderWidth; height += 2 * kTooltipBorderWidth; } + CreateWidgetIfNecessary(window); SetTooltipBounds(location, width, height); } // Shows the tooltip. void Show() { - GetWidget()->Show(); + if (widget_) + widget_->Show(); } // Hides the tooltip. @@ -146,7 +142,7 @@ class TooltipController::Tooltip : public views::WidgetObserver { } bool IsVisible() { - return widget_? widget_->IsVisible() : false; + return widget_ && widget_->IsVisible(); } // Overriden from views::WidgetObserver. @@ -156,21 +152,16 @@ class TooltipController::Tooltip : public views::WidgetObserver { } private: - views::Label label_; - TooltipController* controller_; - 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, + void SetTooltipBounds(const 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 display_bounds = Shell::GetScreen()->GetDisplayNearestPoint( - tooltip_rect.origin()).bounds(); + gfx::Rect display_bounds = controller_->GetBoundsForTooltip(mouse_pos); // If tooltip is out of bounds on the x axis, we simply shift it // horizontally by the offset. @@ -185,25 +176,29 @@ class TooltipController::Tooltip : public views::WidgetObserver { tooltip_rect.set_y(mouse_pos.y() - tooltip_height); tooltip_rect.AdjustToFit(display_bounds); - GetWidget()->SetBounds(tooltip_rect); + widget_->SetBounds(tooltip_rect); } - views::Widget* GetWidget() { - if (!widget_) { - widget_ = CreateTooltip(controller_->mouse_location()); - widget_->SetContentsView(&label_); - widget_->AddObserver(this); - } - return widget_; + void CreateWidgetIfNecessary(aura::Window* tooltip_window) { + if (widget_) + return; + widget_ = CreateTooltip(tooltip_window); + widget_->SetContentsView(&label_); + widget_->AddObserver(this); } + + views::Label label_; + TooltipController* controller_; + views::Widget* widget_; + + DISALLOW_COPY_AND_ASSIGN(Tooltip); }; //////////////////////////////////////////////////////////////////////////////// // TooltipController public: -TooltipController::TooltipController( - aura::client::DragDropClient* drag_drop_client) - : drag_drop_client_(drag_drop_client), +TooltipController::TooltipController(gfx::ScreenType screen_type) + : screen_type_(screen_type), tooltip_window_(NULL), tooltip_window_at_mouse_press_(NULL), mouse_pressed_(false), @@ -211,7 +206,6 @@ TooltipController::TooltipController( tooltip_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTooltipTimeoutMs), this, &TooltipController::TooltipTimerFired); - DCHECK(drag_drop_client_); } TooltipController::~TooltipController() { @@ -272,10 +266,13 @@ void TooltipController::OnMouseEvent(ui::MouseEvent* event) { UpdateIfRequired(); break; case ui::ET_MOUSE_PRESSED: - mouse_pressed_ = true; - tooltip_window_at_mouse_press_ = target; - if (target) - tooltip_text_at_mouse_press_ = aura::client::GetTooltipText(target); + if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0) { + // We don't get a release for non-client areas. + mouse_pressed_ = true; + tooltip_window_at_mouse_press_ = target; + if (target) + tooltip_text_at_mouse_press_ = aura::client::GetTooltipText(target); + } GetTooltip()->Hide(); break; case ui::ET_MOUSE_RELEASED: @@ -320,13 +317,37 @@ void TooltipController::OnWindowDestroyed(aura::Window* window) { //////////////////////////////////////////////////////////////////////////////// // TooltipController private: +int TooltipController::GetMaxWidth(const gfx::Point& location) const { + // TODO(varunjain): implementation duplicated in tooltip_manager_aura. Figure + // out a way to merge. + gfx::Rect display_bounds = GetBoundsForTooltip(location); + return (display_bounds.width() + 1) / 2; +} + +gfx::Rect TooltipController::GetBoundsForTooltip( + const gfx::Point& origin) const { + DCHECK(tooltip_window_); + gfx::Rect widget_bounds; + // For Desktop aura we constrain the tooltip to the bounds of the Widget + // (which comes from the RootWindow). + if (screen_type_ == gfx::SCREEN_TYPE_NATIVE && + gfx::SCREEN_TYPE_NATIVE != gfx::SCREEN_TYPE_ALTERNATE) { + aura::RootWindow* root = tooltip_window_->GetRootWindow(); + widget_bounds = gfx::Rect(root->GetHostOrigin(), root->GetHostSize()); + } + gfx::Screen* screen = gfx::Screen::GetScreenByType(screen_type_); + gfx::Rect bounds(screen->GetDisplayNearestPoint(origin).bounds()); + if (!widget_bounds.IsEmpty()) + bounds.Intersect(widget_bounds); + return bounds; +} + // static -void TooltipController::TrimTooltipToFit(string16* text, - int* max_width, - int* line_count, - int x, - int y) { - *max_width = 0; +void TooltipController::TrimTooltipToFit(int max_width, + string16* text, + int* width, + int* line_count) { + *width = 0; *line_count = 0; // Clamp the tooltip length to kMaxTooltipLength so that we don't @@ -335,7 +356,7 @@ void TooltipController::TrimTooltipToFit(string16* text, *text = text->substr(0, kMaxTooltipLength); // Determine the available width for the tooltip. - int available_width = std::min(kTooltipMaxWidthPixels, GetMaxWidth(x, y)); + int available_width = std::min(kTooltipMaxWidthPixels, max_width); std::vector<string16> lines; base::SplitString(*text, '\n', &lines); @@ -391,10 +412,10 @@ void TooltipController::TrimTooltipToFit(string16* text, // very long word, line_width is greater than the available_width. In such // case, we simply truncate at available_width and add ellipses at the end. if (line_width > available_width) { - *max_width = available_width; + *width = available_width; result.append(ui::ElideText(*l, font, available_width, ui::ELIDE_AT_END)); } else { - *max_width = std::max(*max_width, line_width); + *width = std::max(*width, line_width); result.append(*l); } } @@ -416,7 +437,7 @@ void TooltipController::TooltipShownTimerFired() { void TooltipController::UpdateIfRequired() { if (!tooltips_enabled_ || mouse_pressed_ || IsDragDropInProgress() || - !ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible()) { + !IsCursorVisible()) { GetTooltip()->Hide(); return; } @@ -447,14 +468,19 @@ void TooltipController::UpdateIfRequired() { if (tooltip_text_.empty()) { GetTooltip()->Hide(); } else { - string16 tooltip_text(tooltip_text_); gfx::Point widget_loc = curr_mouse_loc_ + tooltip_window_->GetBoundsInScreen().OffsetFromOrigin(); - GetTooltip()->SetText(tooltip_text, widget_loc); - GetTooltip()->Show(); - tooltip_shown_timer_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(kTooltipShownTimeoutMs), - this, &TooltipController::TooltipShownTimerFired); + gfx::Rect bounds(GetBoundsForTooltip(widget_loc)); + if (bounds.IsEmpty()) { + tooltip_text_.clear(); + GetTooltip()->Hide(); + } else { + GetTooltip()->SetText(tooltip_window_, tooltip_text_, widget_loc); + GetTooltip()->Show(); + tooltip_shown_timer_.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(kTooltipShownTimeoutMs), + this, &TooltipController::TooltipShownTimerFired); + } } } } @@ -464,7 +490,11 @@ bool TooltipController::IsTooltipVisible() { } bool TooltipController::IsDragDropInProgress() { - return drag_drop_client_->IsDragDropInProgress(); + if (!tooltip_window_) + return false; + aura::client::DragDropClient* client = + aura::client::GetDragDropClient(tooltip_window_->GetRootWindow()); + return client && client->IsDragDropInProgress(); } TooltipController::Tooltip* TooltipController::GetTooltip() { @@ -473,5 +503,17 @@ TooltipController::Tooltip* TooltipController::GetTooltip() { return tooltip_.get(); } -} // namespace internal -} // namespace ash +bool TooltipController::IsCursorVisible() { + if (!tooltip_window_) + return false; + aura::RootWindow* root = tooltip_window_->GetRootWindow(); + if (!root) + return false; + aura::client::CursorClient* cursor_client = + aura::client::GetCursorClient(root); + // |cursor_client| may be NULL in tests, treat NULL as always visible. + return !cursor_client || cursor_client->IsCursorVisible(); +} + +} // namespace corewm +} // namespace views diff --git a/ash/tooltips/tooltip_controller.h b/ui/views/corewm/tooltip_controller.h index 3022aee..efce0ac 100644 --- a/ash/tooltips/tooltip_controller.h +++ b/ui/views/corewm/tooltip_controller.h @@ -2,10 +2,9 @@ // 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_ +#ifndef UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_H_ +#define UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_H_ -#include "ash/ash_export.h" #include "base/memory/scoped_ptr.h" #include "base/string16.h" #include "base/timer.h" @@ -13,28 +12,26 @@ #include "ui/aura/window_observer.h" #include "ui/base/events/event_handler.h" #include "ui/gfx/point.h" +#include "ui/gfx/screen_type_delegate.h" +#include "ui/views/views_export.h" namespace aura { class Window; -namespace client { -class DragDropClient; -} } -namespace ash { +namespace views { +namespace corewm { namespace test { -class TooltipControllerTest; +class TooltipControllerTestHelper; } // namespace test -namespace internal { - // TooltipController provides tooltip functionality for aura shell. -class ASH_EXPORT TooltipController : public aura::client::TooltipClient, - public ui::EventHandler, - public aura::WindowObserver { +class VIEWS_EXPORT TooltipController : public aura::client::TooltipClient, + public ui::EventHandler, + public aura::WindowObserver { public: - explicit TooltipController(aura::client::DragDropClient* drag_drop_client); + explicit TooltipController(gfx::ScreenType screen_type); virtual ~TooltipController(); // Overridden from aura::client::TooltipClient. @@ -50,22 +47,28 @@ class ASH_EXPORT TooltipController : public aura::client::TooltipClient, // Overridden from aura::WindowObserver. virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE; - gfx::Point mouse_location() const { return curr_mouse_loc_; } + const gfx::Point& mouse_location() const { return curr_mouse_loc_; } private: - friend class ash::test::TooltipControllerTest; + friend class test::TooltipControllerTestHelper; class Tooltip; - // 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. - static void TrimTooltipToFit(string16* text, - int* max_width, - int* line_count, - int x, - int y); + // Returns the max width of the tooltip when shown at the specified location. + int GetMaxWidth(const gfx::Point& location) const; + + // Returns the bounds to fit the tooltip in. + gfx::Rect GetBoundsForTooltip(const gfx::Point& origin) const; + + // Trims the tooltip to fit in the width |max_width|, setting |text| to the + // clipped result, |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. |max_width| comes + // from GetMaxWidth(). + static void TrimTooltipToFit(int max_width, + string16* text, + int* width, + int* line_count); void TooltipTimerFired(); void TooltipShownTimerFired(); @@ -83,7 +86,10 @@ class ASH_EXPORT TooltipController : public aura::client::TooltipClient, // be initialized with appropriate drop shadows. Tooltip* GetTooltip(); - aura::client::DragDropClient* drag_drop_client_; + // Returns true if the cursor is visible. + bool IsCursorVisible(); + + const gfx::ScreenType screen_type_; aura::Window* tooltip_window_; string16 tooltip_text_; @@ -108,7 +114,7 @@ class ASH_EXPORT TooltipController : public aura::client::TooltipClient, DISALLOW_COPY_AND_ASSIGN(TooltipController); }; -} // namespace internal -} // namespace ash +} // namespace corewm +} // namespace views -#endif // ASH_TOOLTIPS_TOOLTIP_CONTROLLER_H_ +#endif // UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_H_ diff --git a/ui/views/corewm/tooltip_controller_test_helper.cc b/ui/views/corewm/tooltip_controller_test_helper.cc new file mode 100644 index 0000000..9a2f06f --- /dev/null +++ b/ui/views/corewm/tooltip_controller_test_helper.cc @@ -0,0 +1,73 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/corewm/tooltip_controller_test_helper.h" + +#include "ui/aura/window.h" +#include "ui/views/corewm/tooltip_controller.h" + +namespace views { +namespace corewm { +namespace test { + +TooltipControllerTestHelper::TooltipControllerTestHelper( + TooltipController* controller) + : controller_(controller) { +} + +TooltipControllerTestHelper::~TooltipControllerTestHelper() { +} + +string16 TooltipControllerTestHelper::GetTooltipText() { + return controller_->tooltip_text_; +} + +aura::Window* TooltipControllerTestHelper::GetTooltipWindow() { + return controller_->tooltip_window_; +} + +void TooltipControllerTestHelper::FireTooltipTimer() { + controller_->TooltipTimerFired(); +} + +bool TooltipControllerTestHelper::IsTooltipTimerRunning() { + return controller_->tooltip_timer_.IsRunning(); +} + +void TooltipControllerTestHelper::FireTooltipShownTimer() { + controller_->tooltip_shown_timer_.Stop(); + controller_->TooltipShownTimerFired(); +} + +bool TooltipControllerTestHelper::IsTooltipShownTimerRunning() { + return controller_->tooltip_shown_timer_.IsRunning(); +} + +bool TooltipControllerTestHelper::IsTooltipVisible() { + return controller_->IsTooltipVisible(); +} + +// static +void TooltipControllerTestHelper::TrimTooltipToFit(int max_width, + string16* text, + int* width, + int* line_count) { + TooltipController::TrimTooltipToFit(max_width, text, width, line_count); +} + +TooltipTestView::TooltipTestView() { +} + +TooltipTestView::~TooltipTestView() { +} + +bool TooltipTestView::GetTooltipText(const gfx::Point& p, + string16* tooltip) const { + *tooltip = tooltip_text_; + return true; +} + +} // namespace test +} // namespace corewm +} // namespace views diff --git a/ui/views/corewm/tooltip_controller_test_helper.h b/ui/views/corewm/tooltip_controller_test_helper.h new file mode 100644 index 0000000..9c438a0 --- /dev/null +++ b/ui/views/corewm/tooltip_controller_test_helper.h @@ -0,0 +1,75 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_TEST_HELPER_H_ +#define UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_TEST_HELPER_H_ + +#include "base/logging.h" +#include "base/string16.h" +#include "ui/views/view.h" +#include "ui/views/views_export.h" + +namespace aura { +class Window; +} + +namespace views { +namespace corewm { + +class TooltipController; + +namespace test { + +// TooltipControllerTestHelper provides access to TooltipControllers private +// state. +class TooltipControllerTestHelper { + public: + explicit TooltipControllerTestHelper(TooltipController* controller); + ~TooltipControllerTestHelper(); + + TooltipController* controller() { return controller_; } + + // These are mostly cover methods for TooltipController private methods. + string16 GetTooltipText(); + aura::Window* GetTooltipWindow(); + void FireTooltipTimer(); + bool IsTooltipTimerRunning(); + void FireTooltipShownTimer(); + bool IsTooltipShownTimerRunning(); + bool IsTooltipVisible(); + static void TrimTooltipToFit(int max_width, + string16* text, + int* width, + int* line_count); + + private: + TooltipController* controller_; + + DISALLOW_COPY_AND_ASSIGN(TooltipControllerTestHelper); +}; + +// Trivial View subclass that lets you set the tooltip text. +class TooltipTestView : public views::View { + public: + TooltipTestView(); + virtual ~TooltipTestView(); + + void set_tooltip_text(string16 tooltip_text) { tooltip_text_ = tooltip_text; } + + // Overridden from views::View + virtual bool GetTooltipText(const gfx::Point& p, + string16* tooltip) const OVERRIDE; + + private: + string16 tooltip_text_; + + DISALLOW_COPY_AND_ASSIGN(TooltipTestView); +}; + + +} // namespace test +} // namespace corewm +} // namespace views + +#endif // UI_VIEWS_COREWM_TOOLTIP_CONTROLLER_TEST_HELPER_H_ diff --git a/ui/views/corewm/tooltip_controller_unittest.cc b/ui/views/corewm/tooltip_controller_unittest.cc new file mode 100644 index 0000000..a4410c0 --- /dev/null +++ b/ui/views/corewm/tooltip_controller_unittest.cc @@ -0,0 +1,414 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/corewm/tooltip_controller.h" + +#include "base/utf_string_conversions.h" +#include "ui/aura/client/cursor_client.h" +#include "ui/aura/client/tooltip_client.h" +#include "ui/aura/env.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/aura_test_base.h" +#include "ui/aura/test/event_generator.h" +#include "ui/aura/window.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/views/corewm/tooltip_controller_test_helper.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +#if defined(OS_WIN) +#include "ui/base/win/scoped_ole_initializer.h" +#endif +#if !defined(OS_CHROMEOS) +#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" +#endif + +namespace views { +namespace corewm { +namespace test { +namespace { + +views::Widget* CreateWidget(aura::RootWindow* root) { + 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; +#if defined(OS_CHROMEOS) + params.parent = root; +#else + params.native_widget = new DesktopNativeWidgetAura(widget); +#endif + params.bounds = gfx::Rect(0, 0, 200, 100); + widget->Init(params); + widget->Show(); + return widget; +} + +gfx::Font GetDefaultFont() { + return ui::ResourceBundle::GetSharedInstance().GetFont( + ui::ResourceBundle::BaseFont); +} + +TooltipController* GetController(Widget* widget) { + return static_cast<TooltipController*>( + aura::client::GetTooltipClient( + widget->GetNativeWindow()->GetRootWindow())); +} + +} // namespace + +class TooltipControllerTest : public aura::test::AuraTestBase { + public: + TooltipControllerTest() : view_(NULL) {} + virtual ~TooltipControllerTest() {} + + virtual void SetUp() OVERRIDE { + aura::test::AuraTestBase::SetUp(); +#if defined(OS_CHROMEOS) + controller_.reset(new TooltipController(gfx::SCREEN_TYPE_ALTERNATE)); + root_window()->AddPreTargetHandler(controller_.get()); + SetTooltipClient(root_window(), controller_.get()); +#endif + widget_.reset(CreateWidget(root_window())); + widget_->SetContentsView(new View); + view_ = new TooltipTestView; + widget_->GetContentsView()->AddChildView(view_); + view_->SetBoundsRect(widget_->GetContentsView()->GetLocalBounds()); + helper_.reset(new TooltipControllerTestHelper( + GetController(widget_.get()))); + generator_.reset(new aura::test::EventGenerator(GetRootWindow())); + } + + virtual void TearDown() OVERRIDE { +#if defined(OS_CHROMEOS) + root_window()->RemovePreTargetHandler(controller_.get()); + SetTooltipClient(root_window(), NULL); + controller_.reset(); +#endif + generator_.reset(); + helper_.reset(); + widget_.reset(); + aura::test::AuraTestBase::TearDown(); + } + + protected: + aura::Window* GetWindow() { + return widget_->GetNativeWindow(); + } + + aura::RootWindow* GetRootWindow() { + return GetWindow()->GetRootWindow(); + } + + TooltipTestView* PrepareSecondView() { + TooltipTestView* view2 = new TooltipTestView; + widget_->GetContentsView()->AddChildView(view2); + view_->SetBounds(0, 0, 100, 100); + view2->SetBounds(100, 0, 100, 100); + return view2; + } + + scoped_ptr<views::Widget> widget_; + TooltipTestView* view_; + scoped_ptr<TooltipControllerTestHelper> helper_; + scoped_ptr<aura::test::EventGenerator> generator_; + + private: + scoped_ptr<TooltipController> controller_; +#if defined(OS_WIN) + ui::ScopedOleInitializer ole_initializer_; +#endif + + DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest); +}; + +TEST_F(TooltipControllerTest, ViewTooltip) { + view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text")); + EXPECT_EQ(string16(), helper_->GetTooltipText()); + EXPECT_EQ(NULL, helper_->GetTooltipWindow()); + generator_->MoveMouseToCenterOf(GetWindow()); + + EXPECT_EQ(GetWindow(), GetRootWindow()->GetEventHandlerForPoint( + generator_->current_location())); + string16 expected_tooltip = ASCIIToUTF16("Tooltip Text"); + EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(GetWindow())); + EXPECT_EQ(string16(), helper_->GetTooltipText()); + EXPECT_EQ(GetWindow(), helper_->GetTooltipWindow()); + + // Fire tooltip timer so tooltip becomes visible. + helper_->FireTooltipTimer(); + + EXPECT_TRUE(helper_->IsTooltipVisible()); + generator_->MoveMouseBy(1, 0); + + EXPECT_TRUE(helper_->IsTooltipVisible()); + EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(GetWindow())); + EXPECT_EQ(expected_tooltip, helper_->GetTooltipText()); + EXPECT_EQ(GetWindow(), helper_->GetTooltipWindow()); +} + +TEST_F(TooltipControllerTest, TooltipsInMultipleViews) { + view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text")); + EXPECT_EQ(string16(), helper_->GetTooltipText()); + EXPECT_EQ(NULL, helper_->GetTooltipWindow()); + + PrepareSecondView(); + aura::Window* window = GetWindow(); + aura::RootWindow* root_window = GetRootWindow(); + + // Fire tooltip timer so tooltip becomes visible. + generator_->MoveMouseRelativeTo(window, view_->bounds().CenterPoint()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); + for (int i = 0; i < 49; ++i) { + generator_->MoveMouseBy(1, 0); + EXPECT_TRUE(helper_->IsTooltipVisible()); + EXPECT_EQ(window, root_window->GetEventHandlerForPoint( + generator_->current_location())); + string16 expected_tooltip = ASCIIToUTF16("Tooltip Text"); + EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); + EXPECT_EQ(expected_tooltip, helper_->GetTooltipText()); + EXPECT_EQ(window, helper_->GetTooltipWindow()); + } + for (int i = 0; i < 49; ++i) { + generator_->MoveMouseBy(1, 0); + EXPECT_FALSE(helper_->IsTooltipVisible()); + EXPECT_EQ(window, root_window->GetEventHandlerForPoint( + generator_->current_location())); + string16 expected_tooltip; // = "" + EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); + EXPECT_EQ(expected_tooltip, helper_->GetTooltipText()); + EXPECT_EQ(window, helper_->GetTooltipWindow()); + } +} + +TEST_F(TooltipControllerTest, EnableOrDisableTooltips) { + view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text")); + EXPECT_EQ(string16(), helper_->GetTooltipText()); + EXPECT_EQ(NULL, helper_->GetTooltipWindow()); + + generator_->MoveMouseRelativeTo(GetWindow(), view_->bounds().CenterPoint()); + string16 expected_tooltip = ASCIIToUTF16("Tooltip Text"); + + // Fire tooltip timer so tooltip becomes visible. + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); + + // Diable tooltips and check again. + helper_->controller()->SetTooltipsEnabled(false); + EXPECT_FALSE(helper_->IsTooltipVisible()); + helper_->FireTooltipTimer(); + EXPECT_FALSE(helper_->IsTooltipVisible()); + + // Enable tooltips back and check again. + helper_->controller()->SetTooltipsEnabled(true); + EXPECT_FALSE(helper_->IsTooltipVisible()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); +} + +TEST_F(TooltipControllerTest, TrimTooltipToFitTests) { + const int max_width = 4000; + string16 tooltip; + int width, line_count, expect_lines; + int max_pixel_width = 400; // copied from constants in tooltip_controller.cc + int max_lines = 10; // copied from constants in tooltip_controller.cc + gfx::Font font = GetDefaultFont(); + size_t tooltip_len; + + // Error in computed size vs. expected size should not be greater than the + // size of the longest word. + int error_in_pixel_width = font.GetStringWidth(ASCIIToUTF16("tooltip")); + + // Long tooltips should wrap to next line + tooltip.clear(); + width = line_count = -1; + expect_lines = 3; + for (; font.GetStringWidth(tooltip) <= (expect_lines - 1) * max_pixel_width;) + tooltip.append(ASCIIToUTF16("This is part of the tooltip")); + tooltip_len = tooltip.length(); + TooltipControllerTestHelper::TrimTooltipToFit( + max_width, &tooltip, &width, &line_count); + EXPECT_NEAR(max_pixel_width, width, error_in_pixel_width); + EXPECT_EQ(expect_lines, line_count); + EXPECT_EQ(tooltip_len + expect_lines - 1, tooltip.length()); + + // More than |max_lines| lines should get truncated at 10 lines. + tooltip.clear(); + width = line_count = -1; + expect_lines = 13; + for (; font.GetStringWidth(tooltip) <= (expect_lines - 1) * max_pixel_width;) + tooltip.append(ASCIIToUTF16("This is part of the tooltip")); + TooltipControllerTestHelper::TrimTooltipToFit( + max_width, &tooltip, &width, &line_count); + EXPECT_NEAR(max_pixel_width, width, error_in_pixel_width); + EXPECT_EQ(max_lines, line_count); + + // Long multi line tooltips should wrap individual lines. + tooltip.clear(); + width = line_count = -1; + expect_lines = 4; + for (; font.GetStringWidth(tooltip) <= (expect_lines - 2) * max_pixel_width;) + tooltip.append(ASCIIToUTF16("This is part of the tooltip")); + tooltip.insert(tooltip.length() / 2, ASCIIToUTF16("\n")); + tooltip_len = tooltip.length(); + TooltipControllerTestHelper::TrimTooltipToFit( + max_width, &tooltip, &width, &line_count); + EXPECT_NEAR(max_pixel_width, width, error_in_pixel_width); + EXPECT_EQ(expect_lines, line_count); + // We may have inserted the line break above near a space which will get + // trimmed. Hence we may be off by 1 in the final tooltip length calculation. + EXPECT_NEAR(tooltip_len + expect_lines - 2, tooltip.length(), 1); + +#if !defined(OS_WIN) + // Tooltip with really long word gets elided. + tooltip.clear(); + width = line_count = -1; + tooltip = UTF8ToUTF16(std::string('a', max_pixel_width)); + TooltipControllerTestHelper::TrimTooltipToFit( + max_width, &tooltip, &width, &line_count); + EXPECT_NEAR(max_pixel_width, width, 5); + EXPECT_EQ(1, line_count); + EXPECT_EQ(ui::ElideText(UTF8ToUTF16(std::string('a', max_pixel_width)), font, + max_pixel_width, ui::ELIDE_AT_END), tooltip); +#endif + + // Normal small tooltip should stay as is. + tooltip.clear(); + width = line_count = -1; + tooltip = ASCIIToUTF16("Small Tooltip"); + TooltipControllerTestHelper::TrimTooltipToFit( + max_width, &tooltip, &width, &line_count); + EXPECT_EQ(font.GetStringWidth(ASCIIToUTF16("Small Tooltip")), width); + EXPECT_EQ(1, line_count); + EXPECT_EQ(ASCIIToUTF16("Small Tooltip"), tooltip); + + // Normal small multi-line tooltip should stay as is. + tooltip.clear(); + width = line_count = -1; + tooltip = ASCIIToUTF16("Multi line\nTooltip"); + TooltipControllerTestHelper::TrimTooltipToFit( + max_width, &tooltip, &width, &line_count); + int expected_width = font.GetStringWidth(ASCIIToUTF16("Multi line")); + expected_width = std::max(expected_width, + font.GetStringWidth(ASCIIToUTF16("Tooltip"))); + EXPECT_EQ(expected_width, width); + EXPECT_EQ(2, line_count); + EXPECT_EQ(ASCIIToUTF16("Multi line\nTooltip"), tooltip); + + // Whitespaces in tooltips are preserved. + tooltip.clear(); + width = line_count = -1; + tooltip = ASCIIToUTF16("Small Tool t\tip"); + TooltipControllerTestHelper::TrimTooltipToFit( + max_width, &tooltip, &width, &line_count); + EXPECT_EQ(font.GetStringWidth(ASCIIToUTF16("Small Tool t\tip")), width); + EXPECT_EQ(1, line_count); + EXPECT_EQ(ASCIIToUTF16("Small Tool t\tip"), tooltip); +} + +TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) { + view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1")); + EXPECT_EQ(string16(), helper_->GetTooltipText()); + EXPECT_EQ(NULL, helper_->GetTooltipWindow()); + + TooltipTestView* view2 = PrepareSecondView(); + view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2")); + + aura::Window* window = GetWindow(); + + // Fire tooltip timer so tooltip becomes visible. + generator_->MoveMouseRelativeTo(window, view_->bounds().CenterPoint()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); + EXPECT_TRUE(helper_->IsTooltipShownTimerRunning()); + + generator_->PressKey(ui::VKEY_1, 0); + EXPECT_FALSE(helper_->IsTooltipVisible()); + EXPECT_FALSE(helper_->IsTooltipTimerRunning()); + EXPECT_FALSE(helper_->IsTooltipShownTimerRunning()); + + // Moving the mouse inside |view1| should not change the state of the tooltip + // or the timers. + for (int i = 0; i < 49; i++) { + generator_->MoveMouseBy(1, 0); + EXPECT_FALSE(helper_->IsTooltipVisible()); + EXPECT_FALSE(helper_->IsTooltipTimerRunning()); + EXPECT_FALSE(helper_->IsTooltipShownTimerRunning()); + EXPECT_EQ(window, + GetRootWindow()->GetEventHandlerForPoint( + generator_->current_location())); + string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1"); + EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); + EXPECT_EQ(expected_tooltip, helper_->GetTooltipText()); + EXPECT_EQ(window, helper_->GetTooltipWindow()); + } + + // Now we move the mouse on to |view2|. It should re-start the tooltip timer. + generator_->MoveMouseBy(1, 0); + EXPECT_TRUE(helper_->IsTooltipTimerRunning()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); + EXPECT_TRUE(helper_->IsTooltipShownTimerRunning()); + string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 2"); + EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); + EXPECT_EQ(expected_tooltip, helper_->GetTooltipText()); + EXPECT_EQ(window, helper_->GetTooltipWindow()); +} + +TEST_F(TooltipControllerTest, TooltipHidesOnTimeoutAndStaysHiddenUntilChange) { + view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1")); + EXPECT_EQ(string16(), helper_->GetTooltipText()); + EXPECT_EQ(NULL, helper_->GetTooltipWindow()); + + TooltipTestView* view2 = PrepareSecondView(); + view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2")); + + aura::Window* window = GetWindow(); + + // Fire tooltip timer so tooltip becomes visible. + generator_->MoveMouseRelativeTo(window, view_->bounds().CenterPoint()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); + EXPECT_TRUE(helper_->IsTooltipShownTimerRunning()); + + helper_->FireTooltipShownTimer(); + EXPECT_FALSE(helper_->IsTooltipVisible()); + EXPECT_FALSE(helper_->IsTooltipTimerRunning()); + EXPECT_FALSE(helper_->IsTooltipShownTimerRunning()); + + // Moving the mouse inside |view1| should not change the state of the tooltip + // or the timers. + for (int i = 0; i < 49; ++i) { + generator_->MoveMouseBy(1, 0); + EXPECT_FALSE(helper_->IsTooltipVisible()); + EXPECT_FALSE(helper_->IsTooltipTimerRunning()); + EXPECT_FALSE(helper_->IsTooltipShownTimerRunning()); + EXPECT_EQ(window, GetRootWindow()->GetEventHandlerForPoint( + generator_->current_location())); + string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1"); + EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); + EXPECT_EQ(expected_tooltip, helper_->GetTooltipText()); + EXPECT_EQ(window, helper_->GetTooltipWindow()); + } + + // Now we move the mouse on to |view2|. It should re-start the tooltip timer. + generator_->MoveMouseBy(1, 0); + EXPECT_TRUE(helper_->IsTooltipTimerRunning()); + helper_->FireTooltipTimer(); + EXPECT_TRUE(helper_->IsTooltipVisible()); + EXPECT_TRUE(helper_->IsTooltipShownTimerRunning()); + string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 2"); + EXPECT_EQ(expected_tooltip, aura::client::GetTooltipText(window)); + EXPECT_EQ(expected_tooltip, helper_->GetTooltipText()); + EXPECT_EQ(window, helper_->GetTooltipWindow()); +} + +} // namespace test +} // namespace corewm +} // namespace views diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 2c347e0..43cfdaa 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -242,6 +242,8 @@ 'corewm/shadow_controller.h', 'corewm/shadow_types.cc', 'corewm/shadow_types.h', + 'corewm/tooltip_controller.cc', + 'corewm/tooltip_controller.h', 'corewm/visibility_controller.cc', 'corewm/visibility_controller.h', 'corewm/window_animations.cc', @@ -440,6 +442,8 @@ 'widget/aero_tooltip_manager.h', 'widget/child_window_message_processor.cc', 'widget/child_window_message_processor.h', + 'widget/tooltip_manager_win.cc', + 'widget/tooltip_manager_win.h', ], 'conditions': [ ['OS=="mac"', { @@ -551,6 +555,8 @@ '..', ], 'sources': [ + 'corewm/tooltip_controller_test_helper.cc', + 'corewm/tooltip_controller_test_helper.h', 'test/capture_tracking_view.cc', 'test/capture_tracking_view.h', 'test/child_modal_window.cc', @@ -572,6 +578,8 @@ ], }, { # use_aura==0 'sources!': [ + 'corewm/tooltip_controller_test_helper.cc', + 'corewm/tooltip_controller_test_helper.h', 'test/child_modal_window.cc', 'test/child_modal_window.h', ], @@ -660,6 +668,7 @@ 'corewm/image_grid_unittest.cc', 'corewm/input_method_event_filter_unittest.cc', 'corewm/shadow_controller_unittest.cc', + 'corewm/tooltip_controller_unittest.cc', 'corewm/visibility_controller_unittest.cc', 'focus/focus_manager_test.h', 'focus/focus_manager_test.cc', diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index 282e0e8..2203e27 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc @@ -18,6 +18,7 @@ #include "ui/views/corewm/compound_event_filter.h" #include "ui/views/corewm/corewm_switches.h" #include "ui/views/corewm/input_method_event_filter.h" +#include "ui/views/corewm/tooltip_controller.h" #include "ui/views/drag_utils.h" #include "ui/views/ime/input_method.h" #include "ui/views/ime/input_method_bridge.h" @@ -25,6 +26,7 @@ #include "ui/views/widget/drop_helper.h" #include "ui/views/widget/native_widget_aura_window_observer.h" #include "ui/views/widget/root_view.h" +#include "ui/views/widget/tooltip_manager_aura.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_aura_utils.h" #include "ui/views/widget/widget_delegate.h" @@ -150,6 +152,13 @@ void DesktopNativeWidgetAura::InitNativeWidget( static_cast<internal::RootView*>(GetWidget()->GetRootView()))); aura::client::SetDragDropDelegate(window_, this); + tooltip_manager_.reset(new views::TooltipManagerAura(window_, GetWidget())); + tooltip_controller_.reset( + new corewm::TooltipController(gfx::SCREEN_TYPE_NATIVE)); + aura::client::SetTooltipClient(root_window_.get(), + tooltip_controller_.get()); + root_window_->AddPreTargetHandler(tooltip_controller_.get()); + aura::client::SetActivationDelegate(window_, this); } @@ -213,7 +222,7 @@ void* DesktopNativeWidgetAura::GetNativeWindowProperty(const char* name) const { } TooltipManager* DesktopNativeWidgetAura::GetTooltipManager() const { - return NULL; + return tooltip_manager_.get(); } bool DesktopNativeWidgetAura::IsScreenReaderActive() const { @@ -528,6 +537,12 @@ void DesktopNativeWidgetAura::OnDeviceScaleFactorChanged( void DesktopNativeWidgetAura::OnWindowDestroying() { // The DesktopRootWindowHost implementation sends OnNativeWidgetDestroying(). + tooltip_manager_.reset(); + if (tooltip_controller_.get()) { + root_window_->RemovePreTargetHandler(tooltip_controller_.get()); + tooltip_controller_.reset(); + aura::client::SetTooltipClient(root_window_.get(), NULL); + } } void DesktopNativeWidgetAura::OnWindowDestroyed() { @@ -583,6 +598,8 @@ void DesktopNativeWidgetAura::OnKeyEvent(ui::KeyEvent* event) { void DesktopNativeWidgetAura::OnMouseEvent(ui::MouseEvent* event) { DCHECK(window_->IsVisible()); native_widget_delegate_->OnMouseEvent(event); + if (tooltip_manager_.get()) + tooltip_manager_->UpdateTooltip(); } void DesktopNativeWidgetAura::OnScrollEvent(ui::ScrollEvent* event) { diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index 0f4c3cf..87b262c 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h @@ -26,11 +26,13 @@ namespace views { namespace corewm { class CompoundEventFilter; class InputMethodEventFilter; +class TooltipController; } class DesktopRootWindowHost; class DropHelper; class NativeWidgetAuraWindowObserver; +class TooltipManagerAura; // TODO(erg): May also need to be a DragDropDelegate class VIEWS_EXPORT DesktopNativeWidgetAura @@ -230,6 +232,9 @@ class VIEWS_EXPORT DesktopNativeWidgetAura scoped_ptr<DropHelper> drop_helper_; int last_drop_operation_; + scoped_ptr<corewm::TooltipController> tooltip_controller_; + scoped_ptr<TooltipManagerAura> tooltip_manager_; + // See comments in OnLostActive(). bool restore_focus_on_activate_; diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc index 98aa130..06acf0d 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc @@ -610,7 +610,6 @@ void DesktopRootWindowHostWin::HandleCreate() { // 1. Window property association // 2. MouseWheel. - // 3. Tooltip Manager. } void DesktopRootWindowHostWin::HandleDestroying() { diff --git a/ui/views/widget/desktop_aura/desktop_screen_position_client.cc b/ui/views/widget/desktop_aura/desktop_screen_position_client.cc index 73554df..19fcbed 100644 --- a/ui/views/widget/desktop_aura/desktop_screen_position_client.cc +++ b/ui/views/widget/desktop_aura/desktop_screen_position_client.cc @@ -48,7 +48,8 @@ void DesktopScreenPositionClient::SetBounds( if (window->type() == aura::client::WINDOW_TYPE_CONTROL) { window->SetBounds(gfx::Rect(origin, bounds.size())); return; - } else if (window->type() == aura::client::WINDOW_TYPE_POPUP) { + } else if (window->type() == aura::client::WINDOW_TYPE_POPUP || + window->type() == aura::client::WINDOW_TYPE_TOOLTIP) { // The caller expects windows we consider "embedded" to be placed in the // screen coordinate system. So we need to offset the root window's // position (which is in screen coordinates) from these bounds. diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index b1a2738..a2d1e1a 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc @@ -157,7 +157,7 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) { DCHECK(GetWidget()->GetRootView()); #if !defined(OS_MACOSX) if (params.type != Widget::InitParams::TYPE_TOOLTIP) - tooltip_manager_.reset(new views::TooltipManagerAura(this)); + tooltip_manager_.reset(new views::TooltipManagerAura(window_, GetWidget())); #endif // !defined(OS_MACOSX) drop_helper_.reset(new DropHelper(GetWidget()->GetRootView())); @@ -743,7 +743,6 @@ void NativeWidgetAura::OnWindowDestroying() { void NativeWidgetAura::OnWindowDestroyed() { window_ = NULL; - tooltip_manager_.reset(); delegate_->OnNativeWidgetDestroyed(); if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) delete this; diff --git a/ui/views/widget/tooltip_manager_aura.cc b/ui/views/widget/tooltip_manager_aura.cc index 2b76750..a1d4ca8 100644 --- a/ui/views/widget/tooltip_manager_aura.cc +++ b/ui/views/widget/tooltip_manager_aura.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ui/views/widget/tooltip_manager_aura.h" + #include "base/logging.h" #include "ui/aura/client/tooltip_client.h" #include "ui/aura/root_window.h" @@ -9,8 +11,7 @@ #include "ui/gfx/font.h" #include "ui/gfx/rect.h" #include "ui/gfx/screen.h" -#include "ui/views/widget/native_widget_aura.h" -#include "ui/views/widget/tooltip_manager_aura.h" +#include "ui/views/widget/widget.h" namespace views { @@ -38,25 +39,24 @@ int TooltipManager::GetMaxWidth(int x, int y, gfx::NativeView context) { //////////////////////////////////////////////////////////////////////////////// // TooltipManagerAura public: -TooltipManagerAura::TooltipManagerAura(NativeWidgetAura* native_widget_aura) - : native_widget_aura_(native_widget_aura) { - aura::client::SetTooltipText(native_widget_aura_->GetNativeView(), - &tooltip_text_); +TooltipManagerAura::TooltipManagerAura(aura::Window* window, Widget* widget) + : window_(window), + widget_(widget) { + aura::client::SetTooltipText(window_, &tooltip_text_); } TooltipManagerAura::~TooltipManagerAura() { - aura::client::SetTooltipText(native_widget_aura_->GetNativeView(), NULL); + aura::client::SetTooltipText(window_, NULL); } //////////////////////////////////////////////////////////////////////////////// // TooltipManagerAura, TooltipManager implementation: void TooltipManagerAura::UpdateTooltip() { - aura::Window* window = native_widget_aura_->GetNativeView(); - aura::RootWindow* root_window = window->GetRootWindow(); + aura::RootWindow* root_window = window_->GetRootWindow(); if (aura::client::GetTooltipClient(root_window)) { gfx::Point view_point = root_window->GetLastMouseLocationInRoot(); - aura::Window::ConvertPointToTarget(root_window, window, &view_point); + aura::Window::ConvertPointToTarget(root_window, window_, &view_point); View* view = GetViewUnderPoint(view_point); if (view) { View::ConvertPointFromWidget(view, &view_point); @@ -65,16 +65,15 @@ void TooltipManagerAura::UpdateTooltip() { } else { tooltip_text_.clear(); } - aura::client::GetTooltipClient(root_window)->UpdateTooltip(window); + aura::client::GetTooltipClient(root_window)->UpdateTooltip(window_); } } void TooltipManagerAura::TooltipTextChanged(View* view) { - aura::Window* window = native_widget_aura_->GetNativeView(); - aura::RootWindow* root_window = window->GetRootWindow(); + aura::RootWindow* root_window = window_->GetRootWindow(); if (aura::client::GetTooltipClient(root_window)) { gfx::Point view_point = root_window->GetLastMouseLocationInRoot(); - aura::Window::ConvertPointToTarget(root_window, window, &view_point); + aura::Window::ConvertPointToTarget(root_window, window_, &view_point); View* target = GetViewUnderPoint(view_point); if (target != view) return; @@ -85,7 +84,7 @@ void TooltipManagerAura::TooltipTextChanged(View* view) { } else { tooltip_text_.clear(); } - aura::client::GetTooltipClient(root_window)->UpdateTooltip(window); + aura::client::GetTooltipClient(root_window)->UpdateTooltip(window_); } } @@ -98,8 +97,7 @@ void TooltipManagerAura::HideKeyboardTooltip() { } View* TooltipManagerAura::GetViewUnderPoint(const gfx::Point& point) { - View* root_view = native_widget_aura_->GetWidget()->GetRootView(); - return root_view->GetEventHandlerForPoint(point); + return widget_->GetRootView()->GetEventHandlerForPoint(point); } } // namespace views. diff --git a/ui/views/widget/tooltip_manager_aura.h b/ui/views/widget/tooltip_manager_aura.h index 9e10917..6158820 100644 --- a/ui/views/widget/tooltip_manager_aura.h +++ b/ui/views/widget/tooltip_manager_aura.h @@ -10,15 +10,18 @@ #include "ui/gfx/point.h" #include "ui/views/widget/tooltip_manager.h" +namespace aura { +class Window; +} + namespace views { -class NativeWidgetAura; -class View; +class Widget; // TooltipManager implementation for Aura. class TooltipManagerAura : public TooltipManager { public: - explicit TooltipManagerAura(NativeWidgetAura* native_widget_aura); + TooltipManagerAura(aura::Window* window, Widget* widget); virtual ~TooltipManagerAura(); // TooltipManager. @@ -30,7 +33,8 @@ class TooltipManagerAura : public TooltipManager { private: View* GetViewUnderPoint(const gfx::Point& point); - NativeWidgetAura* native_widget_aura_; + aura::Window* window_; + Widget* widget_; string16 tooltip_text_; DISALLOW_COPY_AND_ASSIGN(TooltipManagerAura); |