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