summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/cocoa/panels/display_settings_provider_cocoa.mm
blob: 818f3125bd4c5ea0689e8f673ce677780d2bdc1a (plain)
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
153
// 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/macros.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();
}