diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-26 06:28:18 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-26 06:28:18 +0000 |
commit | 7a91ea9cf3449ef40ca2d4920bee9d6e00190ec4 (patch) | |
tree | b16992d84f10762933d15e0eb03e1a491f6bbd04 | |
parent | 85878bb1463442fe24b274283a578bd67cc263b0 (diff) | |
download | chromium_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
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); |