summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-26 06:28:18 +0000
committerjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-26 06:28:18 +0000
commit7a91ea9cf3449ef40ca2d4920bee9d6e00190ec4 (patch)
treeb16992d84f10762933d15e0eb03e1a491f6bbd04
parent85878bb1463442fe24b274283a578bd67cc263b0 (diff)
downloadchromium_src-7a91ea9cf3449ef40ca2d4920bee9d6e00190ec4.zip
chromium_src-7a91ea9cf3449ef40ca2d4920bee9d6e00190ec4.tar.gz
chromium_src-7a91ea9cf3449ef40ca2d4920bee9d6e00190ec4.tar.bz2
ash: Use immersive mode for fullscreen
* Remove immersive mode button from maximized window frame * Tie immersive mode to browser-fullscreen only, keep tab-fullscreen with existing UI * Size button exits immersive mode * Add ImageButton::GetImage for testing BUG=177549 TEST=added to browser_tests views_unittests ash_unittests Review URL: https://chromiumcodereview.appspot.com/12316086 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@184600 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/wm/frame_painter.cc51
-rw-r--r--ash/wm/frame_painter.h5
-rw-r--r--ash/wm/frame_painter_unittest.cc114
-rw-r--r--chrome/browser/ui/ash/chrome_shell_delegate.cc17
-rw-r--r--chrome/browser/ui/browser.cc9
-rw-r--r--chrome/browser/ui/browser_window.h4
-rw-r--r--chrome/browser/ui/cocoa/browser_window_cocoa.h1
-rw-r--r--chrome/browser/ui/cocoa/browser_window_cocoa.mm5
-rw-r--r--chrome/browser/ui/gtk/browser_window_gtk.cc4
-rw-r--r--chrome/browser/ui/gtk/browser_window_gtk.h1
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc40
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h8
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc36
-rw-r--r--chrome/browser/ui/views/frame/browser_view.cc34
-rw-r--r--chrome/browser/ui/views/frame/browser_view.h1
-rw-r--r--chrome/browser/ui/views/immersive_mode_controller.cc4
-rw-r--r--chrome/browser/ui/views/tabs/tab_strip.cc7
-rw-r--r--chrome/test/base/test_browser_window.cc4
-rw-r--r--chrome/test/base/test_browser_window.h1
-rw-r--r--ui/views/controls/button/image_button.cc10
-rw-r--r--ui/views/controls/button/image_button.h4
-rw-r--r--ui/views/controls/button/image_button_unittest.cc26
22 files changed, 236 insertions, 150 deletions
diff --git a/ash/wm/frame_painter.cc b/ash/wm/frame_painter.cc
index 419cd39..d859c12 100644
--- a/ash/wm/frame_painter.cc
+++ b/ash/wm/frame_painter.cc
@@ -66,9 +66,6 @@ const int kCloseButtonOffsetY = 0;
// The size and close buttons are designed to slightly overlap in order
// to do fancy hover highlighting.
const int kSizeButtonOffsetX = -1;
-// Space between size and immersive buttons.
-// TODO(jamescook): Adjust for final art.
-const int kImmersiveButtonOffsetX = 2;
// In the pre-Ash era the web content area had a frame along the left edge, so
// user-generated theme images for the new tab page assume they are shifted
// right relative to the header. Now that we have removed the left edge frame
@@ -142,7 +139,6 @@ FramePainter::FramePainter()
window_icon_(NULL),
size_button_(NULL),
close_button_(NULL),
- immersive_button_(NULL),
window_(NULL),
button_separator_(NULL),
top_left_corner_(NULL),
@@ -233,12 +229,6 @@ void FramePainter::UpdateSoloWindowHeader(RootWindow* root_window) {
UpdateSoloWindowInRoot(root_window, NULL /* ignorable_window */);
}
-void FramePainter::AddImmersiveButton(views::ToggleImageButton* button) {
- DCHECK(button);
- immersive_button_ = button;
- immersive_button_->SetVisible(frame_->IsMaximized());
-}
-
gfx::Rect FramePainter::GetBoundsForClientView(
int top_height,
const gfx::Rect& window_bounds) const {
@@ -303,10 +293,6 @@ int FramePainter::NonClientHitTest(views::NonClientFrameView* view,
if (size_button_->visible() &&
size_button_->GetMirroredBounds().Contains(point))
return HTMAXBUTTON;
- if (immersive_button_ &&
- immersive_button_->visible() &&
- immersive_button_->GetMirroredBounds().Contains(point))
- return HTCLIENT; // No special constant, but cannot be HTCAPTION.
// Caption is a safe default.
return HTCAPTION;
@@ -322,8 +308,6 @@ gfx::Size FramePainter::GetMinimumSize(views::NonClientFrameView* view) {
int title_width = GetTitleOffsetX() +
size_button_->width() + kSizeButtonOffsetX +
close_button_->width() + kCloseButtonOffsetX;
- if (immersive_button_ && immersive_button_->visible())
- title_width += immersive_button_->width() + kImmersiveButtonOffsetX;
if (title_width > min_size.width())
min_size.set_width(title_width);
return min_size;
@@ -338,10 +322,6 @@ int FramePainter::GetRightInset() const {
gfx::Size size_button_size = size_button_->GetPreferredSize();
int inset = close_size.width() + kCloseButtonOffsetX +
size_button_size.width() + kSizeButtonOffsetX;
- if (immersive_button_ && immersive_button_->visible()) {
- gfx::Size immersive_size = immersive_button_->GetPreferredSize();
- inset += immersive_size.width() + kImmersiveButtonOffsetX;
- }
return inset;
}
@@ -520,8 +500,10 @@ void FramePainter::PaintTitleBar(views::NonClientFrameView* view,
void FramePainter::LayoutHeader(views::NonClientFrameView* view,
bool shorter_layout) {
- // The new assets only make sense if the window is actually maximized.
- if (shorter_layout && frame_->IsMaximized() &&
+ // The new assets only make sense if the window is actually maximized or
+ // fullscreen.
+ if (shorter_layout &&
+ (frame_->IsMaximized() || frame_->IsFullscreen()) &&
GetTrackedByWorkspace(frame_->GetNativeWindow())) {
SetButtonImages(close_button_,
IDR_AURA_WINDOW_MAXIMIZED_CLOSE2,
@@ -559,17 +541,6 @@ void FramePainter::LayoutHeader(views::NonClientFrameView* view,
IDR_AURA_WINDOW_MAXIMIZE_P);
}
- if (immersive_button_) {
- SetButtonImages(immersive_button_,
- IDR_AURA_WINDOW_IMMERSIVE_ENTER,
- IDR_AURA_WINDOW_IMMERSIVE_ENTER_H,
- IDR_AURA_WINDOW_IMMERSIVE_ENTER_P);
- SetToggledButtonImages(immersive_button_,
- IDR_AURA_WINDOW_IMMERSIVE_EXIT,
- IDR_AURA_WINDOW_IMMERSIVE_EXIT_H,
- IDR_AURA_WINDOW_IMMERSIVE_EXIT_P);
- }
-
gfx::Size close_size = close_button_->GetPreferredSize();
close_button_->SetBounds(
view->width() - close_size.width() - kCloseButtonOffsetX,
@@ -584,16 +555,6 @@ void FramePainter::LayoutHeader(views::NonClientFrameView* view,
size_button_size.width(),
size_button_size.height());
- if (immersive_button_) {
- gfx::Size immersive_size = immersive_button_->GetPreferredSize();
- // TODO(jamescook): Fix layout when we have real art.
- immersive_button_->SetBounds(
- size_button_->x() - immersive_size.width() - kImmersiveButtonOffsetX,
- size_button_->y(),
- immersive_size.width(),
- immersive_size.height());
- }
-
if (window_icon_) {
window_icon_->SetBoundsRect(
gfx::Rect(kIconOffsetX, kIconOffsetY, kIconSize, kIconSize));
@@ -633,10 +594,6 @@ void FramePainter::OnWindowPropertyChanged(aura::Window* window,
gfx::Insets(kResizeInsideBoundsSize, kResizeInsideBoundsSize,
kResizeInsideBoundsSize, kResizeInsideBoundsSize));
}
-
- // Immersive button only shows in maximized windows.
- if (immersive_button_)
- immersive_button_->SetVisible(frame_->IsMaximized());
}
void FramePainter::OnWindowVisibilityChanged(aura::Window* window,
diff --git a/ash/wm/frame_painter.h b/ash/wm/frame_painter.h
index 2f7b5d0..e02ca04 100644
--- a/ash/wm/frame_painter.h
+++ b/ash/wm/frame_painter.h
@@ -76,9 +76,6 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver,
// using frame painters across all root windows.
static void UpdateSoloWindowHeader(aura::RootWindow* root_window);
- // Adds an "immersive mode" button to the layout. Does not take ownership.
- void AddImmersiveButton(views::ToggleImageButton* button);
-
// Helpers for views::NonClientFrameView implementations.
gfx::Rect GetBoundsForClientView(int top_height,
const gfx::Rect& window_bounds) const;
@@ -144,7 +141,6 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver,
private:
FRIEND_TEST_ALL_PREFIXES(FramePainterTest, Basics);
- FRIEND_TEST_ALL_PREFIXES(FramePainterTest, ImmersiveButton);
FRIEND_TEST_ALL_PREFIXES(FramePainterTest, CreateAndDeleteSingleWindow);
FRIEND_TEST_ALL_PREFIXES(FramePainterTest, UseSoloWindowHeader);
FRIEND_TEST_ALL_PREFIXES(FramePainterTest, UseSoloWindowHeaderMultiDisplay);
@@ -213,7 +209,6 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver,
views::View* window_icon_; // May be NULL.
views::ImageButton* size_button_;
views::ImageButton* close_button_;
- views::ToggleImageButton* immersive_button_; // May be NULL.
aura::Window* window_;
// Window frame header/caption parts.
diff --git a/ash/wm/frame_painter_unittest.cc b/ash/wm/frame_painter_unittest.cc
index ecd87f2..4fab97b 100644
--- a/ash/wm/frame_painter_unittest.cc
+++ b/ash/wm/frame_painter_unittest.cc
@@ -16,18 +16,36 @@
#include "ui/aura/root_window.h"
#include "ui/aura/window_observer.h"
#include "ui/base/hit_test.h"
+#include "ui/base/theme_provider.h"
#include "ui/gfx/screen.h"
+#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/non_client_view.h"
-using views::Widget;
+using ui::ThemeProvider;
+using views::Button;
using views::ImageButton;
+using views::NonClientFrameView;
using views::ToggleImageButton;
+using views::Widget;
namespace {
+bool ImagesMatch(ImageButton* button,
+ int normal_image_id,
+ int hovered_image_id,
+ int pressed_image_id) {
+ ThemeProvider* theme = button->GetWidget()->GetThemeProvider();
+ gfx::ImageSkia* normal = theme->GetImageSkiaNamed(normal_image_id);
+ gfx::ImageSkia* hovered = theme->GetImageSkiaNamed(hovered_image_id);
+ gfx::ImageSkia* pressed = theme->GetImageSkiaNamed(pressed_image_id);
+ return button->GetImage(Button::STATE_NORMAL).BackedBySameObjectAs(*normal) &&
+ button->GetImage(Button::STATE_HOVERED).BackedBySameObjectAs(*hovered) &&
+ button->GetImage(Button::STATE_PRESSED).BackedBySameObjectAs(*pressed);
+}
+
class ResizableWidgetDelegate : public views::WidgetDelegate {
public:
ResizableWidgetDelegate(views::Widget* widget) {
@@ -132,37 +150,6 @@ TEST_F(FramePainterTest, Basics) {
EXPECT_EQ(0u, FramePainter::instances_->size());
}
-// Ensure that the immersive button is created and visible when it should be.
-TEST_F(FramePainterTest, ImmersiveButton) {
- scoped_ptr<Widget> widget(CreateTestWidget());
- views::NonClientFrameView* frame = widget->non_client_view()->frame_view();
- FramePainter painter;
- ImageButton size(NULL);
- ImageButton close(NULL);
- painter.Init(
- widget.get(), NULL, &size, &close, FramePainter::SIZE_BUTTON_MAXIMIZES);
-
- // No immersive button by default.
- EXPECT_EQ(NULL, painter.immersive_button_);
-
- // Add an immersive button.
- ToggleImageButton immersive(NULL);
- painter.AddImmersiveButton(&immersive);
-
- // Immersive button starts invisible.
- widget->Show();
- EXPECT_FALSE(immersive.visible());
-
- // Maximizing the window makes it visible.
- widget->Maximize();
- EXPECT_TRUE(immersive.visible());
-
- // A point in the button is treated as client area, so button can be clicked.
- painter.LayoutHeader(frame, false);
- gfx::Point point = immersive.bounds().CenterPoint();
- EXPECT_EQ(HTCLIENT, painter.NonClientHitTest(frame, point));
-}
-
TEST_F(FramePainterTest, CreateAndDeleteSingleWindow) {
// Ensure that creating/deleting a window works well and doesn't cause
// crashes. See crbug.com/155634
@@ -197,6 +184,69 @@ TEST_F(FramePainterTest, CreateAndDeleteSingleWindow) {
root->GetProperty(internal::kSoloWindowFramePainterKey));
}
+TEST_F(FramePainterTest, LayoutHeader) {
+ scoped_ptr<Widget> widget(CreateTestWidget());
+ ImageButton size_button(NULL);
+ ImageButton close_button(NULL);
+ NonClientFrameView* frame_view = widget->non_client_view()->frame_view();
+ frame_view->AddChildView(&size_button);
+ frame_view->AddChildView(&close_button);
+ scoped_ptr<FramePainter> painter(new FramePainter);
+ painter->Init(widget.get(),
+ NULL,
+ &size_button,
+ &close_button,
+ FramePainter::SIZE_BUTTON_MAXIMIZES);
+ widget->Show();
+
+ // Basic layout.
+ painter->LayoutHeader(frame_view, false);
+ EXPECT_TRUE(ImagesMatch(&close_button,
+ IDR_AURA_WINDOW_CLOSE,
+ IDR_AURA_WINDOW_CLOSE_H,
+ IDR_AURA_WINDOW_CLOSE_P));
+ EXPECT_TRUE(ImagesMatch(&size_button,
+ IDR_AURA_WINDOW_MAXIMIZE,
+ IDR_AURA_WINDOW_MAXIMIZE_H,
+ IDR_AURA_WINDOW_MAXIMIZE_P));
+
+ // Shorter layout.
+ painter->LayoutHeader(frame_view, true);
+ EXPECT_TRUE(ImagesMatch(&close_button,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE_H,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE_P));
+ EXPECT_TRUE(ImagesMatch(&size_button,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE_H,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE_P));
+
+ // Maximized shorter layout.
+ widget->Maximize();
+ painter->LayoutHeader(frame_view, true);
+ EXPECT_TRUE(ImagesMatch(&close_button,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE2,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P));
+ EXPECT_TRUE(ImagesMatch(&size_button,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE2,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P));
+
+ // Fullscreen can show the buttons during an immersive reveal, so it should
+ // use the same images as maximized.
+ widget->SetFullscreen(true);
+ painter->LayoutHeader(frame_view, true);
+ EXPECT_TRUE(ImagesMatch(&close_button,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE2,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P));
+ EXPECT_TRUE(ImagesMatch(&size_button,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE2,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P));
+}
+
TEST_F(FramePainterTest, UseSoloWindowHeader) {
// Create a widget and a painter for it.
scoped_ptr<Widget> w1(CreateTestWidget());
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index fc1bf57..5699754 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -85,22 +85,25 @@ void ChromeShellDelegate::NewWindow(bool is_incognito) {
}
void ChromeShellDelegate::ToggleMaximized() {
+ // Only toggle if the user has a window open.
aura::Window* window = ash::wm::GetActiveWindow();
if (!window)
return;
+
+ // TODO(jamescook): If immersive mode replaces fullscreen, rename this
+ // function and the interface to ToggleFullscreen.
+ if (CommandLine::ForCurrentProcess()->
+ HasSwitch(ash::switches::kAshImmersiveMode)) {
+ chrome::ToggleFullscreenMode(GetTargetBrowser());
+ return;
+ }
+
// Get out of fullscreen when in fullscreen mode.
if (ash::wm::IsWindowFullscreen(window)) {
chrome::ToggleFullscreenMode(GetTargetBrowser());
return;
}
ash::wm::ToggleMaximizedWindow(window);
- if (CommandLine::ForCurrentProcess()->
- HasSwitch(ash::switches::kAshImmersiveMode)) {
- // Experiment with automatically entering immersive mode when the user
- // presses the F4 maximize key.
- window->SetProperty(ash::internal::kImmersiveModeKey,
- ash::wm::IsWindowMaximized(window));
- }
}
void ChromeShellDelegate::RestoreTab() {
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index e57f286..64e3c65 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -2167,12 +2167,9 @@ void Browser::UpdateBookmarkBarState(BookmarkBarStateChangeReason reason) {
}
bool Browser::ShouldHideUIForFullscreen() const {
- // On Mac, fullscreen mode has most normal things (in a slide-down panel). On
- // other platforms, we hide some controls when in fullscreen mode.
-#if defined(OS_MACOSX)
- return false;
-#endif
- return window_ && window_->IsFullscreen();
+ // Windows and GTK remove the top controls in fullscreen, but Mac and Ash
+ // keep the controls in a slide-down panel.
+ return window_ && window_->ShouldHideUIForFullscreen();
}
bool Browser::MaybeCreateBackgroundContents(int route_id,
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index fea45d9..65e4802 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -120,6 +120,10 @@ class BrowserWindow : public BaseWindow {
const GURL& url,
FullscreenExitBubbleType bubble_type) = 0;
+ // Windows and GTK remove the top controls in fullscreen, but Mac and Ash
+ // keep the controls in a slide-down panel.
+ virtual bool ShouldHideUIForFullscreen() const = 0;
+
// Returns true if the fullscreen bubble is visible.
virtual bool IsFullscreenBubbleVisible() const = 0;
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index 59095c3..8ce489a0 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -72,6 +72,7 @@ class BrowserWindowCocoa :
virtual void UpdateFullscreenExitBubbleContent(
const GURL& url,
FullscreenExitBubbleType bubble_type) OVERRIDE;
+ virtual bool ShouldHideUIForFullscreen() const OVERRIDE;
virtual bool IsFullscreen() const OVERRIDE;
virtual bool IsFullscreenBubbleVisible() const OVERRIDE;
virtual LocationBar* GetLocationBar() const OVERRIDE;
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index fe0670f..ba96f4c 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -355,6 +355,11 @@ void BrowserWindowCocoa::UpdateFullscreenExitBubbleContent(
[controller_ updateFullscreenExitBubbleURL:url bubbleType:bubble_type];
}
+bool BrowserWindowCocoa::ShouldHideUIForFullscreen() const {
+ // On Mac, fullscreen mode has most normal things (in a slide-down panel).
+ return false;
+}
+
bool BrowserWindowCocoa::IsFullscreen() const {
if ([controller_ inPresentationMode])
CHECK([controller_ isFullscreen]); // Presentation mode must be fullscreen.
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc
index b268fba..d120d84 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_window_gtk.cc
@@ -858,6 +858,10 @@ void BrowserWindowGtk::ExitFullscreen() {
gtk_window_maximize(window_);
}
+bool BrowserWindowGtk::ShouldHideUIForFullscreen() const {
+ return IsFullscreen();
+}
+
bool BrowserWindowGtk::IsFullscreen() const {
return (state_ & GDK_WINDOW_STATE_FULLSCREEN);
}
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.h b/chrome/browser/ui/gtk/browser_window_gtk.h
index aad6e17..d227e23 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.h
+++ b/chrome/browser/ui/gtk/browser_window_gtk.h
@@ -106,6 +106,7 @@ class BrowserWindowGtk
virtual void UpdateFullscreenExitBubbleContent(
const GURL& url,
FullscreenExitBubbleType bubble_type) OVERRIDE;
+ virtual bool ShouldHideUIForFullscreen() const OVERRIDE;
virtual bool IsFullscreen() const OVERRIDE;
virtual bool IsFullscreenBubbleVisible() const OVERRIDE;
virtual LocationBar* GetLocationBar() const OVERRIDE;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 11639c4..6aa4cd3 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -77,7 +77,6 @@ BrowserNonClientFrameViewAsh::BrowserNonClientFrameViewAsh(
: BrowserNonClientFrameView(frame, browser_view),
size_button_(NULL),
close_button_(NULL),
- immersive_button_(NULL),
window_icon_(NULL),
frame_painter_(new ash::FramePainter),
size_button_minimizes_(false) {
@@ -120,19 +119,6 @@ void BrowserNonClientFrameViewAsh::Init() {
// Frame painter handles layout of these buttons.
frame_painter_->Init(frame(), window_icon_, size_button_, close_button_,
size_button_behavior);
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(kAshImmersiveMode)) {
- // Button to toggle immersive mode.
- immersive_button_ = new views::ToggleImageButton(this);
- immersive_button_->SetAccessibleName(
- l10n_util::GetStringUTF16(IDS_ACCNAME_IMMERSIVE));
- immersive_button_->SetTooltipText(
- l10n_util::GetStringUTF16(IDS_TOOLTIP_IMMERSIVE));
- immersive_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
- views::ImageButton::ALIGN_BOTTOM);
- AddChildView(immersive_button_);
- frame_painter_->AddImmersiveButton(immersive_button_);
- }
}
///////////////////////////////////////////////////////////////////////////////
@@ -211,12 +197,9 @@ void BrowserNonClientFrameViewAsh::ResetWindowControls() {
browser_view()->immersive_mode_controller();
if (controller->enabled()) {
bool revealed = controller->IsRevealed();
- immersive_button_->SetVisible(revealed);
size_button_->SetVisible(revealed);
close_button_->SetVisible(revealed);
} else {
- // Only show immersive button for maximized windows.
- immersive_button_->SetVisible(frame()->IsMaximized());
size_button_->SetVisible(true);
close_button_->SetVisible(true);
}
@@ -240,8 +223,8 @@ void BrowserNonClientFrameViewAsh::UpdateWindowTitle() {
// views::View overrides:
void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
- if (frame()->IsFullscreen())
- return; // Nothing visible, don't paint.
+ if (!ShouldPaint())
+ return;
// The primary header image changes based on window activation state and
// theme, so we look it up for each paint.
frame_painter_->PaintHeader(
@@ -320,6 +303,8 @@ void BrowserNonClientFrameViewAsh::ButtonPressed(views::Button* sender,
ResetWindowControls();
if (size_button_minimizes_)
frame()->Minimize();
+ else if (frame()->IsFullscreen()) // Can be clicked in immersive mode.
+ frame()->SetFullscreen(false);
else if (frame()->IsMaximized())
frame()->Restore();
else
@@ -327,14 +312,6 @@ void BrowserNonClientFrameViewAsh::ButtonPressed(views::Button* sender,
// |this| may be deleted - some windows delete their frames on maximize.
} else if (sender == close_button_) {
frame()->Close();
- } else if (CommandLine::ForCurrentProcess()->HasSwitch(kAshImmersiveMode) &&
- sender == immersive_button_) {
- // Toggle immersive mode.
- ImmersiveModeController* controller =
- browser_view()->immersive_mode_controller();
- bool enable = !controller->enabled();
- controller->SetEnabled(enable);
- immersive_button_->SetToggled(enable);
}
if (event.IsShiftDown())
@@ -383,13 +360,14 @@ int BrowserNonClientFrameViewAsh::NonClientTopBorderHeight(
bool BrowserNonClientFrameViewAsh::UseShortHeader() const {
// Restored browser -> tall header
// Maximized browser -> short header
+ // Fullscreen browser (header shows with immersive reveal) -> short header
// Popup&App window -> tall header
// Panel -> short header
// Dialogs use short header and are handled via CustomFrameViewAsh.
Browser* browser = browser_view()->browser();
switch (browser->type()) {
case Browser::TYPE_TABBED:
- return frame()->IsMaximized();
+ return frame()->IsMaximized() || frame()->IsFullscreen();
case Browser::TYPE_POPUP:
return false;
case Browser::TYPE_PANEL:
@@ -417,6 +395,12 @@ void BrowserNonClientFrameViewAsh::LayoutAvatar() {
avatar_button()->SetBoundsRect(avatar_bounds);
}
+bool BrowserNonClientFrameViewAsh::ShouldPaint() const {
+ // Immersive mode windows are fullscreen, but need to paint during a reveal.
+ return !frame()->IsFullscreen() ||
+ browser_view()->immersive_mode_controller()->IsRevealed();
+}
+
void BrowserNonClientFrameViewAsh::PaintToolbarBackground(gfx::Canvas* canvas) {
gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
if (toolbar_bounds.IsEmpty())
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
index 445dab9..4fa5871 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
@@ -79,7 +79,10 @@ class BrowserNonClientFrameViewAsh
// Layout the incognito icon.
void LayoutAvatar();
- void PaintTitleBar(gfx::Canvas* canvas);
+ // Returns true if there is anything to paint. Some fullscreen windows do not
+ // need their frames painted.
+ bool ShouldPaint() const;
+
void PaintToolbarBackground(gfx::Canvas* canvas);
// Windows without a toolbar need to draw their own line under the header,
@@ -96,9 +99,6 @@ class BrowserNonClientFrameViewAsh
views::ImageButton* size_button_;
views::ImageButton* close_button_;
- // Optional button to toggle immersive UI. May be NULL.
- views::ToggleImageButton* immersive_button_;
-
// For popups, the window icon.
TabIconView* window_icon_;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index 3248fbf..f5dc9c0 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -96,34 +96,42 @@ IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, ImmersiveMode) {
static_cast<BrowserNonClientFrameViewAsh*>(
widget->non_client_view()->frame_view());
- // Normal window does not have immersive mode button.
- EXPECT_FALSE(frame_view->immersive_button_->visible());
+ // Immersive mode starts disabled.
+ EXPECT_FALSE(browser_view->immersive_mode_controller()->enabled());
- // Maximized window shows immersive mode button.
- widget->Maximize();
- EXPECT_TRUE(frame_view->immersive_button_->visible());
+ // Frame paints by default.
+ EXPECT_TRUE(frame_view->ShouldPaint());
+
+ // Going fullscreen enables immersive mode.
+ browser_view->EnterFullscreen(GURL(), FEB_TYPE_NONE);
+ EXPECT_TRUE(browser_view->immersive_mode_controller()->enabled());
- // Entering immersive mode hides the caption buttons.
- browser_view->immersive_mode_controller()->SetEnabled(true);
- EXPECT_FALSE(frame_view->immersive_button_->visible());
+ // Entering immersive mode hides the caption buttons and the frame.
EXPECT_FALSE(frame_view->size_button_->visible());
EXPECT_FALSE(frame_view->close_button_->visible());
+ EXPECT_FALSE(frame_view->ShouldPaint());
- // An immersive reveal shows the buttons.
+ // Frame abuts top of window.
+ EXPECT_EQ(0, frame_view->NonClientTopBorderHeight(false));
+
+ // An immersive reveal shows the buttons and the top of the frame.
browser_view->immersive_mode_controller()->StartRevealForTest();
- EXPECT_TRUE(frame_view->immersive_button_->visible());
EXPECT_TRUE(frame_view->size_button_->visible());
EXPECT_TRUE(frame_view->close_button_->visible());
+ EXPECT_TRUE(frame_view->ShouldPaint());
// Ending reveal hides them again.
browser_view->immersive_mode_controller()->CancelReveal();
- EXPECT_FALSE(frame_view->immersive_button_->visible());
EXPECT_FALSE(frame_view->size_button_->visible());
EXPECT_FALSE(frame_view->close_button_->visible());
+ EXPECT_FALSE(frame_view->ShouldPaint());
+
+ // Exiting fullscreen exits immersive mode.
+ browser_view->ExitFullscreen();
+ EXPECT_FALSE(browser_view->immersive_mode_controller()->enabled());
- // Exiting immersive mode makes them visible again.
- browser_view->immersive_mode_controller()->SetEnabled(false);
- EXPECT_TRUE(frame_view->immersive_button_->visible());
+ // Exiting immersive mode makes controls and frame visible again.
EXPECT_TRUE(frame_view->size_button_->visible());
EXPECT_TRUE(frame_view->close_button_->visible());
+ EXPECT_TRUE(frame_view->ShouldPaint());
}
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 5e5ec9c..7ae027f 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -121,6 +121,7 @@
#include "ui/views/window/dialog_delegate.h"
#if defined(USE_ASH)
+#include "ash/ash_switches.h"
#include "ash/launcher/launcher.h"
#include "ash/launcher/launcher_model.h"
#include "ash/shell.h"
@@ -194,6 +195,19 @@ bool ShouldSaveOrRestoreWindowPos() {
return true;
}
+// Returns whether immersive mode should replace fullscreen, which should only
+// occur for "browser-fullscreen" and not for "tab-fullscreen" (which has a URL
+// for the tab entering fullscreen).
+bool UseImmersiveFullscreen(const GURL& url) {
+#if defined(USE_ASH)
+ bool is_browser_fullscreen = url.is_empty();
+ return is_browser_fullscreen &&
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ ash::switches::kAshImmersiveMode);
+#endif
+ return false;
+}
+
} // namespace
///////////////////////////////////////////////////////////////////////////////
@@ -766,7 +780,10 @@ void BrowserView::ExitFullscreen() {
void BrowserView::UpdateFullscreenExitBubbleContent(
const GURL& url,
FullscreenExitBubbleType bubble_type) {
- if (bubble_type == FEB_TYPE_NONE) {
+ // Immersive mode has no exit bubble because it has a visible strip at the
+ // top that gives the user a hover target.
+ // TODO(jamescook): Figure out what to do with mouse-lock.
+ if (bubble_type == FEB_TYPE_NONE || UseImmersiveFullscreen(url)) {
fullscreen_bubble_.reset();
} else if (fullscreen_bubble_.get()) {
fullscreen_bubble_->UpdateContent(url, bubble_type);
@@ -776,6 +793,14 @@ void BrowserView::UpdateFullscreenExitBubbleContent(
}
}
+bool BrowserView::ShouldHideUIForFullscreen() const {
+#if defined(USE_ASH)
+ // Immersive reveal needs UI for the slide-down top panel.
+ return IsFullscreen() && !immersive_mode_controller_->IsRevealed();
+#endif
+ return IsFullscreen();
+}
+
bool BrowserView::IsFullscreen() const {
return frame_->IsFullscreen();
}
@@ -2282,7 +2307,9 @@ void BrowserView::ProcessFullscreen(bool fullscreen,
browser_->WindowFullscreenStateChanged();
if (fullscreen) {
- if (!chrome::IsRunningInAppMode() && type != FOR_METRO) {
+ if (!chrome::IsRunningInAppMode() &&
+ type != FOR_METRO &&
+ !UseImmersiveFullscreen(url)) {
fullscreen_bubble_.reset(new FullscreenExitBubbleViews(
GetWidget(), browser_.get(), url, bubble_type));
}
@@ -2296,6 +2323,9 @@ void BrowserView::ProcessFullscreen(bool fullscreen,
#endif
}
+ if (UseImmersiveFullscreen(url))
+ immersive_mode_controller_->SetEnabled(fullscreen);
+
// Undo our anti-jankiness hacks and force the window to re-layout now that
// it's in its final position.
ignore_layout_ = false;
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index d6c3f20..dedbba1 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -287,6 +287,7 @@ class BrowserView : public BrowserWindow,
virtual void UpdateFullscreenExitBubbleContent(
const GURL& url,
FullscreenExitBubbleType bubble_type) OVERRIDE;
+ virtual bool ShouldHideUIForFullscreen() const OVERRIDE;
virtual bool IsFullscreen() const OVERRIDE;
#if defined(OS_WIN)
virtual void SetMetroSnapMode(bool enable) OVERRIDE;
diff --git a/chrome/browser/ui/views/immersive_mode_controller.cc b/chrome/browser/ui/views/immersive_mode_controller.cc
index a532c55..6caffd0 100644
--- a/chrome/browser/ui/views/immersive_mode_controller.cc
+++ b/chrome/browser/ui/views/immersive_mode_controller.cc
@@ -245,8 +245,8 @@ class ImmersiveModeController::WindowObserver : public aura::WindowObserver {
intptr_t old) OVERRIDE {
using aura::client::kShowStateKey;
if (key == kShowStateKey) {
- // Disable immersive mode when leaving the maximized state.
- if (window->GetProperty(kShowStateKey) != ui::SHOW_STATE_MAXIMIZED)
+ // Disable immersive mode when leaving the fullscreen state.
+ if (window->GetProperty(kShowStateKey) != ui::SHOW_STATE_FULLSCREEN)
controller_->SetEnabled(false);
return;
}
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 9b70dec..ac77cd4 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -313,7 +313,7 @@ class NewTabButton : public views::ImageButton {
ui::ScaleFactor scale_factor) const;
gfx::ImageSkia GetImageForState(views::CustomButton::ButtonState state,
ui::ScaleFactor scale_factor) const;
- gfx::ImageSkia GetImage(ui::ScaleFactor scale_factor) const;
+ gfx::ImageSkia GetImageForScale(ui::ScaleFactor scale_factor) const;
// Tab strip that contains this button.
TabStrip* tab_strip_;
@@ -374,7 +374,7 @@ void NewTabButton::OnMouseReleased(const ui::MouseEvent& event) {
#endif
void NewTabButton::OnPaint(gfx::Canvas* canvas) {
- gfx::ImageSkia image = GetImage(canvas->scale_factor());
+ gfx::ImageSkia image = GetImageForScale(canvas->scale_factor());
canvas->DrawImageInt(image, 0, height() - image.height());
}
@@ -497,7 +497,8 @@ gfx::ImageSkia NewTabButton::GetImageForState(
return gfx::ImageSkia(canvas.ExtractImageRep());
}
-gfx::ImageSkia NewTabButton::GetImage(ui::ScaleFactor scale_factor) const {
+gfx::ImageSkia NewTabButton::GetImageForScale(
+ ui::ScaleFactor scale_factor) const {
if (!hover_animation_->is_animating())
return GetImageForState(state(), scale_factor);
return gfx::ImageSkiaOperations::CreateBlendedImage(
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc
index a5a95ec..22a208c 100644
--- a/chrome/test/base/test_browser_window.cc
+++ b/chrome/test/base/test_browser_window.cc
@@ -50,6 +50,10 @@ bool TestBrowserWindow::IsMinimized() const {
return false;
}
+bool TestBrowserWindow::ShouldHideUIForFullscreen() const {
+ return false;
+}
+
bool TestBrowserWindow::IsFullscreen() const {
return false;
}
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index c7dca87..a440dd9 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -59,6 +59,7 @@ class TestBrowserWindow : public BrowserWindow {
virtual void UpdateFullscreenExitBubbleContent(
const GURL& url,
FullscreenExitBubbleType bubble_type) OVERRIDE {}
+ virtual bool ShouldHideUIForFullscreen() const OVERRIDE;
virtual bool IsFullscreen() const OVERRIDE;
#if defined(OS_WIN)
virtual void SetMetroSnapMode(bool enable) OVERRIDE {}
diff --git a/ui/views/controls/button/image_button.cc b/ui/views/controls/button/image_button.cc
index a93a1dc..c93e559 100644
--- a/ui/views/controls/button/image_button.cc
+++ b/ui/views/controls/button/image_button.cc
@@ -32,6 +32,10 @@ ImageButton::ImageButton(ButtonListener* listener)
ImageButton::~ImageButton() {
}
+const gfx::ImageSkia& ImageButton::GetImage(ButtonState state) const {
+ return images_[state];
+}
+
void ImageButton::SetImage(ButtonState state, const gfx::ImageSkia* image) {
images_[state] = image ? *image : gfx::ImageSkia();
PreferredSizeChanged();
@@ -175,6 +179,12 @@ void ToggleImageButton::SetToggledTooltipText(const string16& tooltip) {
////////////////////////////////////////////////////////////////////////////////
// ToggleImageButton, ImageButton overrides:
+const gfx::ImageSkia& ToggleImageButton::GetImage(ButtonState state) const {
+ if (toggled_)
+ return alternate_images_[state];
+ return images_[state];
+}
+
void ToggleImageButton::SetImage(ButtonState state,
const gfx::ImageSkia* image) {
if (toggled_) {
diff --git a/ui/views/controls/button/image_button.h b/ui/views/controls/button/image_button.h
index 180ead0..e61975f 100644
--- a/ui/views/controls/button/image_button.h
+++ b/ui/views/controls/button/image_button.h
@@ -35,6 +35,9 @@ class VIEWS_EXPORT ImageButton : public CustomButton {
explicit ImageButton(ButtonListener* listener);
virtual ~ImageButton();
+ // Returns the image for a given |state|.
+ virtual const gfx::ImageSkia& GetImage(ButtonState state) const;
+
// Set the image the button should use for the provided state.
virtual void SetImage(ButtonState state, const gfx::ImageSkia* image);
@@ -116,6 +119,7 @@ class VIEWS_EXPORT ToggleImageButton : public ImageButton {
void SetToggledTooltipText(const string16& tooltip);
// Overridden from ImageButton:
+ virtual const gfx::ImageSkia& GetImage(ButtonState state) const OVERRIDE;
virtual void SetImage(ButtonState state,
const gfx::ImageSkia* image) OVERRIDE;
diff --git a/ui/views/controls/button/image_button_unittest.cc b/ui/views/controls/button/image_button_unittest.cc
index 2bdc446..e4331b5 100644
--- a/ui/views/controls/button/image_button_unittest.cc
+++ b/ui/views/controls/button/image_button_unittest.cc
@@ -80,6 +80,32 @@ TEST_F(ImageButtonTest, Basics) {
EXPECT_TRUE(button.overlay_image_.isNull());
}
+TEST_F(ImageButtonTest, SetAndGetImage) {
+ ImageButton button(NULL);
+
+ // Images start as null.
+ EXPECT_TRUE(button.GetImage(Button::STATE_NORMAL).isNull());
+ EXPECT_TRUE(button.GetImage(Button::STATE_HOVERED).isNull());
+ EXPECT_TRUE(button.GetImage(Button::STATE_PRESSED).isNull());
+ EXPECT_TRUE(button.GetImage(Button::STATE_DISABLED).isNull());
+
+ // Setting images works as expected.
+ gfx::ImageSkia image1 = CreateTestImage(10, 11);
+ gfx::ImageSkia image2 = CreateTestImage(20, 21);
+ button.SetImage(Button::STATE_NORMAL, &image1);
+ button.SetImage(Button::STATE_HOVERED, &image2);
+ EXPECT_TRUE(
+ button.GetImage(Button::STATE_NORMAL).BackedBySameObjectAs(image1));
+ EXPECT_TRUE(
+ button.GetImage(Button::STATE_HOVERED).BackedBySameObjectAs(image2));
+ EXPECT_TRUE(button.GetImage(Button::STATE_PRESSED).isNull());
+ EXPECT_TRUE(button.GetImage(Button::STATE_DISABLED).isNull());
+
+ // ImageButton supports NULL image pointers.
+ button.SetImage(Button::STATE_NORMAL, NULL);
+ EXPECT_TRUE(button.GetImage(Button::STATE_NORMAL).isNull());
+}
+
TEST_F(ImageButtonTest, ImagePositionWithBorder) {
ImageButton button(NULL);
gfx::ImageSkia image = CreateTestImage(20, 30);