1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// Copyright (c) 2012 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 "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#import "chrome/browser/app_controller_mac.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/fullscreen.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
#include "chrome/browser/ui/panels/display_settings_provider.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "ui/base/work_area_watcher_observer.h"
namespace {
// The time, in milliseconds, that a fullscreen check will be started after
// the active workspace change is notified. This value is from experiment.
const int kCheckFullScreenDelayTimeMs = 200;
class DisplaySettingsProviderCocoa : public DisplaySettingsProvider,
public ui::WorkAreaWatcherObserver,
public content::NotificationObserver {
public:
DisplaySettingsProviderCocoa();
~DisplaySettingsProviderCocoa() override;
void ActiveSpaceChanged();
protected:
// Overridden from DisplaySettingsProvider:
bool NeedsPeriodicFullScreenCheck() const override;
bool IsFullScreen() override;
// Overridden from ui::WorkAreaWatcherObserver:
void WorkAreaChanged() override;
// Overridden from content::NotificationObserver:
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
private:
void ActiveWorkSpaceChanged();
content::NotificationRegistrar registrar_;
id active_space_change_;
// Owned by MessageLoop after posting.
base::WeakPtrFactory<DisplaySettingsProviderCocoa> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DisplaySettingsProviderCocoa);
};
DisplaySettingsProviderCocoa::DisplaySettingsProviderCocoa()
: active_space_change_(nil),
weak_factory_(this) {
AppController* appController = static_cast<AppController*>([NSApp delegate]);
[appController addObserverForWorkAreaChange:this];
registrar_.Add(
this,
chrome::NOTIFICATION_FULLSCREEN_CHANGED,
content::NotificationService::AllSources());
active_space_change_ = [[[NSWorkspace sharedWorkspace] notificationCenter]
addObserverForName:NSWorkspaceActiveSpaceDidChangeNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification* notification) {
ActiveWorkSpaceChanged();
}];
}
DisplaySettingsProviderCocoa::~DisplaySettingsProviderCocoa() {
AppController* appController = static_cast<AppController*>([NSApp delegate]);
[appController removeObserverForWorkAreaChange:this];
[[[NSWorkspace sharedWorkspace] notificationCenter]
removeObserver:active_space_change_];
}
bool DisplaySettingsProviderCocoa::NeedsPeriodicFullScreenCheck() const {
// Lion system introduces fullscreen support. When a window of an application
// enters fullscreen mode, the system will automatically hide all other
// windows, even including topmost windows that come from other applications.
// So we don't need to do anything when any other application enters
// fullscreen mode. We still need to handle the case when chrome enters
// fullscreen mode and our topmost windows will not get hided by the system.
return !chrome::mac::SupportsSystemFullscreen();
}
bool DisplaySettingsProviderCocoa::IsFullScreen() {
// For Lion and later, we only need to check if chrome enters fullscreen mode
// (see detailed reason above in NeedsPeriodicFullScreenCheck).
if (!chrome::mac::SupportsSystemFullscreen())
return DisplaySettingsProvider::IsFullScreen();
Browser* browser = chrome::GetLastActiveBrowser();
if (!browser)
return false;
BrowserWindow* browser_window = browser->window();
if (!browser_window->IsFullscreen())
return false;
// If the user switches to another space where the fullscreen browser window
// does not live, we do not call it fullscreen.
NSWindow* native_window = browser_window->GetNativeWindow();
return [native_window isOnActiveSpace];
}
void DisplaySettingsProviderCocoa::WorkAreaChanged() {
OnDisplaySettingsChanged();
}
void DisplaySettingsProviderCocoa::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(chrome::NOTIFICATION_FULLSCREEN_CHANGED, type);
// When we receive the fullscreen notification, the Chrome Window has not been
// put on the active space yet and thus IsFullScreen will return false.
// Since the fullscreen result is already known here, we can pass it dierctly
// to CheckFullScreenMode.
bool is_fullscreen = *(content::Details<bool>(details)).ptr();
CheckFullScreenMode(
is_fullscreen ? ASSUME_FULLSCREEN_ON : ASSUME_FULLSCREEN_OFF);
}
void DisplaySettingsProviderCocoa::ActiveWorkSpaceChanged() {
// The active workspace notification might be received earlier than the
// browser window knows that it is not in active space.
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&DisplaySettingsProviderCocoa::CheckFullScreenMode,
weak_factory_.GetWeakPtr(),
PERFORM_FULLSCREEN_CHECK),
base::TimeDelta::FromMilliseconds(kCheckFullScreenDelayTimeMs));
}
} // namespace
// static
DisplaySettingsProvider* DisplaySettingsProvider::Create() {
return new DisplaySettingsProviderCocoa();
}
|