Chromium Code Reviews| Index: chrome/browser/ui/fullscreen_controller.cc |
| diff --git a/chrome/browser/ui/fullscreen_controller.cc b/chrome/browser/ui/fullscreen_controller.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..06747586826d9c6ac49f001a2e23ad34bf114b16 |
| --- /dev/null |
| +++ b/chrome/browser/ui/fullscreen_controller.cc |
| @@ -0,0 +1,347 @@ |
| +// 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/fullscreen_controller.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/command_line.h" |
| +#include "chrome/browser/content_settings/host_content_settings_map.h" |
| +#include "chrome/browser/profiles/profile.h" |
| +#include "chrome/browser/ui/browser.h" |
| +#include "chrome/browser/ui/browser_window.h" |
| +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| +#include "chrome/common/chrome_notification_types.h" |
| +#include "chrome/common/chrome_switches.h" |
| +#include "content/browser/user_metrics.h" |
| +#include "content/public/browser/notification_service.h" |
| + |
| +FullscreenController::FullscreenController(BrowserWindow* window, |
| + Profile* profile, |
| + Browser* browser) |
| + : window_(window), |
| + profile_(profile), |
| + browser_(browser), |
| + fullscreened_tab_(NULL), |
| + tab_caused_fullscreen_(false), |
| + tab_fullscreen_accepted_(false), |
| + mouse_lock_state_(MOUSELOCK_NOT_REQUESTED) { |
| +} |
| + |
| +FullscreenController::~FullscreenController() {} |
| + |
| +bool FullscreenController::IsFullscreenForTab() const { |
| + return fullscreened_tab_ != NULL; |
| +} |
| + |
| +bool FullscreenController::IsFullscreenForTab(const TabContents* tab) const { |
| + const TabContentsWrapper* wrapper = |
| + TabContentsWrapper::GetCurrentWrapperForContents(tab); |
| + if (!wrapper || (wrapper != fullscreened_tab_)) |
| + return false; |
| + DCHECK(tab == browser_->GetSelectedTabContents()); |
| + DCHECK(window_->IsFullscreen()); |
| + return true; |
| +} |
| + |
| +void FullscreenController::RequestToLockMouse(TabContents* tab) { |
| + // Mouse Lock is only permitted when browser is in tab fullscreen. |
| + if (!IsFullscreenForTab(tab)) { |
| + tab->GotResponseToLockMouseRequest(false); |
| + return; |
| + } |
| + |
| + if (mouse_lock_state_ == MOUSELOCK_ACCEPTED) { |
| + tab->GotResponseToLockMouseRequest(true); |
| + return; |
| + } |
| + |
| + switch (GetMouseLockSetting(tab->GetURL())) { |
| + case CONTENT_SETTING_ALLOW: |
| + mouse_lock_state_ = MOUSELOCK_ACCEPTED; |
| + tab->GotResponseToLockMouseRequest(true); |
| + break; |
| + case CONTENT_SETTING_BLOCK: |
| + mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED; |
| + tab->GotResponseToLockMouseRequest(false); |
| + break; |
| + case CONTENT_SETTING_ASK: |
| + mouse_lock_state_ = MOUSELOCK_REQUESTED; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| + UpdateFullscreenExitBubbleContent(); |
| +} |
| + |
| +void FullscreenController::ToggleFullscreenModeForTab(TabContents* tab, |
| + bool enter_fullscreen) { |
| + if (tab != browser_->GetSelectedTabContents()) |
| + return; |
| + |
| + bool in_browser_or_tab_fullscreen_mode; |
| +#if defined(OS_MACOSX) |
| + in_browser_or_tab_fullscreen_mode = window_->InPresentationMode(); |
| +#else |
| + in_browser_or_tab_fullscreen_mode = window_->IsFullscreen(); |
| +#endif |
| + |
| + if (enter_fullscreen) { |
| + fullscreened_tab_ = TabContentsWrapper::GetCurrentWrapperForContents(tab); |
| + if (!in_browser_or_tab_fullscreen_mode) { |
| + tab_caused_fullscreen_ = true; |
| +#if defined(OS_MACOSX) |
| + TogglePresentationMode(true); |
| +#else |
| + ToggleFullscreenMode(true); |
| +#endif |
| + } else { |
| + // We need to update the fullscreen exit bubble, e.g., going from browser |
| + // fullscreen to tab fullscreen will need to show different content. |
| + const GURL& url = tab->GetURL(); |
| + if (!tab_fullscreen_accepted_) { |
| + tab_fullscreen_accepted_ = |
| + GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW; |
| + } |
| + UpdateFullscreenExitBubbleContent(); |
| + } |
| + } else { |
| + if (in_browser_or_tab_fullscreen_mode) { |
| + if (tab_caused_fullscreen_) { |
| +#if defined(OS_MACOSX) |
| + TogglePresentationMode(true); |
| +#else |
| + ToggleFullscreenMode(true); |
| +#endif |
| + } else { |
| + // If currently there is a tab in "tab fullscreen" mode and fullscreen |
| + // was not caused by it (i.e., previously it was in "browser fullscreen" |
| + // mode), we need to switch back to "browser fullscreen" mode. In this |
| + // case, all we have to do is notifying the tab that it has exited "tab |
| + // fullscreen" mode. |
| + NotifyTabOfFullscreenExitIfNecessary(); |
| + } |
| + } |
| + } |
| +} |
| + |
| +#if defined(OS_MACOSX) |
| +void FullscreenController::TogglePresentationMode(bool for_tab) { |
| + bool entering_fullscreen = !window_->InPresentationMode(); |
| + GURL url; |
| + if (for_tab) { |
| + url = browser_->GetSelectedTabContents()->GetURL(); |
| + tab_fullscreen_accepted_ = entering_fullscreen && |
| + GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW; |
| + } |
| + if (entering_fullscreen) |
| + window_->EnterPresentationMode(url, GetFullscreenExitBubbleType()); |
| + else |
| + window_->ExitPresentationMode(); |
| + WindowFullscreenStateChanged(); |
| +} |
| +#endif |
| + |
| +// TODO(koz): Change |for_tab| to an enum. |
| +void FullscreenController::ToggleFullscreenMode(bool for_tab) { |
| + bool entering_fullscreen = !window_->IsFullscreen(); |
| + |
| +#if !defined(OS_MACOSX) |
| + // In kiosk mode, we always want to be fullscreen. When the browser first |
| + // starts we're not yet fullscreen, so let the initial toggle go through. |
| + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode) && |
| + window_->IsFullscreen()) |
| + return; |
| +#endif |
| + |
| + GURL url; |
| + if (for_tab) { |
| + url = browser_->GetSelectedTabContents()->GetURL(); |
| + tab_fullscreen_accepted_ = entering_fullscreen && |
| + GetFullscreenSetting(url) == CONTENT_SETTING_ALLOW; |
| + } else { |
| + UserMetrics::RecordAction(UserMetricsAction("ToggleFullscreen")); |
| + } |
| + if (entering_fullscreen) |
| + window_->EnterFullscreen(url, GetFullscreenExitBubbleType()); |
| + else |
| + window_->ExitFullscreen(); |
| + |
| + // Once the window has become fullscreen it'll call back to |
| + // WindowFullscreenStateChanged(). We don't do this immediately as |
| + // BrowserWindow::EnterFullscreen() asks for bookmark_bar_state_, so we let |
| + // the BrowserWindow invoke WindowFullscreenStateChanged when appropriate. |
| + |
| + // TODO: convert mac to invoke WindowFullscreenStateChanged once it updates |
| + // the necessary state of the frame. |
| +#if defined(OS_MACOSX) |
| + WindowFullscreenStateChanged(); |
| +#endif |
| +} |
| + |
| +void FullscreenController::LostMouseLock() { |
| + mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED; |
| + UpdateFullscreenExitBubbleContent(); |
| +} |
| + |
| +void FullscreenController::OnTabClosing(TabContents* tab_contents) { |
| + if (IsFullscreenForTab(tab_contents)) { |
| + ExitTabbedFullscreenModeIfNecessary(); |
| + // The call to exit fullscreen may result in asynchronous notification of |
| + // fullscreen state change (e.g., on Linux). We don't want to rely on it |
| + // to call NotifyTabOfFullscreenExitIfNecessary(), because at that point |
| + // |fullscreen_tab_| may not be valid. Instead, we call it here to clean up |
| + // tab fullscreen related state. |
| + NotifyTabOfFullscreenExitIfNecessary(); |
| + } |
| +} |
| + |
| +void FullscreenController::OnTabDeactivated(TabContentsWrapper* contents) { |
| + if (contents == fullscreened_tab_) |
| + ExitTabbedFullscreenModeIfNecessary(); |
| +} |
| + |
| +void FullscreenController::OnAcceptFullscreenPermission( |
| + const GURL& url, |
| + FullscreenExitBubbleType bubble_type) { |
| + bool mouse_lock = false; |
| + bool fullscreen = false; |
| + fullscreen_bubble::PermissionRequestedByType(bubble_type, &fullscreen, |
| + &mouse_lock); |
| + DCHECK(fullscreened_tab_); |
| + DCHECK_NE(tab_fullscreen_accepted_, fullscreen); |
| + |
| + HostContentSettingsMap* settings_map = profile_->GetHostContentSettingsMap(); |
| + if (mouse_lock) { |
| + DCHECK_EQ(mouse_lock_state_, MOUSELOCK_REQUESTED); |
| + settings_map->SetContentSetting(ContentSettingsPattern::FromURL(url), |
| + ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_MOUSELOCK, |
| + std::string(), CONTENT_SETTING_ALLOW); |
| + mouse_lock_state_ = |
| + fullscreened_tab_->tab_contents()->GotResponseToLockMouseRequest(true) ? |
| + MOUSELOCK_ACCEPTED : MOUSELOCK_NOT_REQUESTED; |
| + } |
| + if (!tab_fullscreen_accepted_) { |
| + settings_map->SetContentSetting(ContentSettingsPattern::FromURL(url), |
| + ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_FULLSCREEN, |
| + std::string(), CONTENT_SETTING_ALLOW); |
| + tab_fullscreen_accepted_ = true; |
| + } |
| + UpdateFullscreenExitBubbleContent(); |
| +} |
| + |
| +void FullscreenController::OnDenyFullscreenPermission( |
| + FullscreenExitBubbleType bubble_type) { |
| + bool mouse_lock = false; |
| + bool fullscreen = false; |
| + fullscreen_bubble::PermissionRequestedByType(bubble_type, &fullscreen, |
| + &mouse_lock); |
| + DCHECK(fullscreened_tab_); |
| + DCHECK_NE(tab_fullscreen_accepted_, fullscreen); |
| + |
| + if (mouse_lock) { |
| + DCHECK_EQ(mouse_lock_state_, MOUSELOCK_REQUESTED); |
| + mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED; |
| + fullscreened_tab_->tab_contents()->GotResponseToLockMouseRequest(false); |
| + if (!fullscreen) |
| + UpdateFullscreenExitBubbleContent(); |
| + } |
| + |
| + if (fullscreen) |
| + ExitTabbedFullscreenModeIfNecessary(); |
| +} |
| + |
| +void FullscreenController::WindowFullscreenStateChanged() { |
| + MessageLoop::current()->PostTask(FROM_HERE, |
| + base::Bind(&FullscreenController::NotifyFullscreenChange, this)); |
|
sky
2011/12/08 23:34:13
I just came across this in tracking down a regress
koz (OOO until 15th September)
2011/12/08 23:45:39
This notification has always been async (see the d
|
| + bool notify_tab_of_exit; |
| +#if defined(OS_MACOSX) |
| + notify_tab_of_exit = !window_->InPresentationMode(); |
| +#else |
| + notify_tab_of_exit = !window_->IsFullscreen(); |
| +#endif |
| + if (notify_tab_of_exit) |
| + NotifyTabOfFullscreenExitIfNecessary(); |
| +} |
| + |
| +bool FullscreenController::HandleUserPressedEscape() { |
| + if (!IsFullscreenForTab()) |
| + return false; |
| + ExitTabbedFullscreenModeIfNecessary(); |
| + return true; |
| +} |
| + |
| +void FullscreenController::NotifyTabOfFullscreenExitIfNecessary() { |
| + if (fullscreened_tab_) |
| + fullscreened_tab_->ExitFullscreenMode(); |
| + else |
| + DCHECK_EQ(mouse_lock_state_, MOUSELOCK_NOT_REQUESTED); |
| + |
| + fullscreened_tab_ = NULL; |
| + tab_caused_fullscreen_ = false; |
| + tab_fullscreen_accepted_ = false; |
| + mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED; |
| + |
| + UpdateFullscreenExitBubbleContent(); |
| +} |
| + |
| +void FullscreenController::ExitTabbedFullscreenModeIfNecessary() { |
| + if (tab_caused_fullscreen_) |
| + ToggleFullscreenMode(false); |
| + else |
| + NotifyTabOfFullscreenExitIfNecessary(); |
| +} |
| + |
| +void FullscreenController::UpdateFullscreenExitBubbleContent() { |
| + GURL url; |
| + if (fullscreened_tab_) |
| + url = fullscreened_tab_->tab_contents()->GetURL(); |
| + |
| + window_->UpdateFullscreenExitBubbleContent(url, |
| + GetFullscreenExitBubbleType()); |
| +} |
| + |
| +void FullscreenController::NotifyFullscreenChange() { |
| + content::NotificationService::current()->Notify( |
| + chrome::NOTIFICATION_FULLSCREEN_CHANGED, |
| + content::Source<FullscreenController>(this), |
| + content::NotificationService::NoDetails()); |
| +} |
| + |
| +FullscreenExitBubbleType |
| + FullscreenController::GetFullscreenExitBubbleType() const { |
| + if (!fullscreened_tab_) { |
| + DCHECK_EQ(MOUSELOCK_NOT_REQUESTED, mouse_lock_state_); |
| + return FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION; |
| + } |
| + if (fullscreened_tab_ && !tab_fullscreen_accepted_) { |
| + DCHECK_NE(MOUSELOCK_ACCEPTED, mouse_lock_state_); |
| + return mouse_lock_state_ == MOUSELOCK_REQUESTED ? |
| + FEB_TYPE_FULLSCREEN_MOUSELOCK_BUTTONS : FEB_TYPE_FULLSCREEN_BUTTONS; |
| + } |
| + if (mouse_lock_state_ == MOUSELOCK_REQUESTED) |
| + return FEB_TYPE_MOUSELOCK_BUTTONS; |
| + return mouse_lock_state_ == MOUSELOCK_ACCEPTED ? |
| + FEB_TYPE_FULLSCREEN_MOUSELOCK_EXIT_INSTRUCTION : |
| + FEB_TYPE_FULLSCREEN_EXIT_INSTRUCTION; |
| +} |
| + |
| +ContentSetting |
|
Peter Kasting
2011/11/21 19:17:46
Nit: Prefer to wrap these next two functions like:
|
| + FullscreenController::GetFullscreenSetting(const GURL& url) const { |
| + if (url.SchemeIsFile()) |
| + return CONTENT_SETTING_ALLOW; |
| + |
| + return profile_->GetHostContentSettingsMap()->GetContentSetting(url, url, |
| + CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string()); |
| + |
|
Peter Kasting
2011/11/21 19:17:46
Nit: Extra blank line
|
| +} |
| + |
| +ContentSetting |
| + FullscreenController::GetMouseLockSetting(const GURL& url) const { |
| + if (url.SchemeIsFile()) |
| + return CONTENT_SETTING_ALLOW; |
| + |
| + HostContentSettingsMap* settings_map = profile_->GetHostContentSettingsMap(); |
| + return settings_map->GetContentSetting(url, url, |
| + CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string()); |
| +} |