diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 12 | ||||
-rw-r--r-- | chrome/browser/views/browser_views.vcproj | 8 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.cc | 9 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.h | 3 | ||||
-rw-r--r-- | chrome/browser/views/fullscreen_exit_bubble.cc | 219 | ||||
-rw-r--r-- | chrome/browser/views/fullscreen_exit_bubble.h | 85 | ||||
-rw-r--r-- | chrome/browser/views/toolbar_view.cc | 2 | ||||
-rw-r--r-- | chrome/views/accelerator.cc | 3 |
8 files changed, 340 insertions, 1 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index b61864d..463736a 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -559,6 +559,9 @@ each locale. --> <message name="IDS_SHOW_BOOKMARK_BAR" desc="The toggle to show the bookmark bar"> &Always show bookmarks bar </message> + <message name="IDS_FULLSCREEN" desc="Switches into fullscreen mode"> + &Full screen + </message> <message name="IDS_CLEAR_BROWSING_DATA" desc="The text label for the menu item for clearing of browsing data"> &Clear browsing data... </message> @@ -1487,6 +1490,12 @@ each locale. --> Close find bar </message> + + <!-- Fullscreen mode --> + <message name="IDS_EXIT_FULLSCREEN_MODE" desc="Clickable message displayed on entering fullscreen mode to tell users how to return to normal mode"> + Exit full screen (<ph name="ACCELERATOR">$1<ex>F11</ex></ph>) + </message> + <!-- Task Manager Window --> <message name="IDS_TASK_MANAGER_KILL" desc="The caption of the Task Manager kill button"> @@ -3189,6 +3198,9 @@ each locale. --> <message name="IDS_F1_KEY" desc="F1 key"> F1 </message> + <message name="IDS_F11_KEY" desc="F11 key"> + F11 + </message> <!-- Strings used in local directory listings --> <message name="IDS_DIRECTORY_LISTING_HEADER" desc="When viewing a local directory, this is the title of the page."> diff --git a/chrome/browser/views/browser_views.vcproj b/chrome/browser/views/browser_views.vcproj index 870ab14..92d345d 100644 --- a/chrome/browser/views/browser_views.vcproj +++ b/chrome/browser/views/browser_views.vcproj @@ -554,6 +554,14 @@ > </File> <File + RelativePath=".\fullscreen_exit_bubble.cc" + > + </File> + <File + RelativePath=".\fullscreen_exit_bubble.h" + > + </File> + <File RelativePath=".\go_button.cc" > </File> diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index b2fbe13a..c0476d5 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -22,6 +22,7 @@ #include "chrome/browser/views/clear_browsing_data.h" #include "chrome/browser/views/download_shelf_view.h" #include "chrome/browser/views/frame/browser_frame.h" +#include "chrome/browser/views/fullscreen_exit_bubble.h" #include "chrome/browser/views/html_dialog_view.h" #include "chrome/browser/views/importer_view.h" #include "chrome/browser/views/infobars/infobar_container.h" @@ -577,7 +578,9 @@ void BrowserView::SetFullscreen(bool fullscreen) { if (bookmark_bar_view_.get()) bookmark_bar_view_->OnFullscreenToggled(fullscreen_); - HWND hwnd = GetWidget()->GetHWND(); + // Size/position/style window appropriately. + views::Widget* widget = GetWidget(); + HWND hwnd = widget->GetHWND(); gfx::Rect new_rect; if (fullscreen_) { // Save current window information. @@ -605,6 +608,10 @@ void BrowserView::SetFullscreen(bool fullscreen) { // This will cause the window to re-layout. SetWindowPos(hwnd, NULL, new_rect.x(), new_rect.y(), new_rect.width(), new_rect.height(), SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + + // Turn fullscreen bubble on or off. + fullscreen_bubble_.reset(fullscreen_ ? + new FullscreenExitBubble(widget, browser_.get()) : NULL); } bool BrowserView::IsFullscreen() const { diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index dccd54d..c91af8e 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -24,6 +24,7 @@ class BookmarkBarView; class Browser; class BrowserToolbarView; class EncodingMenuControllerDelegate; +class FullscreenExitBubble; class InfoBarContainer; class Menu; class StatusBubbleViews; @@ -389,6 +390,8 @@ class BrowserView : public BrowserWindow, // Saved window information from before entering fullscreen mode. SavedWindowInfo saved_window_info_; + scoped_ptr<FullscreenExitBubble> fullscreen_bubble_; + // Lazily created representation of the system menu. scoped_ptr<Menu> system_menu_; diff --git a/chrome/browser/views/fullscreen_exit_bubble.cc b/chrome/browser/views/fullscreen_exit_bubble.cc new file mode 100644 index 0000000..667088a --- /dev/null +++ b/chrome/browser/views/fullscreen_exit_bubble.cc @@ -0,0 +1,219 @@ +// Copyright (c) 2009 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/views/fullscreen_exit_bubble.h" + +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/views/root_view.h" +#include "grit/generated_resources.h" + + +// FullscreenExitView ---------------------------------------------------------- + +class FullscreenExitBubble::FullscreenExitView : public views::View { + public: + FullscreenExitView(FullscreenExitBubble* bubble, + views::WidgetWin* popup, + const std::wstring& accelerator); + virtual ~FullscreenExitView(); + + // views::View + virtual gfx::Size GetPreferredSize(); + + private: + static const int kPaddingPixels; // Number of pixels around all sides of link + + // views::View + virtual void Layout(); + virtual void Paint(ChromeCanvas* canvas); + + // Handle to the HWND that contains us. + views::WidgetWin* popup_; + + // Clickable hint text to show in the bubble. + views::Link link_; +}; + +const int FullscreenExitBubble::FullscreenExitView::kPaddingPixels = 8; + +FullscreenExitBubble::FullscreenExitView::FullscreenExitView( + FullscreenExitBubble* bubble, + views::WidgetWin* popup, + const std::wstring& accelerator) + : popup_(popup) { + link_.SetParentOwned(false); + link_.SetText(l10n_util::GetStringF(IDS_EXIT_FULLSCREEN_MODE, accelerator)); + link_.SetController(bubble); + link_.SetFont(ResourceBundle::GetSharedInstance().GetFont( + ResourceBundle::LargeFont)); + link_.SetNormalColor(SK_ColorWHITE); + link_.SetHighlightedColor(SK_ColorWHITE); + AddChildView(&link_); +} + +FullscreenExitBubble::FullscreenExitView::~FullscreenExitView() { +} + +gfx::Size FullscreenExitBubble::FullscreenExitView::GetPreferredSize() { + gfx::Size preferred_size(link_.GetPreferredSize()); + preferred_size.Enlarge(kPaddingPixels * 2, kPaddingPixels * 2); + return preferred_size; +} + +void FullscreenExitBubble::FullscreenExitView::Layout() { + gfx::Size link_preferred_size(link_.GetPreferredSize()); + link_.SetBounds(kPaddingPixels, + height() - kPaddingPixels - link_preferred_size.height(), + link_preferred_size.width(), link_preferred_size.height()); +} + +void FullscreenExitBubble::FullscreenExitView::Paint(ChromeCanvas* canvas) { + // Create a round-bottomed rect to fill the whole View. + CRect parent_rect; + SkRect rect; + SkScalar padding = SkIntToScalar(kPaddingPixels); + // The "-padding" top coordinate ensures that the rect is always tall enough + // to contain the complete rounded corner radius. If we set this to 0, as the + // popup slides offscreen (in reality, squishes to 0 height), the corners will + // flatten out as the height becomes less than the corner radius. + rect.set(0, -padding, SkIntToScalar(width()), SkIntToScalar(height())); + SkScalar rad[8] = { 0, 0, 0, 0, padding, padding, padding, padding }; + SkPath path; + path.addRoundRect(rect, rad, SkPath::kCW_Direction); + + // Fill it black. + SkPaint paint; + paint.setStyle(SkPaint::kFill_Style); + paint.setFlags(SkPaint::kAntiAlias_Flag); + paint.setColor(SK_ColorBLACK); + canvas->drawPath(path, paint); +} + + +// FullscreenExitBubble -------------------------------------------------------- + +const double FullscreenExitBubble::kOpacity = 0.7; +const int FullscreenExitBubble::kInitialDelayMs = 2300; +const int FullscreenExitBubble::kPositionCheckHz = 10; +const int FullscreenExitBubble::kSlideInRegionHeightPx = 4; +const int FullscreenExitBubble::kSlideInDurationMs = 350; +const int FullscreenExitBubble::kSlideOutDurationMs = 700; + +FullscreenExitBubble::FullscreenExitBubble( + views::Widget* frame, + CommandUpdater::CommandUpdaterDelegate* delegate) + : root_view_(frame->GetRootView()), + delegate_(delegate), + popup_(new views::WidgetWin()), + size_animation_(new SlideAnimation(this)) { + size_animation_->Reset(1); + + // Create the contents view. + views::Accelerator accelerator(0, false, false, false); + bool got_accelerator = frame->GetAccelerator(IDC_FULLSCREEN, &accelerator); + DCHECK(got_accelerator); + view_ = new FullscreenExitView(this, popup_, accelerator.GetShortcutText()); + + // Initialize the popup. + popup_->set_delete_on_destroy(false); + popup_->set_window_style(WS_POPUP); + popup_->set_window_ex_style(WS_EX_LAYERED | WS_EX_TOOLWINDOW | + l10n_util::GetExtendedTooltipStyles()); + popup_->SetLayeredAlpha(static_cast<int>(0xff * kOpacity)); + popup_->Init(frame->GetHWND(), GetPopupRect(false), false); + popup_->SetContentsView(view_); + popup_->Show(); + + // Start the initial delay timer. + initial_delay_.Start(base::TimeDelta::FromMilliseconds(kInitialDelayMs), this, + &FullscreenExitBubble::AfterInitialDelay); +} + +FullscreenExitBubble::~FullscreenExitBubble() { + // This is tricky. We may be in an ATL message handler stack, in which case + // the popup cannot be deleted yet. We also can't blindly use + // set_delete_on_destroy(true) on the popup to delete it when it closes, + // because if the user closed the last tab while in fullscreen mode, Windows + // has already destroyed the popup HWND by the time we get here, and thus + // either the popup will already have been deleted (if we set this in our + // constructor) or the popup will never get another OnFinalMessage() call (if + // not, as currently). So instead, we tell the popup to synchronously hide, + // and then asynchronously close and delete itself. + popup_->Close(); + MessageLoop::current()->DeleteSoon(FROM_HERE, popup_); +} + +void FullscreenExitBubble::LinkActivated(views::Link* source, int event_flags) { + delegate_->ExecuteCommand(IDC_FULLSCREEN); +} + +void FullscreenExitBubble::AnimationProgressed( + const Animation* animation) { + gfx::Rect popup_rect(GetPopupRect(false)); + if (popup_rect.IsEmpty()) { + popup_->Hide(); + } else { + popup_->MoveWindow(popup_rect.x(), popup_rect.y(), popup_rect.width(), + popup_rect.height()); + popup_->Show(); + } +} +void FullscreenExitBubble::AnimationEnded( + const Animation* animation) { + AnimationProgressed(animation); +} + +void FullscreenExitBubble::AfterInitialDelay() { + // Check the mouse position immediately and every 50 ms afterwards. + CheckMousePosition(); + mouse_position_checker_.Start( + base::TimeDelta::FromMilliseconds(1000 / kPositionCheckHz), this, + &FullscreenExitBubble::CheckMousePosition); +} + +void FullscreenExitBubble::CheckMousePosition() { + // Desired behavior: + // + // +------------+-----------------------------+------------+ + // | _ _ _ _ | Exit full screen mode (F11) | _ _ _ _ | Slide-in region + // | _ _ _ _ \_____________________________/ _ _ _ _ | Neutral region + // | | Slide-out region + // : : + // + // * If the mouse is in the slide-in region, we show the popup. + // * If the mouse is in the slide-out region, we hide the popup. + // * If the mouse is in the neutral region, we do nothing, except if the popup + // is currently sliding out, in which case we show it again. This + // facilitates users correcting us if they try to mouse horizontally towards + // the popup and unintentionally drop too low. + + POINT cursor_pos; + GetCursorPos(&cursor_pos); + gfx::Point transformed_pos(cursor_pos); + views::View::ConvertPointToView(NULL, root_view_, &transformed_pos); + gfx::Rect trigger_rect(GetPopupRect(true)); + if (!root_view_->HitTest(transformed_pos) || + (cursor_pos.y >= trigger_rect.bottom())) { + size_animation_->SetSlideDuration(kSlideOutDurationMs); + size_animation_->Hide(); + } else if ((cursor_pos.y < kSlideInRegionHeightPx) || + (size_animation_->GetCurrentValue() != 0)) { + size_animation_->SetSlideDuration(kSlideInDurationMs); + size_animation_->Show(); + } +} + +gfx::Rect FullscreenExitBubble::GetPopupRect( + bool ignore_animation_state) const { + gfx::Size size(view_->GetPreferredSize()); + if (!ignore_animation_state) { + size.set_height(static_cast<int>(static_cast<double>(size.height()) * + size_animation_->GetCurrentValue())); + } + gfx::Point origin((root_view_->width() - size.width()) / 2, 0); + views::View::ConvertPointToScreen(root_view_, &origin); + return gfx::Rect(origin, size); +} diff --git a/chrome/browser/views/fullscreen_exit_bubble.h b/chrome/browser/views/fullscreen_exit_bubble.h new file mode 100644 index 0000000..ff855be --- /dev/null +++ b/chrome/browser/views/fullscreen_exit_bubble.h @@ -0,0 +1,85 @@ +// Copyright (c) 2009 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_VIEWS_FULLSCREEN_EXIT_BUBBLE_H__ +#define CHROME_BROWSER_VIEWS_FULLSCREEN_EXIT_BUBBLE_H__ + +#include "base/scoped_ptr.h" +#include "chrome/browser/command_updater.h" +#include "chrome/common/slide_animation.h" +#include "chrome/views/link.h" +#include "chrome/views/widget_win.h" + +// FullscreenExitBubble is responsible for showing a bubble atop the screen in +// fullscreen mode, telling users how to exit and providing a click target. +// The bubble auto-hides, and re-shows when the user moves to the screen top. + +class FullscreenExitBubble : public views::LinkController, + public AnimationDelegate { + public: + explicit FullscreenExitBubble( + views::Widget* frame, + CommandUpdater::CommandUpdaterDelegate* delegate); + virtual ~FullscreenExitBubble(); + + private: + class FullscreenExitView; + + static const double kOpacity; // Opacity of the bubble, 0.0 - 1.0 + static const int kInitialDelayMs; // Initial time bubble remains onscreen + static const int kPositionCheckHz; // How fast to check the mouse position + static const int kSlideInRegionHeightPx; + // Height of region triggering slide-in + static const int kSlideInDurationMs; // Duration of slide-in animation + static const int kSlideOutDurationMs; // Duration of slide-out animation + + // views::LinkController + virtual void LinkActivated(views::Link* source, int event_flags); + + // AnimationDelegate + virtual void AnimationProgressed(const Animation* animation); + virtual void AnimationEnded(const Animation* animation); + + // Called after the initial delay to start checking the mouse position. + void AfterInitialDelay(); + + // Called repeatedly to get the current mouse position and animate the bubble + // on or off the screen as appropriate. + void CheckMousePosition(); + + // Returns the current desirable rect for the popup window. If + // |ignore_animation_state| is true this returns the rect assuming the popup + // is fully onscreen. + gfx::Rect GetPopupRect(bool ignore_animation_state) const; + + // The root view containing us. + views::View* root_view_; + + // Someone who can toggle fullscreen mode on and off when the user requests + // it. + CommandUpdater::CommandUpdaterDelegate* delegate_; + + // We use an HWND for the popup so that it may float above any plugins in the + // page. + views::WidgetWin* popup_; + + // The contents of the popup. + FullscreenExitView* view_; + + // Animation controlling sliding into/out of the top of the screen. + scoped_ptr<SlideAnimation> size_animation_; + + // Timer to delay before starting the mouse checking/bubble hiding code. + base::OneShotTimer<FullscreenExitBubble> initial_delay_; + + // Timer to poll the current mouse position. We can't just listen for mouse + // events without putting a non-empty HWND onscreen (or hooking Windows, which + // has other problems), so instead we run a low-frequency poller to see if the + // user has moved in or out of our show/hide regions. + base::RepeatingTimer<FullscreenExitBubble> mouse_position_checker_; + + DISALLOW_COPY_AND_ASSIGN(FullscreenExitBubble); +}; + +#endif // CHROME_BROWSER_VIEWS_FULLSCREEN_EXIT_BUBBLE_H__ diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc index 16f6a69..bc2d778 100644 --- a/chrome/browser/views/toolbar_view.cc +++ b/chrome/browser/views/toolbar_view.cc @@ -563,6 +563,8 @@ void BrowserToolbarView::RunAppMenu(const CPoint& pt, HWND hwnd) { menu.AppendSeparator(); menu.AppendMenuItemWithLabel(IDC_SHOW_BOOKMARK_BAR, l10n_util::GetString(IDS_SHOW_BOOKMARK_BAR)); + menu.AppendMenuItemWithLabel(IDC_FULLSCREEN, + l10n_util::GetString(IDS_FULLSCREEN)); menu.AppendSeparator(); menu.AppendMenuItemWithLabel(IDC_SHOW_HISTORY, l10n_util::GetString(IDS_SHOW_HISTORY)); diff --git a/chrome/views/accelerator.cc b/chrome/views/accelerator.cc index 8619394..e2a5f18 100644 --- a/chrome/views/accelerator.cc +++ b/chrome/views/accelerator.cc @@ -44,6 +44,9 @@ std::wstring Accelerator::GetShortcutText() const { case VK_F1: string_id = IDS_F1_KEY; break; + case VK_F11: + string_id = IDS_F11_KEY; + break; } std::wstring shortcut; |