diff options
author | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-30 23:59:12 +0000 |
---|---|---|
committer | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-30 23:59:12 +0000 |
commit | 714fe56f1a80a4844f3c1c9fa44c791179863e24 (patch) | |
tree | 67b28398d7210584d6def2f2858d3932d7750133 | |
parent | d88bf0abc08d368fd615a645bd0125ee6ab4f7c2 (diff) | |
download | chromium_src-714fe56f1a80a4844f3c1c9fa44c791179863e24.zip chromium_src-714fe56f1a80a4844f3c1c9fa44c791179863e24.tar.gz chromium_src-714fe56f1a80a4844f3c1c9fa44c791179863e24.tar.bz2 |
Support auto-hide taskbar for panels on Windows.
BUG=none
TEST=browser test
Review URL: http://codereview.chromium.org/7646003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98898 0039d316-1c4b-4281-b951-d872f2087c98
20 files changed, 1331 insertions, 310 deletions
diff --git a/chrome/browser/ui/panels/auto_hiding_desktop_bar.h b/chrome/browser/ui/panels/auto_hiding_desktop_bar.h new file mode 100644 index 0000000..d910a15 --- /dev/null +++ b/chrome/browser/ui/panels/auto_hiding_desktop_bar.h @@ -0,0 +1,72 @@ +// 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 CHROME_BROWSER_UI_PANELS_AUTO_HIDING_DESKTOP_BAR_H_ +#define CHROME_BROWSER_UI_PANELS_AUTO_HIDING_DESKTOP_BAR_H_ +#pragma once + +#include "base/memory/ref_counted.h" + +namespace gfx { +class Rect; +} + +// Encapsulates the logic to deal with always-on-top auto-hiding desktop bars, +// like Windows taskbar or MacOSX dock. +// Note that the ref count is needed by using PostTask in the implementation of +// MockAutoHidingDesktopBar that derives from AutoHidingDesktopBar. +class AutoHidingDesktopBar : public base::RefCounted<AutoHidingDesktopBar> { + public: + // Indicates which screen edge the desktop bar is aligned to. + // We do not care about the desktop aligned to the top screen edge. + enum Alignment { + ALIGN_BOTTOM = 0, + ALIGN_LEFT = 1, + ALIGN_RIGHT = 2 + }; + + enum Visibility { + VISIBLE, + ANIMATING, + HIDDEN + }; + + // Observer can listen to various events regarding the desktop bar changes. + class Observer { + public: + // Called when any of the desktop bars get their thickness changed. + // Note that if an auto-hiding desktop bar is moved from one edge + // to another edge, it will cause thickness changes to both edges. + virtual void OnAutoHidingDesktopBarThicknessChanged() = 0; + + // Called when an auto-hiding desktop bar has its visibility changed. + virtual void OnAutoHidingDesktopBarVisibilityChanged( + Alignment alignment, Visibility visibility) = 0; + }; + + static AutoHidingDesktopBar* Create(Observer* observer); + + virtual ~AutoHidingDesktopBar() { } + + // This should be called each time when the work area is changed. We only + // care about the desktop bars that sit on the screen that hosts the specified + // work area. + virtual void UpdateWorkArea(const gfx::Rect& work_area) = 0; + + // Returns true if there is a desktop bar that is aligned to the specified + // screen edge and set to auto-hide. + virtual bool IsEnabled(Alignment alignment) = 0; + + // Returns the thickness of the desktop bar that is aligned to the specified + // screen edge, when it is visible. When the desktop bar is aligned to bottom + // edge, this is the height of the bar. If the desktop bar is aligned to + // left or right edge, this is the width of the bar. + virtual int GetThickness(Alignment alignment) const = 0; + + // Returns the visibility state of the desktop bar that is aligned to the + // specified screen edge. + virtual Visibility GetVisibility(Alignment alignment) const = 0; +}; + +#endif // CHROME_BROWSER_UI_PANELS_AUTO_HIDING_DESKTOP_BAR_H_ diff --git a/chrome/browser/ui/panels/auto_hiding_desktop_bar_chromeos.cc b/chrome/browser/ui/panels/auto_hiding_desktop_bar_chromeos.cc new file mode 100644 index 0000000..60a8daa --- /dev/null +++ b/chrome/browser/ui/panels/auto_hiding_desktop_bar_chromeos.cc @@ -0,0 +1,56 @@ +// 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 "chrome/browser/ui/panels/auto_hiding_desktop_bar.h" + +#include "base/compiler_specific.h" + +namespace { + +class AutoHidingDesktopBarChromeOS : public AutoHidingDesktopBar { + public: + explicit AutoHidingDesktopBarChromeOS(Observer* observer); + virtual ~AutoHidingDesktopBarChromeOS() { } + + // Overridden from AutoHidingDesktopBar: + virtual void UpdateWorkArea(const gfx::Rect& work_area) OVERRIDE; + virtual bool IsEnabled(Alignment alignment) OVERRIDE; + virtual int GetThickness(Alignment alignment) const OVERRIDE; + virtual Visibility GetVisibility(Alignment alignment) const OVERRIDE; + + private: + Observer* observer_; + + DISALLOW_COPY_AND_ASSIGN(AutoHidingDesktopBarChromeOS); +}; + +AutoHidingDesktopBarChromeOS::AutoHidingDesktopBarChromeOS(Observer* observer) + : observer_(observer) { +} + +void AutoHidingDesktopBarChromeOS::UpdateWorkArea(const gfx::Rect& work_area) { +} + +bool AutoHidingDesktopBarChromeOS::IsEnabled( + AutoHidingDesktopBar::Alignment alignment) { + // No taskbar exists on ChromeOS. + return false; +} + +int AutoHidingDesktopBarChromeOS::GetThickness( + AutoHidingDesktopBar::Alignment alignment) const { + return 0; +} + +AutoHidingDesktopBar::Visibility AutoHidingDesktopBarChromeOS::GetVisibility( + AutoHidingDesktopBar::Alignment alignment) const { + return AutoHidingDesktopBar::HIDDEN; +} + +} // namespace + +// static +AutoHidingDesktopBar* AutoHidingDesktopBar::Create(Observer* observer) { + return new AutoHidingDesktopBarChromeOS(observer); +} diff --git a/chrome/browser/ui/panels/auto_hiding_desktop_bar_cocoa.mm b/chrome/browser/ui/panels/auto_hiding_desktop_bar_cocoa.mm new file mode 100644 index 0000000..45d404a --- /dev/null +++ b/chrome/browser/ui/panels/auto_hiding_desktop_bar_cocoa.mm @@ -0,0 +1,61 @@ +// 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 "chrome/browser/ui/panels/auto_hiding_desktop_bar.h" + +#include "base/compiler_specific.h" +#include "base/logging.h" + +namespace { + +class AutoHidingDesktopBarCocoa : public AutoHidingDesktopBar { + public: + explicit AutoHidingDesktopBarCocoa(Observer* observer); + virtual ~AutoHidingDesktopBarCocoa() { } + + // Overridden from AutoHidingDesktopBar: + virtual void UpdateWorkArea(const gfx::Rect& work_area) OVERRIDE; + virtual bool IsEnabled(Alignment alignment) OVERRIDE; + virtual int GetThickness(Alignment alignment) const OVERRIDE; + virtual Visibility GetVisibility(Alignment alignment) const OVERRIDE; + + private: + Observer* observer_; + + DISALLOW_COPY_AND_ASSIGN(AutoHidingDesktopBarCocoa); +}; + +AutoHidingDesktopBarCocoa::AutoHidingDesktopBarCocoa(Observer* observer) + : observer_(observer) { + DCHECK(observer); +} + +void AutoHidingDesktopBarCocoa::UpdateWorkArea(const gfx::Rect& work_area) { + NOTIMPLEMENTED(); +} + +bool AutoHidingDesktopBarCocoa::IsEnabled( + AutoHidingDesktopBar::Alignment alignment) { + NOTIMPLEMENTED(); + return false; +} + +int AutoHidingDesktopBarCocoa::GetThickness( + AutoHidingDesktopBar::Alignment alignment) const { + NOTIMPLEMENTED(); + return 0; +} + +AutoHidingDesktopBar::Visibility AutoHidingDesktopBarCocoa::GetVisibility( + AutoHidingDesktopBar::Alignment alignment) const { + NOTIMPLEMENTED(); + return AutoHidingDesktopBar::HIDDEN; +} + +} // namespace + +// static +AutoHidingDesktopBar* AutoHidingDesktopBar::Create(Observer* observer) { + return new AutoHidingDesktopBarCocoa(observer); +} diff --git a/chrome/browser/ui/panels/auto_hiding_desktop_bar_gtk.cc b/chrome/browser/ui/panels/auto_hiding_desktop_bar_gtk.cc new file mode 100644 index 0000000..e0e12d1 --- /dev/null +++ b/chrome/browser/ui/panels/auto_hiding_desktop_bar_gtk.cc @@ -0,0 +1,61 @@ +// 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 "chrome/browser/ui/panels/auto_hiding_desktop_bar.h" + +#include "base/compiler_specific.h" +#include "base/logging.h" + +namespace { + +class AutoHidingDesktopBarGtk : public AutoHidingDesktopBar { + public: + explicit AutoHidingDesktopBarGtk(Observer* observer); + virtual ~AutoHidingDesktopBarGtk() { } + + // Overridden from AutoHidingDesktopBar: + virtual void UpdateWorkArea(const gfx::Rect& work_area) OVERRIDE; + virtual bool IsEnabled(Alignment alignment) OVERRIDE; + virtual int GetThickness(Alignment alignment) const OVERRIDE; + virtual Visibility GetVisibility(Alignment alignment) const OVERRIDE; + + private: + Observer* observer_; + + DISALLOW_COPY_AND_ASSIGN(AutoHidingDesktopBarGtk); +}; + +AutoHidingDesktopBarGtk::AutoHidingDesktopBarGtk(Observer* observer) + : observer_(observer) { + DCHECK(observer); +} + +void AutoHidingDesktopBarGtk::UpdateWorkArea(const gfx::Rect& work_area) { + NOTIMPLEMENTED(); +} + +bool AutoHidingDesktopBarGtk::IsEnabled( + AutoHidingDesktopBar::Alignment alignment) { + NOTIMPLEMENTED(); + return false; +} + +int AutoHidingDesktopBarGtk::GetThickness( + AutoHidingDesktopBar::Alignment alignment) const { + NOTIMPLEMENTED(); + return 0; +} + +AutoHidingDesktopBar::Visibility AutoHidingDesktopBarGtk::GetVisibility( + AutoHidingDesktopBar::Alignment alignment) const { + NOTIMPLEMENTED(); + return AutoHidingDesktopBar::HIDDEN; +} + +} // namespace + +// static +AutoHidingDesktopBar* AutoHidingDesktopBar::Create(Observer* observer) { + return new AutoHidingDesktopBarGtk(observer); +} diff --git a/chrome/browser/ui/panels/auto_hiding_desktop_bar_win.cc b/chrome/browser/ui/panels/auto_hiding_desktop_bar_win.cc new file mode 100644 index 0000000..944c6b1 --- /dev/null +++ b/chrome/browser/ui/panels/auto_hiding_desktop_bar_win.cc @@ -0,0 +1,194 @@ +// 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 "chrome/browser/ui/panels/auto_hiding_desktop_bar_win.h" + +#include <shellapi.h> + +#include "base/logging.h" +#include "views/widget/monitor_win.h" + +namespace { +// The thickness of the area of an auto-hiding taskbar that is still visible +// when the taskbar becomes hidden. +const int kHiddenAutoHideTaskbarThickness = 2; + +// The polling interval to check auto-hiding taskbars. +const int kCheckTaskbarPollingIntervalMs = 500; +} // namespace + +AutoHidingDesktopBarWin::AutoHidingDesktopBarWin(Observer* observer) + : observer_(observer) { + DCHECK(observer); + memset(taskbars_, 0, sizeof(taskbars_)); +} + +AutoHidingDesktopBarWin::~AutoHidingDesktopBarWin() { +} + +void AutoHidingDesktopBarWin::UpdateWorkArea(const gfx::Rect& work_area) { + if (work_area_ == work_area) + return; + work_area_ = work_area; + + RECT rect = work_area_.ToRECT(); + monitor_ = ::MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY); + DCHECK(monitor_); + + bool taskbar_exists = CheckTaskbars(false); + + // If no auto-hiding taskbar exists, we do not need to start the polling + // timer. If a taskbar is then set to auto-hiding, UpdateWorkArea will be + // called due to the work area change. + if (taskbar_exists) { + if (!polling_timer_.IsRunning()) { + polling_timer_.Start( + base::TimeDelta::FromMilliseconds(kCheckTaskbarPollingIntervalMs), + this, + &AutoHidingDesktopBarWin::OnPollingTimer); + } + } else { + if (polling_timer_.IsRunning()) + polling_timer_.Stop(); + } +} + +bool AutoHidingDesktopBarWin::IsEnabled( + AutoHidingDesktopBar::Alignment alignment) { + CheckTaskbars(false); + return taskbars_[static_cast<int>(alignment)].window != NULL; +} + +int AutoHidingDesktopBarWin::GetThickness( + AutoHidingDesktopBar::Alignment alignment) const { + return GetThicknessFromBounds(alignment, GetBounds(alignment)); +} + +AutoHidingDesktopBar::Visibility AutoHidingDesktopBarWin::GetVisibility( + AutoHidingDesktopBar::Alignment alignment) const { + return GetVisibilityFromBounds(alignment, GetBounds(alignment)); +} + +gfx::Rect AutoHidingDesktopBarWin::GetBounds( + AutoHidingDesktopBar::Alignment alignment) const { + HWND taskbar_window = taskbars_[static_cast<int>(alignment)].window; + if (!taskbar_window) + return gfx::Rect(); + + RECT rect; + if (!::GetWindowRect(taskbar_window, &rect)) + return gfx::Rect(); + return gfx::Rect(rect); +} + +int AutoHidingDesktopBarWin::GetThicknessFromBounds( + AutoHidingDesktopBar::Alignment alignment, + const gfx::Rect& taskbar_bounds) const { + switch (alignment) { + case AutoHidingDesktopBar::ALIGN_BOTTOM: + return taskbar_bounds.height(); + case AutoHidingDesktopBar::ALIGN_LEFT: + case AutoHidingDesktopBar::ALIGN_RIGHT: + return taskbar_bounds.width(); + default: + NOTREACHED(); + return 0; + } +} + +AutoHidingDesktopBar::Visibility +AutoHidingDesktopBarWin::GetVisibilityFromBounds( + AutoHidingDesktopBar::Alignment alignment, + const gfx::Rect& taskbar_bounds) const { + switch (alignment) { + case AutoHidingDesktopBar::ALIGN_BOTTOM: + if (taskbar_bounds.bottom() <= work_area_.bottom()) + return VISIBLE; + else if (taskbar_bounds.y() >= + work_area_.bottom() - kHiddenAutoHideTaskbarThickness) + return HIDDEN; + else + return ANIMATING; + + case AutoHidingDesktopBar::ALIGN_LEFT: + if (taskbar_bounds.x() >= work_area_.x()) + return VISIBLE; + else if (taskbar_bounds.right() <= + work_area_.x() + kHiddenAutoHideTaskbarThickness) + return HIDDEN; + else + return ANIMATING; + + case AutoHidingDesktopBar::ALIGN_RIGHT: + if (taskbar_bounds.right() <= work_area_.right()) + return VISIBLE; + else if (taskbar_bounds.x() >= + work_area_.right() - kHiddenAutoHideTaskbarThickness) + return HIDDEN; + else + return ANIMATING; + + default: + NOTREACHED(); + return VISIBLE; + } +} + +void AutoHidingDesktopBarWin::OnPollingTimer() { + CheckTaskbars(true); +} + +bool AutoHidingDesktopBarWin::CheckTaskbars(bool notify_observer) { + bool taskbar_exists = false; + UINT edges[] = { ABE_BOTTOM, ABE_LEFT, ABE_RIGHT }; + for (size_t i = 0; i < kMaxTaskbars; ++i) { + taskbars_[i].window = + views::GetTopmostAutoHideTaskbarForEdge(edges[i], monitor_); + if (taskbars_[i].window) + taskbar_exists = true; + } + if (!taskbar_exists) { + for (size_t i = 0; i < kMaxTaskbars; ++i) { + taskbars_[i].thickness = 0; + taskbars_[i].visibility = AutoHidingDesktopBar::HIDDEN; + } + return false; + } + + bool thickness_changed = false; + for (size_t i = 0; i < kMaxTaskbars; ++i) { + AutoHidingDesktopBar::Alignment alignment = static_cast<Alignment>(i); + + gfx::Rect bounds = GetBounds(alignment); + + // Check the thickness change. + int thickness = GetThicknessFromBounds(alignment, bounds); + if (thickness != taskbars_[i].thickness) { + taskbars_[i].thickness = thickness; + thickness_changed = true; + } + + // Check and notify the visibility change. + AutoHidingDesktopBar::Visibility visibility = + GetVisibilityFromBounds(alignment, bounds); + if (visibility != taskbars_[i].visibility) { + taskbars_[i].visibility = visibility; + if (notify_observer) { + observer_->OnAutoHidingDesktopBarVisibilityChanged(alignment, + visibility); + } + } + } + + // Notify the thickness change if needed. + if (thickness_changed && notify_observer) + observer_->OnAutoHidingDesktopBarThicknessChanged(); + + return true; +} + +// static +AutoHidingDesktopBar* AutoHidingDesktopBar::Create(Observer* observer) { + return new AutoHidingDesktopBarWin(observer); +} diff --git a/chrome/browser/ui/panels/auto_hiding_desktop_bar_win.h b/chrome/browser/ui/panels/auto_hiding_desktop_bar_win.h new file mode 100644 index 0000000..5bc1206 --- /dev/null +++ b/chrome/browser/ui/panels/auto_hiding_desktop_bar_win.h @@ -0,0 +1,66 @@ +// 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 CHROME_BROWSER_UI_PANELS_AUTO_HIDING_DESKTOP_BAR_WIN_H_ +#define CHROME_BROWSER_UI_PANELS_AUTO_HIDING_DESKTOP_BAR_WIN_H_ +#pragma once + +#include "chrome/browser/ui/panels/auto_hiding_desktop_bar.h" + +#include <windows.h> +#include "base/compiler_specific.h" +#include "base/timer.h" +#include "ui/gfx/rect.h" + +class AutoHidingDesktopBarWin : public AutoHidingDesktopBar { + public: + explicit AutoHidingDesktopBarWin(Observer* observer); + virtual ~AutoHidingDesktopBarWin(); + + // Overridden from AutoHidingDesktopBar: + virtual void UpdateWorkArea(const gfx::Rect& work_area) OVERRIDE; + virtual bool IsEnabled(Alignment alignment) OVERRIDE; + virtual int GetThickness(Alignment alignment) const OVERRIDE; + virtual Visibility GetVisibility(Alignment alignment) const OVERRIDE; + +#ifdef UNIT_TEST + void set_work_area(const gfx::Rect& work_area) { + work_area_ = work_area; + } +#endif + + private: + friend class AutoHidingDesktopBarWinTest; + + struct Taskbar { + HWND window; + AutoHidingDesktopBar::Visibility visibility; + int thickness; + }; + + // Callback to perform periodic check for taskbar changes. + void OnPollingTimer(); + + // Returns true if there is at least one auto-hiding taskbar found. + bool CheckTaskbars(bool notify_observer); + + gfx::Rect GetBounds(Alignment alignment) const; + int GetThicknessFromBounds( + Alignment alignment, const gfx::Rect& taskbar_bounds) const; + Visibility GetVisibilityFromBounds( + Alignment alignment, const gfx::Rect& taskbar_bounds) const; + + // Maximum number of taskbars we're interested in: bottom, left, and right. + static const int kMaxTaskbars = 3; + + Observer* observer_; + gfx::Rect work_area_; + HMONITOR monitor_; + Taskbar taskbars_[kMaxTaskbars]; + base::RepeatingTimer<AutoHidingDesktopBarWin> polling_timer_; + + DISALLOW_COPY_AND_ASSIGN(AutoHidingDesktopBarWin); +}; + +#endif // CHROME_BROWSER_UI_PANELS_AUTO_HIDING_DESKTOP_BAR_WIN_H_ diff --git a/chrome/browser/ui/panels/auto_hiding_desktop_bar_win_unittest.cc b/chrome/browser/ui/panels/auto_hiding_desktop_bar_win_unittest.cc new file mode 100644 index 0000000..0a3ca3f --- /dev/null +++ b/chrome/browser/ui/panels/auto_hiding_desktop_bar_win_unittest.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 "chrome/browser/ui/panels/auto_hiding_desktop_bar_win.h" + +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + + +class AutoHidingDesktopBarWinTest : public testing::Test, + public AutoHidingDesktopBar::Observer { + protected: + // Overridden from AutoHidingDesktopBar::Observer: + virtual void OnAutoHidingDesktopBarThicknessChanged() OVERRIDE { + } + + virtual void OnAutoHidingDesktopBarVisibilityChanged( + AutoHidingDesktopBar::Alignment alignment, + AutoHidingDesktopBar::Visibility visibility) OVERRIDE { + } + + void TestGetVisibilityFromBounds() { + scoped_refptr<AutoHidingDesktopBarWin> bar = + new AutoHidingDesktopBarWin(this); + bar->set_work_area(gfx::Rect(0, 0, 800, 600)); + + AutoHidingDesktopBar::Visibility visibility; + + // Tests for bottom bar. + visibility = bar->GetVisibilityFromBounds( + AutoHidingDesktopBar::ALIGN_BOTTOM, gfx::Rect(0, 560, 800, 40)); + EXPECT_EQ(AutoHidingDesktopBar::VISIBLE, visibility); + visibility = bar->GetVisibilityFromBounds( + AutoHidingDesktopBar::ALIGN_BOTTOM, gfx::Rect(0, 598, 800, 40)); + EXPECT_EQ(AutoHidingDesktopBar::HIDDEN, visibility); + visibility = bar->GetVisibilityFromBounds( + AutoHidingDesktopBar::ALIGN_BOTTOM, gfx::Rect(0, 580, 800, 40)); + EXPECT_EQ(AutoHidingDesktopBar::ANIMATING, visibility); + + // Tests for right bar. + visibility = bar->GetVisibilityFromBounds( + AutoHidingDesktopBar::ALIGN_RIGHT, gfx::Rect(760, 0, 40, 600)); + EXPECT_EQ(AutoHidingDesktopBar::VISIBLE, visibility); + visibility = bar->GetVisibilityFromBounds( + AutoHidingDesktopBar::ALIGN_RIGHT, gfx::Rect(798, 0, 40, 600)); + EXPECT_EQ(AutoHidingDesktopBar::HIDDEN, visibility); + visibility = bar->GetVisibilityFromBounds( + AutoHidingDesktopBar::ALIGN_RIGHT, gfx::Rect(780, 0, 40, 600)); + EXPECT_EQ(AutoHidingDesktopBar::ANIMATING, visibility); + + // Tests for left bar. + visibility = bar->GetVisibilityFromBounds( + AutoHidingDesktopBar::ALIGN_LEFT, gfx::Rect(0, 0, 40, 600)); + EXPECT_EQ(AutoHidingDesktopBar::VISIBLE, visibility); + visibility = bar->GetVisibilityFromBounds( + AutoHidingDesktopBar::ALIGN_LEFT, gfx::Rect(-38, 0, 40, 600)); + EXPECT_EQ(AutoHidingDesktopBar::HIDDEN, visibility); + visibility = bar->GetVisibilityFromBounds( + AutoHidingDesktopBar::ALIGN_LEFT, gfx::Rect(-15, 0, 40, 600)); + EXPECT_EQ(AutoHidingDesktopBar::ANIMATING, visibility); + } +}; + +TEST_F(AutoHidingDesktopBarWinTest, GetVisibilityFromBounds) { + TestGetVisibilityFromBounds(); +} diff --git a/chrome/browser/ui/panels/base_panel_browser_test.cc b/chrome/browser/ui/panels/base_panel_browser_test.cc new file mode 100644 index 0000000..b0a4c05 --- /dev/null +++ b/chrome/browser/ui/panels/base_panel_browser_test.cc @@ -0,0 +1,241 @@ +// 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 "chrome/browser/ui/panels/base_panel_browser_test.h" + +#include "base/command_line.h" +#include "base/mac/scoped_nsautorelease_pool.h" +#include "base/message_loop.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/panels/panel_manager.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" +#include "chrome/common/chrome_switches.h" +#include "content/browser/tab_contents/test_tab_contents.h" + +#if defined(OS_MACOSX) +#include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h" +#endif + +namespace { + +const int kTestingWorkAreaWidth = 800; +const int kTestingWorkAreaHeight = 600; +const int kDefaultAutoHidingDesktopBarThickness = 40; +const int kDefaultPanelWidth = 150; +const int kDefaultPanelHeight = 120; + +struct MockDesktopBar { + bool auto_hiding_enabled; + AutoHidingDesktopBar::Visibility visibility; + int thickness; +}; + +class MockAutoHidingDesktopBarImpl : + public BasePanelBrowserTest::MockAutoHidingDesktopBar { + public: + explicit MockAutoHidingDesktopBarImpl(Observer* observer); + virtual ~MockAutoHidingDesktopBarImpl() { } + + // Overridden from AutoHidingDesktopBar: + virtual void UpdateWorkArea(const gfx::Rect& work_area) OVERRIDE; + virtual bool IsEnabled(Alignment alignment) OVERRIDE; + virtual int GetThickness(Alignment alignment) const OVERRIDE; + virtual Visibility GetVisibility(Alignment alignment) const OVERRIDE; + + // Overridden from MockAutoHidingDesktopBar: + virtual void EnableAutoHiding(Alignment alignment, + bool enabled, + int thickness) OVERRIDE; + virtual void SetVisibility(Alignment alignment, + Visibility visibility) OVERRIDE; + virtual void SetThickness(Alignment alignment, int thickness) OVERRIDE; + + void set_observer(Observer* observer) { observer_ = observer; } + + private: + void NotifyVisibilityChange(Alignment alignment, Visibility visibility); + void NotifyThicknessChange(); + + Observer* observer_; + MockDesktopBar mock_desktop_bars[3]; + ScopedRunnableMethodFactory<MockAutoHidingDesktopBarImpl> method_factory_; + + DISALLOW_COPY_AND_ASSIGN(MockAutoHidingDesktopBarImpl); +}; + + +MockAutoHidingDesktopBarImpl::MockAutoHidingDesktopBarImpl( + AutoHidingDesktopBar::Observer* observer) + : observer_(observer), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + memset(mock_desktop_bars, 0, sizeof(mock_desktop_bars)); +} + +void MockAutoHidingDesktopBarImpl::UpdateWorkArea( + const gfx::Rect& work_area) { +} + +bool MockAutoHidingDesktopBarImpl::IsEnabled( + AutoHidingDesktopBar::Alignment alignment) { + return mock_desktop_bars[static_cast<int>(alignment)].auto_hiding_enabled; +} + +int MockAutoHidingDesktopBarImpl::GetThickness( + AutoHidingDesktopBar::Alignment alignment) const { + return mock_desktop_bars[static_cast<int>(alignment)].thickness; +} + +AutoHidingDesktopBar::Visibility +MockAutoHidingDesktopBarImpl::GetVisibility( + AutoHidingDesktopBar::Alignment alignment) const { + return mock_desktop_bars[static_cast<int>(alignment)].visibility; +} + +void MockAutoHidingDesktopBarImpl::EnableAutoHiding( + AutoHidingDesktopBar::Alignment alignment, bool enabled, int thickness) { + MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]); + bar->auto_hiding_enabled = enabled; + bar->thickness = thickness; + observer_->OnAutoHidingDesktopBarThicknessChanged(); +} + +void MockAutoHidingDesktopBarImpl::SetVisibility( + AutoHidingDesktopBar::Alignment alignment, + AutoHidingDesktopBar::Visibility visibility) { + MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]); + if (!bar->auto_hiding_enabled) + return; + if (visibility == bar->visibility) + return; + bar->visibility = visibility; + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &MockAutoHidingDesktopBarImpl::NotifyVisibilityChange, + alignment, + visibility)); +} + +void MockAutoHidingDesktopBarImpl::SetThickness( + AutoHidingDesktopBar::Alignment alignment, int thickness) { + MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]); + if (!bar->auto_hiding_enabled) + return; + if (thickness == bar->thickness) + return; + bar->thickness = thickness; + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &MockAutoHidingDesktopBarImpl::NotifyThicknessChange)); +} + +void MockAutoHidingDesktopBarImpl::NotifyVisibilityChange( + AutoHidingDesktopBar::Alignment alignment, + AutoHidingDesktopBar::Visibility visibility) { + observer_->OnAutoHidingDesktopBarVisibilityChanged(alignment, visibility); +} + +void MockAutoHidingDesktopBarImpl::NotifyThicknessChange() { + observer_->OnAutoHidingDesktopBarThicknessChanged(); +} + +} // namespace + +BasePanelBrowserTest::BasePanelBrowserTest() + : InProcessBrowserTest(), + testing_work_area_(0, 0, kTestingWorkAreaWidth, + kTestingWorkAreaHeight) { +#if defined(OS_MACOSX) + FindBarBridge::disable_animations_during_testing_ = true; +#endif +} + +BasePanelBrowserTest::~BasePanelBrowserTest() { +} + +void BasePanelBrowserTest::SetUpCommandLine(CommandLine* command_line) { + command_line->AppendSwitch(switches::kEnablePanels); +} + +void BasePanelBrowserTest::SetUpOnMainThread() { + InProcessBrowserTest::SetUpOnMainThread(); + + // Setup the work area and desktop bar so that we have consistent testing + // environment for all panel related tests. + PanelManager* panel_manager = PanelManager::GetInstance(); + mock_auto_hiding_desktop_bar_ = new MockAutoHidingDesktopBarImpl( + panel_manager); + panel_manager->set_auto_hiding_desktop_bar(mock_auto_hiding_desktop_bar_); + panel_manager->SetWorkAreaForTesting(testing_work_area_); +} + +Panel* BasePanelBrowserTest::CreatePanelWithParams( + const CreatePanelParams& params) { + // Opening panels on a Mac causes NSWindowController of the Panel window + // to be autoreleased. We need a pool drained after it's done so the test + // can close correctly. The NSWindowController of the Panel window controls + // lifetime of the Browser object so we want to release it as soon as + // possible. In real Chrome, this is done by message pump. + // On non-Mac platform, this is an empty class. + base::mac::ScopedNSAutoreleasePool autorelease_pool; + + Browser* panel_browser = Browser::CreateForApp(Browser::TYPE_PANEL, + params.name, + params.bounds, + browser()->profile()); + EXPECT_TRUE(panel_browser->is_type_panel()); + + TabContentsWrapper* tab_contents = + new TabContentsWrapper(new TestTabContents(browser()->profile(), NULL)); + panel_browser->AddTab(tab_contents, PageTransition::LINK); + + Panel* panel = static_cast<Panel*>(panel_browser->window()); + if (params.show_flag == SHOW_AS_ACTIVE) + panel->Show(); + else + panel->ShowInactive(); + MessageLoopForUI::current()->RunAllPending(); + + return panel; +} + +Panel* BasePanelBrowserTest::CreatePanelWithBounds( + const std::string& panel_name, const gfx::Rect& bounds) { + CreatePanelParams params(panel_name, bounds, SHOW_AS_ACTIVE); + return CreatePanelWithParams(params); +} + +Panel* BasePanelBrowserTest::CreatePanel(const std::string& panel_name) { + CreatePanelParams params(panel_name, gfx::Rect(), SHOW_AS_ACTIVE); + return CreatePanelWithParams(params); +} + +scoped_refptr<Extension> BasePanelBrowserTest::CreateExtension( + const FilePath::StringType& path, + Extension::Location location, + const DictionaryValue& extra_value) { +#if defined(OS_WIN) + FilePath full_path(FILE_PATH_LITERAL("c:\\")); +#else + FilePath full_path(FILE_PATH_LITERAL("/")); +#endif + full_path = full_path.Append(path); + + scoped_ptr<DictionaryValue> input_value(extra_value.DeepCopy()); + input_value->SetString(extension_manifest_keys::kVersion, "1.0.0.0"); + input_value->SetString(extension_manifest_keys::kName, "Sample Extension"); + + std::string error; + scoped_refptr<Extension> extension = Extension::Create( + full_path, location, *input_value, + Extension::STRICT_ERROR_CHECKS, &error); + EXPECT_TRUE(extension.get()); + EXPECT_STREQ("", error.c_str()); + browser()->GetProfile()->GetExtensionService()->OnLoadSingleExtension( + extension.get(), false); + return extension; +} diff --git a/chrome/browser/ui/panels/base_panel_browser_test.h b/chrome/browser/ui/panels/base_panel_browser_test.h new file mode 100644 index 0000000..2f08401 --- /dev/null +++ b/chrome/browser/ui/panels/base_panel_browser_test.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 CHROME_BROWSER_UI_PANELS_BASE_PANEL_BROWSER_TEST_H_ +#define CHROME_BROWSER_UI_PANELS_BASE_PANEL_BROWSER_TEST_H_ +#pragma once + +#include "base/task.h" +#include "base/values.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/panels/auto_hiding_desktop_bar.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "ui/gfx/rect.h" + +class Panel; + +class BasePanelBrowserTest : public InProcessBrowserTest { + public: + class MockAutoHidingDesktopBar : public AutoHidingDesktopBar { + public: + virtual ~MockAutoHidingDesktopBar() { } + + virtual void EnableAutoHiding(Alignment alignment, + bool enabled, + int thickness) = 0; + virtual void SetVisibility(Alignment alignment, Visibility visibility) = 0; + virtual void SetThickness(Alignment alignment, int thickness) = 0; + }; + + BasePanelBrowserTest(); + virtual ~BasePanelBrowserTest(); + + virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE; + virtual void SetUpOnMainThread() OVERRIDE; + + protected: + enum ShowFlag { SHOW_AS_ACTIVE, SHOW_AS_INACTIVE }; + + struct CreatePanelParams { + std::string name; + gfx::Rect bounds; + ShowFlag show_flag; + + CreatePanelParams(const std::string& name, + const gfx::Rect& bounds, + ShowFlag show_flag) + : name(name), + bounds(bounds), + show_flag(show_flag) { + } + }; + + Panel* CreatePanelWithParams(const CreatePanelParams& params); + Panel* CreatePanelWithBounds(const std::string& panel_name, + const gfx::Rect& bounds); + Panel* CreatePanel(const std::string& panel_name); + + scoped_refptr<Extension> CreateExtension(const FilePath::StringType& path, + Extension::Location location, + const DictionaryValue& extra_value); + + gfx::Rect testing_work_area() const { return testing_work_area_; } + + MockAutoHidingDesktopBar* mock_auto_hiding_desktop_bar() const { + return mock_auto_hiding_desktop_bar_.get(); + } + + private: + + gfx::Rect testing_work_area_; + scoped_refptr<MockAutoHidingDesktopBar> mock_auto_hiding_desktop_bar_; +}; + +#endif // CHROME_BROWSER_UI_PANELS_BASE_PANEL_BROWSER_TEST_H_ diff --git a/chrome/browser/ui/panels/panel_browser_view.cc b/chrome/browser/ui/panels/panel_browser_view.cc index 854d703..603b6d6 100644 --- a/chrome/browser/ui/panels/panel_browser_view.cc +++ b/chrome/browser/ui/panels/panel_browser_view.cc @@ -84,7 +84,7 @@ bool PanelBrowserView::CanMaximize() const { void PanelBrowserView::SetBounds(const gfx::Rect& bounds) { bounds_ = bounds; - //// No animation if the panel is being dragged. + // No animation if the panel is being dragged. if (mouse_dragging_) { ::BrowserView::SetBounds(bounds); return; @@ -207,8 +207,10 @@ void PanelBrowserView::OnPanelExpansionStateChanged( break; } + int bottom = panel_->manager()->GetBottomPositionForExpansionState( + expansion_state); gfx::Rect bounds = bounds_; - bounds.set_y(bounds.y() + bounds.height() - height); + bounds.set_y(bottom - height); bounds.set_height(height); SetBounds(bounds); } diff --git a/chrome/browser/ui/panels/panel_browser_view_browsertest.cc b/chrome/browser/ui/panels/panel_browser_view_browsertest.cc index 9fe9db7..6f7d563 100644 --- a/chrome/browser/ui/panels/panel_browser_view_browsertest.cc +++ b/chrome/browser/ui/panels/panel_browser_view_browsertest.cc @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/command_line.h" #include "base/i18n/time_formatting.h" +#include "base/memory/scoped_ptr.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/panels/base_panel_browser_test.h" #include "chrome/browser/ui/panels/panel.h" #include "chrome/browser/ui/panels/panel_browser_frame_view.h" #include "chrome/browser/ui/panels/panel_browser_view.h" @@ -16,7 +16,6 @@ #include "chrome/browser/web_applications/web_app.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" -#include "chrome/test/base/in_process_browser_test.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -28,13 +27,9 @@ #include "views/controls/link.h" #include "views/controls/textfield/textfield.h" -class PanelBrowserViewTest : public InProcessBrowserTest { +class PanelBrowserViewTest : public BasePanelBrowserTest { public: - PanelBrowserViewTest() : InProcessBrowserTest() { } - - virtual void SetUpCommandLine(CommandLine* command_line) { - command_line->AppendSwitch(switches::kEnablePanels); - } + PanelBrowserViewTest() : BasePanelBrowserTest() { } protected: struct MenuItem { @@ -71,19 +66,7 @@ class PanelBrowserViewTest : public InProcessBrowserTest { bool is_cursor_in_view_; }; - enum ShowFlag { SHOW_AS_ACTIVE, SHOW_AS_INACTIVE }; - - PanelBrowserView* CreatePanelBrowserView(const std::string& panel_name, - ShowFlag show_flag) { - Browser* panel_browser = Browser::CreateForApp(Browser::TYPE_PANEL, - panel_name, - gfx::Rect(), - browser()->profile()); - Panel* panel = static_cast<Panel*>(panel_browser->window()); - if (show_flag == SHOW_AS_ACTIVE) - panel->Show(); - else - panel->ShowInactive(); + PanelBrowserView* GetBrowserView(Panel* panel) { return static_cast<PanelBrowserView*>(panel->native_panel()); } @@ -119,37 +102,22 @@ class PanelBrowserViewTest : public InProcessBrowserTest { const std::string& homepage_url, const std::string& options_page) { // Creates a testing extension. -#if defined(OS_WIN) - FilePath full_path(FILE_PATH_LITERAL("c:\\")); -#else - FilePath full_path(FILE_PATH_LITERAL("/")); -#endif - full_path = full_path.Append(path); - DictionaryValue input_value; - input_value.SetString(extension_manifest_keys::kVersion, "1.0.0.0"); - input_value.SetString(extension_manifest_keys::kName, "Sample Extension"); + DictionaryValue extra_value; if (!homepage_url.empty()) { - input_value.SetString(extension_manifest_keys::kHomepageURL, + extra_value.SetString(extension_manifest_keys::kHomepageURL, homepage_url); } if (!options_page.empty()) { - input_value.SetString(extension_manifest_keys::kOptionsPage, + extra_value.SetString(extension_manifest_keys::kOptionsPage, options_page); } - std::string error; - scoped_refptr<Extension> extension = Extension::Create( - full_path, location, input_value, Extension::STRICT_ERROR_CHECKS, - &error); - ASSERT_TRUE(extension.get()); - EXPECT_STREQ("", error.c_str()); - browser()->GetProfile()->GetExtensionService()->OnLoadSingleExtension( - extension.get(), false); + scoped_refptr<Extension> extension = CreateExtension( + path, location, extra_value); // Creates a panel with the app name that comes from the extension ID. - PanelBrowserView* browser_view = CreatePanelBrowserView( - web_app::GenerateApplicationNameFromExtensionId(extension->id()), - SHOW_AS_ACTIVE); - PanelBrowserFrameView* frame_view = browser_view->GetFrameView(); + Panel* panel = CreatePanel( + web_app::GenerateApplicationNameFromExtensionId(extension->id())); + PanelBrowserFrameView* frame_view = GetBrowserView(panel)->GetFrameView(); frame_view->EnsureSettingsMenuCreated(); @@ -175,54 +143,70 @@ class PanelBrowserViewTest : public InProcessBrowserTest { arraysize(expected_panel_menu_items), expected_panel_menu_items); - browser_view->panel()->Close(); + panel->Close(); } void TestShowPanelActiveOrInactive() { - PanelBrowserView* browser_view1 = CreatePanelBrowserView("PanelTest1", - SHOW_AS_ACTIVE); + CreatePanelParams params1("PanelTest1", gfx::Rect(), SHOW_AS_ACTIVE); + Panel* panel1 = CreatePanelWithParams(params1); + PanelBrowserView* browser_view1 = GetBrowserView(panel1); PanelBrowserFrameView* frame_view1 = browser_view1->GetFrameView(); - EXPECT_TRUE(browser_view1->panel()->IsActive()); + EXPECT_TRUE(panel1->IsActive()); EXPECT_EQ(PanelBrowserFrameView::PAINT_AS_ACTIVE, frame_view1->paint_state_); - PanelBrowserView* browser_view2 = CreatePanelBrowserView("PanelTest2", - SHOW_AS_INACTIVE); + CreatePanelParams params2("PanelTest2", gfx::Rect(), SHOW_AS_INACTIVE); + Panel* panel2 = CreatePanelWithParams(params2); + PanelBrowserView* browser_view2 = GetBrowserView(panel2); PanelBrowserFrameView* frame_view2 = browser_view2->GetFrameView(); - EXPECT_FALSE(browser_view2->panel()->IsActive()); + EXPECT_FALSE(panel2->IsActive()); EXPECT_EQ(PanelBrowserFrameView::PAINT_AS_INACTIVE, frame_view2->paint_state_); - browser_view1->panel()->Close(); - browser_view2->panel()->Close(); + panel1->Close(); + panel2->Close(); } // We put all the testing logic in this class instead of the test so that // we do not need to declare each new test as a friend of PanelBrowserView // for the purpose of accessing its private members. - void TestMinimizeAndRestore() { - PanelBrowserView* browser_view1 = CreatePanelBrowserView("PanelTest1", - SHOW_AS_ACTIVE); - Panel* panel1 = browser_view1->panel_.get(); + void TestMinimizeAndRestore(bool enable_auto_hiding) { + PanelManager* panel_manager = PanelManager::GetInstance(); + int expected_bottom_on_minimized = testing_work_area().height(); + int expected_bottom_on_unminimized = expected_bottom_on_minimized; + + // Turn on auto-hiding if requested. + static const int bottom_thickness = 40; + mock_auto_hiding_desktop_bar()->EnableAutoHiding( + AutoHidingDesktopBar::ALIGN_BOTTOM, + enable_auto_hiding, + bottom_thickness); + if (enable_auto_hiding) + expected_bottom_on_unminimized -= bottom_thickness; + + // Create and test one panel first. + Panel* panel1 = CreatePanel("PanelTest1"); + PanelBrowserView* browser_view1 = GetBrowserView(panel1); PanelBrowserFrameView* frame_view1 = browser_view1->GetFrameView(); // Test minimizing/restoring an individual panel. EXPECT_EQ(Panel::EXPANDED, panel1->expansion_state()); int initial_height = panel1->GetBounds().height(); - int titlebar_height = - browser_view1->GetFrameView()->NonClientTopBorderHeight(); + int titlebar_height = frame_view1->NonClientTopBorderHeight(); panel1->SetExpansionState(Panel::MINIMIZED); EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state()); EXPECT_LT(panel1->GetBounds().height(), titlebar_height); EXPECT_GT(panel1->GetBounds().height(), 0); + EXPECT_EQ(expected_bottom_on_minimized, panel1->GetBounds().bottom()); EXPECT_TRUE(IsMouseWatcherStarted()); - EXPECT_FALSE(panel1->IsActive()); WaitTillBoundsAnimationFinished(browser_view1); + EXPECT_FALSE(panel1->IsActive()); panel1->SetExpansionState(Panel::TITLE_ONLY); EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state()); EXPECT_EQ(titlebar_height, panel1->GetBounds().height()); + EXPECT_EQ(expected_bottom_on_unminimized, panel1->GetBounds().bottom()); WaitTillBoundsAnimationFinished(browser_view1); EXPECT_TRUE(frame_view1->close_button_->IsVisible()); EXPECT_TRUE(frame_view1->title_icon_->IsVisible()); @@ -231,6 +215,7 @@ class PanelBrowserViewTest : public InProcessBrowserTest { panel1->SetExpansionState(Panel::EXPANDED); EXPECT_EQ(Panel::EXPANDED, panel1->expansion_state()); EXPECT_EQ(initial_height, panel1->GetBounds().height()); + EXPECT_EQ(expected_bottom_on_unminimized, panel1->GetBounds().bottom()); WaitTillBoundsAnimationFinished(browser_view1); EXPECT_TRUE(frame_view1->close_button_->IsVisible()); EXPECT_TRUE(frame_view1->title_icon_->IsVisible()); @@ -239,59 +224,60 @@ class PanelBrowserViewTest : public InProcessBrowserTest { panel1->SetExpansionState(Panel::TITLE_ONLY); EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state()); EXPECT_EQ(titlebar_height, panel1->GetBounds().height()); + EXPECT_EQ(expected_bottom_on_unminimized, panel1->GetBounds().bottom()); panel1->SetExpansionState(Panel::MINIMIZED); EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state()); EXPECT_LT(panel1->GetBounds().height(), titlebar_height); EXPECT_GT(panel1->GetBounds().height(), 0); + EXPECT_EQ(expected_bottom_on_minimized, panel1->GetBounds().bottom()); // Create 2 more panels for more testing. - PanelBrowserView* browser_view2 = CreatePanelBrowserView("PanelTest2", - SHOW_AS_ACTIVE); - Panel* panel2 = browser_view2->panel_.get(); - - PanelBrowserView* browser_view3 = CreatePanelBrowserView("PanelTest3", - SHOW_AS_ACTIVE); - Panel* panel3 = browser_view3->panel_.get(); + Panel* panel2 = CreatePanel("PanelTest2"); + Panel* panel3 = CreatePanel("PanelTest3"); // Test bringing up or down the title-bar of all minimized panels. EXPECT_EQ(Panel::EXPANDED, panel2->expansion_state()); panel3->SetExpansionState(Panel::MINIMIZED); EXPECT_EQ(Panel::MINIMIZED, panel3->expansion_state()); - PanelManager* panel_manager = PanelManager::GetInstance(); - - panel_manager->BringUpOrDownTitlebarForAllMinimizedPanels(true); + mock_auto_hiding_desktop_bar()->SetVisibility( + AutoHidingDesktopBar::ALIGN_BOTTOM, AutoHidingDesktopBar::VISIBLE); + panel_manager->BringUpOrDownTitlebars(true); + MessageLoop::current()->RunAllPending(); EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state()); EXPECT_EQ(Panel::EXPANDED, panel2->expansion_state()); EXPECT_EQ(Panel::TITLE_ONLY, panel3->expansion_state()); - panel_manager->BringUpOrDownTitlebarForAllMinimizedPanels(false); + mock_auto_hiding_desktop_bar()->SetVisibility( + AutoHidingDesktopBar::ALIGN_BOTTOM, AutoHidingDesktopBar::HIDDEN); + panel_manager->BringUpOrDownTitlebars(false); + MessageLoop::current()->RunAllPending(); EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state()); EXPECT_EQ(Panel::EXPANDED, panel2->expansion_state()); EXPECT_EQ(Panel::MINIMIZED, panel3->expansion_state()); // Test if it is OK to bring up title-bar given the mouse position. - EXPECT_TRUE(panel_manager->ShouldBringUpTitlebarForAllMinimizedPanels( + EXPECT_TRUE(panel_manager->ShouldBringUpTitlebars( panel1->GetBounds().x(), panel1->GetBounds().y())); - EXPECT_FALSE(panel_manager->ShouldBringUpTitlebarForAllMinimizedPanels( + EXPECT_FALSE(panel_manager->ShouldBringUpTitlebars( panel2->GetBounds().x(), panel2->GetBounds().y())); - EXPECT_TRUE(panel_manager->ShouldBringUpTitlebarForAllMinimizedPanels( + EXPECT_TRUE(panel_manager->ShouldBringUpTitlebars( panel3->GetBounds().right() - 1, panel3->GetBounds().bottom() - 1)); - EXPECT_TRUE(panel_manager->ShouldBringUpTitlebarForAllMinimizedPanels( + EXPECT_TRUE(panel_manager->ShouldBringUpTitlebars( panel3->GetBounds().right() - 1, panel3->GetBounds().bottom() + 10)); - EXPECT_FALSE(panel_manager->ShouldBringUpTitlebarForAllMinimizedPanels( + EXPECT_FALSE(panel_manager->ShouldBringUpTitlebars( 0, 0)); // Test that the panel in title-only state should not be minimized // regardless of the current mouse position when the panel is being dragged. panel1->SetExpansionState(Panel::TITLE_ONLY); - EXPECT_FALSE(panel_manager->ShouldBringUpTitlebarForAllMinimizedPanels( + EXPECT_FALSE(panel_manager->ShouldBringUpTitlebars( 0, 0)); browser_view1->OnTitlebarMousePressed(panel1->GetBounds().origin()); browser_view1->OnTitlebarMouseDragged( panel1->GetBounds().origin().Subtract(gfx::Point(5, 5))); - EXPECT_TRUE(panel_manager->ShouldBringUpTitlebarForAllMinimizedPanels( + EXPECT_TRUE(panel_manager->ShouldBringUpTitlebars( 0, 0)); browser_view1->OnTitlebarMouseReleased(); @@ -304,10 +290,9 @@ class PanelBrowserViewTest : public InProcessBrowserTest { } void TestDrawAttention() { - PanelBrowserView* browser_view = CreatePanelBrowserView("PanelTest", - SHOW_AS_ACTIVE); + Panel* panel = CreatePanel("PanelTest"); + PanelBrowserView* browser_view = GetBrowserView(panel); PanelBrowserFrameView* frame_view = browser_view->GetFrameView(); - Panel* panel = browser_view->panel_.get(); SkColor attention_color = frame_view->GetTitleColor( PanelBrowserFrameView::PAINT_FOR_ATTENTION); @@ -345,12 +330,10 @@ class PanelBrowserViewTest : public InProcessBrowserTest { // Test that we cannot bring up other minimized panel if the mouse is over // the panel that draws attension. EXPECT_FALSE(PanelManager::GetInstance()-> - ShouldBringUpTitlebarForAllMinimizedPanels( - panel->GetBounds().x(), panel->GetBounds().y())); + ShouldBringUpTitlebars(panel->GetBounds().x(), panel->GetBounds().y())); // Test that we cannot bring down the panel that is drawing the attention. - PanelManager::GetInstance()->BringUpOrDownTitlebarForAllMinimizedPanels( - false); + PanelManager::GetInstance()->BringUpOrDownTitlebars(false); EXPECT_EQ(Panel::TITLE_ONLY, panel->expansion_state()); // Test that the attention is cleared. @@ -362,13 +345,54 @@ class PanelBrowserViewTest : public InProcessBrowserTest { panel->Close(); } + + void TestChangeAutoHideTaskBarThickness() { + int bottom_bar_thickness = 20; + int right_bar_thickness = 30; + mock_auto_hiding_desktop_bar()->EnableAutoHiding( + AutoHidingDesktopBar::ALIGN_BOTTOM, true, bottom_bar_thickness); + mock_auto_hiding_desktop_bar()->EnableAutoHiding( + AutoHidingDesktopBar::ALIGN_RIGHT, true, right_bar_thickness); + + Panel* panel = CreatePanel("PanelTest"); + EXPECT_EQ(testing_work_area().height() - bottom_bar_thickness, + panel->GetBounds().bottom()); + EXPECT_EQ(testing_work_area().right() - right_bar_thickness, + panel->GetBounds().right()); + + bottom_bar_thickness += 10; + right_bar_thickness += 15; + mock_auto_hiding_desktop_bar()->SetThickness( + AutoHidingDesktopBar::ALIGN_BOTTOM, bottom_bar_thickness); + mock_auto_hiding_desktop_bar()->SetThickness( + AutoHidingDesktopBar::ALIGN_RIGHT, right_bar_thickness); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(testing_work_area().height() - bottom_bar_thickness, + panel->GetBounds().bottom()); + EXPECT_EQ(testing_work_area().right() - right_bar_thickness, + panel->GetBounds().right()); + + bottom_bar_thickness -= 20; + right_bar_thickness -= 10; + mock_auto_hiding_desktop_bar()->SetThickness( + AutoHidingDesktopBar::ALIGN_BOTTOM, bottom_bar_thickness); + mock_auto_hiding_desktop_bar()->SetThickness( + AutoHidingDesktopBar::ALIGN_RIGHT, right_bar_thickness); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(testing_work_area().height() - bottom_bar_thickness, + panel->GetBounds().bottom()); + EXPECT_EQ(testing_work_area().right() - right_bar_thickness, + panel->GetBounds().right()); + + panel->Close(); + } }; // Panel is not supported for Linux view yet. #if !defined(OS_LINUX) || !defined(TOOLKIT_VIEWS) IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, CreatePanel) { - PanelBrowserView* browser_view = CreatePanelBrowserView("PanelTest", - SHOW_AS_ACTIVE); + Panel* panel = CreatePanel("PanelTest"); + PanelBrowserView* browser_view = GetBrowserView(panel); PanelBrowserFrameView* frame_view = browser_view->GetFrameView(); // The bounds animation should not be triggered when the panel is up for the @@ -418,7 +442,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, CreatePanel) { SkColor title_label_color2 = frame_view->title_label_->GetColor(); EXPECT_NE(title_label_color1, title_label_color2); - browser_view->panel()->Close(); + panel->Close(); } IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, ShowPanelActiveOrInactive) { @@ -426,9 +450,8 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, ShowPanelActiveOrInactive) { } IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, ShowOrHideSettingsButton) { - PanelBrowserView* browser_view = CreatePanelBrowserView("PanelTest", - SHOW_AS_ACTIVE); - PanelBrowserFrameView* frame_view = browser_view->GetFrameView(); + Panel* panel = CreatePanel("PanelTest"); + PanelBrowserFrameView* frame_view = GetBrowserView(panel)->GetFrameView(); // Create and hook up the MockMouseWatcher so that we can simulate if the // mouse is over the panel. @@ -438,7 +461,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, ShowOrHideSettingsButton) { // When the panel is created, it is active. Since we cannot programatically // bring the panel back to active state once it is deactivated, we have to // test the cases that the panel is active first. - EXPECT_TRUE(browser_view->panel()->IsActive()); + EXPECT_TRUE(panel->IsActive()); // When the panel is active, the settings button should always be visible. mouse_watcher->MoveMouse(true); @@ -448,8 +471,8 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, ShowOrHideSettingsButton) { // When the panel is inactive, the options button is active per the mouse over // the panel or not. - browser_view->panel()->Deactivate(); - EXPECT_FALSE(browser_view->panel()->IsActive()); + panel->Deactivate(); + EXPECT_FALSE(panel->IsActive()); mouse_watcher->MoveMouse(true); EXPECT_TRUE(frame_view->settings_button_->IsVisible()); @@ -458,8 +481,8 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, ShowOrHideSettingsButton) { } IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, SetBoundsAnimation) { - PanelBrowserView* browser_view = CreatePanelBrowserView("PanelTest", - SHOW_AS_ACTIVE); + Panel* panel = CreatePanel("PanelTest"); + PanelBrowserView* browser_view = GetBrowserView(panel); // Validate that animation should be triggered when SetBounds is called. gfx::Rect target_bounds(browser_view->GetBounds()); @@ -482,7 +505,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, SetBoundsAnimation) { EXPECT_FALSE(browser_view->bounds_animator_->is_animating()); browser_view->OnTitlebarMouseCaptureLost(); - browser_view->panel()->Close(); + panel->Close(); } IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, CreateSettingsMenu) { @@ -494,11 +517,21 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, CreateSettingsMenu) { "http://home", "options.html"); } -IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, MinimizeAndRestore) { - TestMinimizeAndRestore(); +IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, + MinimizeAndRestoreOnNormalTaskBar) { + TestMinimizeAndRestore(false); +} + +IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, + MinimizeAndRestoreOnAutoHideTaskBar) { + TestMinimizeAndRestore(true); } IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, DrawAttention) { TestDrawAttention(); } + +IN_PROC_BROWSER_TEST_F(PanelBrowserViewTest, ChangeAutoHideTaskBarThickness) { + TestChangeAutoHideTaskBarThickness(); +} #endif diff --git a/chrome/browser/ui/panels/panel_browsertest.cc b/chrome/browser/ui/panels/panel_browsertest.cc index 4934fd7..025aa79 100644 --- a/chrome/browser/ui/panels/panel_browsertest.cc +++ b/chrome/browser/ui/panels/panel_browsertest.cc @@ -2,75 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/command_line.h" -#include "base/mac/scoped_nsautorelease_pool.h" -#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/find_bar/find_bar.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" +#include "chrome/browser/ui/panels/base_panel_browser_test.h" #include "chrome/browser/ui/panels/native_panel.h" #include "chrome/browser/ui/panels/panel.h" #include "chrome/browser/ui/panels/panel_manager.h" -#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/common/chrome_notification_types.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/extensions/extension.h" #include "chrome/common/pref_names.h" -#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "content/browser/download/download_manager.h" #include "content/browser/net/url_request_mock_http_job.h" -#include "content/browser/tab_contents/test_tab_contents.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_MACOSX) -#include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h" -#endif - -class PanelBrowserTest : public InProcessBrowserTest { +class PanelBrowserTest : public BasePanelBrowserTest { public: - PanelBrowserTest() : InProcessBrowserTest() { -#if defined(OS_MACOSX) - FindBarBridge::disable_animations_during_testing_ = true; -#endif - } - - virtual void SetUpCommandLine(CommandLine* command_line) { - command_line->AppendSwitch(switches::kEnablePanels); + PanelBrowserTest() : BasePanelBrowserTest() { } protected: - Panel* CreatePanel(const std::string& name, const gfx::Rect& bounds) { - // Opening panels on a Mac causes NSWindowController of the Panel window - // to be autoreleased. We need a pool drained after it's done so the test - // can close correctly. The NSWindowController of the Panel window controls - // lifetime of the Browser object so we want to release it as soon as - // possible. In real Chrome, this is done by message pump. - // On non-Mac platform, this is an empty class. - base::mac::ScopedNSAutoreleasePool autorelease_pool; - - Browser* panel_browser = Browser::CreateForApp(Browser::TYPE_PANEL, - name, - bounds, - browser()->profile()); - EXPECT_TRUE(panel_browser->is_type_panel()); - - TabContentsWrapper* tab_contents = - new TabContentsWrapper(new TestTabContents(browser()->profile(), NULL)); - panel_browser->AddTab(tab_contents, PageTransition::LINK); - - Panel* panel = static_cast<Panel*>(panel_browser->window()); - panel->Show(); - MessageLoopForUI::current()->RunAllPending(); - - return panel; - } - void CloseWindowAndWait(Browser* browser) { // Closing a browser window may involve several async tasks. Need to use // message pump and wait for the notification. @@ -84,51 +39,30 @@ class PanelBrowserTest : public InProcessBrowserTest { EXPECT_EQ(browser_count - 1, BrowserList::size()); } - // Creates a testing extension. - scoped_refptr<Extension> CreateExtension(const FilePath::StringType& path) { -#if defined(OS_WIN) - FilePath full_path(FILE_PATH_LITERAL("c:\\")); -#else - FilePath full_path(FILE_PATH_LITERAL("/")); -#endif - full_path = full_path.Append(path); - DictionaryValue input_value; - input_value.SetString(extension_manifest_keys::kVersion, "1.0.0.0"); - input_value.SetString(extension_manifest_keys::kName, "Sample Extension"); - std::string error; - scoped_refptr<Extension> extension = Extension::Create( - full_path, Extension::INVALID, input_value, - Extension::STRICT_ERROR_CHECKS, &error); - EXPECT_TRUE(extension.get()); - EXPECT_STREQ("", error.c_str()); - browser()->GetProfile()->GetExtensionService()->OnLoadSingleExtension( - extension.get(), false); - return extension; - } - void TestCreatePanelOnOverflow() { PanelManager* panel_manager = PanelManager::GetInstance(); EXPECT_EQ(0, panel_manager->num_panels()); // No panels initially. - // Specify the work area for testing purpose. - panel_manager->SetWorkArea(gfx::Rect(0, 0, 800, 600)); - // Create testing extensions. + DictionaryValue empty_value; scoped_refptr<Extension> extension1 = - CreateExtension(FILE_PATH_LITERAL("extension1")); + CreateExtension(FILE_PATH_LITERAL("extension1"), + Extension::INVALID, empty_value); scoped_refptr<Extension> extension2 = - CreateExtension(FILE_PATH_LITERAL("extension2")); + CreateExtension(FILE_PATH_LITERAL("extension2"), + Extension::INVALID, empty_value); scoped_refptr<Extension> extension3 = - CreateExtension(FILE_PATH_LITERAL("extension3")); + CreateExtension(FILE_PATH_LITERAL("extension3"), + Extension::INVALID, empty_value); // First, create 3 panels. - Panel* panel1 = CreatePanel( + Panel* panel1 = CreatePanelWithBounds( web_app::GenerateApplicationNameFromExtensionId(extension1->id()), gfx::Rect(0, 0, 250, 200)); - Panel* panel2 = CreatePanel( + Panel* panel2 = CreatePanelWithBounds( web_app::GenerateApplicationNameFromExtensionId(extension2->id()), gfx::Rect(0, 0, 300, 200)); - Panel* panel3 = CreatePanel( + Panel* panel3 = CreatePanelWithBounds( web_app::GenerateApplicationNameFromExtensionId(extension1->id()), gfx::Rect(0, 0, 200, 200)); ASSERT_EQ(3, panel_manager->num_panels()); @@ -137,7 +71,7 @@ class PanelBrowserTest : public InProcessBrowserTest { ui_test_utils::WindowedNotificationObserver signal( chrome::NOTIFICATION_BROWSER_CLOSED, Source<Browser>(panel2->browser())); - Panel* panel4 = CreatePanel( + Panel* panel4 = CreatePanelWithBounds( web_app::GenerateApplicationNameFromExtensionId(extension2->id()), gfx::Rect(0, 0, 280, 200)); signal.Wait(); @@ -149,7 +83,7 @@ class PanelBrowserTest : public InProcessBrowserTest { ui_test_utils::WindowedNotificationObserver signal2( chrome::NOTIFICATION_BROWSER_CLOSED, Source<Browser>(panel4->browser())); - Panel* panel5 = CreatePanel( + Panel* panel5 = CreatePanelWithBounds( web_app::GenerateApplicationNameFromExtensionId(extension3->id()), gfx::Rect(0, 0, 300, 200)); signal2.Wait(); @@ -164,7 +98,7 @@ class PanelBrowserTest : public InProcessBrowserTest { ui_test_utils::WindowedNotificationObserver signal4( chrome::NOTIFICATION_BROWSER_CLOSED, Source<Browser>(panel5->browser())); - Panel* panel6 = CreatePanel( + Panel* panel6 = CreatePanelWithBounds( web_app::GenerateApplicationNameFromExtensionId(extension3->id()), gfx::Rect(0, 0, 500, 200)); signal3.Wait(); @@ -176,10 +110,6 @@ class PanelBrowserTest : public InProcessBrowserTest { panel6->Close(); } - void SetWorkArea(const gfx::Rect& work_area) { - PanelManager::GetInstance()->SetWorkArea(gfx::Rect(0, 0, 800, 600)); - } - int horizontal_spacing() { return PanelManager::horizontal_spacing(); } @@ -296,7 +226,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CreatePanel) { PanelManager* panel_manager = PanelManager::GetInstance(); EXPECT_EQ(0, panel_manager->num_panels()); // No panels initially. - Panel* panel = CreatePanel("PanelTest", gfx::Rect()); + Panel* panel = CreatePanel("PanelTest"); EXPECT_EQ(1, panel_manager->num_panels()); gfx::Rect bounds = panel->GetBounds(); @@ -311,7 +241,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CreatePanel) { } IN_PROC_BROWSER_TEST_F(PanelBrowserTest, FindBar) { - Panel* panel = CreatePanel("PanelTest", gfx::Rect(0, 0, 400, 400)); + Panel* panel = CreatePanelWithBounds("PanelTest", gfx::Rect(0, 0, 400, 400)); Browser* browser = panel->browser(); browser->ShowFindBar(); ASSERT_TRUE(browser->GetFindBarController()->find_bar()->IsFindBarVisible()); @@ -329,9 +259,6 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CreatePanelOnOverflow) { #endif IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_DragPanels) { - // Set work area to make the test consistent on different monitor sizes. - SetWorkArea(gfx::Rect(0, 0, 800, 600)); - static const int max_panels = 3; static const int zero_delta = 0; static const int small_delta = 10; @@ -347,7 +274,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_DragPanels) { // Tests with a single panel. { - CreatePanel("PanelTest1", gfx::Rect(0, 0, 100, 100)); + CreatePanelWithBounds("PanelTest1", gfx::Rect(0, 0, 100, 100)); // Drag left. expected_delta_x_after_drag[0] = -big_delta; @@ -385,7 +312,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_DragPanels) { // Tests with two panels. { - CreatePanel("PanelTest2", gfx::Rect(0, 0, 120, 120)); + CreatePanelWithBounds("PanelTest2", gfx::Rect(0, 0, 120, 120)); // Drag left, small delta, expect no shuffle. { @@ -458,7 +385,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_DragPanels) { // Tests with three panels. { - CreatePanel("PanelTest3", gfx::Rect(0, 0, 110, 110)); + CreatePanelWithBounds("PanelTest3", gfx::Rect(0, 0, 110, 110)); // Drag leftmost panel to become rightmost with two shuffles. // We test both shuffles. diff --git a/chrome/browser/ui/panels/panel_manager.cc b/chrome/browser/ui/panels/panel_manager.cc index 4374a72a6..20c0198 100644 --- a/chrome/browser/ui/panels/panel_manager.cc +++ b/chrome/browser/ui/panels/panel_manager.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/window_sizer.h" @@ -28,26 +29,29 @@ const int kPanelDefaultHeightPixels = 290; const double kPanelMaxWidthFactor = 1.0; const double kPanelMaxHeightFactor = 0.5; +// Occasionally some system, like Windows, might not bring up or down the bottom +// bar when the mouse enters or leaves the bottom screen area. This is the +// maximum time we will wait for the bottom bar visibility change notification. +// After the time expires, we bring up/down the titlebars as planned. +const int kMaxMillisecondsWaitForBottomBarVisibilityChange = 1000; + // Single instance of PanelManager. -scoped_ptr<PanelManager> panel_instance; +scoped_refptr<PanelManager> panel_instance; } // namespace // static PanelManager* PanelManager::GetInstance() { - if (!panel_instance.get()) { - panel_instance.reset(new PanelManager()); - } + if (!panel_instance.get()) + panel_instance = new PanelManager(); return panel_instance.get(); } PanelManager::PanelManager() - : max_width_(0), - max_height_(0), - min_x_(0), - current_x_(0), - bottom_edge_y_(0), - dragging_panel_index_(kInvalidPanelIndex), - dragging_panel_original_x_(0) { + : dragging_panel_index_(kInvalidPanelIndex), + dragging_panel_original_x_(0), + delayed_titlebar_action_(NO_ACTION), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { + auto_hiding_desktop_bar_ = AutoHidingDesktopBar::Create(this); OnDisplayChanged(); } @@ -67,13 +71,10 @@ void PanelManager::SetWorkArea(const gfx::Rect& work_area) { return; work_area_ = work_area; - min_x_ = work_area.x(); - current_x_ = work_area.right(); - bottom_edge_y_ = work_area.bottom(); - max_width_ = static_cast<int>(work_area.width() * kPanelMaxWidthFactor); - max_height_ = static_cast<int>(work_area.height() * kPanelMaxHeightFactor); + auto_hiding_desktop_bar_->UpdateWorkArea(work_area_); + AdjustWorkAreaForAutoHidingDesktopBars(); - Rearrange(panels_.begin()); + Rearrange(panels_.begin(), adjusted_work_area_.right()); } void PanelManager::FindAndClosePanelOnOverflow(const Extension* extension) { @@ -97,20 +98,55 @@ void PanelManager::FindAndClosePanelOnOverflow(const Extension* extension) { } Panel* PanelManager::CreatePanel(Browser* browser) { + // Adjust the width and height to fit into our constraint. + int width = browser->override_bounds().width(); + int height = browser->override_bounds().height(); + + if (width == 0 && height == 0) { + width = kPanelDefaultWidthPixels; + height = kPanelDefaultHeightPixels; + } + + int max_panel_width = + static_cast<int>(adjusted_work_area_.width() * kPanelMaxWidthFactor); + int max_panel_height = + static_cast<int>(adjusted_work_area_.height() * kPanelMaxHeightFactor); + + if (width < kPanelMinWidthPixels) + width = kPanelMinWidthPixels; + else if (width > max_panel_width) + width = max_panel_width; + + if (height < kPanelMinHeightPixels) + height = kPanelMinHeightPixels; + else if (height > max_panel_height) + height = max_panel_height; + + // Compute the origin. Ensure that it falls within the adjusted work area by + // closing other panels if needed. + int y = adjusted_work_area_.bottom() - height; + const Extension* extension = NULL; - gfx::Rect bounds = browser->override_bounds(); - while (!ComputeBoundsForNextPanel(&bounds, true)) { + int x; + while ((x = GetRightMostAvaialblePosition() - width) < + adjusted_work_area_.x() ) { if (!extension) extension = Panel::GetExtension(browser); FindAndClosePanelOnOverflow(extension); } - Panel* panel = new Panel(browser, bounds); + // Now create the panel with the computed bounds. + Panel* panel = new Panel(browser, gfx::Rect(x, y, width, height)); panels_.push_back(panel); return panel; } +int PanelManager::GetRightMostAvaialblePosition() const { + return panels_.empty() ? adjusted_work_area_.right() : + (panels_.back()->GetBounds().x() - kPanelsHorizontalSpacing); +} + void PanelManager::Remove(Panel* panel) { // If we're in the process of dragging, delay the removal. if (dragging_panel_index_ != kInvalidPanelIndex) { @@ -133,8 +169,7 @@ void PanelManager::DoRemove(Panel* panel) { return; gfx::Rect bounds = (*iter)->GetBounds(); - current_x_ = bounds.x() + bounds.width(); - Rearrange(panels_.erase(iter)); + Rearrange(panels_.erase(iter), bounds.right()); } void PanelManager::StartDragging(Panel* panel) { @@ -268,8 +303,16 @@ void PanelManager::EndDragging(bool cancelled) { DelayedRemove(); } -bool PanelManager::ShouldBringUpTitlebarForAllMinimizedPanels( - int mouse_x, int mouse_y) const { +bool PanelManager::ShouldBringUpTitlebars(int mouse_x, int mouse_y) const { + // We should always bring up the titlebar if the mouse is over the + // visible auto-hiding bottom bar. + if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM) && + auto_hiding_desktop_bar_->GetVisibility( + AutoHidingDesktopBar::ALIGN_BOTTOM) == + AutoHidingDesktopBar::VISIBLE && + mouse_y >= adjusted_work_area_.bottom()) + return true; + for (Panels::const_iterator iter = panels_.begin(); iter != panels_.end(); ++iter) { if ((*iter)->ShouldBringUpTitlebar(mouse_x, mouse_y)) @@ -278,7 +321,45 @@ bool PanelManager::ShouldBringUpTitlebarForAllMinimizedPanels( return false; } -void PanelManager::BringUpOrDownTitlebarForAllMinimizedPanels(bool bring_up) { +void PanelManager::BringUpOrDownTitlebars(bool bring_up) { + // If the auto-hiding bottom bar exists, delay the action until the bottom + // bar is fully visible or hidden. We do not want both bottom bar and panel + // titlebar to move at the same time but with different speeds. + if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM)) { + AutoHidingDesktopBar::Visibility visibility = auto_hiding_desktop_bar_-> + GetVisibility(AutoHidingDesktopBar::ALIGN_BOTTOM); + if (visibility != (bring_up ? AutoHidingDesktopBar::VISIBLE + : AutoHidingDesktopBar::HIDDEN)) { + // OnAutoHidingDesktopBarVisibilityChanged will handle this. + delayed_titlebar_action_ = bring_up ? BRING_UP : BRING_DOWN; + + // Occasionally some system, like Windows, might not bring up or down the + // bottom bar when the mouse enters or leaves the bottom screen area. + // Thus, we schedule a delayed task to do the work if we do not receive + // the bottom bar visibility change notification within a certain period + // of time. + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &PanelManager::DelayedBringUpOrDownTitlebarsCheck), + kMaxMillisecondsWaitForBottomBarVisibilityChange); + + return; + } + } + + DoBringUpOrDownTitlebars(bring_up); +} + +void PanelManager::DelayedBringUpOrDownTitlebarsCheck() { + if (delayed_titlebar_action_ == NO_ACTION) + return; + + DoBringUpOrDownTitlebars(delayed_titlebar_action_ == BRING_UP); + delayed_titlebar_action_ = NO_ACTION; +} + +void PanelManager::DoBringUpOrDownTitlebars(bool bring_up) { for (Panels::const_iterator iter = panels_.begin(); iter != panels_.end(); ++iter) { Panel* panel = *iter; @@ -297,51 +378,78 @@ void PanelManager::BringUpOrDownTitlebarForAllMinimizedPanels(bool bring_up) { } } -void PanelManager::Rearrange(Panels::iterator iter_to_start) { - if (iter_to_start == panels_.end()) - return; +void PanelManager::AdjustWorkAreaForAutoHidingDesktopBars() { + // Note that we do not care about the desktop bar aligned to the top edge + // since panels could not reach so high due to size constraint. + adjusted_work_area_ = work_area_; + if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM)) { + int space = auto_hiding_desktop_bar_->GetThickness( + AutoHidingDesktopBar::ALIGN_BOTTOM); + adjusted_work_area_.set_height(adjusted_work_area_.height() - space); + } + if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_LEFT)) { + int space = auto_hiding_desktop_bar_->GetThickness( + AutoHidingDesktopBar::ALIGN_LEFT); + adjusted_work_area_.set_x(adjusted_work_area_.x() + space); + adjusted_work_area_.set_width(adjusted_work_area_.width() - space); + } + if (auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_RIGHT)) { + int space = auto_hiding_desktop_bar_->GetThickness( + AutoHidingDesktopBar::ALIGN_RIGHT); + adjusted_work_area_.set_width(adjusted_work_area_.width() - space); + } +} - for (Panels::iterator iter = iter_to_start; iter != panels_.end(); ++iter) { - gfx::Rect new_bounds((*iter)->GetBounds()); - ComputeBoundsForNextPanel(&new_bounds, false); - if (new_bounds != (*iter)->GetBounds()) - (*iter)->SetPanelBounds(new_bounds); +int PanelManager::GetBottomPositionForExpansionState( + Panel::ExpansionState expansion_state) const { + // If there is an auto-hiding desktop bar aligned to the bottom edge, we need + // to move the minimize panel down to the bottom edge. + int bottom = adjusted_work_area_.bottom(); + if (expansion_state == Panel::MINIMIZED && + auto_hiding_desktop_bar_->IsEnabled(AutoHidingDesktopBar::ALIGN_BOTTOM)) { + bottom += auto_hiding_desktop_bar_->GetThickness( + AutoHidingDesktopBar::ALIGN_BOTTOM); } + return bottom; } -bool PanelManager::ComputeBoundsForNextPanel(gfx::Rect* bounds, - bool allow_size_change) { - int width = bounds->width(); - int height = bounds->height(); +void PanelManager::OnAutoHidingDesktopBarThicknessChanged() { + AdjustWorkAreaForAutoHidingDesktopBars(); + Rearrange(panels_.begin(), adjusted_work_area_.right()); +} - // Update the width and/or height to fit into our constraint. - if (allow_size_change) { - if (width == 0 && height == 0) { - width = kPanelDefaultWidthPixels; - height = kPanelDefaultHeightPixels; - } +void PanelManager::OnAutoHidingDesktopBarVisibilityChanged( + AutoHidingDesktopBar::Alignment alignment, + AutoHidingDesktopBar::Visibility visibility) { + if (delayed_titlebar_action_ == NO_ACTION) + return; - if (width < kPanelMinWidthPixels) - width = kPanelMinWidthPixels; - else if (width > max_width_) - width = max_width_; + AutoHidingDesktopBar::Visibility expected_visibility = + delayed_titlebar_action_ == BRING_UP ? AutoHidingDesktopBar::VISIBLE + : AutoHidingDesktopBar::HIDDEN; + if (visibility != expected_visibility) + return; - if (height < kPanelMinHeightPixels) - height = kPanelMinHeightPixels; - else if (height > max_height_) - height = max_height_; - } + DoBringUpOrDownTitlebars(delayed_titlebar_action_ == BRING_UP); + delayed_titlebar_action_ = NO_ACTION; +} - int x = current_x_ - width; - int y = bottom_edge_y_ - height; +void PanelManager::Rearrange(Panels::iterator iter_to_start, + int rightmost_position) { + if (iter_to_start == panels_.end()) + return; - if (x < min_x_) - return false; + for (Panels::iterator iter = iter_to_start; iter != panels_.end(); ++iter) { + Panel* panel = *iter; - current_x_ -= width + kPanelsHorizontalSpacing; + gfx::Rect new_bounds(panel->GetBounds()); + new_bounds.set_x(rightmost_position - new_bounds.width()); + new_bounds.set_y(adjusted_work_area_.bottom() - new_bounds.height()); + if (new_bounds != panel->GetBounds()) + panel->SetPanelBounds(new_bounds); - bounds->SetRect(x, y, width, height); - return true; + rightmost_position = new_bounds.x() - kPanelsHorizontalSpacing; + } } void PanelManager::RemoveAll() { diff --git a/chrome/browser/ui/panels/panel_manager.h b/chrome/browser/ui/panels/panel_manager.h index 7dacd55..998f91f 100644 --- a/chrome/browser/ui/panels/panel_manager.h +++ b/chrome/browser/ui/panels/panel_manager.h @@ -8,7 +8,10 @@ #include <vector> #include "base/basictypes.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/task.h" +#include "chrome/browser/ui/panels/auto_hiding_desktop_bar.h" #include "chrome/browser/ui/panels/panel.h" #include "ui/gfx/rect.h" @@ -16,12 +19,16 @@ class Browser; class Panel; // This class manages a set of panels. -class PanelManager { +// Note that the ref count is needed by using PostTask in the implementation. +class PanelManager : public AutoHidingDesktopBar::Observer, + public base::RefCounted<PanelManager> { public: + typedef std::vector<Panel*> Panels; + // Returns a single instance. static PanelManager* GetInstance(); - ~PanelManager(); + virtual ~PanelManager(); // Called when the display is changed, i.e. work area is updated. void OnDisplayChanged(); @@ -38,32 +45,62 @@ class PanelManager { void Drag(int delta_x); void EndDragging(bool cancelled); - // Should we bring up the titlebar, given the current mouse point? - bool ShouldBringUpTitlebarForAllMinimizedPanels(int mouse_x, - int mouse_y) const; + // Returns true if we should bring up the titlebars, given the current mouse + // point. + bool ShouldBringUpTitlebars(int mouse_x, int mouse_y) const; + + // Brings up or down the titlebars for all minimized panels. + void BringUpOrDownTitlebars(bool bring_up); - // Brings up or down the title-bar for all minimized panels. - void BringUpOrDownTitlebarForAllMinimizedPanels(bool bring_up); + // Returns the bottom position for the panel per its expansion state. If auto- + // hide bottom bar is present, we want to move the minimized panel to the + // bottom of the screen, not the bottom of the work area. + int GetBottomPositionForExpansionState( + Panel::ExpansionState expansion_state) const; int num_panels() const { return panels_.size(); } bool is_dragging_panel() const; - private: - friend class PanelBrowserTest; +#ifdef UNIT_TEST + const Panels& panels() const { return panels_; } + static int horizontal_spacing() { return kPanelsHorizontalSpacing; } - typedef std::vector<Panel*> Panels; + const gfx::Rect& work_area() const { + return work_area_; + } - PanelManager(); + void set_auto_hiding_desktop_bar( + AutoHidingDesktopBar* auto_hiding_desktop_bar) { + auto_hiding_desktop_bar_ = auto_hiding_desktop_bar; + } -#if UNIT_TEST - const Panels& panels() const { return panels_; } - static int horizontal_spacing() { return kPanelsHorizontalSpacing; } + void SetWorkAreaForTesting(const gfx::Rect& work_area) { + SetWorkArea(work_area); + } #endif + private: + enum TitlebarAction { + NO_ACTION, + BRING_UP, + BRING_DOWN + }; + + PanelManager(); + + // Overridden from AutoHidingDesktopBar::Observer: + virtual void OnAutoHidingDesktopBarThicknessChanged() OVERRIDE; + virtual void OnAutoHidingDesktopBarVisibilityChanged( + AutoHidingDesktopBar::Alignment alignment, + AutoHidingDesktopBar::Visibility visibility) OVERRIDE; + // Applies the new work area. This is called by OnDisplayChanged and the test // code. void SetWorkArea(const gfx::Rect& work_area); + // Adjusts the work area to exclude the influence of auto-hiding desktop bars. + void AdjustWorkAreaForAutoHidingDesktopBars(); + // Handles all the panels that're delayed to be removed. void DelayedRemove(); @@ -73,13 +110,7 @@ class PanelManager { // Rearranges the positions of the panels starting from the given iterator. // This is called when the display space has been changed, i.e. working // area being changed or a panel being closed. - void Rearrange(Panels::iterator iter_to_start); - - // Computes the bounds for next panel. - // |allow_size_change| is used to indicate if the panel size can be changed to - // fall within the size constraint, e.g., when the panel is created. - // Returns true if computed bounds are within the displayable area. - bool ComputeBoundsForNextPanel(gfx::Rect* bounds, bool allow_size_change); + void Rearrange(Panels::iterator iter_to_start, int rightmost_position); // Finds one panel to close so that we may have space for the new panel // created by |extension|. @@ -89,7 +120,15 @@ class PanelManager { void DragLeft(); void DragRight(); - // Horizontal spacing between panels. Used for unit testing. + // Checks if the titlebars have been brought up or down. If not, do not wait + // for the notifications to trigger it any more, and start to bring them up or + // down immediately. + void DelayedBringUpOrDownTitlebarsCheck(); + + // Does the real job of bringing up or down the titlebars. + void DoBringUpOrDownTitlebars(bool bring_up); + + int GetRightMostAvaialblePosition() const; Panels panels_; @@ -97,15 +136,15 @@ class PanelManager { // when we're in the process of the dragging. Panels panels_pending_to_remove_; - // Current work area used in computing the panel bounds. + // The maximum work area avaialble. This area does not include the area taken + // by the always-visible (non-auto-hiding) desktop bars. gfx::Rect work_area_; - // Used in computing the bounds of the next panel. - int max_width_; - int max_height_; - int min_x_; - int current_x_; - int bottom_edge_y_; + // The useable work area for computing the panel bounds. This area excludes + // the potential area that could be taken by the auto-hiding desktop + // bars (we only consider those bars that are aligned to bottom, left, and + // right of the screen edges) when they become fully visible. + gfx::Rect adjusted_work_area_; // Panel to drag. size_t dragging_panel_index_; @@ -119,6 +158,12 @@ class PanelManager { // to when the dragging ends. gfx::Rect dragging_panel_bounds_; + scoped_refptr<AutoHidingDesktopBar> auto_hiding_desktop_bar_; + + TitlebarAction delayed_titlebar_action_; + + ScopedRunnableMethodFactory<PanelManager> method_factory_; + static const int kPanelsHorizontalSpacing = 4; DISALLOW_COPY_AND_ASSIGN(PanelManager); diff --git a/chrome/browser/ui/panels/panel_mouse_watcher_win.cc b/chrome/browser/ui/panels/panel_mouse_watcher_win.cc index 590125b..cb7a6ed 100644 --- a/chrome/browser/ui/panels/panel_mouse_watcher_win.cc +++ b/chrome/browser/ui/panels/panel_mouse_watcher_win.cc @@ -36,7 +36,7 @@ class PanelMouseWatcherWin { void OnMouseAction(int mouse_x, int mouse_y); HHOOK mouse_hook_; - bool bring_up_titlebar_; + bool bring_up_titlebars_; DISALLOW_COPY_AND_ASSIGN(PanelMouseWatcherWin); }; @@ -45,7 +45,7 @@ scoped_ptr<PanelMouseWatcherWin> mouse_watcher; PanelMouseWatcherWin::PanelMouseWatcherWin() : mouse_hook_(NULL), - bring_up_titlebar_(false) { + bring_up_titlebars_(false) { mouse_hook_ = ::SetWindowsHookEx( WH_MOUSE_LL, MouseHookProc, GetCurrentModuleHandle(), 0); DCHECK(mouse_hook_); @@ -69,14 +69,13 @@ LRESULT CALLBACK PanelMouseWatcherWin::MouseHookProc(int code, void PanelMouseWatcherWin::OnMouseAction(int mouse_x, int mouse_y) { PanelManager* panel_manager = PanelManager::GetInstance(); - bool bring_up_titlebar = - panel_manager->ShouldBringUpTitlebarForAllMinimizedPanels( - mouse_x, mouse_y); - if (bring_up_titlebar == bring_up_titlebar_) + bool bring_up_titlebars = panel_manager->ShouldBringUpTitlebars( + mouse_x, mouse_y); + if (bring_up_titlebars == bring_up_titlebars_) return; - bring_up_titlebar_ = bring_up_titlebar; + bring_up_titlebars_ = bring_up_titlebars; - panel_manager->BringUpOrDownTitlebarForAllMinimizedPanels(bring_up_titlebar); + panel_manager->BringUpOrDownTitlebars(bring_up_titlebars); } } // namespace diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 4dbb767..2c39a0f 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2975,6 +2975,12 @@ 'browser/ui/omnibox/omnibox_view.h', 'browser/ui/options/options_util.cc', 'browser/ui/options/options_util.h', + 'browser/ui/panels/auto_hiding_desktop_bar_chromeos.cc', + 'browser/ui/panels/auto_hiding_desktop_bar_cocoa.mm', + 'browser/ui/panels/auto_hiding_desktop_bar_gtk.cc', + 'browser/ui/panels/auto_hiding_desktop_bar_win.cc', + 'browser/ui/panels/auto_hiding_desktop_bar_win.h', + 'browser/ui/panels/auto_hiding_desktop_bar.h', 'browser/ui/panels/native_panel.h', 'browser/ui/panels/panel.cc', 'browser/ui/panels/panel.h', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 0e20965..fe7f1ba 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1873,6 +1873,7 @@ 'browser/ui/intents/intents_model_unittest.cc', 'browser/ui/login/login_prompt_unittest.cc', 'browser/ui/omnibox/omnibox_view_unittest.cc', + 'browser/ui/panels/auto_hiding_desktop_bar_win_unittest.cc', 'browser/ui/panels/panel_browser_window_cocoa_unittest.mm', 'browser/ui/search_engines/keyword_editor_controller_unittest.cc', 'browser/ui/shell_dialogs_unittest.cc', @@ -2570,6 +2571,8 @@ 'browser/ui/find_bar/find_bar_host_browsertest.cc', 'browser/ui/gtk/view_id_util_browsertest.cc', 'browser/ui/login/login_prompt_browsertest.cc', + 'browser/ui/panels/base_panel_browser_test.cc', + 'browser/ui/panels/base_panel_browser_test.h', 'browser/ui/panels/panel_app_browsertest.cc', 'browser/ui/panels/panel_browsertest.cc', 'browser/ui/panels/panel_browser_view_browsertest.cc', diff --git a/views/widget/monitor_win.cc b/views/widget/monitor_win.cc index 8e60b90..d840893 100644 --- a/views/widget/monitor_win.cc +++ b/views/widget/monitor_win.cc @@ -4,7 +4,7 @@ #include "views/widget/monitor_win.h" -#include <windows.h> +#include <shellapi.h> #include "base/logging.h" #include "ui/gfx/rect.h" @@ -24,4 +24,14 @@ gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect) { return gfx::Rect(); } +HWND GetTopmostAutoHideTaskbarForEdge(UINT edge, HMONITOR monitor) { + APPBARDATA taskbar_data = { sizeof APPBARDATA, NULL, 0, edge }; + HWND taskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAR, + &taskbar_data)); + return (::IsWindow(taskbar) && (monitor != NULL) && + (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONULL) == monitor) && + (GetWindowLong(taskbar, GWL_EXSTYLE) & WS_EX_TOPMOST)) ? + taskbar : NULL; +} + } // namespace views diff --git a/views/widget/monitor_win.h b/views/widget/monitor_win.h index ac92f9b..7ceacfa 100644 --- a/views/widget/monitor_win.h +++ b/views/widget/monitor_win.h @@ -6,6 +6,7 @@ #define VIEWS_WIDGET_MONITOR_WIN_H_ #pragma once +#include <windows.h> #include "views/views_export.h" namespace gfx { @@ -18,6 +19,11 @@ namespace views { // intersection with the specified rectangle. VIEWS_EXPORT gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect); +// Returns the always-on-top auto-hiding taskbar for edge |edge| (one of +// ABE_LEFT, TOP, RIGHT, or BOTTOM) of monitor |monitor|. NULL is returned +// if nothing is found. +VIEWS_EXPORT HWND GetTopmostAutoHideTaskbarForEdge(UINT edge, HMONITOR monitor); + } // namespace views #endif // VIEWS_WIDGET_MONITOR_WIN_H_ diff --git a/views/widget/native_widget_win.cc b/views/widget/native_widget_win.cc index 2701173..a1bb956 100644 --- a/views/widget/native_widget_win.cc +++ b/views/widget/native_widget_win.cc @@ -39,6 +39,7 @@ #include "views/widget/aero_tooltip_manager.h" #include "views/widget/child_window_message_processor.h" #include "views/widget/drop_target_win.h" +#include "views/widget/monitor_win.h" #include "views/widget/native_widget_delegate.h" #include "views/widget/native_widget_views.h" #include "views/widget/root_view.h" @@ -285,19 +286,6 @@ bool GetMonitorAndRects(const RECT& rect, return true; } -// Returns true if edge |edge| (one of ABE_LEFT, TOP, RIGHT, or BOTTOM) of -// monitor |monitor| has an auto-hiding taskbar that's always-on-top. -bool EdgeHasTopmostAutoHideTaskbar(UINT edge, HMONITOR monitor) { - APPBARDATA taskbar_data = { 0 }; - taskbar_data.cbSize = sizeof APPBARDATA; - taskbar_data.uEdge = edge; - HWND taskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAR, - &taskbar_data)); - return ::IsWindow(taskbar) && (monitor != NULL) && - (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONULL) == monitor) && - (GetWindowLong(taskbar, GWL_EXSTYLE) & WS_EX_TOPMOST); -} - // Links the HWND to its NativeWidget. const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__"; @@ -1639,9 +1627,9 @@ LRESULT NativeWidgetWin::OnNCCalcSize(BOOL mode, LPARAM l_param) { return 0; } } - if (EdgeHasTopmostAutoHideTaskbar(ABE_LEFT, monitor)) + if (GetTopmostAutoHideTaskbarForEdge(ABE_LEFT, monitor)) client_rect->left += kAutoHideTaskbarThicknessPx; - if (EdgeHasTopmostAutoHideTaskbar(ABE_TOP, monitor)) { + if (GetTopmostAutoHideTaskbarForEdge(ABE_TOP, monitor)) { if (GetWidget()->ShouldUseNativeFrame()) { // Tricky bit. Due to a bug in DwmDefWindowProc()'s handling of // WM_NCHITTEST, having any nonclient area atop the window causes the @@ -1657,9 +1645,9 @@ LRESULT NativeWidgetWin::OnNCCalcSize(BOOL mode, LPARAM l_param) { client_rect->top += kAutoHideTaskbarThicknessPx; } } - if (EdgeHasTopmostAutoHideTaskbar(ABE_RIGHT, monitor)) + if (GetTopmostAutoHideTaskbarForEdge(ABE_RIGHT, monitor)) client_rect->right -= kAutoHideTaskbarThicknessPx; - if (EdgeHasTopmostAutoHideTaskbar(ABE_BOTTOM, monitor)) + if (GetTopmostAutoHideTaskbarForEdge(ABE_BOTTOM, monitor)) client_rect->bottom -= kAutoHideTaskbarThicknessPx; // We cannot return WVR_REDRAW when there is nonclient area, or Windows |