browser_view.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 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 "chrome/browser/chromeos/frame/browser_view.h" 6 7#include <algorithm> 8#include <string> 9#include <vector> 10 11#include "app/menus/simple_menu_model.h" 12#include "base/command_line.h" 13#include "chrome/app/chrome_dll_resource.h" 14#include "chrome/browser/chromeos/frame/panel_browser_view.h" 15#include "chrome/browser/chromeos/status/input_method_menu_button.h" 16#include "chrome/browser/chromeos/status/network_menu_button.h" 17#include "chrome/browser/chromeos/status/status_area_button.h" 18#include "chrome/browser/chromeos/status/status_area_view.h" 19#include "chrome/browser/chromeos/view_ids.h" 20#include "chrome/browser/chromeos/wm_ipc.h" 21#include "chrome/browser/views/frame/browser_frame_gtk.h" 22#include "chrome/browser/views/frame/browser_view.h" 23#include "chrome/browser/views/frame/browser_view_layout.h" 24#include "chrome/browser/views/tabs/tab.h" 25#include "chrome/browser/views/tabs/tab_strip.h" 26#include "chrome/browser/views/theme_background.h" 27#include "chrome/browser/views/toolbar_view.h" 28#include "chrome/common/chrome_switches.h" 29#include "cros/chromeos_wm_ipc_enums.h" 30#include "gfx/canvas.h" 31#include "grit/generated_resources.h" 32#include "views/controls/button/button.h" 33#include "views/controls/button/image_button.h" 34#include "views/controls/menu/menu_2.h" 35#include "views/screen.h" 36#include "views/widget/root_view.h" 37#include "views/window/hit_test.h" 38#include "views/window/window.h" 39 40namespace { 41 42// Amount to offset the toolbar by when vertical tabs are enabled. 43const int kVerticalTabStripToolbarOffset = 2; 44 45} // namespace 46 47namespace chromeos { 48 49// LayoutManager for BrowserView, which layouts extra components such as 50// the status views as follows: 51// ____ __ __ 52// / \ \ \ [StatusArea] 53// 54class BrowserViewLayout : public ::BrowserViewLayout { 55 public: 56 BrowserViewLayout() : ::BrowserViewLayout() {} 57 virtual ~BrowserViewLayout() {} 58 59 ////////////////////////////////////////////////////////////////////////////// 60 // BrowserViewLayout overrides: 61 62 void Installed(views::View* host) { 63 status_area_ = NULL; 64 ::BrowserViewLayout::Installed(host); 65 } 66 67 void ViewAdded(views::View* host, 68 views::View* view) { 69 ::BrowserViewLayout::ViewAdded(host, view); 70 switch (view->GetID()) { 71 case VIEW_ID_STATUS_AREA: 72 status_area_ = static_cast<chromeos::StatusAreaView*>(view); 73 break; 74 } 75 } 76 77 // In the normal and the compact navigation bar mode, ChromeOS 78 // layouts compact navigation buttons and status views in the title 79 // area. See Layout 80 virtual int LayoutTabStrip() { 81 if (browser_view_->IsFullscreen() || !browser_view_->IsTabStripVisible()) { 82 status_area_->SetVisible(false); 83 tabstrip_->SetVisible(false); 84 tabstrip_->SetBounds(0, 0, 0, 0); 85 return 0; 86 } 87 88 gfx::Rect tabstrip_bounds( 89 browser_view_->frame()->GetBoundsForTabStrip(tabstrip_)); 90 gfx::Point tabstrip_origin = tabstrip_bounds.origin(); 91 views::View::ConvertPointToView(browser_view_->GetParent(), browser_view_, 92 &tabstrip_origin); 93 tabstrip_bounds.set_origin(tabstrip_origin); 94 return browser_view_->UseVerticalTabs() ? 95 LayoutTitlebarComponentsWithVerticalTabs(tabstrip_bounds) : 96 LayoutTitlebarComponents(tabstrip_bounds); 97 } 98 99 virtual int LayoutToolbar(int top) { 100 if (!browser_view_->IsFullscreen() && browser_view_->IsTabStripVisible() && 101 browser_view_->UseVerticalTabs()) { 102 // For vertical tabs the toolbar is positioned in 103 // LayoutTitlebarComponentsWithVerticalTabs. 104 return top; 105 } 106 return ::BrowserViewLayout::LayoutToolbar(top); 107 } 108 109 virtual bool IsPositionInWindowCaption(const gfx::Point& point) { 110 return ::BrowserViewLayout::IsPositionInWindowCaption(point) 111 && !IsPointInViewsInTitleArea(point); 112 } 113 114 virtual int NonClientHitTest(const gfx::Point& point) { 115 gfx::Point point_in_browser_view_coords(point); 116 views::View::ConvertPointToView( 117 browser_view_->GetParent(), browser_view_, 118 &point_in_browser_view_coords); 119 return IsPointInViewsInTitleArea(point_in_browser_view_coords) ? 120 HTCLIENT : ::BrowserViewLayout::NonClientHitTest(point); 121 } 122 123 private: 124 chromeos::BrowserView* chromeos_browser_view() { 125 return static_cast<chromeos::BrowserView*>(browser_view_); 126 } 127 128 // Tests if the point is on one of views that are within the 129 // considered title bar area of client view. 130 bool IsPointInViewsInTitleArea(const gfx::Point& point) 131 const { 132 gfx::Point point_in_status_area_coords(point); 133 views::View::ConvertPointToView(browser_view_, status_area_, 134 &point_in_status_area_coords); 135 if (status_area_->HitTest(point_in_status_area_coords)) 136 return true; 137 138 return false; 139 } 140 141 // Positions the titlebar, toolbar and tabstrip. This is 142 // used when side tabs are enabled. 143 int LayoutTitlebarComponentsWithVerticalTabs(const gfx::Rect& bounds) { 144 if (bounds.IsEmpty()) 145 return 0; 146 147 tabstrip_->SetVisible(true); 148 status_area_->SetVisible(true); 149 150 gfx::Size status_size = status_area_->GetPreferredSize(); 151 int status_height = status_size.height(); 152 153 int status_x = bounds.x(); 154 // Layout the status area. 155 status_area_->SetBounds(status_x, bounds.bottom() - status_height, 156 status_size.width(), status_height); 157 158 // The tabstrip's width is the bigger of it's preferred width and the width 159 // the status area. 160 int tabstrip_w = std::max(status_x + status_size.width(), 161 tabstrip_->GetPreferredSize().width()); 162 tabstrip_->SetBounds(bounds.x(), bounds.y(), tabstrip_w, 163 bounds.height() - status_height); 164 165 // The toolbar is promoted to the title for vertical tabs. 166 bool toolbar_visible = browser_view_->IsToolbarVisible(); 167 toolbar_->SetVisible(toolbar_visible); 168 int toolbar_height = 0; 169 if (toolbar_visible) 170 toolbar_height = toolbar_->GetPreferredSize().height(); 171 int tabstrip_max_x = tabstrip_->bounds().right(); 172 toolbar_->SetBounds(tabstrip_max_x, 173 bounds.y() - kVerticalTabStripToolbarOffset, 174 browser_view_->width() - tabstrip_max_x, 175 toolbar_height); 176 177 // Adjust the available bounds for other components. 178 gfx::Rect available_bounds = vertical_layout_rect(); 179 available_bounds.Inset(tabstrip_w, 0, 0, 0); 180 set_vertical_layout_rect(available_bounds); 181 182 return bounds.y() + toolbar_height; 183 } 184 185 // Lays out tabstrip and status area in the title bar area (given by 186 // |bounds|). 187 int LayoutTitlebarComponents(const gfx::Rect& bounds) { 188 if (bounds.IsEmpty()) 189 return 0; 190 191 tabstrip_->SetVisible(true); 192 status_area_->SetVisible(true); 193 194 // Layout status area after tab strip. 195 gfx::Size status_size = status_area_->GetPreferredSize(); 196 status_area_->SetBounds(bounds.right() - status_size.width(), bounds.y(), 197 status_size.width(), status_size.height()); 198 tabstrip_->SetBounds(bounds.x(), bounds.y(), 199 std::max(0, status_area_->bounds().x() - bounds.x()), 200 bounds.height()); 201 return bounds.bottom(); 202 } 203 204 chromeos::StatusAreaView* status_area_; 205 206 DISALLOW_COPY_AND_ASSIGN(BrowserViewLayout); 207}; 208 209BrowserView::BrowserView(Browser* browser) 210 : ::BrowserView(browser), 211 status_area_(NULL) { 212} 213 214BrowserView::~BrowserView() { 215} 216 217//////////////////////////////////////////////////////////////////////////////// 218// BrowserView, ::BrowserView overrides: 219 220void BrowserView::Init() { 221 ::BrowserView::Init(); 222 status_area_ = new StatusAreaView(this); 223 status_area_->SetID(VIEW_ID_STATUS_AREA); 224 AddChildView(status_area_); 225 status_area_->Init(); 226 InitSystemMenu(); 227 228 // The ContextMenuController has to be set to a NonClientView but 229 // not to a NonClientFrameView because a TabStrip is not a child of 230 // a NonClientFrameView even though visually a TabStrip is over a 231 // NonClientFrameView. 232 BrowserFrameGtk* gtk_frame = static_cast<BrowserFrameGtk*>(frame()); 233 gtk_frame->GetNonClientView()->SetContextMenuController(this); 234 235 // Make sure the window is set to the right type. 236 std::vector<int> params; 237 params.push_back(browser()->tab_count()); 238 params.push_back(browser()->selected_index()); 239 params.push_back(gtk_get_current_event_time()); 240 WmIpc::instance()->SetWindowType( 241 GTK_WIDGET(frame()->GetWindow()->GetNativeWindow()), 242 WM_IPC_WINDOW_CHROME_TOPLEVEL, 243 ¶ms); 244} 245 246void BrowserView::Show() { 247 bool was_visible = frame()->GetWindow()->IsVisible(); 248 ::BrowserView::Show(); 249 if (!was_visible) { 250 // Have to update the tab count and selected index to reflect reality. 251 std::vector<int> params; 252 params.push_back(browser()->tab_count()); 253 params.push_back(browser()->selected_index()); 254 WmIpc::instance()->SetWindowType( 255 GTK_WIDGET(frame()->GetWindow()->GetNativeWindow()), 256 WM_IPC_WINDOW_CHROME_TOPLEVEL, 257 ¶ms); 258 } 259} 260 261void BrowserView::FocusChromeOSStatus() { 262 SaveFocusedView(); 263 status_area_->SetPaneFocus(last_focused_view_storage_id(), NULL); 264} 265 266views::LayoutManager* BrowserView::CreateLayoutManager() const { 267 return new BrowserViewLayout(); 268} 269 270void BrowserView::ChildPreferredSizeChanged(View* child) { 271 Layout(); 272 SchedulePaint(); 273} 274 275bool BrowserView::GetSavedWindowBounds(gfx::Rect* bounds) const { 276 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeosFrame)) { 277 // Typically we don't request a full screen size. This means we'll request a 278 // non-full screen size, layout/paint at that size, then the window manager 279 // will snap us to full screen size. This results in an ugly 280 // resize/paint. To avoid this we always request a full screen size. 281 *bounds = views::Screen::GetMonitorWorkAreaNearestWindow( 282 GTK_WIDGET(GetWindow()->GetNativeWindow())); 283 return true; 284 } 285 return ::BrowserView::GetSavedWindowBounds(bounds); 286} 287 288// views::ContextMenuController overrides. 289void BrowserView::ShowContextMenu(views::View* source, 290 const gfx::Point& p, 291 bool is_mouse_gesture) { 292 // Only show context menu if point is in unobscured parts of browser, i.e. 293 // if NonClientHitTest returns : 294 // - HTCAPTION: in title bar or unobscured part of tabstrip 295 // - HTNOWHERE: as the name implies. 296 gfx::Point point_in_parent_coords(p); 297 views::View::ConvertPointToView(NULL, GetParent(), &point_in_parent_coords); 298 int hit_test = NonClientHitTest(point_in_parent_coords); 299 if (hit_test == HTCAPTION || hit_test == HTNOWHERE) 300 system_menu_menu_->RunMenuAt(p, views::Menu2::ALIGN_TOPLEFT); 301} 302 303// StatusAreaHost overrides. 304Profile* BrowserView::GetProfile() const { 305 return browser()->profile(); 306} 307 308gfx::NativeWindow BrowserView::GetNativeWindow() const { 309 return GetWindow()->GetNativeWindow(); 310} 311 312bool BrowserView::ShouldOpenButtonOptions( 313 const views::View* button_view) const { 314 return true; 315} 316 317void BrowserView::ExecuteBrowserCommand(int id) const { 318 browser()->ExecuteCommand(id); 319} 320 321void BrowserView::OpenButtonOptions(const views::View* button_view) const { 322 if (button_view == status_area_->network_view()) { 323 browser()->OpenInternetOptionsDialog(); 324 } else if (button_view == status_area_->input_method_view()) { 325 browser()->OpenLanguageOptionsDialog(); 326 } else { 327 browser()->OpenSystemOptionsDialog(); 328 } 329} 330 331bool BrowserView::IsBrowserMode() const { 332 return true; 333} 334 335bool BrowserView::IsScreenLockerMode() const { 336 return false; 337} 338 339//////////////////////////////////////////////////////////////////////////////// 340// BrowserView protected: 341 342void BrowserView::GetAccessiblePanes( 343 std::vector<AccessiblePaneView*>* panes) { 344 ::BrowserView::GetAccessiblePanes(panes); 345 panes->push_back(status_area_); 346} 347 348//////////////////////////////////////////////////////////////////////////////// 349// BrowserView private: 350 351void BrowserView::InitSystemMenu() { 352 system_menu_contents_.reset(new menus::SimpleMenuModel(this)); 353 system_menu_contents_->AddItemWithStringId(IDC_RESTORE_TAB, 354 IDS_RESTORE_TAB); 355 system_menu_contents_->AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB); 356 system_menu_contents_->AddSeparator(); 357 system_menu_contents_->AddItemWithStringId(IDC_TASK_MANAGER, 358 IDS_TASK_MANAGER); 359 system_menu_menu_.reset(new views::Menu2(system_menu_contents_.get())); 360} 361 362} // namespace chromeos 363 364// static 365BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) { 366 // Create a browser view for chromeos. 367 BrowserView* view; 368 if (browser->type() & Browser::TYPE_POPUP) 369 view = new chromeos::PanelBrowserView(browser); 370 else 371 view = new chromeos::BrowserView(browser); 372 BrowserFrame::Create(view, browser->profile()); 373 return view; 374} 375