diff options
Diffstat (limited to 'chrome/browser/chromeos/chromeos_browser_view.cc')
-rw-r--r-- | chrome/browser/chromeos/chromeos_browser_view.cc | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/chrome/browser/chromeos/chromeos_browser_view.cc b/chrome/browser/chromeos/chromeos_browser_view.cc new file mode 100644 index 0000000..861c393 --- /dev/null +++ b/chrome/browser/chromeos/chromeos_browser_view.cc @@ -0,0 +1,505 @@ +// 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/chromeos_browser_view.h" + +#include <algorithm> +#include <string> + +#include "app/gfx/canvas.h" +#include "app/menus/simple_menu_model.h" +#include "app/theme_provider.h" +#include "base/command_line.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/chromeos/browser_status_area_view.h" +#include "chrome/browser/chromeos/compact_location_bar_host.h" +#include "chrome/browser/chromeos/compact_navigation_bar.h" +#include "chrome/browser/chromeos/main_menu.h" +#include "chrome/browser/chromeos/panel_browser_view.h" +#include "chrome/browser/chromeos/status_area_button.h" +#include "chrome/browser/view_ids.h" +#include "chrome/browser/views/frame/browser_extender.h" +#include "chrome/browser/views/frame/browser_frame_gtk.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/frame/chrome_browser_view_layout_manager.h" +#include "chrome/browser/views/tabs/tab.h" +#include "chrome/browser/views/tabs/tab_overview_types.h" +#include "chrome/browser/views/tabs/tab_strip.h" +#include "chrome/browser/views/toolbar_view.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/x11_util.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" +#include "views/controls/button/button.h" +#include "views/controls/button/image_button.h" +#include "views/controls/menu/menu_2.h" +#include "views/window/hit_test.h" +#include "views/window/window.h" + +namespace { + +const char* kChromeOsWindowManagerName = "chromeos-wm"; +const int kCompactNavbarSpaceHeight = 3; + +// A space we insert between the tabstrip and the content in +// Compact mode. +class Spacer : public views::View { + SkBitmap* background_; + public: + explicit Spacer(SkBitmap* bitmap) : background_(bitmap) {} + + void Paint(gfx::Canvas* canvas) { + canvas->TileImageInt(*background_, 0, 0, width(), height()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(Spacer); +}; + +// A chromeos implementation of Tab that shows the compact location bar. +class ChromeosTab : public Tab { + public: + ChromeosTab(TabStrip* tab_strip, chromeos::ChromeosBrowserView* browser_view) + : Tab(tab_strip), + browser_view_(browser_view) { + } + virtual ~ChromeosTab() {} + + // Overridden from views::View. + virtual void OnMouseEntered(const views::MouseEvent& event) { + TabRenderer::OnMouseEntered(event); + browser_view_->ShowCompactLocationBarUnderSelectedTab(); + } + + private: + chromeos::ChromeosBrowserView* browser_view_; + + DISALLOW_COPY_AND_ASSIGN(ChromeosTab); +}; + +// A Tabstrip that uses ChromeosTab as a Tab implementation. +class ChromeosTabStrip : public TabStrip { + public: + ChromeosTabStrip(TabStripModel* model, + chromeos::ChromeosBrowserView* browser_view) + : TabStrip(model), browser_view_(browser_view) { + } + virtual ~ChromeosTabStrip() {} + + protected: + // Overridden from TabStrip. + virtual Tab* CreateTab() { + return new ChromeosTab(this, browser_view_); + } + + private: + chromeos::ChromeosBrowserView* browser_view_; + + DISALLOW_COPY_AND_ASSIGN(ChromeosTabStrip); +}; + +// View ID used only in ChromeOS. +enum ChromeOSViewIds { + // Start with the offset that is big enough to avoid possible + // collison. + VIEW_ID_MAIN_MENU = VIEW_ID_PREDEFINED_COUNT + 10000, + VIEW_ID_COMPACT_NAV_BAR, + VIEW_ID_STATUS_AREA, + VIEW_ID_SPACER, +}; + +// LayoutManager for ChromeosBrowserView, which layouts extra components such as +// main menu, stataus views. +class ChromeosBrowserViewLayoutManager : public ChromeBrowserViewLayoutManager { + public: + ChromeosBrowserViewLayoutManager() : ChromeBrowserViewLayoutManager() {} + virtual ~ChromeosBrowserViewLayoutManager() {} + + ////////////////////////////////////////////////////////////////////////////// + // ChromeBrowserViewLayoutManager overrides: + + void Installed(views::View* host) { + main_menu_ = NULL; + compact_navigation_bar_ = NULL; + status_area_ = NULL; + spacer_ = NULL; + ChromeBrowserViewLayoutManager::Installed(host); + } + + void ViewAdded(views::View* host, + views::View* view) { + ChromeBrowserViewLayoutManager::ViewAdded(host, view); + switch (view->GetID()) { + case VIEW_ID_SPACER: + spacer_ = view; + break; + case VIEW_ID_MAIN_MENU: + main_menu_ = view; + break; + case VIEW_ID_STATUS_AREA: + status_area_ = static_cast<chromeos::StatusAreaView*>(view); + break; + case VIEW_ID_COMPACT_NAV_BAR: + compact_navigation_bar_ = view; + break; + } + } + + virtual int LayoutTabStrip() { + if (!browser_view_->IsTabStripVisible()) { + tabstrip_->SetVisible(false); + tabstrip_->SetBounds(0, 0, 0, 0); + return 0; + } else { + gfx::Rect layout_bounds = + browser_view_->frame()->GetBoundsForTabStrip(tabstrip_); + gfx::Rect toolbar_bounds = browser_view_->GetToolbarBounds(); + tabstrip_->SetBackgroundOffset( + gfx::Point(layout_bounds.x() - toolbar_bounds.x(), + layout_bounds.y())); + gfx::Point tabstrip_origin = layout_bounds.origin(); + views::View::ConvertPointToView(browser_view_->GetParent(), browser_view_, + &tabstrip_origin); + layout_bounds.set_origin(tabstrip_origin); + tabstrip_->SetVisible(true); + tabstrip_->SetBounds(layout_bounds); + + int bottom = 0; + gfx::Rect tabstrip_bounds; + LayoutCompactNavigationBar( + layout_bounds, &tabstrip_bounds, &bottom); + tabstrip_->SetVisible(true); + tabstrip_->SetBounds(tabstrip_bounds); + return bottom; + } + } + + virtual bool IsPositionInWindowCaption(const gfx::Point& point) { + return ChromeBrowserViewLayoutManager::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); + if (IsPointInViewsInTitleArea(point_in_browser_view_coords)) { + return HTCLIENT; + } + return ChromeBrowserViewLayoutManager::NonClientHitTest(point); + } + + private: + chromeos::ChromeosBrowserView* chromeos_browser_view() { + return static_cast<chromeos::ChromeosBrowserView*>(browser_view_); + } + + // Test 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_main_menu_coords(point); + views::View::ConvertPointToView(browser_view_, main_menu_, + &point_in_main_menu_coords); + if (main_menu_->HitTest(point_in_main_menu_coords)) + return true; + + 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; + + if (compact_navigation_bar_->IsVisible()) { + gfx::Point point_in_cnb_coords(point); + views::View::ConvertPointToView(browser_view_, + compact_navigation_bar_, + &point_in_cnb_coords); + return compact_navigation_bar_->HitTest(point_in_cnb_coords); + } + return false; + } + + void LayoutCompactNavigationBar(const gfx::Rect& bounds, + gfx::Rect* tabstrip_bounds, + int* bottom) { + if (browser_view_->IsTabStripVisible()) { + *bottom = bounds.bottom(); + } else { + *bottom = 0; + } + // Skip if there is no space to layout, or if the browser is in + // fullscreen mode. + if (bounds.IsEmpty() || browser_view_->IsFullscreen()) { + main_menu_->SetVisible(false); + compact_navigation_bar_->SetVisible(false); + status_area_->SetVisible(false); + tabstrip_bounds->SetRect(bounds.x(), bounds.y(), + bounds.width(), bounds.height()); + return; + } else { + main_menu_->SetVisible(true); + compact_navigation_bar_->SetVisible( + chromeos_browser_view()->is_compact_style()); + status_area_->SetVisible(true); + } + + /* TODO(oshima): + * Disabling the ability to update location bar on re-layout bacause + * tabstrip state may not be in sync with the browser's state when + * new tab is added. We should decide when we know more about this + * feature. May be we should simply hide the location? + * Filed a bug: http://crbug.com/30612. + if (compact_navigation_bar_->IsVisible()) { + // Update the size and location of the compact location bar. + int index = browser_view()->browser()->selected_index(); + compact_location_bar_host_->Update(index, false); + } + */ + + // Layout main menu before tab strip. + gfx::Size main_menu_size = main_menu_->GetPreferredSize(); + + // TODO(oshima): Use 0 for x position for now as this is + // sufficient for chromeos where the window is always + // maximized. The correct value is + // OpaqueBrowserFrameView::NonClientBorderThickness() and we will + // consider exposing it once we settle on the UI. + main_menu_->SetBounds(0, bounds.y(), + main_menu_size.width(), bounds.height()); + + status_area_->Update(); + // 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()); + int curx = bounds.x(); + int remaining_width = bounds.width() - status_size.width(); + + if (compact_navigation_bar_->IsVisible()) { + gfx::Size cnb_size = compact_navigation_bar_->GetPreferredSize(); + // Adjust the size of the compact nativation bar to avoid creating + // a fixed widget with its own gdk window. AutocompleteEditView + // expects the parent view to be transparent, but a fixed with + // its own window is not. + gfx::Rect cnb_bounds(curx, bounds.y(), cnb_size.width(), bounds.height()); + compact_navigation_bar_->SetBounds( + cnb_bounds.Intersect(browser_view_->GetVisibleBounds())); + curx += cnb_bounds.width(); + remaining_width -= cnb_bounds.width(); + + spacer_->SetVisible(true); + spacer_->SetBounds(0, *bottom, browser_view_->width(), + kCompactNavbarSpaceHeight); + *bottom += kCompactNavbarSpaceHeight; + } else { + spacer_->SetVisible(false); + } + // In case there is no space left. + remaining_width = std::max(0, remaining_width); + tabstrip_bounds->SetRect(curx, bounds.y(), + remaining_width, bounds.height()); + } + + + views::View* main_menu_; + chromeos::StatusAreaView* status_area_; + views::View* compact_navigation_bar_; + views::View* spacer_; + + DISALLOW_COPY_AND_ASSIGN(ChromeosBrowserViewLayoutManager); +}; + +} // namespace + +namespace chromeos { + +ChromeosBrowserView::ChromeosBrowserView(Browser* browser) + : BrowserView(browser), + main_menu_(NULL), + status_area_(NULL), + compact_navigation_bar_(NULL), + // Standard style is default. + // TODO(oshima): Get this info from preference. + ui_style_(StandardStyle), + force_maximized_window_(false) { +} + +ChromeosBrowserView::~ChromeosBrowserView() { +} + +//////////////////////////////////////////////////////////////////////////////// +// ChromeosBrowserView, ChromeBrowserView overrides: + +void ChromeosBrowserView::Init() { + BrowserView::Init(); + main_menu_ = new views::ImageButton(this); + main_menu_->SetID(VIEW_ID_MAIN_MENU); + ThemeProvider* theme_provider = + frame()->GetThemeProviderForFrame(); + SkBitmap* image = theme_provider->GetBitmapNamed(IDR_MAIN_MENU_BUTTON); + main_menu_->SetImage(views::CustomButton::BS_NORMAL, image); + main_menu_->SetImage(views::CustomButton::BS_HOT, image); + main_menu_->SetImage(views::CustomButton::BS_PUSHED, image); + AddChildView(main_menu_); + + compact_location_bar_host_.reset( + new chromeos::CompactLocationBarHost(this)); + compact_navigation_bar_ = + new chromeos::CompactNavigationBar(this); + compact_navigation_bar_->SetID(VIEW_ID_COMPACT_NAV_BAR); + AddChildView(compact_navigation_bar_); + compact_navigation_bar_->Init(); + status_area_ = new BrowserStatusAreaView(this); + status_area_->SetID(VIEW_ID_STATUS_AREA); + AddChildView(status_area_); + status_area_->Init(); + ToolbarView* toolbar_view = GetToolbarView(); + toolbar_view->SetAppMenuModel(status_area_->CreateAppMenuModel(toolbar_view)); + + SkBitmap* theme_toolbar = theme_provider->GetBitmapNamed(IDR_THEME_TOOLBAR); + spacer_ = new Spacer(theme_toolbar); + spacer_->SetID(VIEW_ID_SPACER); + AddChildView(spacer_); + + InitSystemMenu(); + chromeos::MainMenu::ScheduleCreation(); + + // 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); + + if (browser()->type() == Browser::TYPE_NORMAL) { + std::string wm_name; + bool wm_name_valid = x11_util::GetWindowManagerName(&wm_name); + // NOTE: On Chrome OS the wm and Chrome are started in parallel. This + // means it's possible for us not to be able to get the name of the window + // manager. We assume that when this happens we're on Chrome OS. + force_maximized_window_ = (!wm_name_valid || + wm_name == kChromeOsWindowManagerName || + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kChromeosFrame)); + } +} + +void ChromeosBrowserView::Show() { + bool was_visible = frame()->GetWindow()->IsVisible(); + BrowserView::Show(); + if (!was_visible) { + TabOverviewTypes::instance()->SetWindowType( + GTK_WIDGET(frame()->GetWindow()->GetNativeWindow()), + TabOverviewTypes::WINDOW_TYPE_CHROME_TOPLEVEL, + NULL); + } +} + +bool ChromeosBrowserView::IsToolbarVisible() const { + if (is_compact_style()) + return false; + return BrowserView::IsToolbarVisible(); +} + +void ChromeosBrowserView::SetFocusToLocationBar() { + if (compact_navigation_bar_->IsFocusable()) { + compact_navigation_bar_->FocusLocation(); + } else { + BrowserView::SetFocusToLocationBar(); + } +} + +void ChromeosBrowserView::ToggleCompactNavigationBar() { + ui_style_ = static_cast<UIStyle>((ui_style_ + 1) % 2); + compact_navigation_bar_->SetFocusable(is_compact_style()); + compact_location_bar_host_->SetEnabled(is_compact_style()); + Layout(); +} + +views::LayoutManager* ChromeosBrowserView::CreateLayoutManager() const { + return new ChromeosBrowserViewLayoutManager(); +} + +TabStrip* ChromeosBrowserView::CreateTabStrip( + TabStripModel* tab_strip_model) { + return new ChromeosTabStrip(tab_strip_model, this); +} + +// views::ButtonListener overrides. +void ChromeosBrowserView::ButtonPressed(views::Button* sender, + const views::Event& event) { + chromeos::MainMenu::Show(browser()); +} + +// views::ContextMenuController overrides. +void ChromeosBrowserView::ShowContextMenu(views::View* source, + int x, + int y, + bool is_mouse_gesture) { + system_menu_menu_->RunMenuAt(gfx::Point(x, y), views::Menu2::ALIGN_TOPLEFT); +} + +// StatusAreaHost overrides. +gfx::NativeWindow ChromeosBrowserView::GetNativeWindow() const { + return GetWindow()->GetNativeWindow(); +} + +void ChromeosBrowserView::OpenSystemOptionsDialog() const { + browser()->OpenSystemOptionsDialog(); +} + +bool ChromeosBrowserView::IsButtonVisible(views::View* button_view) const { + if (button_view == status_area_->menu_view()) + return !IsToolbarVisible(); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// ChromeosBrowserView public: + +void ChromeosBrowserView::ShowCompactLocationBarUnderSelectedTab() { + if (!is_compact_style()) + return; + int index = browser()->selected_index(); + compact_location_bar_host_->Update(index, true); +} + +bool ChromeosBrowserView::ShouldForceMaximizedWindow() const { + return force_maximized_window_; +} + +int ChromeosBrowserView::GetMainMenuWidth() const { + return main_menu_->GetPreferredSize().width(); +} + +//////////////////////////////////////////////////////////////////////////////// +// ChromeosBrowserView private: + +void ChromeosBrowserView::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())); +} + +} // 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::ChromeosBrowserView(browser); + BrowserFrame::Create(view, browser->profile()); + return view; +} |