diff options
Diffstat (limited to 'chrome/browser/chromeos/frame/browser_view.cc')
-rw-r--r-- | chrome/browser/chromeos/frame/browser_view.cc | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/chrome/browser/chromeos/frame/browser_view.cc b/chrome/browser/chromeos/frame/browser_view.cc new file mode 100644 index 0000000..25ecefd --- /dev/null +++ b/chrome/browser/chromeos/frame/browser_view.cc @@ -0,0 +1,454 @@ +// 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 "cros/chromeos_wm_ipc_enums.h" +#include "views/controls/button/button.h" +#include "views/controls/button/image_button.h" +#include "views/controls/image_view.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; + } else { + gfx::Rect layout_bounds = + browser_view_->frame()->GetBoundsForTabStrip(tabstrip_); + gfx::Point tabstrip_origin = layout_bounds.origin(); + views::View::ConvertPointToView(browser_view_->GetParent(), browser_view_, + &tabstrip_origin); + layout_bounds.set_origin(tabstrip_origin); + if (browser_view_->UseVerticalTabs()) + return LayoutTitlebarComponentsWithVerticalTabs(layout_bounds); + return LayoutTitlebarComponents(layout_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; + } + + // Layouts components in the title bar area (given by + // |bounds|). These include the main menu, the otr avatar icon (in + // incognito window), 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); + + int bottom = bounds.bottom(); + + // Layout status area after tab strip. + gfx::Size status_size = status_area_->GetPreferredSize(); + status_area_->SetBounds(bounds.x() + bounds.width() - status_size.width(), + bounds.y(), status_size.width(), + status_size.height()); + LayoutOTRAvatar(bounds); + + int curx = bounds.x(); + int remaining_width = std::max( + 0, // In case there is no space left. + otr_avatar_icon_->bounds().x() - curx); + + tabstrip_->SetBounds(curx, bounds.y(), remaining_width, bounds.height()); + + gfx::Rect toolbar_bounds = browser_view_->GetToolbarBounds(); + tabstrip_->SetBackgroundOffset( + gfx::Point(curx - toolbar_bounds.x(), bounds.y())); + return 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, + ¶ms); +} + +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, + ¶ms); + } +} + +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; +} |