Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

browser_view.cc

// Copyright (c) 2010 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/chromeos/frame/browser_view.h"

#include <algorithm>
#include <string>
#include <vector>

#include "app/menus/simple_menu_model.h"
#include "base/command_line.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/chromeos/frame/panel_browser_view.h"
#include "chrome/browser/chromeos/options/language_config_view.h"
#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/status/language_menu_button.h"
#include "chrome/browser/chromeos/status/network_menu_button.h"
#include "chrome/browser/chromeos/status/status_area_button.h"
#include "chrome/browser/chromeos/view_ids.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/views/app_launcher.h"
#include "chrome/browser/views/frame/browser_frame_gtk.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/frame/browser_view_layout.h"
#include "chrome/browser/views/tabs/tab.h"
#include "chrome/browser/views/tabs/tab_strip.h"
#include "chrome/browser/views/theme_background.h"
#include "chrome/browser/views/toolbar_view.h"
#include "chrome/common/chrome_switches.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "views/controls/button/button.h"
#include "views/controls/button/image_button.h"
#include "views/controls/menu/menu_2.h"
#include "views/screen.h"
#include "views/widget/root_view.h"
#include "views/window/hit_test.h"
#include "views/window/window.h"

namespace {

// The OTR avatar ends 2 px above the bottom of the tabstrip (which, given the
// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
// user).
const int kOTRBottomSpacing = 2;

// There are 2 px on each side of the OTR avatar (between the frame border and
// it on the left, and between it and the tabstrip on the right).
const int kOTRSideSpacing = 2;

// Amount to offset the toolbar by when vertical tabs are enabled.
const int kVerticalTabStripToolbarOffset = 2;

}  // namespace

namespace chromeos {

// LayoutManager for BrowserView, which layouts extra components such as
// the status views as follows:
//       ____  __ __
//      /    \   \  \     [StatusArea]
//
class BrowserViewLayout : public ::BrowserViewLayout {
 public:
  BrowserViewLayout() : ::BrowserViewLayout() {}
  virtual ~BrowserViewLayout() {}

  //////////////////////////////////////////////////////////////////////////////
  // BrowserViewLayout overrides:

  void Installed(views::View* host) {
    status_area_ = NULL;
    ::BrowserViewLayout::Installed(host);
  }

  void ViewAdded(views::View* host,
                 views::View* view) {
    ::BrowserViewLayout::ViewAdded(host, view);
    switch (view->GetID()) {
      case VIEW_ID_STATUS_AREA:
        status_area_ = static_cast<chromeos::StatusAreaView*>(view);
        break;
      case VIEW_ID_OTR_AVATAR:
        otr_avatar_icon_ = view;
        break;
    }
  }

  // In the normal and the compact navigation bar mode, ChromeOS
  // layouts compact navigation buttons and status views in the title
  // area. See Layout
  virtual int LayoutTabStrip() {
    if (browser_view_->IsFullscreen() || !browser_view_->IsTabStripVisible()) {
      status_area_->SetVisible(false);
      otr_avatar_icon_->SetVisible(false);
      tabstrip_->SetVisible(false);
      tabstrip_->SetBounds(0, 0, 0, 0);
      return 0;
    }

    gfx::Rect tabstrip_bounds(
        browser_view_->frame()->GetBoundsForTabStrip(tabstrip_));
    gfx::Point tabstrip_origin = tabstrip_bounds.origin();
    views::View::ConvertPointToView(browser_view_->GetParent(), browser_view_,
                                    &tabstrip_origin);
    tabstrip_bounds.set_origin(tabstrip_origin);
    return browser_view_->UseVerticalTabs() ?
        LayoutTitlebarComponentsWithVerticalTabs(tabstrip_bounds) :
        LayoutTitlebarComponents(tabstrip_bounds);
  }

  virtual int LayoutToolbar(int top) {
    if (!browser_view_->IsFullscreen() && browser_view_->IsTabStripVisible() &&
        browser_view_->UseVerticalTabs()) {
      // For vertical tabs the toolbar is positioned in
      // LayoutTitlebarComponentsWithVerticalTabs.
      return top;
    }
    return ::BrowserViewLayout::LayoutToolbar(top);
  }

  virtual bool IsPositionInWindowCaption(const gfx::Point& point) {
    return ::BrowserViewLayout::IsPositionInWindowCaption(point)
        && !IsPointInViewsInTitleArea(point);
  }

  virtual int NonClientHitTest(const gfx::Point& point) {
    gfx::Point point_in_browser_view_coords(point);
    views::View::ConvertPointToView(
        browser_view_->GetParent(), browser_view_,
        &point_in_browser_view_coords);
    return IsPointInViewsInTitleArea(point_in_browser_view_coords) ?
        HTCLIENT : ::BrowserViewLayout::NonClientHitTest(point);
  }

 private:
  chromeos::BrowserView* chromeos_browser_view() {
    return static_cast<chromeos::BrowserView*>(browser_view_);
  }

  // Tests if the point is on one of views that are within the
  // considered title bar area of client view.
  bool IsPointInViewsInTitleArea(const gfx::Point& point)
      const {
    gfx::Point point_in_status_area_coords(point);
    views::View::ConvertPointToView(browser_view_, status_area_,
                                    &point_in_status_area_coords);
    if (status_area_->HitTest(point_in_status_area_coords))
      return true;

    return false;
  }

  // Positions the titlebar, toolbar, tabstrip, tabstrip and otr icon. This is
  // used when side tabs are enabled.
  int LayoutTitlebarComponentsWithVerticalTabs(const gfx::Rect& bounds) {
    if (bounds.IsEmpty())
      return 0;

    tabstrip_->SetVisible(true);
    otr_avatar_icon_->SetVisible(browser_view_->ShouldShowOffTheRecordAvatar());
    status_area_->SetVisible(true);

    gfx::Size status_size = status_area_->GetPreferredSize();
    int status_height = status_size.height();

    // Layout the otr icon.
    int status_x = bounds.x();
    if (!otr_avatar_icon_->IsVisible()) {
      otr_avatar_icon_->SetBounds(0, 0, 0, 0);
    } else {
      gfx::Size otr_size = otr_avatar_icon_->GetPreferredSize();

      status_height = std::max(status_height, otr_size.height());
      int y = bounds.bottom() - status_height;
      otr_avatar_icon_->SetBounds(status_x, y, otr_size.width(), status_height);
      status_x += otr_size.width();
    }

    // Layout the status area after the otr icon.
    status_area_->SetBounds(status_x, bounds.bottom() - status_height,
                            status_size.width(), status_height);

    // The tabstrip's width is the bigger of it's preferred width and the width
    // the status area.
    int tabstrip_w = std::max(status_x + status_size.width(),
                              tabstrip_->GetPreferredSize().width());
    tabstrip_->SetBounds(bounds.x(), bounds.y(), tabstrip_w,
                         bounds.height() - status_height);

    // The toolbar is promoted to the title for vertical tabs.
    bool toolbar_visible = browser_view_->IsToolbarVisible();
    toolbar_->SetVisible(toolbar_visible);
    int toolbar_height = 0;
    if (toolbar_visible)
      toolbar_height = toolbar_->GetPreferredSize().height();
    int tabstrip_max_x = tabstrip_->bounds().right();
    toolbar_->SetBounds(tabstrip_max_x,
                        bounds.y() - kVerticalTabStripToolbarOffset,
                        browser_view_->width() - tabstrip_max_x,
                        toolbar_height);

    // Adjust the available bounds for other components.
    gfx::Rect available_bounds = vertical_layout_rect();
    available_bounds.Inset(tabstrip_w, 0, 0, 0);
    set_vertical_layout_rect(available_bounds);

    return bounds.y() + toolbar_height;
  }

  // Lays out components in the title bar area (given by |bounds|). These
  // include the main menu, the otr avatar icon (in incognito windows), the
  // tabstrip and the the status area.
  int LayoutTitlebarComponents(const gfx::Rect& bounds) {
    if (bounds.IsEmpty())
      return 0;

    tabstrip_->SetVisible(true);
    otr_avatar_icon_->SetVisible(browser_view_->ShouldShowOffTheRecordAvatar());
    status_area_->SetVisible(true);

    // Layout status area after tab strip.
    gfx::Size status_size = status_area_->GetPreferredSize();
    status_area_->SetBounds(bounds.right() - status_size.width(), bounds.y(),
                            status_size.width(), status_size.height());
    LayoutOTRAvatar(bounds);

    tabstrip_->SetBounds(bounds.x(), bounds.y(),
        std::max(0, otr_avatar_icon_->bounds().x() - bounds.x()),
        bounds.height());
    return bounds.bottom();
  }

  // Layouts OTR avatar within the given |bounds|.
  void LayoutOTRAvatar(const gfx::Rect& bounds) {
    gfx::Rect status_bounds = status_area_->bounds();
    if (!otr_avatar_icon_->IsVisible()) {
      otr_avatar_icon_->SetBounds(status_bounds.x(), status_bounds.y(), 0, 0);
    } else {
      gfx::Size preferred_size = otr_avatar_icon_->GetPreferredSize();

      int y = bounds.bottom() - preferred_size.height() - kOTRBottomSpacing;
      int x = status_bounds.x() - kOTRSideSpacing - preferred_size.width();
      otr_avatar_icon_->SetBounds(x, y, preferred_size.width(),
                                  preferred_size.height());
    }
  }


  chromeos::StatusAreaView* status_area_;
  views::View* otr_avatar_icon_;

  DISALLOW_COPY_AND_ASSIGN(BrowserViewLayout);
};

BrowserView::BrowserView(Browser* browser)
    : ::BrowserView(browser),
      status_area_(NULL),
      force_maximized_window_(false),
      otr_avatar_icon_(new views::ImageView()) {
}

BrowserView::~BrowserView() {
}

////////////////////////////////////////////////////////////////////////////////
// BrowserView, ::BrowserView overrides:

void BrowserView::Init() {
  ::BrowserView::Init();
  status_area_ = new StatusAreaView(this);
  status_area_->SetID(VIEW_ID_STATUS_AREA);
  AddChildView(status_area_);
  status_area_->Init();
  InitSystemMenu();

  // The ContextMenuController has to be set to a NonClientView but
  // not to a NonClientFrameView because a TabStrip is not a child of
  // a NonClientFrameView even though visually a TabStrip is over a
  // NonClientFrameView.
  BrowserFrameGtk* gtk_frame = static_cast<BrowserFrameGtk*>(frame());
  gtk_frame->GetNonClientView()->SetContextMenuController(this);

  otr_avatar_icon_->SetImage(GetOTRAvatarIcon());
  otr_avatar_icon_->SetID(VIEW_ID_OTR_AVATAR);
  AddChildView(otr_avatar_icon_);

  // Make sure the window is set to the right type.
  std::vector<int> params;
  params.push_back(browser()->tab_count());
  params.push_back(browser()->selected_index());
  params.push_back(gtk_get_current_event_time());
  WmIpc::instance()->SetWindowType(
      GTK_WIDGET(frame()->GetWindow()->GetNativeWindow()),
      WM_IPC_WINDOW_CHROME_TOPLEVEL,
      &params);
}

void BrowserView::Show() {
  bool was_visible = frame()->GetWindow()->IsVisible();
  ::BrowserView::Show();
  if (!was_visible) {
    // Have to update the tab count and selected index to reflect reality.
    std::vector<int> params;
    params.push_back(browser()->tab_count());
    params.push_back(browser()->selected_index());
    WmIpc::instance()->SetWindowType(
        GTK_WIDGET(frame()->GetWindow()->GetNativeWindow()),
        WM_IPC_WINDOW_CHROME_TOPLEVEL,
        &params);
  }
}

void BrowserView::FocusChromeOSStatus() {
  SaveFocusedView();
  status_area_->SetToolbarFocus(last_focused_view_storage_id(), NULL);
}

views::LayoutManager* BrowserView::CreateLayoutManager() const {
  return new BrowserViewLayout();
}

void BrowserView::InitTabStrip(TabStripModel* tab_strip_model) {
  ::BrowserView::InitTabStrip(tab_strip_model);
  UpdateOTRBackground();
}

void BrowserView::ChildPreferredSizeChanged(View* child) {
  Layout();
  SchedulePaint();
}

bool BrowserView::GetSavedWindowBounds(gfx::Rect* bounds) const {
  if ((browser()->type() & Browser::TYPE_POPUP) == 0 &&
      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeosFrame)) {
    // Typically we don't request a full screen size. This means we'll request a
    // non-full screen size, layout/paint at that size, then the window manager
    // will snap us to full screen size. This results in an ugly
    // resize/paint. To avoid this we always request a full screen size.
    *bounds = views::Screen::GetMonitorWorkAreaNearestWindow(
        GTK_WIDGET(GetWindow()->GetNativeWindow()));
    return true;
  }
  return ::BrowserView::GetSavedWindowBounds(bounds);
}

// views::ContextMenuController overrides.
void BrowserView::ShowContextMenu(views::View* source,
                                  const gfx::Point& p,
                                  bool is_mouse_gesture) {
  // Only show context menu if point is in unobscured parts of browser, i.e.
  // if NonClientHitTest returns :
  // - HTCAPTION: in title bar or unobscured part of tabstrip
  // - HTNOWHERE: as the name implies.
  gfx::Point point_in_parent_coords(p);
  views::View::ConvertPointToView(NULL, GetParent(), &point_in_parent_coords);
  int hit_test = NonClientHitTest(point_in_parent_coords);
  if (hit_test == HTCAPTION || hit_test == HTNOWHERE)
    system_menu_menu_->RunMenuAt(p, views::Menu2::ALIGN_TOPLEFT);
}

// StatusAreaHost overrides.
Profile* BrowserView::GetProfile() const {
  return browser()->profile();
}

gfx::NativeWindow BrowserView::GetNativeWindow() const {
  return GetWindow()->GetNativeWindow();
}

bool BrowserView::ShouldOpenButtonOptions(
    const views::View* button_view) const {
  return true;
}

void BrowserView::ExecuteBrowserCommand(int id) const {
  browser()->ExecuteCommand(id);
}

void BrowserView::OpenButtonOptions(const views::View* button_view) const {
  if (button_view == status_area_->network_view()) {
    browser()->OpenInternetOptionsDialog();
  } else if (button_view == status_area_->language_view()) {
    LanguageConfigView::Show(GetProfile(),
                             frame()->GetWindow()->GetNativeWindow());
  } else {
    browser()->OpenSystemOptionsDialog();
  }
}

bool BrowserView::IsBrowserMode() const {
  return true;
}

bool BrowserView::IsScreenLockerMode() const {
  return false;
}

////////////////////////////////////////////////////////////////////////////////
// BrowserView protected:

void BrowserView::GetAccessibleToolbars(
    std::vector<AccessibleToolbarView*>* toolbars) {
  ::BrowserView::GetAccessibleToolbars(toolbars);
  toolbars->push_back(status_area_);
}

////////////////////////////////////////////////////////////////////////////////
// BrowserView private:

void BrowserView::InitSystemMenu() {
  system_menu_contents_.reset(new menus::SimpleMenuModel(this));
  system_menu_contents_->AddItemWithStringId(IDC_RESTORE_TAB,
                                               IDS_RESTORE_TAB);
  system_menu_contents_->AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
  system_menu_contents_->AddSeparator();
  system_menu_contents_->AddItemWithStringId(IDC_TASK_MANAGER,
                                               IDS_TASK_MANAGER);
  system_menu_menu_.reset(new views::Menu2(system_menu_contents_.get()));
}

void BrowserView::UpdateOTRBackground() {
  if (UseVerticalTabs())
    otr_avatar_icon_->set_background(new ThemeBackground(this));
  else
    otr_avatar_icon_->set_background(NULL);
}

}  // namespace chromeos

// static
BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
  // Create a browser view for chromeos.
  BrowserView* view;
  if (browser->type() & Browser::TYPE_POPUP)
    view = new chromeos::PanelBrowserView(browser);
  else
    view = new chromeos::BrowserView(browser);
  BrowserFrame::Create(view, browser->profile());
  return view;
}

Generated by  Doxygen 1.6.0   Back to index