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