text: // Copyright 2013 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/views/frame/browser_frame_ash.h"
  
  #include "ash/wm/window_state.h"
  #include "ash/wm/window_state_delegate.h"
  #include "ash/wm/window_util.h"
  #include "chrome/browser/ui/browser_commands.h"
  #include "chrome/browser/ui/browser_finder.h"
  #include "chrome/browser/ui/views/frame/browser_view.h"
  #include "ui/aura/client/aura_constants.h"
  #include "ui/aura/window.h"
  #include "ui/aura/window_observer.h"
  #include "ui/views/view.h"
  
  using aura::Window;
  
  namespace {
  
  // BrowserWindowStateDelegate classe handles a user's fullscreen
  // request (Shift+F4/F4) for browser (tabbed/popup) windows.
  class BrowserWindowStateDelegate : public ash::wm::WindowStateDelegate {
   public:
    explicit BrowserWindowStateDelegate(Browser* browser)
        : browser_(browser) {
      DCHECK(browser_);
    }
    virtual ~BrowserWindowStateDelegate(){}
  
    // Overridden from ash::wm::WindowStateDelegate.
    virtual bool ToggleFullscreen(ash::wm::WindowState* window_state) OVERRIDE {
      DCHECK(window_state->IsFullscreen() || window_state->CanMaximize());
      // Windows which cannot be maximized should not be fullscreened.
      if (!window_state->IsFullscreen() && !window_state->CanMaximize())
        return true;
      chrome::ToggleFullscreenMode(browser_);
      return true;
    }
   private:
    Browser* browser_;  // not owned.
  
    DISALLOW_COPY_AND_ASSIGN(BrowserWindowStateDelegate);
  };
  
  // AppNonClientFrameViewAsh shows only the window controls and no
  // other window decorations which is pretty close to fullscreen. Put
  // v1 apps into maximized mode instead of fullscreen to avoid showing
  // the ugly fullscreen exit bubble.  This is used for V1 apps.
  class AppWindowStateDelegate : public ash::wm::WindowStateDelegate {
   public:
    explicit AppWindowStateDelegate(Browser* browser)
        : browser_(browser) {
      DCHECK(browser_);
    }
    virtual ~AppWindowStateDelegate(){}
  
    // Overridden from ash::wm::WindowStateDelegate.
    virtual bool ToggleFullscreen(ash::wm::WindowState* window_state) OVERRIDE {
      DCHECK(window_state->IsFullscreen() || window_state->CanMaximize());
      if (window_state->IsFullscreen())
        chrome::ToggleFullscreenMode(browser_);
      else
        window_state->ToggleMaximized();
      return true;
    }
  
   private:
    Browser* browser_;  // not owned.
  
    DISALLOW_COPY_AND_ASSIGN(AppWindowStateDelegate);
  };
  
  
  }  // namespace
  
  ////////////////////////////////////////////////////////////////////////////////
  // BrowserFrameAsh::WindowPropertyWatcher
  
  class BrowserFrameAsh::WindowPropertyWatcher : public aura::WindowObserver {
   public:
    explicit WindowPropertyWatcher(BrowserFrameAsh* browser_frame_ash,
                                   BrowserFrame* browser_frame)
        : browser_frame_ash_(browser_frame_ash),
          browser_frame_(browser_frame) {}
  
    virtual void OnWindowPropertyChanged(aura::Window* window,
                                         const void* key,
                                         intptr_t old) OVERRIDE {
      if (key != aura::client::kShowStateKey)
        return;
  
      ui::WindowShowState old_state = static_cast<ui::WindowShowState>(old);
      ui::WindowShowState new_state =
          window->GetProperty(aura::client::kShowStateKey);
  
      // Allow the frame to be replaced when entering or exiting the maximized
      // state.
      if (browser_frame_->non_client_view() &&
          browser_frame_ash_->browser_view()->browser()->is_app() &&
          (old_state == ui::SHOW_STATE_MAXIMIZED ||
           new_state == ui::SHOW_STATE_MAXIMIZED)) {
        // Defer frame layout when replacing the frame. Layout will occur when the
        // window's bounds are updated. The window maximize/restore animations
        // clone the window's layers and rely on the subsequent layout to set
        // the layer sizes.
        // If the window is minimized, the frame view needs to be updated via
        // an OnBoundsChanged event so that the frame will change its size
        // properly.
        browser_frame_->non_client_view()->UpdateFrame(
            old_state == ui::SHOW_STATE_MINIMIZED);
      }
    }
  
    virtual void OnWindowBoundsChanged(aura::Window* window,
                                       const gfx::Rect& old_bounds,
                                       const gfx::Rect& new_bounds) OVERRIDE {
      // Don't do anything if we don't have our non-client view yet.
      if (!browser_frame_->non_client_view())
        return;
  
      // If the window just moved to the top of the screen, or just moved away
      // from it, invoke Layout() so the header size can change.
      if ((old_bounds.y() == 0 && new_bounds.y() != 0) ||
          (old_bounds.y() != 0 && new_bounds.y() == 0))
        browser_frame_->non_client_view()->Layout();
    }
  
   private:
    BrowserFrameAsh* browser_frame_ash_;
    BrowserFrame* browser_frame_;
  
    DISALLOW_COPY_AND_ASSIGN(WindowPropertyWatcher);
  };
  
  ///////////////////////////////////////////////////////////////////////////////
  // BrowserFrameAsh, public:
  
  // static
  const char BrowserFrameAsh::kWindowName[] = "BrowserFrameAsh";
  
  BrowserFrameAsh::BrowserFrameAsh(BrowserFrame* browser_frame,
                                   BrowserView* browser_view)
      : views::NativeWidgetAura(browser_frame),
        browser_view_(browser_view),
        window_property_watcher_(new WindowPropertyWatcher(this, browser_frame)) {
    GetNativeWindow()->SetName(kWindowName);
    GetNativeWindow()->AddObserver(window_property_watcher_.get());
    Browser* browser = browser_view->browser();
    ash::wm::WindowState* window_state =
        ash::wm::GetWindowState(GetNativeWindow());
    if (browser->is_app() && browser->app_type() != Browser::APP_TYPE_CHILD) {
      window_state->SetDelegate(
          scoped_ptr<ash::wm::WindowStateDelegate>(
              new AppWindowStateDelegate(browser)).Pass());
    } else {
      window_state->SetDelegate(
          scoped_ptr<ash::wm::WindowStateDelegate>(
              new BrowserWindowStateDelegate(browser)).Pass());
    }
    window_state->set_animate_to_fullscreen(!browser->is_type_tabbed());
  
    // Turn on auto window management if we don't need an explicit bounds.
    // This way the requested bounds are honored.
    if (!browser->bounds_overridden() && !browser->is_session_restore())
      SetWindowAutoManaged();
  #if defined(OS_CHROMEOS)
    // For legacy reasons v1 apps (like Secure Shell) are allowed to consume keys
    // like brightness, volume, etc. Otherwise these keys are handled by the
    // Ash window manager.
    window_state->set_can_consume_system_keys(browser->is_app());
  #endif  // defined(OS_CHROMEOS)
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  // BrowserFrameAsh, views::NativeWidgetAura overrides:
  
  void BrowserFrameAsh::OnWindowDestroying() {
    // Window is destroyed before our destructor is called, so clean up our
    // observer here.
    GetNativeWindow()->RemoveObserver(window_property_watcher_.get());
    views::NativeWidgetAura::OnWindowDestroying();
  }
  
  void BrowserFrameAsh::OnWindowTargetVisibilityChanged(bool visible) {
    if (visible) {
      // Once the window has been shown we know the requested bounds
      // (if provided) have been honored and we can switch on window management.
      SetWindowAutoManaged();
    }
    views::NativeWidgetAura::OnWindowTargetVisibilityChanged(visible);
  }
  
  ////////////////////////////////////////////////////////////////////////////////
  // BrowserFrameAsh, NativeBrowserFrame implementation:
  
  views::NativeWidget* BrowserFrameAsh::AsNativeWidget() {
    return this;
  }
  
  const views::NativeWidget* BrowserFrameAsh::AsNativeWidget() const {
    return this;
  }
  
  bool BrowserFrameAsh::UsesNativeSystemMenu() const {
    return false;
  }
  
  int BrowserFrameAsh::GetMinimizeButtonOffset() const {
    return 0;
  }
  
  void BrowserFrameAsh::TabStripDisplayModeChanged() {
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  // BrowserFrameAsh, private:
  
  BrowserFrameAsh::~BrowserFrameAsh() {
  }
  
  void BrowserFrameAsh::SetWindowAutoManaged() {
    if (browser_view_->browser()->type() != Browser::TYPE_POPUP ||
        browser_view_->browser()->is_app()) {
      ash::wm::GetWindowState(GetNativeWindow())->
          set_window_position_managed(true);
    }
  }
  