browser_view.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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/ui/views/frame/browser_view.h" 6 7#include <algorithm> 8 9#include "base/auto_reset.h" 10#include "base/command_line.h" 11#include "base/i18n/rtl.h" 12#include "base/metrics/histogram.h" 13#include "base/string_number_conversions.h" 14#include "base/utf_string_conversions.h" 15#include "chrome/app/chrome_command_ids.h" 16#include "chrome/app/chrome_dll_resource.h" 17#include "chrome/browser/bookmarks/bookmark_model.h" 18#include "chrome/browser/bookmarks/bookmark_model_factory.h" 19#include "chrome/browser/bookmarks/bookmark_utils.h" 20#include "chrome/browser/browser_process.h" 21#include "chrome/browser/extensions/tab_helper.h" 22#include "chrome/browser/infobars/infobar_tab_helper.h" 23#include "chrome/browser/instant/instant_controller.h" 24#include "chrome/browser/managed_mode/managed_mode.h" 25#include "chrome/browser/native_window_notification_source.h" 26#include "chrome/browser/password_manager/password_manager.h" 27#include "chrome/browser/prefs/pref_service.h" 28#include "chrome/browser/profiles/avatar_menu_model.h" 29#include "chrome/browser/profiles/profile.h" 30#include "chrome/browser/profiles/profile_info_cache.h" 31#include "chrome/browser/profiles/profile_manager.h" 32#include "chrome/browser/sessions/tab_restore_service.h" 33#include "chrome/browser/sessions/tab_restore_service_factory.h" 34#include "chrome/browser/speech/extension_api/tts_extension_api.h" 35#include "chrome/browser/themes/theme_service.h" 36#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" 37#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h" 38#include "chrome/browser/ui/browser.h" 39#include "chrome/browser/ui/browser_command_controller.h" 40#include "chrome/browser/ui/browser_commands.h" 41#include "chrome/browser/ui/browser_dialogs.h" 42#include "chrome/browser/ui/browser_finder.h" 43#include "chrome/browser/ui/browser_instant_controller.h" 44#include "chrome/browser/ui/browser_list.h" 45#include "chrome/browser/ui/browser_tabstrip.h" 46#include "chrome/browser/ui/browser_window_state.h" 47#include "chrome/browser/ui/ntp_background_util.h" 48#include "chrome/browser/ui/omnibox/omnibox_popup_model.h" 49#include "chrome/browser/ui/omnibox/omnibox_popup_view.h" 50#include "chrome/browser/ui/omnibox/omnibox_view.h" 51#include "chrome/browser/ui/search/search.h" 52#include "chrome/browser/ui/search/search_delegate.h" 53#include "chrome/browser/ui/search/search_model.h" 54#include "chrome/browser/ui/search/search_ui.h" 55#include "chrome/browser/ui/tab_contents/tab_contents.h" 56#include "chrome/browser/ui/tabs/tab_menu_model.h" 57#include "chrome/browser/ui/tabs/tab_strip_model.h" 58#include "chrome/browser/ui/view_ids.h" 59#include "chrome/browser/ui/views/accessibility/invert_bubble_view.h" 60#include "chrome/browser/ui/views/avatar_menu_bubble_view.h" 61#include "chrome/browser/ui/views/avatar_menu_button.h" 62#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" 63#include "chrome/browser/ui/views/browser_dialogs.h" 64#include "chrome/browser/ui/views/download/download_in_progress_dialog_view.h" 65#include "chrome/browser/ui/views/download/download_shelf_view.h" 66#include "chrome/browser/ui/views/frame/browser_view_layout.h" 67#include "chrome/browser/ui/views/frame/contents_container.h" 68#include "chrome/browser/ui/views/frame/instant_preview_controller_views.h" 69#include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h" 70#include "chrome/browser/ui/views/infobars/infobar_container_view.h" 71#include "chrome/browser/ui/views/location_bar/location_icon_view.h" 72#include "chrome/browser/ui/views/omnibox/omnibox_view_views.h" 73#include "chrome/browser/ui/views/omnibox/omnibox_views.h" 74#include "chrome/browser/ui/views/password_generation_bubble_view.h" 75#include "chrome/browser/ui/views/status_bubble_views.h" 76#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h" 77#include "chrome/browser/ui/views/tabs/tab_strip.h" 78#include "chrome/browser/ui/views/toolbar_view.h" 79#include "chrome/browser/ui/views/update_recommended_message_box.h" 80#include "chrome/browser/ui/views/website_settings/website_settings_popup_view.h" 81#include "chrome/browser/ui/window_sizer/window_sizer.h" 82#include "chrome/common/chrome_notification_types.h" 83#include "chrome/common/chrome_switches.h" 84#include "chrome/common/extensions/extension_resource.h" 85#include "chrome/common/pref_names.h" 86#include "chrome/common/url_constants.h" 87#include "content/public/browser/download_manager.h" 88#include "content/public/browser/native_web_keyboard_event.h" 89#include "content/public/browser/notification_service.h" 90#include "content/public/browser/render_view_host.h" 91#include "content/public/browser/render_widget_host.h" 92#include "content/public/browser/user_metrics.h" 93#include "content/public/browser/web_contents.h" 94#include "content/public/browser/web_contents_view.h" 95#include "content/public/common/content_switches.h" 96#include "grit/chromium_strings.h" 97#include "grit/generated_resources.h" 98#include "grit/locale_settings.h" 99#include "grit/theme_resources.h" 100#include "grit/ui_resources.h" 101#include "grit/webkit_resources.h" 102#include "ui/base/accelerators/accelerator.h" 103#include "ui/base/accessibility/accessible_view_state.h" 104#include "ui/base/events/event_utils.h" 105#include "ui/base/hit_test.h" 106#include "ui/base/l10n/l10n_util.h" 107#include "ui/base/resource/resource_bundle.h" 108#include "ui/gfx/canvas.h" 109#include "ui/gfx/color_utils.h" 110#include "ui/gfx/sys_color_change_listener.h" 111#include "ui/ui_controls/ui_controls.h" 112#include "ui/views/controls/single_split_view.h" 113#include "ui/views/controls/webview/webview.h" 114#include "ui/views/focus/external_focus_tracker.h" 115#include "ui/views/focus/view_storage.h" 116#include "ui/views/layout/grid_layout.h" 117#include "ui/views/widget/native_widget.h" 118#include "ui/views/widget/root_view.h" 119#include "ui/views/widget/widget.h" 120#include "ui/views/window/dialog_delegate.h" 121 122#if defined(USE_ASH) 123#include "ash/launcher/launcher.h" 124#include "ash/launcher/launcher_model.h" 125#include "ash/shell.h" 126#include "chrome/browser/ui/ash/ash_util.h" 127#include "chrome/browser/ui/ash/chrome_shell_delegate.h" 128#include "chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h" 129#include "chrome/browser/ui/ash/window_positioner.h" 130#elif defined(OS_WIN) && !defined(USE_AURA) 131#include "base/win/metro.h" 132#include "chrome/browser/jumplist_win.h" 133#include "chrome/browser/ui/views/omnibox/omnibox_view_win.h" 134#include "ui/views/widget/native_widget_win.h" 135#include "ui/views/win/scoped_fullscreen_visibility.h" 136#endif 137 138#if defined(USE_AURA) 139#include "chrome/browser/ui/views/accelerator_table.h" 140#include "chrome/browser/ui/webui/task_manager/task_manager_dialog.h" 141#include "ui/aura/window.h" 142#include "ui/gfx/screen.h" 143#endif 144 145#if defined(ENABLE_ONE_CLICK_SIGNIN) 146#include "chrome/browser/ui/views/sync/one_click_signin_bubble_view.h" 147#endif 148 149using base::TimeDelta; 150using content::NativeWebKeyboardEvent; 151using content::SSLStatus; 152using content::UserMetricsAction; 153using content::WebContents; 154using views::ColumnSet; 155using views::GridLayout; 156 157namespace { 158// The height of the status bubble. 159const int kStatusBubbleHeight = 20; 160// The name of a key to store on the window handle so that other code can 161// locate this object using just the handle. 162const char* const kBrowserViewKey = "__BROWSER_VIEW__"; 163 164// The number of milliseconds between loading animation frames. 165const int kLoadingAnimationFrameTimeMs = 30; 166// The amount of space we expect the window border to take up. 167const int kWindowBorderWidth = 5; 168 169// How round the 'new tab' style bookmarks bar is. 170const int kNewtabBarRoundness = 5; 171 172} // namespace 173 174// Returned from BrowserView::GetClassName. 175const char BrowserView::kViewClassName[] = "browser/ui/views/BrowserView"; 176 177namespace { 178 179bool ShouldSaveOrRestoreWindowPos() { 180#if defined(OS_WIN) && !defined(USE_AURA) 181 // In Windows 8 metro mode the window is always maximized (without the 182 // WS_MAXIMIZE) style. 183 if (base::win::IsMetroProcess()) 184 return false; 185#endif 186 return true; 187} 188 189} // namespace 190 191/////////////////////////////////////////////////////////////////////////////// 192// BookmarkExtensionBackground, private: 193// This object serves as the views::Background object which is used to layout 194// and paint the bookmark bar. 195class BookmarkExtensionBackground : public views::Background { 196 public: 197 BookmarkExtensionBackground(BrowserView* browser_view, 198 DetachableToolbarView* host_view, 199 Browser* browser); 200 201 // View methods overridden from views:Background. 202 virtual void Paint(gfx::Canvas* canvas, views::View* view) const; 203 204 private: 205 BrowserView* browser_view_; 206 207 // The view hosting this background. 208 DetachableToolbarView* host_view_; 209 210 Browser* browser_; 211 212 DISALLOW_COPY_AND_ASSIGN(BookmarkExtensionBackground); 213}; 214 215BookmarkExtensionBackground::BookmarkExtensionBackground( 216 BrowserView* browser_view, 217 DetachableToolbarView* host_view, 218 Browser* browser) 219 : browser_view_(browser_view), 220 host_view_(host_view), 221 browser_(browser) { 222} 223 224void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas, 225 views::View* view) const { 226 ui::ThemeProvider* tp = host_view_->GetThemeProvider(); 227 228 // If search mode is |NTP|, bookmark bar is detached and floating on top of 229 // the content view (in z-order) and below the "Most Visited" thumbnails (in 230 // the y-direction). It's visually nicer without the bookmark background, so 231 // utilize the existing background of content view, giving the impression that 232 // each bookmark button is part of the content view. 233 const chrome::search::Mode& search_mode = 234 browser_view_->browser()->search_model()->mode(); 235 if (search_mode.is_ntp()) { 236 BookmarkModel* bookmark_model = 237 BookmarkModelFactory::GetForProfile(browser_->profile()); 238 if (bookmark_model && bookmark_model->HasBookmarks()) { 239 // If a theme is being used, paint the theme background color at maximum 240 // 80% opacity to make the the bookmark bar more legible; 241 // otherwise, use a transparent background. 242 if (tp->HasCustomImage(IDR_THEME_NTP_BACKGROUND)) { 243 const U8CPU kBackgroundOpacity = 204; // 80% opacity 244 SkColor color = tp->GetColor(ThemeService::COLOR_NTP_BACKGROUND); 245 if (gfx::IsInvertedColorScheme()) 246 color = color_utils::InvertColor(color); 247 if (SkColorGetA(color) > kBackgroundOpacity) 248 color = SkColorSetA(color, kBackgroundOpacity); 249 canvas->DrawColor(color); 250 DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_); 251 } else { 252 const SkColor kBorderColor = SkColorSetARGB(25, 0, 0, 0); // 10% black 253 DetachableToolbarView::PaintHorizontalBorderWithColor( 254 canvas, host_view_, kBorderColor); 255 } 256 } 257 return; 258 } 259 260 int toolbar_overlap = host_view_->GetToolbarOverlap(); 261 // The client edge is drawn below the toolbar bounds. 262 if (toolbar_overlap) 263 toolbar_overlap += views::NonClientFrameView::kClientEdgeThickness; 264 if (host_view_->IsDetached()) { 265 // Draw the background to match the new tab page. 266 int height = 0; 267 WebContents* contents = chrome::GetActiveWebContents(browser_); 268 if (contents && contents->GetView()) 269 height = contents->GetView()->GetContainerSize().height(); 270 NtpBackgroundUtil::PaintBackgroundDetachedMode( 271 tp, canvas, 272 gfx::Rect(0, toolbar_overlap, host_view_->width(), 273 host_view_->height() - toolbar_overlap), 274 height); 275 276 // As 'hidden' according to the animation is the full in-tab state, 277 // we invert the value - when current_state is at '0', we expect the 278 // bar to be docked. 279 double current_state = 1 - host_view_->GetAnimationValue(); 280 double h_padding = 281 static_cast<double>(BookmarkBarView::kNewtabHorizontalPadding) * 282 current_state; 283 double v_padding = 284 static_cast<double>(BookmarkBarView::kNewtabVerticalPadding) * 285 current_state; 286 287 SkRect rect; 288 double roundness = 0; 289 DetachableToolbarView::CalculateContentArea(current_state, h_padding, 290 v_padding, &rect, &roundness, host_view_); 291 DetachableToolbarView::PaintContentAreaBackground(canvas, tp, rect, 292 roundness); 293 DetachableToolbarView::PaintContentAreaBorder(canvas, tp, rect, roundness); 294 if (!toolbar_overlap) 295 DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_); 296 } else { 297 DetachableToolbarView::PaintBackgroundAttachedMode(canvas, host_view_, 298 browser_view_->OffsetPointForToolbarBackgroundImage( 299 gfx::Point(host_view_->GetMirroredX(), host_view_->y()))); 300 if (host_view_->height() >= toolbar_overlap) 301 DetachableToolbarView::PaintHorizontalBorder(canvas, host_view_); 302 } 303} 304 305/////////////////////////////////////////////////////////////////////////////// 306// ResizeCorner, private: 307 308class ResizeCorner : public views::View { 309 public: 310 ResizeCorner() { 311 EnableCanvasFlippingForRTLUI(true); 312 } 313 314 virtual void OnPaint(gfx::Canvas* canvas) { 315 views::Widget* widget = GetWidget(); 316 if (!widget || (widget->IsMaximized() || widget->IsFullscreen())) 317 return; 318 319 gfx::ImageSkia* image = ui::ResourceBundle::GetSharedInstance(). 320 GetImageSkiaNamed(IDR_TEXTAREA_RESIZER); 321 canvas->DrawImageInt(*image, width() - image->width(), 322 height() - image->height()); 323 } 324 325 static gfx::Size GetSize() { 326 // This is disabled until we find what makes us slower when we let 327 // WebKit know that we have a resizer rect... 328 // int scrollbar_thickness = gfx::scrollbar_size(); 329 // return gfx::Size(scrollbar_thickness, scrollbar_thickness); 330 return gfx::Size(); 331 } 332 333 virtual gfx::Size GetPreferredSize() { 334 views::Widget* widget = GetWidget(); 335 return (!widget || widget->IsMaximized() || widget->IsFullscreen()) ? 336 gfx::Size() : GetSize(); 337 } 338 339 virtual void Layout() { 340 if (parent()) { 341 gfx::Size ps = GetPreferredSize(); 342 // No need to handle Right to left text direction here, 343 // our parent must take care of it for us... 344 SetBounds(parent()->width() - ps.width(), 345 parent()->height() - ps.height(), ps.width(), ps.height()); 346 } 347 } 348 349 private: 350 DISALLOW_COPY_AND_ASSIGN(ResizeCorner); 351}; 352 353/////////////////////////////////////////////////////////////////////////////// 354// BrowserView, public: 355 356BrowserView::BrowserView(Browser* browser) 357 : views::ClientView(NULL, NULL), 358 last_focused_view_storage_id_( 359 views::ViewStorage::GetInstance()->CreateStorageID()), 360 frame_(NULL), 361 browser_(browser), 362 active_bookmark_bar_(NULL), 363 tabstrip_(NULL), 364 toolbar_(NULL), 365 window_switcher_button_(NULL), 366 infobar_container_(NULL), 367 contents_container_(NULL), 368 devtools_container_(NULL), 369 contents_(NULL), 370 contents_split_(NULL), 371 devtools_dock_side_(DEVTOOLS_DOCK_SIDE_BOTTOM), 372 devtools_window_(NULL), 373 initialized_(false), 374 ignore_layout_(true), 375#if defined(OS_WIN) && !defined(USE_AURA) 376 hung_window_detector_(&hung_plugin_action_), 377 ticker_(0), 378#endif 379 force_location_bar_focus_(false), 380 ALLOW_THIS_IN_INITIALIZER_LIST(color_change_listener_(this)), 381 ALLOW_THIS_IN_INITIALIZER_LIST(activate_modal_dialog_factory_(this)) { 382 browser_->tab_strip_model()->AddObserver(this); 383} 384 385BrowserView::~BrowserView() { 386#if defined(USE_ASH) 387 // Destroy BrowserLauncherItemController early on as it listens to the 388 // TabstripModel, which is destroyed by the browser. 389 launcher_item_controller_.reset(); 390#endif 391 392 preview_controller_.reset(NULL); 393 394 browser_->tab_strip_model()->RemoveObserver(this); 395 396#if defined(OS_WIN) && !defined(USE_AURA) 397 // Stop hung plugin monitoring. 398 ticker_.Stop(); 399 ticker_.UnregisterTickHandler(&hung_window_detector_); 400 401 // Terminate the jumplist (must be called before browser_->profile() is 402 // destroyed. 403 if (jumplist_) { 404 jumplist_->Terminate(); 405 } 406#endif 407 408 // We destroy the download shelf before |browser_| to remove its child 409 // download views from the set of download observers (since the observed 410 // downloads can be destroyed along with |browser_| and the observer 411 // notifications will call back into deleted objects). 412 download_shelf_.reset(); 413 414 // The TabStrip attaches a listener to the model. Make sure we shut down the 415 // TabStrip first so that it can cleanly remove the listener. 416 if (tabstrip_) { 417 tabstrip_->parent()->RemoveChildView(tabstrip_); 418 delete tabstrip_; 419 tabstrip_ = NULL; 420 } 421 // Child views maintain PrefMember attributes that point to 422 // OffTheRecordProfile's PrefService which gets deleted by ~Browser. 423 RemoveAllChildViews(true); 424 // Explicitly set browser_ to NULL. 425 browser_.reset(); 426} 427 428#if defined(OS_WIN) || defined(USE_AURA) 429// static 430BrowserView* BrowserView::GetBrowserViewForNativeWindow( 431 gfx::NativeWindow window) { 432 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window); 433 return widget ? 434 reinterpret_cast<BrowserView*>(widget->GetNativeWindowProperty( 435 kBrowserViewKey)) : NULL; 436} 437#endif 438 439// static 440BrowserView* BrowserView::GetBrowserViewForBrowser(const Browser* browser) { 441 return static_cast<BrowserView*>(browser->window()); 442} 443 444gfx::Rect BrowserView::GetToolbarBounds() const { 445 gfx::Rect toolbar_bounds(toolbar_->bounds()); 446 if (toolbar_bounds.IsEmpty()) 447 return toolbar_bounds; 448 // The apparent toolbar edges are outside the "real" toolbar edges. 449 toolbar_bounds.Inset(-views::NonClientFrameView::kClientEdgeThickness, 0); 450 return toolbar_bounds; 451} 452 453gfx::Rect BrowserView::GetClientAreaBounds() const { 454 gfx::Rect container_bounds = contents_->bounds(); 455 gfx::Point container_origin = container_bounds.origin(); 456 ConvertPointToTarget(this, parent(), &container_origin); 457 container_bounds.set_origin(container_origin); 458 return container_bounds; 459} 460 461gfx::Rect BrowserView::GetFindBarBoundingBox() const { 462 return GetBrowserViewLayout()->GetFindBarBoundingBox(); 463} 464 465int BrowserView::GetTabStripHeight() const { 466 // We want to return tabstrip_->height(), but we might be called in the midst 467 // of layout, when that hasn't yet been updated to reflect the current state. 468 // So return what the tabstrip height _ought_ to be right now. 469 return IsTabStripVisible() ? tabstrip_->GetPreferredSize().height() : 0; 470} 471 472gfx::Point BrowserView::OffsetPointForToolbarBackgroundImage( 473 const gfx::Point& point) const { 474 // The background image starts tiling horizontally at the window left edge and 475 // vertically at the top edge of the horizontal tab strip (or where it would 476 // be). We expect our parent's origin to be the window origin. 477 gfx::Point window_point(point + GetMirroredPosition().OffsetFromOrigin()); 478 window_point.Offset(frame_->GetThemeBackgroundXInset(), 479 -frame_->GetTabStripInsets(false).top); 480 return window_point; 481} 482 483bool BrowserView::IsTabStripVisible() const { 484 return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP); 485} 486 487bool BrowserView::IsOffTheRecord() const { 488 return browser_->profile()->IsOffTheRecord(); 489} 490 491bool BrowserView::IsGuestSession() const { 492 return browser_->profile()->IsGuestSession(); 493} 494 495bool BrowserView::ShouldShowAvatar() const { 496 if (!IsBrowserTypeNormal()) 497 return false; 498 if (IsOffTheRecord() && !IsGuestSession()) 499 return true; 500 if (ManagedMode::IsInManagedMode()) 501 return true; 502 503 ProfileInfoCache& cache = 504 g_browser_process->profile_manager()->GetProfileInfoCache(); 505 if (cache.GetIndexOfProfileWithPath(browser_->profile()->GetPath()) == 506 std::string::npos) { 507 return false; 508 } 509 510 return AvatarMenuModel::ShouldShowAvatarMenu(); 511} 512 513bool BrowserView::AcceleratorPressed(const ui::Accelerator& accelerator) { 514#if defined(OS_CHROMEOS) 515 // If accessibility is enabled, stop speech and return false so that key 516 // combinations involving Search can be used for extra accessibility 517 // functionality. 518 if (accelerator.key_code() == ui::VKEY_LWIN && 519 g_browser_process->local_state()->GetBoolean( 520 prefs::kSpokenFeedbackEnabled)) { 521 ExtensionTtsController::GetInstance()->Stop(); 522 return false; 523 } 524#endif 525 526 std::map<ui::Accelerator, int>::const_iterator iter = 527 accelerator_table_.find(accelerator); 528 DCHECK(iter != accelerator_table_.end()); 529 int command_id = iter->second; 530 531 chrome::BrowserCommandController* controller = browser_->command_controller(); 532 if (!controller->block_command_execution()) 533 UpdateAcceleratorMetrics(accelerator, command_id); 534 return chrome::ExecuteCommand(browser_.get(), command_id); 535} 536 537bool BrowserView::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) { 538 // The standard Ctrl-X, Ctrl-V and Ctrl-C are not defined as accelerators 539 // anywhere so we need to check for them explicitly here. 540 switch (cmd_id) { 541 case IDC_CUT: 542 *accelerator = ui::Accelerator(ui::VKEY_X, ui::EF_CONTROL_DOWN); 543 return true; 544 case IDC_COPY: 545 *accelerator = ui::Accelerator(ui::VKEY_C, ui::EF_CONTROL_DOWN); 546 return true; 547 case IDC_PASTE: 548 *accelerator = ui::Accelerator(ui::VKEY_V, ui::EF_CONTROL_DOWN); 549 return true; 550 } 551 // Else, we retrieve the accelerator information from the accelerator table. 552 std::map<ui::Accelerator, int>::iterator it = accelerator_table_.begin(); 553 for (; it != accelerator_table_.end(); ++it) { 554 if (it->second == cmd_id) { 555 *accelerator = it->first; 556 return true; 557 } 558 } 559 return false; 560} 561 562WebContents* BrowserView::GetActiveWebContents() const { 563 return chrome::GetActiveWebContents(browser_.get()); 564} 565 566TabContents* BrowserView::GetActiveTabContents() const { 567 return chrome::GetActiveTabContents(browser_.get()); 568} 569 570gfx::ImageSkia BrowserView::GetOTRAvatarIcon() const { 571 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 572 const gfx::ImageSkia* otr_avatar = 573 rb.GetNativeImageNamed(GetOTRIconResourceID()).ToImageSkia(); 574 return *otr_avatar; 575} 576 577bool BrowserView::IsPositionInWindowCaption(const gfx::Point& point) { 578 if (window_switcher_button_) { 579 gfx::Point window_switcher_point(point); 580 views::View::ConvertPointToTarget(this, window_switcher_button_, 581 &window_switcher_point); 582 if (window_switcher_button_->HitTestPoint(window_switcher_point)) 583 return false; 584 } 585 return GetBrowserViewLayout()->IsPositionInWindowCaption(point); 586} 587 588/////////////////////////////////////////////////////////////////////////////// 589// BrowserView, BrowserWindow implementation: 590 591void BrowserView::Show() { 592 // If the window is already visible, just activate it. 593 if (frame_->IsVisible()) { 594 frame_->Activate(); 595 return; 596 } 597 598 CreateLauncherIcon(); 599 600 // Showing the window doesn't make the browser window active right away. 601 // This can cause SetFocusToLocationBar() to skip setting focus to the 602 // location bar. To avoid this we explicilty let SetFocusToLocationBar() 603 // know that it's ok to steal focus. 604 force_location_bar_focus_ = true; 605 606 // Setting the focus doesn't work when the window is invisible, so any focus 607 // initialization that happened before this will be lost. 608 // 609 // We really "should" restore the focus whenever the window becomes unhidden, 610 // but I think initializing is the only time where this can happen where 611 // there is some focus change we need to pick up, and this is easier than 612 // plumbing through an un-hide message all the way from the frame. 613 // 614 // If we do find there are cases where we need to restore the focus on show, 615 // that should be added and this should be removed. 616 RestoreFocus(); 617 618 frame_->Show(); 619 620 force_location_bar_focus_ = false; 621 622 browser()->OnWindowDidShow(); 623 624 chrome::MaybeShowInvertBubbleView(browser_.get(), contents_); 625} 626 627void BrowserView::ShowInactive() { 628 if (frame_->IsVisible()) 629 return; 630 CreateLauncherIcon(); 631 frame_->ShowInactive(); 632} 633 634void BrowserView::Hide() { 635 // Not implemented. 636} 637 638void BrowserView::SetBounds(const gfx::Rect& bounds) { 639 ExitFullscreen(); 640 GetWidget()->SetBounds(bounds); 641} 642 643void BrowserView::Close() { 644 frame_->Close(); 645} 646 647void BrowserView::Activate() { 648 frame_->Activate(); 649} 650 651void BrowserView::Deactivate() { 652 frame_->Deactivate(); 653} 654 655bool BrowserView::IsActive() const { 656 return frame_->IsActive(); 657} 658 659void BrowserView::FlashFrame(bool flash) { 660 frame_->FlashFrame(flash); 661} 662 663bool BrowserView::IsAlwaysOnTop() const { 664 return false; 665} 666 667gfx::NativeWindow BrowserView::GetNativeWindow() { 668 return GetWidget()->GetTopLevelWidget()->GetNativeWindow(); 669} 670 671BrowserWindowTesting* BrowserView::GetBrowserWindowTesting() { 672 return this; 673} 674 675StatusBubble* BrowserView::GetStatusBubble() { 676 return status_bubble_.get(); 677} 678 679namespace { 680 // Only used by ToolbarSizeChanged() below, but placed here because template 681 // arguments (to AutoReset<>) must have external linkage. 682 enum CallState { NORMAL, REENTRANT, REENTRANT_FORCE_FAST_RESIZE }; 683} 684 685void BrowserView::UpdateTitleBar() { 686 frame_->UpdateWindowTitle(); 687 if (ShouldShowWindowIcon() && !loading_animation_timer_.IsRunning()) 688 frame_->UpdateWindowIcon(); 689} 690 691void BrowserView::BookmarkBarStateChanged( 692 BookmarkBar::AnimateChangeType change_type) { 693 if (bookmark_bar_view_.get()) { 694 bookmark_bar_view_->SetBookmarkBarState( 695 browser_->bookmark_bar_state(), change_type, 696 browser_->search_model()->mode()); 697 } 698 if (MaybeShowBookmarkBar(GetActiveTabContents())) 699 Layout(); 700} 701 702void BrowserView::UpdateDevTools() { 703 UpdateDevToolsForContents(GetActiveTabContents()); 704 Layout(); 705} 706 707 708void BrowserView::UpdateLoadingAnimations(bool should_animate) { 709 if (should_animate) { 710 if (!loading_animation_timer_.IsRunning()) { 711 // Loads are happening, and the timer isn't running, so start it. 712 last_animation_time_ = base::TimeTicks::Now(); 713 loading_animation_timer_.Start(FROM_HERE, 714 TimeDelta::FromMilliseconds(kLoadingAnimationFrameTimeMs), this, 715 &BrowserView::LoadingAnimationCallback); 716 } 717 } else { 718 if (loading_animation_timer_.IsRunning()) { 719 last_animation_time_ = base::TimeTicks(); 720 loading_animation_timer_.Stop(); 721 // Loads are now complete, update the state if a task was scheduled. 722 LoadingAnimationCallback(); 723 } 724 } 725} 726 727void BrowserView::SetStarredState(bool is_starred) { 728 GetLocationBarView()->SetStarToggled(is_starred); 729} 730 731void BrowserView::ZoomChangedForActiveTab(bool can_show_bubble) { 732 GetLocationBarView()->ZoomChangedForActiveTab( 733 can_show_bubble && !toolbar_->IsWrenchMenuShowing()); 734} 735 736gfx::Rect BrowserView::GetRestoredBounds() const { 737 return frame_->GetRestoredBounds(); 738} 739 740gfx::Rect BrowserView::GetBounds() const { 741 return frame_->GetWindowBoundsInScreen(); 742} 743 744bool BrowserView::IsMaximized() const { 745 return frame_->IsMaximized(); 746} 747 748bool BrowserView::IsMinimized() const { 749 return frame_->IsMinimized(); 750} 751 752void BrowserView::Maximize() { 753 frame_->Maximize(); 754} 755 756void BrowserView::Minimize() { 757 frame_->Minimize(); 758} 759 760void BrowserView::Restore() { 761 frame_->Restore(); 762} 763 764void BrowserView::EnterFullscreen( 765 const GURL& url, FullscreenExitBubbleType bubble_type) { 766 if (IsFullscreen()) 767 return; // Nothing to do. 768 769 ProcessFullscreen(true, FOR_DESKTOP, url, bubble_type); 770} 771 772void BrowserView::ExitFullscreen() { 773 if (!IsFullscreen()) 774 return; // Nothing to do. 775 776 ProcessFullscreen(false, FOR_DESKTOP, GURL(), FEB_TYPE_NONE); 777} 778 779void BrowserView::UpdateFullscreenExitBubbleContent( 780 const GURL& url, 781 FullscreenExitBubbleType bubble_type) { 782 if (bubble_type == FEB_TYPE_NONE) { 783 fullscreen_bubble_.reset(); 784 } else if (fullscreen_bubble_.get()) { 785 fullscreen_bubble_->UpdateContent(url, bubble_type); 786 } else { 787 fullscreen_bubble_.reset(new FullscreenExitBubbleViews( 788 GetWidget(), browser_.get(), url, bubble_type)); 789 } 790} 791 792bool BrowserView::IsFullscreen() const { 793 return frame_->IsFullscreen(); 794} 795 796bool BrowserView::IsFullscreenBubbleVisible() const { 797 return fullscreen_bubble_ != NULL; 798} 799 800void BrowserView::FullScreenStateChanged() { 801 if (IsFullscreen()) { 802 if (fullscreen_request_.pending) { 803 fullscreen_request_.pending = false; 804 ProcessFullscreen(true, FOR_DESKTOP, 805 fullscreen_request_.url, 806 fullscreen_request_.bubble_type); 807 } else { 808 ProcessFullscreen(true, FOR_DESKTOP, GURL(), 809 FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION); 810 } 811 } else { 812 ProcessFullscreen(false, FOR_DESKTOP, GURL(), FEB_TYPE_NONE); 813 } 814} 815 816#if defined(OS_WIN) 817void BrowserView::SetMetroSnapMode(bool enable) { 818 HISTOGRAM_COUNTS("Metro.SnapModeToggle", enable); 819 ProcessFullscreen(enable, FOR_METRO, GURL(), FEB_TYPE_NONE); 820} 821 822bool BrowserView::IsInMetroSnapMode() const { 823#if defined(USE_AURA) 824 return false; 825#else 826 return static_cast<views::NativeWidgetWin*>( 827 frame_->native_widget())->IsInMetroSnapMode(); 828#endif 829} 830#endif // defined(OS_WIN) 831 832void BrowserView::RestoreFocus() { 833 WebContents* selected_web_contents = GetActiveWebContents(); 834 if (selected_web_contents) 835 selected_web_contents->GetView()->RestoreFocus(); 836} 837 838void BrowserView::SetWindowSwitcherButton(views::Button* button) { 839 if (window_switcher_button_) 840 RemoveChildView(window_switcher_button_); 841 window_switcher_button_ = button; 842 AddChildView(button); 843} 844 845void BrowserView::ToolbarSizeChanged(bool is_animating) { 846 // The call to InfoBarContainer::SetMaxTopArrowHeight() below can result in 847 // reentrancy; |call_state| tracks whether we're reentrant. We can't just 848 // early-return in this case because we need to layout again so the infobar 849 // container's bounds are set correctly. 850 static CallState call_state = NORMAL; 851 852 // A reentrant call can (and should) use the fast resize path unless both it 853 // and the normal call are both non-animating. 854 bool use_fast_resize = 855 is_animating || (call_state == REENTRANT_FORCE_FAST_RESIZE); 856 if (use_fast_resize) 857 contents_container_->SetFastResize(true); 858 UpdateUIForContents(GetActiveTabContents()); 859 if (use_fast_resize) 860 contents_container_->SetFastResize(false); 861 862 // Inform the InfoBarContainer that the distance to the location icon may have 863 // changed. We have to do this after the block above so that the toolbars are 864 // laid out correctly for calculating the maximum arrow height below. 865 { 866 int top_arrow_height = 0; 867 // Hide the arrows on the Instant Extended NTP. 868 if (!chrome::search::IsInstantExtendedAPIEnabled(browser()->profile()) || 869 !browser()->search_model()->mode().is_ntp()) { 870 const LocationIconView* location_icon_view = 871 toolbar_->location_bar()->location_icon_view(); 872 // The +1 in the next line creates a 1-px gap between icon and arrow tip. 873 gfx::Point icon_bottom(0, location_icon_view->GetImageBounds().bottom() - 874 LocationBarView::kIconInternalPadding + 1); 875 ConvertPointToTarget(location_icon_view, this, &icon_bottom); 876 gfx::Point infobar_top(0, infobar_container_->GetVerticalOverlap(NULL)); 877 ConvertPointToTarget(infobar_container_, this, &infobar_top); 878 top_arrow_height = infobar_top.y() - icon_bottom.y(); 879 } 880 AutoReset<CallState> resetter(&call_state, 881 is_animating ? REENTRANT_FORCE_FAST_RESIZE : REENTRANT); 882 infobar_container_->SetMaxTopArrowHeight(top_arrow_height); 883 } 884 885 // When transitioning from animating to not animating we need to make sure the 886 // contents_container_ gets laid out. If we don't do this and the bounds 887 // haven't changed contents_container_ won't get a Layout out and we'll end up 888 // with a gray rect because the clip wasn't updated. Note that a reentrant 889 // call never needs to do this, because after it returns, the normal call 890 // wrapping it will do it. 891 if ((call_state == NORMAL) && !is_animating) { 892 contents_container_->InvalidateLayout(); 893 contents_split_->Layout(); 894 } 895} 896 897gfx::Size BrowserView::GetNTPBackgroundFillSize() const { 898 if (!chrome::search::IsInstantExtendedAPIEnabled(browser()->profile())) 899 return gfx::Size(); 900 // Convert bounds of content view relatve to browser view. 901 // Fill size is right and bottom of content view. 902 gfx::Rect content_bounds = contents_container_->bounds(); 903 gfx::Point origin(content_bounds.origin()); 904 View::ConvertPointToTarget(contents_container_->parent(), this, &origin); 905 content_bounds.set_origin(origin); 906 return gfx::Size(content_bounds.right(), content_bounds.bottom()); 907} 908 909LocationBar* BrowserView::GetLocationBar() const { 910 return GetLocationBarView(); 911} 912 913void BrowserView::SetFocusToLocationBar(bool select_all) { 914#if defined(OS_WIN) 915 // On Windows changing focus to the location bar causes the browser window 916 // to become active. This can steal focus if the user has another window 917 // open already. 918 if (!force_location_bar_focus_ && !IsActive()) 919 return; 920#endif 921 922 LocationBarView* location_bar = GetLocationBarView(); 923 if (location_bar->IsLocationEntryFocusableInRootView()) { 924 // Location bar got focus. 925 location_bar->FocusLocation(select_all); 926 } else { 927 // If none of location bar got focus, 928 // then clear focus. 929 views::FocusManager* focus_manager = GetFocusManager(); 930 DCHECK(focus_manager); 931 focus_manager->ClearFocus(); 932 } 933} 934 935void BrowserView::UpdateReloadStopState(bool is_loading, bool force) { 936 toolbar_->reload_button()->ChangeMode( 937 is_loading ? ReloadButton::MODE_STOP : ReloadButton::MODE_RELOAD, force); 938} 939 940void BrowserView::UpdateToolbar(TabContents* contents, 941 bool should_restore_state) { 942 toolbar_->Update(contents->web_contents(), should_restore_state); 943} 944 945void BrowserView::FocusToolbar() { 946 // Start the traversal within the main toolbar. SetPaneFocus stores 947 // the current focused view before changing focus. 948 toolbar_->SetPaneFocus(NULL); 949} 950 951void BrowserView::FocusBookmarksToolbar() { 952 if (active_bookmark_bar_ && bookmark_bar_view_->visible()) 953 bookmark_bar_view_->SetPaneFocus(bookmark_bar_view_.get()); 954} 955 956void BrowserView::FocusAppMenu() { 957 // Chrome doesn't have a traditional menu bar, but it has a menu button in the 958 // main toolbar that plays the same role. If the user presses a key that 959 // would typically focus the menu bar, tell the toolbar to focus the menu 960 // button. If the user presses the key again, return focus to the previous 961 // location. 962 // 963 // Not used on the Mac, which has a normal menu bar. 964 if (toolbar_->IsAppMenuFocused()) { 965 RestoreFocus(); 966 } else { 967 toolbar_->SetPaneFocusAndFocusAppMenu(); 968 } 969} 970 971void BrowserView::RotatePaneFocus(bool forwards) { 972 // This gets called when the user presses F6 (forwards) or Shift+F6 973 // (backwards) to rotate to the next pane. Here, our "panes" are the 974 // tab contents and each of our accessible toolbars, infobars, downloads 975 // shelf, etc. When a pane has focus, all of its controls are accessible 976 // in the tab traversal, and the tab traversal is "trapped" within that pane. 977 // 978 // Get a vector of all panes in the order we want them to be focused, 979 // with NULL to represent the tab contents getting focus. If one of these 980 // is currently invisible or has no focusable children it will be 981 // automatically skipped. 982 std::vector<views::AccessiblePaneView*> accessible_panes; 983 GetAccessiblePanes(&accessible_panes); 984 int pane_count = static_cast<int>(accessible_panes.size()); 985 int special_index = -1; 986 987 std::vector<views::View*> accessible_views( 988 accessible_panes.begin(), accessible_panes.end()); 989 accessible_views.push_back(GetTabContentsContainerView()); 990 if (devtools_container_->visible()) 991 accessible_views.push_back(devtools_container_); 992 int count = static_cast<int>(accessible_views.size()); 993 994 // Figure out which view (if any) currently has the focus. 995 const views::View* focused_view = GetFocusManager()->GetFocusedView(); 996 int index = -1; 997 if (focused_view) { 998 for (int i = 0; i < count; ++i) { 999 if (accessible_views[i] == focused_view || 1000 accessible_views[i]->Contains(focused_view)) { 1001 index = i; 1002 break; 1003 } 1004 } 1005 } 1006 1007 // If the focus isn't currently in a pane, save the focus so we 1008 // can restore it if the user presses Escape. 1009 if (focused_view && index >= pane_count) 1010 GetFocusManager()->StoreFocusedView(); 1011 1012#if defined(OS_CHROMEOS) && defined(USE_AURA) 1013 // Add the special panes to the rotation. 1014 special_index = count; 1015 ++count; 1016#endif 1017 1018 // Try to focus the next pane; if SetPaneFocusAndFocusDefault returns 1019 // false it means the pane didn't have any focusable controls, so skip 1020 // it and try the next one. 1021 for (;;) { 1022 if (forwards) 1023 index = (index + 1) % count; 1024 else 1025 index = ((index - 1) + count) % count; 1026 1027 if (index == special_index) { 1028#if defined(USE_ASH) 1029 ash::Shell::GetInstance()->RotateFocus( 1030 forwards ? ash::Shell::FORWARD : ash::Shell::BACKWARD); 1031#endif 1032 break; 1033 } else if (index < pane_count) { 1034 if (accessible_panes[index]->SetPaneFocusAndFocusDefault()) 1035 break; 1036 } else { 1037 accessible_views[index]->RequestFocus(); 1038 break; 1039 } 1040 } 1041} 1042 1043void BrowserView::DestroyBrowser() { 1044 // After this returns other parts of Chrome are going to be shutdown. Close 1045 // the window now so that we are deleted immediately and aren't left holding 1046 // references to deleted objects. 1047 GetWidget()->RemoveObserver(this); 1048 frame_->CloseNow(); 1049} 1050 1051bool BrowserView::IsBookmarkBarVisible() const { 1052 return browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR) && 1053 active_bookmark_bar_ && 1054 (active_bookmark_bar_->GetPreferredSize().height() != 0); 1055} 1056 1057bool BrowserView::IsBookmarkBarAnimating() const { 1058 return bookmark_bar_view_.get() && bookmark_bar_view_->is_animating(); 1059} 1060 1061bool BrowserView::IsTabStripEditable() const { 1062 return tabstrip_->IsTabStripEditable(); 1063} 1064 1065bool BrowserView::IsToolbarVisible() const { 1066 return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) || 1067 browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR); 1068} 1069 1070gfx::Rect BrowserView::GetRootWindowResizerRect() const { 1071 if (frame_->IsMaximized() || frame_->IsFullscreen()) 1072 return gfx::Rect(); 1073 1074 // We don't specify a resize corner size if we have a bottom shelf either. 1075 // This is because we take care of drawing the resize corner on top of that 1076 // shelf, so we don't want others to do it for us in this case. 1077 // Currently, the only visible bottom shelf is the download shelf. 1078 // Other tests should be added here if we add more bottom shelves. 1079 if (IsDownloadShelfVisible()) 1080 return gfx::Rect(); 1081 1082 gfx::Rect client_rect = contents_split_->bounds(); 1083 gfx::Size resize_corner_size = ResizeCorner::GetSize(); 1084 int x = client_rect.width() - resize_corner_size.width(); 1085 if (base::i18n::IsRTL()) 1086 x = 0; 1087 return gfx::Rect(x, client_rect.height() - resize_corner_size.height(), 1088 resize_corner_size.width(), resize_corner_size.height()); 1089} 1090 1091bool BrowserView::IsPanel() const { 1092 return false; 1093} 1094 1095void BrowserView::DisableInactiveFrame() { 1096#if defined(OS_WIN) && !defined(USE_AURA) 1097 frame_->DisableInactiveRendering(); 1098#endif // No tricks are needed to get the right behavior on Linux. 1099} 1100 1101void BrowserView::ConfirmAddSearchProvider(TemplateURL* template_url, 1102 Profile* profile) { 1103 chrome::EditSearchEngine(GetWidget()->GetNativeWindow(), template_url, NULL, 1104 profile); 1105} 1106 1107void BrowserView::ToggleBookmarkBar() { 1108 bookmark_utils::ToggleWhenVisible(browser_->profile()); 1109} 1110 1111void BrowserView::ShowUpdateChromeDialog() { 1112 UpdateRecommendedMessageBox::Show(GetWidget()->GetNativeWindow()); 1113} 1114 1115void BrowserView::ShowTaskManager() { 1116#if defined(USE_AURA) 1117 TaskManagerDialog::Show(); 1118#else 1119 chrome::ShowTaskManager(); 1120#endif // defined(USE_AURA) 1121} 1122 1123void BrowserView::ShowBackgroundPages() { 1124#if defined(USE_AURA) 1125 TaskManagerDialog::ShowBackgroundPages(); 1126#else 1127 chrome::ShowBackgroundPages(); 1128#endif // defined(USE_AURA) 1129} 1130 1131void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) { 1132 chrome::ShowBookmarkBubbleView(GetToolbarView()->GetBookmarkBubbleAnchor(), 1133 browser_->profile(), url, !already_bookmarked); 1134} 1135 1136void BrowserView::ShowBookmarkPrompt() { 1137 GetLocationBarView()->ShowBookmarkPrompt(); 1138} 1139 1140void BrowserView::ShowChromeToMobileBubble() { 1141 GetLocationBarView()->ShowChromeToMobileBubble(); 1142} 1143 1144#if defined(ENABLE_ONE_CLICK_SIGNIN) 1145void BrowserView::ShowOneClickSigninBubble( 1146 const StartSyncCallback& start_sync_callback) { 1147 OneClickSigninBubbleView::ShowBubble(toolbar_->app_menu(), 1148 start_sync_callback); 1149} 1150#endif 1151 1152void BrowserView::SetDownloadShelfVisible(bool visible) { 1153 // This can be called from the superclass destructor, when it destroys our 1154 // child views. At that point, browser_ is already gone. 1155 if (browser_ == NULL) 1156 return; 1157 1158 if (visible && IsDownloadShelfVisible() != visible) { 1159 // Invoke GetDownloadShelf to force the shelf to be created. 1160 GetDownloadShelf(); 1161 } 1162 1163 if (browser_ != NULL) 1164 browser_->UpdateDownloadShelfVisibility(visible); 1165 1166 // SetDownloadShelfVisible can force-close the shelf, so make sure we lay out 1167 // everything correctly, as if the animation had finished. This doesn't 1168 // matter for showing the shelf, as the show animation will do it. 1169 ToolbarSizeChanged(false); 1170} 1171 1172bool BrowserView::IsDownloadShelfVisible() const { 1173 return download_shelf_.get() && download_shelf_->IsShowing(); 1174} 1175 1176DownloadShelf* BrowserView::GetDownloadShelf() { 1177 if (!download_shelf_.get()) { 1178 download_shelf_.reset(new DownloadShelfView(browser_.get(), this)); 1179 download_shelf_->set_owned_by_client(); 1180 } 1181 return download_shelf_.get(); 1182} 1183 1184void BrowserView::ConfirmBrowserCloseWithPendingDownloads() { 1185 DownloadInProgressDialogView::Show(browser_.get(), GetNativeWindow()); 1186} 1187 1188void BrowserView::ShowCreateChromeAppShortcutsDialog( 1189 Profile* profile, 1190 const extensions::Extension* app) { 1191 chrome::ShowCreateChromeAppShortcutsDialog(GetNativeWindow(), profile, app); 1192} 1193 1194void BrowserView::UserChangedTheme() { 1195 frame_->FrameTypeChanged(); 1196} 1197 1198int BrowserView::GetExtraRenderViewHeight() const { 1199 // Currently this is only used on linux. 1200 return 0; 1201} 1202 1203void BrowserView::WebContentsFocused(WebContents* contents) { 1204 if (contents_container_->GetWebContents() == contents) 1205 contents_container_->OnWebContentsFocused(contents); 1206 else 1207 devtools_container_->OnWebContentsFocused(contents); 1208} 1209 1210void BrowserView::ShowPageInfo(content::WebContents* web_contents, 1211 const GURL& url, 1212 const SSLStatus& ssl, 1213 bool show_history) { 1214 chrome::ShowPageInfoBubble(GetLocationBarView()->location_icon_view(), 1215 web_contents, url, ssl, show_history, browser_.get()); 1216} 1217 1218void BrowserView::ShowWebsiteSettings(Profile* profile, 1219 TabContents* tab_contents, 1220 const GURL& url, 1221 const content::SSLStatus& ssl, 1222 bool show_history) { 1223 WebsiteSettingsPopupView::ShowPopup( 1224 GetLocationBarView()->location_icon_view(), profile, 1225 tab_contents, url, ssl, browser_.get()); 1226} 1227 1228void BrowserView::ShowAppMenu() { 1229 toolbar_->app_menu()->Activate(); 1230} 1231 1232bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, 1233 bool* is_keyboard_shortcut) { 1234 *is_keyboard_shortcut = false; 1235 1236 if ((event.type != WebKit::WebInputEvent::RawKeyDown) && 1237 (event.type != WebKit::WebInputEvent::KeyUp)) { 1238 return false; 1239 } 1240 1241#if defined(OS_WIN) && !defined(USE_AURA) 1242 // As Alt+F4 is the close-app keyboard shortcut, it needs processing 1243 // immediately. 1244 if (event.windowsKeyCode == ui::VKEY_F4 && 1245 event.type == WebKit::WebInputEvent::RawKeyDown && 1246 event.modifiers == NativeWebKeyboardEvent::AltKey) { 1247 DefWindowProc(event.os_event.hwnd, event.os_event.message, 1248 event.os_event.wParam, event.os_event.lParam); 1249 return true; 1250 } 1251#endif 1252 1253 views::FocusManager* focus_manager = GetFocusManager(); 1254 DCHECK(focus_manager); 1255 1256 if (focus_manager->shortcut_handling_suspended()) 1257 return false; 1258 1259 ui::Accelerator accelerator( 1260 static_cast<ui::KeyboardCode>(event.windowsKeyCode), 1261 content::GetModifiersFromNativeWebKeyboardEvent(event)); 1262 if (event.type == WebKit::WebInputEvent::KeyUp) 1263 accelerator.set_type(ui::ET_KEY_RELEASED); 1264 1265 // What we have to do here is as follows: 1266 // - If the |browser_| is for an app, do nothing. 1267 // - If the |browser_| is not for an app, and the |accelerator| is not 1268 // associated with the browser (e.g. an Ash shortcut), process it. 1269 // - If the |browser_| is not for an app, and the |accelerator| is associated 1270 // with the browser, and it is a reserved one (e.g. Ctrl+w), process it. 1271 // - If the |browser_| is not for an app, and the |accelerator| is associated 1272 // with the browser, and it is not a reserved one, do nothing. 1273 1274 if (browser_->is_app()) { 1275 // We don't have to flip |is_keyboard_shortcut| here. If we do that, the app 1276 // might not be able to see a subsequent Char event. See OnHandleInputEvent 1277 // in content/renderer/render_widget.cc for details. 1278 return false; 1279 } 1280 1281 chrome::BrowserCommandController* controller = browser_->command_controller(); 1282 1283 // Here we need to retrieve the command id (if any) associated to the 1284 // keyboard event. Instead of looking up the command id in the 1285 // |accelerator_table_| by ourselves, we block the command execution of 1286 // the |browser_| object then send the keyboard event to the 1287 // |focus_manager| as if we are activating an accelerator key. 1288 // Then we can retrieve the command id from the |browser_| object. 1289 controller->SetBlockCommandExecution(true); 1290 // If the |accelerator| is a non-browser shortcut (e.g. Ash shortcut), the 1291 // command execution cannot be blocked and true is returned. However, it is 1292 // okay as long as is_app() is false. See comments in this function. 1293 const bool processed = focus_manager->ProcessAccelerator(accelerator); 1294 const int id = controller->GetLastBlockedCommand(NULL); 1295 controller->SetBlockCommandExecution(false); 1296 1297 // Executing the command may cause |this| object to be destroyed. 1298 if (controller->IsReservedCommandOrKey(id, event)) { 1299 UpdateAcceleratorMetrics(accelerator, id); 1300 return chrome::ExecuteCommand(browser_.get(), id); 1301 } 1302 1303 if (id != -1) { 1304 // |accelerator| is a non-reserved browser shortcut (e.g. Ctrl+f). 1305 if (event.type == WebKit::WebInputEvent::RawKeyDown) 1306 *is_keyboard_shortcut = true; 1307 } else if (processed) { 1308 // |accelerator| is a non-browser shortcut (e.g. F4-F10 on Ash). 1309 return true; 1310 } 1311 1312 return false; 1313} 1314 1315void BrowserView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { 1316 unhandled_keyboard_event_handler_.HandleKeyboardEvent(event, 1317 GetFocusManager()); 1318} 1319 1320// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always 1321// enabled in the page menu regardless of whether the command will do 1322// anything. When someone selects the menu item, we just act as if they hit 1323// the keyboard shortcut for the command by sending the associated key press 1324// to windows. The real fix to this bug is to disable the commands when they 1325// won't do anything. We'll need something like an overall clipboard command 1326// manager to do that. 1327void BrowserView::Cut() { 1328 // If a WebContent is focused, call RenderWidgetHost::Cut. Otherwise, e.g. if 1329 // Omnibox is focused, send a Ctrl+x key event to Chrome. Using RWH interface 1330 // rather than the fake key event for a WebContent is important since the fake 1331 // event might be consumed by the web content (crbug.com/137908). 1332 if (!DoCutCopyPaste(&content::RenderWidgetHost::Cut)) { 1333 ui_controls::SendKeyPress(GetNativeWindow(), ui::VKEY_X, 1334 true, false, false, false); 1335 } 1336} 1337 1338void BrowserView::Copy() { 1339 if (!DoCutCopyPaste(&content::RenderWidgetHost::Copy)) { 1340 ui_controls::SendKeyPress(GetNativeWindow(), ui::VKEY_C, 1341 true, false, false, false); 1342 } 1343} 1344 1345void BrowserView::Paste() { 1346 if (!DoCutCopyPaste(&content::RenderWidgetHost::Paste)) { 1347 ui_controls::SendKeyPress(GetNativeWindow(), ui::VKEY_V, 1348 true, false, false, false); 1349 } 1350} 1351 1352gfx::Rect BrowserView::GetInstantBounds() { 1353 return contents_->GetPreviewBounds(); 1354} 1355 1356bool BrowserView::IsInstantTabShowing() { 1357 return preview_controller_->preview_container() != NULL; 1358} 1359 1360WindowOpenDisposition BrowserView::GetDispositionForPopupBounds( 1361 const gfx::Rect& bounds) { 1362#if defined(OS_WIN) 1363#if defined(USE_AURA) 1364 return NEW_POPUP; 1365#else 1366 // If we are in windows metro-mode, we can't allow popup windows. 1367 return base::win::IsMetroProcess() ? NEW_BACKGROUND_TAB : NEW_POPUP; 1368#endif 1369#else 1370 return NEW_POPUP; 1371#endif 1372} 1373 1374FindBar* BrowserView::CreateFindBar() { 1375 return chrome::CreateFindBar(this); 1376} 1377 1378bool BrowserView::GetConstrainedWindowTopY(int* top_y) { 1379 return GetBrowserViewLayout()->GetConstrainedWindowTopY(top_y); 1380} 1381 1382/////////////////////////////////////////////////////////////////////////////// 1383// BrowserView, BrowserWindowTesting implementation: 1384 1385BookmarkBarView* BrowserView::GetBookmarkBarView() const { 1386 return bookmark_bar_view_.get(); 1387} 1388 1389LocationBarView* BrowserView::GetLocationBarView() const { 1390 return toolbar_ ? toolbar_->location_bar() : NULL; 1391} 1392 1393views::View* BrowserView::GetTabContentsContainerView() const { 1394 return contents_container_; 1395} 1396 1397ToolbarView* BrowserView::GetToolbarView() const { 1398 return toolbar_; 1399} 1400 1401/////////////////////////////////////////////////////////////////////////////// 1402// BrowserView, TabStripModelObserver implementation: 1403 1404void BrowserView::TabDetachedAt(WebContents* contents, int index) { 1405 // We use index here rather than comparing |contents| because by this time 1406 // the model has already removed |contents| from its list, so 1407 // browser_->GetActiveWebContents() will return NULL or something else. 1408 if (index == browser_->active_index()) { 1409 // We need to reset the current tab contents to NULL before it gets 1410 // freed. This is because the focus manager performs some operations 1411 // on the selected WebContents when it is removed. 1412 contents_container_->SetWebContents(NULL); 1413 infobar_container_->ChangeTabContents(NULL); 1414 UpdateDevToolsForContents(NULL); 1415 } 1416} 1417 1418void BrowserView::TabDeactivated(TabContents* contents) { 1419 // We do not store the focus when closing the tab to work-around bug 4633. 1420 // Some reports seem to show that the focus manager and/or focused view can 1421 // be garbage at that point, it is not clear why. 1422 if (!contents->in_destructor()) 1423 contents->web_contents()->GetView()->StoreFocus(); 1424} 1425 1426void BrowserView::ActiveTabChanged(TabContents* old_contents, 1427 TabContents* new_contents, 1428 int index, 1429 bool user_gesture) { 1430 DCHECK(new_contents); 1431 1432 // See if the Instant preview is being activated (committed). 1433 if (contents_->preview_web_contents() == new_contents->web_contents()) { 1434 contents_->MakePreviewContentsActiveContents(); 1435 views::WebView* old_container = contents_container_; 1436 contents_container_ = preview_controller_->release_preview_container(); 1437 old_container->SetWebContents(NULL); 1438 delete old_container; 1439 } 1440 1441 // If |contents_container_| already has the correct WebContents, we can save 1442 // some work. This also prevents extra events from being reported by the 1443 // Visibility API under Windows, as ChangeWebContents will briefly hide 1444 // the WebContents window. 1445 bool change_tab_contents = 1446 contents_container_->web_contents() != new_contents->web_contents(); 1447 1448 // Update various elements that are interested in knowing the current 1449 // WebContents. 1450 1451 // When we toggle the NTP floating bookmarks bar and/or the info bar, 1452 // we don't want any WebContents to be attached, so that we 1453 // avoid an unnecessary resize and re-layout of a WebContents. 1454 if (change_tab_contents) 1455 contents_container_->SetWebContents(NULL); 1456 InfoBarTabHelper* new_infobar_tab_helper = 1457 InfoBarTabHelper::FromWebContents(new_contents->web_contents()); 1458 infobar_container_->ChangeTabContents(new_infobar_tab_helper); 1459 if (bookmark_bar_view_.get()) { 1460 bookmark_bar_view_->SetBookmarkBarState( 1461 browser_->bookmark_bar_state(), 1462 BookmarkBar::DONT_ANIMATE_STATE_CHANGE, 1463 browser_->search_model()->mode()); 1464 } 1465 UpdateUIForContents(new_contents); 1466 1467 // Layout for DevTools _before_ setting the main WebContents to avoid 1468 // toggling the size of the main WebContents. 1469 UpdateDevToolsForContents(new_contents); 1470 1471 if (change_tab_contents) { 1472 contents_container_->SetWebContents(new_contents->web_contents()); 1473#if defined(USE_AURA) 1474 // Put the Instant preview back on top in case it is showing custom new tab 1475 // page content. 1476 if (contents_->preview_web_contents()) { 1477 ui::Layer* preview_layer = 1478 contents_->preview_web_contents()->GetNativeView()->layer(); 1479 preview_layer->parent()->StackAtTop(preview_layer); 1480 } 1481#endif 1482 } 1483 1484 if (!browser_->tab_strip_model()->closing_all() && GetWidget()->IsActive() && 1485 GetWidget()->IsVisible()) { 1486 // We only restore focus if our window is visible, to avoid invoking blur 1487 // handlers when we are eventually shown. 1488 new_contents->web_contents()->GetView()->RestoreFocus(); 1489 } 1490 1491 // Update all the UI bits. 1492 UpdateTitleBar(); 1493 1494 MaybeStackBookmarkBarAtTop(); 1495 1496 // No need to update Toolbar because it's already updated in 1497 // browser.cc. 1498} 1499 1500void BrowserView::TabStripEmpty() { 1501 // Make sure all optional UI is removed before we are destroyed, otherwise 1502 // there will be consequences (since our view hierarchy will still have 1503 // references to freed views). 1504 UpdateUIForContents(NULL); 1505} 1506 1507/////////////////////////////////////////////////////////////////////////////// 1508// BrowserView, ui::AcceleratorProvider implementation: 1509 1510bool BrowserView::GetAcceleratorForCommandId(int command_id, 1511 ui::Accelerator* accelerator) { 1512 // Let's let the ToolbarView own the canonical implementation of this method. 1513 return toolbar_->GetAcceleratorForCommandId(command_id, accelerator); 1514} 1515 1516/////////////////////////////////////////////////////////////////////////////// 1517// BrowserView, views::WidgetDelegate implementation: 1518 1519bool BrowserView::CanResize() const { 1520 return true; 1521} 1522 1523bool BrowserView::CanMaximize() const { 1524 return true; 1525} 1526 1527bool BrowserView::CanActivate() const { 1528 if (!AppModalDialogQueue::GetInstance()->active_dialog()) 1529 return true; 1530 1531 // If another browser is app modal, flash and activate the modal browser. This 1532 // has to be done in a post task, otherwise if the user clicked on a window 1533 // that doesn't have the modal dialog the windows keep trying to get the focus 1534 // from each other on Windows. http://crbug.com/141650. 1535 MessageLoop::current()->PostTask( 1536 FROM_HERE, 1537 base::Bind(&BrowserView::ActivateAppModalDialog, 1538 activate_modal_dialog_factory_.GetWeakPtr())); 1539 return false; 1540} 1541 1542string16 BrowserView::GetWindowTitle() const { 1543 return browser_->GetWindowTitleForCurrentTab(); 1544} 1545 1546string16 BrowserView::GetAccessibleWindowTitle() const { 1547 if (IsOffTheRecord()) { 1548 return l10n_util::GetStringFUTF16( 1549 IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT, 1550 GetWindowTitle()); 1551 } 1552 return GetWindowTitle(); 1553} 1554 1555views::View* BrowserView::GetInitiallyFocusedView() { 1556 // We set the frame not focus on creation so this should never be called. 1557 NOTREACHED(); 1558 return NULL; 1559} 1560 1561bool BrowserView::ShouldShowWindowTitle() const { 1562#if defined(USE_ASH) 1563 // For Ash only, app host windows do not show an icon, crbug.com/119411. 1564 // Child windows (e.g. extension panels, popups) do show an icon. 1565 if (browser_->is_app() && browser_->app_type() == Browser::APP_TYPE_HOST) 1566 return false; 1567#endif 1568 return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR); 1569} 1570 1571gfx::ImageSkia BrowserView::GetWindowAppIcon() { 1572 if (browser_->is_app()) { 1573 WebContents* contents = chrome::GetActiveWebContents(browser_.get()); 1574 extensions::TabHelper* extensions_tab_helper = 1575 contents ? extensions::TabHelper::FromWebContents(contents) : NULL; 1576 if (extensions_tab_helper && extensions_tab_helper->GetExtensionAppIcon()) 1577 return gfx::ImageSkia(*extensions_tab_helper->GetExtensionAppIcon()); 1578 } 1579 1580 return GetWindowIcon(); 1581} 1582 1583gfx::ImageSkia BrowserView::GetWindowIcon() { 1584 if (browser_->is_app()) 1585 return browser_->GetCurrentPageIcon().AsImageSkia(); 1586 return gfx::ImageSkia(); 1587} 1588 1589bool BrowserView::ShouldShowWindowIcon() const { 1590#if defined(USE_ASH) 1591 // For Ash only, app host windows do not show an icon, crbug.com/119411. 1592 // Child windows (e.g. extension panels, popups) do show an icon. 1593 if (browser_->is_app() && browser_->app_type() == Browser::APP_TYPE_HOST) 1594 return false; 1595#endif 1596 return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR); 1597} 1598 1599bool BrowserView::ExecuteWindowsCommand(int command_id) { 1600 // This function handles WM_SYSCOMMAND, WM_APPCOMMAND, and WM_COMMAND. 1601#if defined(OS_WIN) && !defined(USE_AURA) 1602 if (command_id == IDC_DEBUG_FRAME_TOGGLE) 1603 GetWidget()->DebugToggleFrameType(); 1604 1605 // In Windows 8 metro mode prevent sizing and moving. 1606 if (base::win::IsMetroProcess()) { 1607 // Windows uses the 4 lower order bits of |notification_code| for type- 1608 // specific information so we must exclude this when comparing. 1609 static const int sc_mask = 0xFFF0; 1610 if (((command_id & sc_mask) == SC_MOVE) || 1611 ((command_id & sc_mask) == SC_SIZE) || 1612 ((command_id & sc_mask) == SC_MAXIMIZE)) 1613 return true; 1614 } 1615#endif 1616 // Translate WM_APPCOMMAND command ids into a command id that the browser 1617 // knows how to handle. 1618 int command_id_from_app_command = GetCommandIDForAppCommandID(command_id); 1619 if (command_id_from_app_command != -1) 1620 command_id = command_id_from_app_command; 1621 1622 return chrome::ExecuteCommand(browser_.get(), command_id); 1623} 1624 1625std::string BrowserView::GetWindowName() const { 1626 return chrome::GetWindowPlacementKey(browser_.get()); 1627} 1628 1629void BrowserView::SaveWindowPlacement(const gfx::Rect& bounds, 1630 ui::WindowShowState show_state) { 1631 // If IsFullscreen() is true, we've just changed into fullscreen mode, and 1632 // we're catching the going-into-fullscreen sizing and positioning calls, 1633 // which we want to ignore. 1634 if (!ShouldSaveOrRestoreWindowPos()) 1635 return; 1636 1637 if (!IsFullscreen() && chrome::ShouldSaveWindowPlacement(browser_.get())) { 1638 WidgetDelegate::SaveWindowPlacement(bounds, show_state); 1639 chrome::SaveWindowPlacement(browser_.get(), bounds, show_state); 1640 } 1641} 1642 1643bool BrowserView::GetSavedWindowPlacement( 1644 gfx::Rect* bounds, 1645 ui::WindowShowState* show_state) const { 1646 if (!ShouldSaveOrRestoreWindowPos()) 1647 return false; 1648 chrome::GetSavedWindowBoundsAndShowState(browser_.get(), bounds, show_state); 1649 1650#if defined(USE_ASH) 1651 if (browser_->is_type_popup() || browser_->is_type_panel()) { 1652 // In case of a popup or panel with an 'unspecified' location we are looking 1653 // for a good screen location. We are interpreting (0,0) as an unspecified 1654 // location. 1655 if (bounds->x() == 0 && bounds->y() == 0) { 1656 *bounds = ChromeShellDelegate::instance()->window_positioner()-> 1657 GetPopupPosition(*bounds); 1658 } 1659 } 1660#endif 1661 1662 if ((browser_->is_type_popup() && 1663 !browser_->is_devtools() && !browser_->is_app()) || 1664 (browser_->is_type_panel())) { 1665 // We are a popup window. The value passed in |bounds| represents two 1666 // pieces of information: 1667 // - the position of the window, in screen coordinates (outer position). 1668 // - the size of the content area (inner size). 1669 // We need to use these values to determine the appropriate size and 1670 // position of the resulting window. 1671 if (IsToolbarVisible()) { 1672 // If we're showing the toolbar, we need to adjust |*bounds| to include 1673 // its desired height, since the toolbar is considered part of the 1674 // window's client area as far as GetWindowBoundsForClientBounds is 1675 // concerned... 1676 bounds->set_height( 1677 bounds->height() + toolbar_->GetPreferredSize().height()); 1678 } 1679 1680 gfx::Rect window_rect = frame_->non_client_view()-> 1681 GetWindowBoundsForClientBounds(*bounds); 1682 window_rect.set_origin(bounds->origin()); 1683 1684 // When we are given x/y coordinates of 0 on a created popup window, 1685 // assume none were given by the window.open() command. 1686 if (window_rect.x() == 0 && window_rect.y() == 0) { 1687 gfx::Size size = window_rect.size(); 1688 window_rect.set_origin( 1689 WindowSizer::GetDefaultPopupOrigin(size, 1690 browser_->host_desktop_type())); 1691 } 1692 1693 *bounds = window_rect; 1694 *show_state = ui::SHOW_STATE_NORMAL; 1695 } 1696 1697 // We return true because we can _always_ locate reasonable bounds using the 1698 // WindowSizer, and we don't want to trigger the Window's built-in "size to 1699 // default" handling because the browser window has no default preferred 1700 // size. 1701 return true; 1702} 1703 1704views::View* BrowserView::GetContentsView() { 1705 return contents_container_; 1706} 1707 1708views::ClientView* BrowserView::CreateClientView(views::Widget* widget) { 1709 return this; 1710} 1711 1712void BrowserView::OnWidgetActivationChanged(views::Widget* widget, 1713 bool active) { 1714#if defined(USE_ASH) 1715 if (launcher_item_controller_.get()) 1716 launcher_item_controller_->BrowserActivationStateChanged(); 1717#endif 1718 1719 if (active) { 1720 BrowserList::SetLastActive(browser_.get()); 1721 browser_->OnWindowActivated(); 1722 } 1723} 1724 1725void BrowserView::OnWindowBeginUserBoundsChange() { 1726 WebContents* web_contents = GetActiveWebContents(); 1727 if (!web_contents) 1728 return; 1729 web_contents->GetRenderViewHost()->NotifyMoveOrResizeStarted(); 1730} 1731 1732void BrowserView::OnWidgetMove() { 1733 if (!initialized_) { 1734 // Creating the widget can trigger a move. Ignore it until we've initialized 1735 // things. 1736 return; 1737 } 1738 1739 // Cancel any tabstrip animations, some of them may be invalidated by the 1740 // window being repositioned. 1741 // Comment out for one cycle to see if this fixes dist tests. 1742 // tabstrip_->DestroyDragController(); 1743 1744 // status_bubble_ may be NULL if this is invoked during construction. 1745 if (status_bubble_.get()) 1746 status_bubble_->Reposition(); 1747 1748 chrome::HideBookmarkBubbleView(); 1749 1750 // Close the omnibox popup, if any. 1751 LocationBarView* location_bar_view = GetLocationBarView(); 1752 if (location_bar_view) 1753 location_bar_view->GetLocationEntry()->CloseOmniboxPopup(); 1754} 1755 1756views::Widget* BrowserView::GetWidget() { 1757 return View::GetWidget(); 1758} 1759 1760const views::Widget* BrowserView::GetWidget() const { 1761 return View::GetWidget(); 1762} 1763 1764/////////////////////////////////////////////////////////////////////////////// 1765// BrowserView, views::ClientView overrides: 1766 1767bool BrowserView::CanClose() { 1768 // You cannot close a frame for which there is an active originating drag 1769 // session. 1770 if (tabstrip_ && !tabstrip_->IsTabStripCloseable()) 1771 return false; 1772 1773 // Give beforeunload handlers the chance to cancel the close before we hide 1774 // the window below. 1775 if (!browser_->ShouldCloseWindow()) 1776 return false; 1777 1778 if (!browser_->tab_strip_model()->empty()) { 1779 // Tab strip isn't empty. Hide the frame (so it appears to have closed 1780 // immediately) and close all the tabs, allowing the renderers to shut 1781 // down. When the tab strip is empty we'll be called back again. 1782 frame_->Hide(); 1783 browser_->OnWindowClosing(); 1784 return false; 1785 } 1786 1787 // Empty TabStripModel, it's now safe to allow the Window to be closed. 1788 content::NotificationService::current()->Notify( 1789 chrome::NOTIFICATION_WINDOW_CLOSED, 1790 content::Source<gfx::NativeWindow>(frame_->GetNativeWindow()), 1791 content::NotificationService::NoDetails()); 1792 return true; 1793} 1794 1795int BrowserView::NonClientHitTest(const gfx::Point& point) { 1796#if defined(OS_WIN) && !defined(USE_AURA) 1797 // The following code is not in the LayoutManager because it's 1798 // independent of layout and also depends on the ResizeCorner which 1799 // is private. 1800 if (!frame_->IsMaximized() && !frame_->IsFullscreen()) { 1801 CRect client_rect; 1802 ::GetClientRect(frame_->GetNativeWindow(), &client_rect); 1803 gfx::Size resize_corner_size = ResizeCorner::GetSize(); 1804 gfx::Rect resize_corner_rect(client_rect.right - resize_corner_size.width(), 1805 client_rect.bottom - resize_corner_size.height(), 1806 resize_corner_size.width(), resize_corner_size.height()); 1807 bool rtl_dir = base::i18n::IsRTL(); 1808 if (rtl_dir) 1809 resize_corner_rect.set_x(0); 1810 if (resize_corner_rect.Contains(point)) { 1811 if (rtl_dir) 1812 return HTBOTTOMLEFT; 1813 return HTBOTTOMRIGHT; 1814 } 1815 } 1816#endif 1817 1818 return GetBrowserViewLayout()->NonClientHitTest(point); 1819} 1820 1821gfx::Size BrowserView::GetMinimumSize() { 1822 return GetBrowserViewLayout()->GetMinimumSize(); 1823} 1824 1825/////////////////////////////////////////////////////////////////////////////// 1826// BrowserView, protected 1827 1828void BrowserView::GetAccessiblePanes( 1829 std::vector<views::AccessiblePaneView*>* panes) { 1830 // This should be in the order of pane traversal of the panes using F6. 1831 // If one of these is invisible or has no focusable children, it will be 1832 // automatically skipped. 1833 panes->push_back(toolbar_); 1834 if (bookmark_bar_view_.get()) 1835 panes->push_back(bookmark_bar_view_.get()); 1836 if (infobar_container_) 1837 panes->push_back(infobar_container_); 1838 if (download_shelf_.get()) 1839 panes->push_back(download_shelf_.get()); 1840} 1841 1842/////////////////////////////////////////////////////////////////////////////// 1843// BrowserView, views::View overrides: 1844 1845std::string BrowserView::GetClassName() const { 1846 return kViewClassName; 1847} 1848 1849void BrowserView::Layout() { 1850 if (ignore_layout_) 1851 return; 1852 views::View::Layout(); 1853 1854 // The status bubble position requires that all other layout finish first. 1855 LayoutStatusBubble(); 1856 1857 MaybeStackBookmarkBarAtTop(); 1858} 1859 1860void BrowserView::PaintChildren(gfx::Canvas* canvas) { 1861 // Paint the |infobar_container_| last so that it may paint its 1862 // overlapping tabs. 1863 for (int i = 0; i < child_count(); ++i) { 1864 View* child = child_at(i); 1865 if (child != infobar_container_) 1866 child->Paint(canvas); 1867 } 1868 1869 infobar_container_->Paint(canvas); 1870} 1871 1872void BrowserView::ViewHierarchyChanged(bool is_add, 1873 views::View* parent, 1874 views::View* child) { 1875 if (!initialized_ && is_add && child == this && GetWidget()) { 1876 Init(); 1877 initialized_ = true; 1878 } 1879} 1880 1881void BrowserView::ChildPreferredSizeChanged(View* child) { 1882 Layout(); 1883} 1884 1885void BrowserView::GetAccessibleState(ui::AccessibleViewState* state) { 1886 state->name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); 1887 state->role = ui::AccessibilityTypes::ROLE_CLIENT; 1888} 1889 1890SkColor BrowserView::GetInfoBarSeparatorColor() const { 1891 // NOTE: Keep this in sync with ToolbarView::OnPaint()! 1892 return (IsTabStripVisible() || !frame_->ShouldUseNativeFrame()) ? 1893 ThemeService::GetDefaultColor(ThemeService::COLOR_TOOLBAR_SEPARATOR) : 1894 SK_ColorBLACK; 1895} 1896 1897void BrowserView::InfoBarContainerStateChanged(bool is_animating) { 1898 ToolbarSizeChanged(is_animating); 1899} 1900 1901bool BrowserView::DrawInfoBarArrows(int* x) const { 1902 if (x) { 1903 const LocationIconView* location_icon_view = 1904 toolbar_->location_bar()->location_icon_view(); 1905 gfx::Point icon_center(location_icon_view->GetImageBounds().CenterPoint()); 1906 ConvertPointToTarget(location_icon_view, this, &icon_center); 1907 *x = icon_center.x(); 1908 } 1909 return true; 1910} 1911 1912bool BrowserView::SplitHandleMoved(views::SingleSplitView* sender) { 1913 for (int i = 0; i < sender->child_count(); ++i) 1914 sender->child_at(i)->InvalidateLayout(); 1915 SchedulePaint(); 1916 Layout(); 1917 return false; 1918} 1919 1920void BrowserView::OnSysColorChange() { 1921 chrome::MaybeShowInvertBubbleView(browser_.get(), contents_); 1922} 1923 1924int BrowserView::GetOTRIconResourceID() const { 1925 int otr_resource_id = IDR_OTR_ICON; 1926 if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) { 1927 if (IsFullscreen()) 1928 otr_resource_id = IDR_OTR_ICON_FULLSCREEN; 1929#if defined(OS_WIN) && !defined(USE_AURA) 1930 if (base::win::IsMetroProcess()) 1931 otr_resource_id = IDR_OTR_ICON_FULLSCREEN; 1932#endif 1933 } 1934 1935 return otr_resource_id; 1936} 1937 1938views::LayoutManager* BrowserView::CreateLayoutManager() const { 1939 return new BrowserViewLayout; 1940} 1941 1942void BrowserView::Init() { 1943 GetWidget()->AddObserver(this); 1944 1945 SetLayoutManager(CreateLayoutManager()); 1946 // Stow a pointer to this object onto the window handle so that we can get at 1947 // it later when all we have is a native view. 1948 GetWidget()->SetNativeWindowProperty(kBrowserViewKey, this); 1949 1950 // Stow a pointer to the browser's profile onto the window handle so that we 1951 // can get it later when all we have is a native view. 1952 GetWidget()->SetNativeWindowProperty(Profile::kProfileKey, 1953 browser_->profile()); 1954 1955 // Start a hung plugin window detector for this browser object (as long as 1956 // hang detection is not disabled). 1957 if (!CommandLine::ForCurrentProcess()->HasSwitch( 1958 switches::kDisableHangMonitor)) { 1959 InitHangMonitor(); 1960 } 1961 1962 LoadAccelerators(); 1963 1964 // TabStrip takes ownership of the controller. 1965 BrowserTabStripController* tabstrip_controller = 1966 new BrowserTabStripController(browser_.get(), 1967 browser_->tab_strip_model()); 1968 tabstrip_ = new TabStrip(tabstrip_controller); 1969 AddChildView(tabstrip_); 1970 tabstrip_controller->InitFromModel(tabstrip_); 1971 1972 infobar_container_ = new InfoBarContainerView(this, 1973 browser()->search_model()); 1974 AddChildView(infobar_container_); 1975 1976 contents_container_ = new views::WebView(browser_->profile()); 1977 contents_container_->set_id(VIEW_ID_TAB_CONTAINER); 1978 contents_ = new ContentsContainer(contents_container_); 1979 1980 toolbar_ = new ToolbarView(browser_.get()); 1981 AddChildView(toolbar_); 1982 toolbar_->Init(); 1983 1984 preview_controller_.reset( 1985 new InstantPreviewControllerViews(browser(), this, contents_)); 1986 1987 SkColor bg_color = GetWidget()->GetThemeProvider()-> 1988 GetColor(ThemeService::COLOR_TOOLBAR); 1989 1990 devtools_container_ = new views::WebView(browser_->profile()); 1991 devtools_container_->set_id(VIEW_ID_DEV_TOOLS_DOCKED); 1992 devtools_container_->SetVisible(false); 1993 1994 views::View* contents_view = contents_; 1995 1996 contents_split_ = new views::SingleSplitView( 1997 contents_view, 1998 devtools_container_, 1999 views::SingleSplitView::VERTICAL_SPLIT, 2000 this); 2001 contents_split_->set_id(VIEW_ID_CONTENTS_SPLIT); 2002 contents_split_->SetAccessibleName( 2003 l10n_util::GetStringUTF16(IDS_ACCNAME_WEB_CONTENTS)); 2004 contents_split_->set_background( 2005 views::Background::CreateSolidBackground(bg_color)); 2006 AddChildView(contents_split_); 2007 set_contents_view(contents_split_); 2008 2009 status_bubble_.reset(new StatusBubbleViews(contents_)); 2010 2011#if defined(OS_WIN) && !defined(USE_AURA) 2012 // Create a custom JumpList and add it to an observer of TabRestoreService 2013 // so we can update the custom JumpList when a tab is added or removed. 2014 if (JumpList::Enabled()) { 2015 jumplist_ = new JumpList(); 2016 jumplist_->AddObserver(browser_->profile()); 2017 } 2018#endif 2019 2020 // We're now initialized and ready to process Layout requests. 2021 ignore_layout_ = false; 2022} 2023 2024void BrowserView::LoadingAnimationCallback() { 2025 base::TimeTicks now = base::TimeTicks::Now(); 2026 if (!last_animation_time_.is_null()) { 2027 UMA_HISTOGRAM_TIMES( 2028 "Tabs.LoadingAnimationTime", 2029 now - last_animation_time_); 2030 } 2031 last_animation_time_ = now; 2032 if (browser_->is_type_tabbed()) { 2033 // Loading animations are shown in the tab for tabbed windows. We check the 2034 // browser type instead of calling IsTabStripVisible() because the latter 2035 // will return false for fullscreen windows, but we still need to update 2036 // their animations (so that when they come out of fullscreen mode they'll 2037 // be correct). 2038 tabstrip_->UpdateLoadingAnimations(); 2039 } else if (ShouldShowWindowIcon()) { 2040 // ... or in the window icon area for popups and app windows. 2041 WebContents* web_contents = chrome::GetActiveWebContents(browser_.get()); 2042 // GetActiveWebContents can return NULL for example under Purify when 2043 // the animations are running slowly and this function is called on a timer 2044 // through LoadingAnimationCallback. 2045 frame_->UpdateThrobber(web_contents && web_contents->IsLoading()); 2046 } 2047} 2048 2049// BrowserView, private -------------------------------------------------------- 2050 2051BrowserViewLayout* BrowserView::GetBrowserViewLayout() const { 2052 return static_cast<BrowserViewLayout*>(GetLayoutManager()); 2053} 2054 2055void BrowserView::LayoutStatusBubble() { 2056 // In restored mode, the client area has a client edge between it and the 2057 // frame. 2058 int overlap = StatusBubbleViews::kShadowThickness; 2059 // The extra pixels defined by kClientEdgeThickness is only drawn in frame 2060 // content border on windows for non-aura build. 2061#if !defined(USE_ASH) 2062 overlap += 2063 IsMaximized() ? 0 : views::NonClientFrameView::kClientEdgeThickness; 2064#endif 2065 int height = status_bubble_->GetPreferredSize().height(); 2066 int contents_height = status_bubble_->base_view()->bounds().height(); 2067 gfx::Point origin(-overlap, contents_height - height + overlap); 2068 status_bubble_->SetBounds(origin.x(), origin.y(), width() / 3, height); 2069} 2070 2071bool BrowserView::MaybeShowBookmarkBar(TabContents* contents) { 2072 views::View* new_bookmark_bar_view = NULL; 2073 if (browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR) && 2074 contents) { 2075 if (!bookmark_bar_view_.get()) { 2076 bookmark_bar_view_.reset(new BookmarkBarView(browser_.get(), this)); 2077 bookmark_bar_view_->set_owned_by_client(); 2078 bookmark_bar_view_->set_background( 2079 new BookmarkExtensionBackground(this, bookmark_bar_view_.get(), 2080 browser_.get())); 2081 bookmark_bar_view_->SetBookmarkBarState( 2082 browser_->bookmark_bar_state(), 2083 BookmarkBar::DONT_ANIMATE_STATE_CHANGE, 2084 browser_->search_model()->mode()); 2085 } 2086 bookmark_bar_view_->SetPageNavigator(contents->web_contents()); 2087 new_bookmark_bar_view = bookmark_bar_view_.get(); 2088 } 2089 return UpdateChildViewAndLayout(new_bookmark_bar_view, &active_bookmark_bar_); 2090} 2091 2092bool BrowserView::MaybeShowInfoBar(TabContents* contents) { 2093 // TODO(beng): Remove this function once the interface between 2094 // InfoBarContainer, DownloadShelfView and WebContents and this 2095 // view is sorted out. 2096 return true; 2097} 2098 2099void BrowserView::UpdateDevToolsForContents(TabContents* tab_contents) { 2100 DevToolsWindow* new_devtools_window = tab_contents ? 2101 DevToolsWindow::GetDockedInstanceForInspectedTab( 2102 tab_contents->web_contents()) : NULL; 2103 // Fast return in case of the same window having same orientation. 2104 if (devtools_window_ == new_devtools_window) { 2105 if (!new_devtools_window || 2106 (new_devtools_window->dock_side() == devtools_dock_side_)) { 2107 return; 2108 } 2109 } 2110 2111 // Replace tab contents. 2112 if (devtools_window_ != new_devtools_window) { 2113 devtools_container_->SetWebContents(new_devtools_window ? 2114 new_devtools_window->tab_contents()->web_contents() : NULL); 2115 } 2116 2117 // Store last used position. 2118 if (devtools_window_) { 2119 if (devtools_dock_side_ == DEVTOOLS_DOCK_SIDE_RIGHT) { 2120 devtools_window_->SetWidth( 2121 contents_split_->width() - contents_split_->divider_offset()); 2122 } else { 2123 devtools_window_->SetHeight( 2124 contents_split_->height() - contents_split_->divider_offset()); 2125 } 2126 } 2127 2128 // Show / hide container if necessary. Changing dock orientation is 2129 // hide + show. 2130 bool should_hide = devtools_window_ && (!new_devtools_window || 2131 devtools_dock_side_ != new_devtools_window->dock_side()); 2132 bool should_show = new_devtools_window && (!devtools_window_ || should_hide); 2133 2134 if (should_hide) 2135 HideDevToolsContainer(); 2136 2137 devtools_window_ = new_devtools_window; 2138 2139 if (should_show) { 2140 devtools_dock_side_ = new_devtools_window->dock_side(); 2141 ShowDevToolsContainer(); 2142 } else if (new_devtools_window) { 2143 UpdateDevToolsSplitPosition(); 2144 } 2145} 2146 2147void BrowserView::ShowDevToolsContainer() { 2148 if (!devtools_focus_tracker_.get()) { 2149 // Install devtools focus tracker when dev tools window is shown for the 2150 // first time. 2151 devtools_focus_tracker_.reset( 2152 new views::ExternalFocusTracker(devtools_container_, 2153 GetFocusManager())); 2154 } 2155 devtools_container_->SetVisible(true); 2156 devtools_dock_side_ = devtools_window_->dock_side(); 2157 bool dock_to_right = devtools_dock_side_ == DEVTOOLS_DOCK_SIDE_RIGHT; 2158 contents_split_->set_orientation( 2159 dock_to_right ? views::SingleSplitView::HORIZONTAL_SPLIT 2160 : views::SingleSplitView::VERTICAL_SPLIT); 2161 UpdateDevToolsSplitPosition(); 2162 contents_split_->InvalidateLayout(); 2163 Layout(); 2164} 2165 2166void BrowserView::HideDevToolsContainer() { 2167 // Restore focus to the last focused view when hiding devtools window. 2168 devtools_focus_tracker_->FocusLastFocusedExternalView(); 2169 devtools_container_->SetVisible(false); 2170 contents_split_->InvalidateLayout(); 2171 Layout(); 2172} 2173 2174void BrowserView::UpdateDevToolsSplitPosition() { 2175 if (devtools_window_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT) { 2176 int split_offset = contents_split_->width() - 2177 devtools_window_->GetWidth(contents_split_->width()); 2178 contents_split_->set_divider_offset(split_offset); 2179 } else { 2180 int split_offset = contents_split_->height() - 2181 devtools_window_->GetHeight(contents_split_->height()); 2182 contents_split_->set_divider_offset(split_offset); 2183 } 2184} 2185 2186void BrowserView::UpdateUIForContents(TabContents* contents) { 2187 bool needs_layout = MaybeShowBookmarkBar(contents); 2188 needs_layout |= MaybeShowInfoBar(contents); 2189 if (needs_layout) 2190 Layout(); 2191} 2192 2193bool BrowserView::UpdateChildViewAndLayout(views::View* new_view, 2194 views::View** old_view) { 2195 DCHECK(old_view); 2196 if (*old_view == new_view) { 2197 // The views haven't changed, if the views pref changed schedule a layout. 2198 if (new_view) { 2199 if (new_view->GetPreferredSize().height() != new_view->height()) 2200 return true; 2201 } 2202 return false; 2203 } 2204 2205 // The views differ, and one may be null (but not both). Remove the old 2206 // view (if it non-null), and add the new one (if it is non-null). If the 2207 // height has changed, schedule a layout, otherwise reuse the existing 2208 // bounds to avoid scheduling a layout. 2209 2210 int current_height = 0; 2211 if (*old_view) { 2212 current_height = (*old_view)->height(); 2213 RemoveChildView(*old_view); 2214 } 2215 2216 int new_height = 0; 2217 if (new_view) { 2218 new_height = new_view->GetPreferredSize().height(); 2219 AddChildView(new_view); 2220 } 2221 bool changed = false; 2222 if (new_height != current_height) { 2223 changed = true; 2224 } else if (new_view && *old_view) { 2225 // The view changed, but the new view wants the same size, give it the 2226 // bounds of the last view and have it repaint. 2227 new_view->SetBoundsRect((*old_view)->bounds()); 2228 new_view->SchedulePaint(); 2229 } else if (new_view) { 2230 DCHECK_EQ(0, new_height); 2231 // The heights are the same, but the old view is null. This only happens 2232 // when the height is zero. Zero out the bounds. 2233 new_view->SetBounds(0, 0, 0, 0); 2234 } 2235 *old_view = new_view; 2236 return changed; 2237} 2238 2239void BrowserView::ProcessFullscreen(bool fullscreen, 2240 FullscreenType type, 2241 const GURL& url, 2242 FullscreenExitBubbleType bubble_type) { 2243 // Reduce jankiness during the following position changes by: 2244 // * Hiding the window until it's in the final position 2245 // * Ignoring all intervening Layout() calls, which resize the webpage and 2246 // thus are slow and look ugly 2247 ignore_layout_ = true; 2248 LocationBarView* location_bar = GetLocationBarView(); 2249#if defined(OS_WIN) && !defined(USE_AURA) 2250 OmniboxViewWin* omnibox_win = 2251 GetOmniboxViewWin(location_bar->GetLocationEntry()); 2252#endif 2253 2254 if (type == FOR_METRO || !fullscreen) { 2255 // Hide the fullscreen bubble as soon as possible, since the mode toggle can 2256 // take enough time for the user to notice. 2257 fullscreen_bubble_.reset(); 2258 } 2259 2260 if (fullscreen) { 2261 // Move focus out of the location bar if necessary. 2262 views::FocusManager* focus_manager = GetFocusManager(); 2263 DCHECK(focus_manager); 2264 // Look for focus in the location bar itself or any child view. 2265 if (location_bar->Contains(focus_manager->GetFocusedView())) 2266 focus_manager->ClearFocus(); 2267 2268#if defined(OS_WIN) && !defined(USE_AURA) 2269 if (omnibox_win) { 2270 // If we don't hide the edit and force it to not show until we come out of 2271 // fullscreen, then if the user was on the New Tab Page, the edit contents 2272 // will appear atop the web contents once we go into fullscreen mode. This 2273 // has something to do with how we move the main window while it's hidden; 2274 // if we don't hide the main window below, we don't get this problem. 2275 omnibox_win->set_force_hidden(true); 2276 ShowWindow(omnibox_win->m_hWnd, SW_HIDE); 2277 } 2278#endif 2279 } 2280#if defined(OS_WIN) && !defined(USE_AURA) 2281 views::ScopedFullscreenVisibility visibility(frame_->GetNativeView()); 2282#endif 2283 2284 if (type == FOR_METRO) { 2285#if defined(OS_WIN) && !defined(USE_AURA) 2286 // Enter metro snap mode. 2287 static_cast<views::NativeWidgetWin*>( 2288 frame_->native_widget())->SetMetroSnapFullscreen(fullscreen); 2289#endif 2290 } else { 2291 // Toggle fullscreen mode. 2292 frame_->SetFullscreen(fullscreen); 2293 } 2294 2295 browser_->WindowFullscreenStateChanged(); 2296 2297 if (fullscreen) { 2298 bool is_kiosk = 2299 CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode); 2300 if (!is_kiosk && type != FOR_METRO) { 2301 fullscreen_bubble_.reset(new FullscreenExitBubbleViews( 2302 GetWidget(), browser_.get(), url, bubble_type)); 2303 } 2304 } else { 2305#if defined(OS_WIN) && !defined(USE_AURA) 2306 if (omnibox_win) { 2307 // Show the edit again since we're no longer in fullscreen mode. 2308 omnibox_win->set_force_hidden(false); 2309 ShowWindow(omnibox_win->m_hWnd, SW_SHOW); 2310 } 2311#endif 2312 } 2313 2314 // Undo our anti-jankiness hacks and force the window to re-layout now that 2315 // it's in its final position. 2316 ignore_layout_ = false; 2317 Layout(); 2318} 2319 2320void BrowserView::LoadAccelerators() { 2321#if defined(OS_WIN) && !defined(USE_AURA) 2322 HACCEL accelerator_table = AtlLoadAccelerators(IDR_MAINFRAME); 2323 DCHECK(accelerator_table); 2324 2325 // We have to copy the table to access its contents. 2326 int count = CopyAcceleratorTable(accelerator_table, 0, 0); 2327 if (count == 0) { 2328 // Nothing to do in that case. 2329 return; 2330 } 2331 2332 ACCEL* accelerators = static_cast<ACCEL*>(malloc(sizeof(ACCEL) * count)); 2333 CopyAcceleratorTable(accelerator_table, accelerators, count); 2334 2335 views::FocusManager* focus_manager = GetFocusManager(); 2336 DCHECK(focus_manager); 2337 2338 // Let's fill our own accelerator table. 2339 for (int i = 0; i < count; ++i) { 2340 ui::Accelerator accelerator( 2341 static_cast<ui::KeyboardCode>(accelerators[i].key), 2342 ui::GetModifiersFromACCEL(accelerators[i])); 2343 accelerator_table_[accelerator] = accelerators[i].cmd; 2344 2345 // Also register with the focus manager. 2346 focus_manager->RegisterAccelerator( 2347 accelerator, ui::AcceleratorManager::kNormalPriority, this); 2348 } 2349 2350 // We don't need the Windows accelerator table anymore. 2351 free(accelerators); 2352#else 2353 views::FocusManager* focus_manager = GetFocusManager(); 2354 DCHECK(focus_manager); 2355 // Let's fill our own accelerator table. 2356 for (size_t i = 0; i < chrome::kAcceleratorMapLength; ++i) { 2357 ui::Accelerator accelerator(chrome::kAcceleratorMap[i].keycode, 2358 chrome::kAcceleratorMap[i].modifiers); 2359 accelerator_table_[accelerator] = chrome::kAcceleratorMap[i].command_id; 2360 2361 // Also register with the focus manager. 2362 focus_manager->RegisterAccelerator( 2363 accelerator, ui::AcceleratorManager::kNormalPriority, this); 2364 } 2365#endif 2366} 2367 2368int BrowserView::GetCommandIDForAppCommandID(int app_command_id) const { 2369#if defined(OS_WIN) && !defined(USE_AURA) 2370 switch (app_command_id) { 2371 // NOTE: The order here matches the APPCOMMAND declaration order in the 2372 // Windows headers. 2373 case APPCOMMAND_BROWSER_BACKWARD: return IDC_BACK; 2374 case APPCOMMAND_BROWSER_FORWARD: return IDC_FORWARD; 2375 case APPCOMMAND_BROWSER_REFRESH: return IDC_RELOAD; 2376 case APPCOMMAND_BROWSER_HOME: return IDC_HOME; 2377 case APPCOMMAND_BROWSER_STOP: return IDC_STOP; 2378 case APPCOMMAND_BROWSER_SEARCH: return IDC_FOCUS_SEARCH; 2379 case APPCOMMAND_HELP: return IDC_HELP_PAGE_VIA_KEYBOARD; 2380 case APPCOMMAND_NEW: return IDC_NEW_TAB; 2381 case APPCOMMAND_OPEN: return IDC_OPEN_FILE; 2382 case APPCOMMAND_CLOSE: return IDC_CLOSE_TAB; 2383 case APPCOMMAND_SAVE: return IDC_SAVE_PAGE; 2384 case APPCOMMAND_PRINT: return IDC_PRINT; 2385 case APPCOMMAND_COPY: return IDC_COPY; 2386 case APPCOMMAND_CUT: return IDC_CUT; 2387 case APPCOMMAND_PASTE: return IDC_PASTE; 2388 2389 // TODO(pkasting): http://b/1113069 Handle these. 2390 case APPCOMMAND_UNDO: 2391 case APPCOMMAND_REDO: 2392 case APPCOMMAND_SPELL_CHECK: 2393 default: return -1; 2394 } 2395#else 2396 // App commands are Windows-specific so there's nothing to do here. 2397 return -1; 2398#endif 2399} 2400 2401void BrowserView::InitHangMonitor() { 2402#if defined(OS_WIN) && !defined(USE_AURA) 2403 PrefService* pref_service = g_browser_process->local_state(); 2404 if (!pref_service) 2405 return; 2406 2407 int plugin_message_response_timeout = 2408 pref_service->GetInteger(prefs::kPluginMessageResponseTimeout); 2409 int hung_plugin_detect_freq = 2410 pref_service->GetInteger(prefs::kHungPluginDetectFrequency); 2411 if ((hung_plugin_detect_freq > 0) && 2412 hung_window_detector_.Initialize(GetWidget()->GetNativeView(), 2413 plugin_message_response_timeout)) { 2414 ticker_.set_tick_interval(hung_plugin_detect_freq); 2415 ticker_.RegisterTickHandler(&hung_window_detector_); 2416 ticker_.Start(); 2417 2418 pref_service->SetInteger(prefs::kPluginMessageResponseTimeout, 2419 plugin_message_response_timeout); 2420 pref_service->SetInteger(prefs::kHungPluginDetectFrequency, 2421 hung_plugin_detect_freq); 2422 } 2423#endif 2424} 2425 2426void BrowserView::UpdateAcceleratorMetrics( 2427 const ui::Accelerator& accelerator, int command_id) { 2428 const ui::KeyboardCode key_code = accelerator.key_code(); 2429 if (command_id == IDC_HELP_PAGE_VIA_KEYBOARD && key_code == ui::VKEY_F1) 2430 content::RecordAction(UserMetricsAction("ShowHelpTabViaF1")); 2431 2432 if (command_id == IDC_BOOKMARK_PAGE) 2433 UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint", 2434 bookmark_utils::ENTRY_POINT_ACCELERATOR, 2435 bookmark_utils::ENTRY_POINT_LIMIT); 2436 2437#if defined(OS_CHROMEOS) 2438 // Collect information about the relative popularity of various accelerators 2439 // on Chrome OS. 2440 switch (command_id) { 2441 case IDC_BACK: 2442 if (key_code == ui::VKEY_BACK) 2443 content::RecordAction(UserMetricsAction("Accel_Back_Backspace")); 2444 else if (key_code == ui::VKEY_F1) 2445 content::RecordAction(UserMetricsAction("Accel_Back_F1")); 2446 else if (key_code == ui::VKEY_LEFT) 2447 content::RecordAction(UserMetricsAction("Accel_Back_Left")); 2448 break; 2449 case IDC_FORWARD: 2450 if (key_code == ui::VKEY_BACK) 2451 content::RecordAction(UserMetricsAction("Accel_Forward_Backspace")); 2452 else if (key_code == ui::VKEY_F2) 2453 content::RecordAction(UserMetricsAction("Accel_Forward_F2")); 2454 else if (key_code == ui::VKEY_RIGHT) 2455 content::RecordAction(UserMetricsAction("Accel_Forward_Right")); 2456 break; 2457 case IDC_RELOAD: 2458 case IDC_RELOAD_IGNORING_CACHE: 2459 if (key_code == ui::VKEY_R) 2460 content::RecordAction(UserMetricsAction("Accel_Reload_R")); 2461 else if (key_code == ui::VKEY_F3) 2462 content::RecordAction(UserMetricsAction("Accel_Reload_F3")); 2463 break; 2464 case IDC_FULLSCREEN: 2465 if (key_code == ui::VKEY_F4) 2466 content::RecordAction(UserMetricsAction("Accel_Fullscreen_F4")); 2467 break; 2468 case IDC_FOCUS_LOCATION: 2469 if (key_code == ui::VKEY_D) 2470 content::RecordAction(UserMetricsAction("Accel_FocusLocation_D")); 2471 else if (key_code == ui::VKEY_L) 2472 content::RecordAction(UserMetricsAction("Accel_FocusLocation_L")); 2473 break; 2474 case IDC_FOCUS_SEARCH: 2475 if (key_code == ui::VKEY_E) 2476 content::RecordAction(UserMetricsAction("Accel_FocusSearch_E")); 2477 else if (key_code == ui::VKEY_K) 2478 content::RecordAction(UserMetricsAction("Accel_FocusSearch_K")); 2479 break; 2480 default: 2481 // Do nothing. 2482 break; 2483 } 2484#endif 2485} 2486 2487gfx::Size BrowserView::GetResizeCornerSize() const { 2488 return ResizeCorner::GetSize(); 2489} 2490 2491void BrowserView::CreateLauncherIcon() { 2492#if defined(USE_ASH) 2493 if (chrome::IsNativeWindowInAsh(GetNativeWindow()) && 2494 !launcher_item_controller_.get()) { 2495 launcher_item_controller_.reset( 2496 BrowserLauncherItemController::Create(browser_.get())); 2497 } 2498#endif // defined(USE_ASH) 2499} 2500 2501// static 2502BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) { 2503 // Create the view and the frame. The frame will attach itself via the view 2504 // so we don't need to do anything with the pointer. 2505 BrowserView* view = new BrowserView(browser); 2506 (new BrowserFrame(view))->InitBrowserFrame(); 2507 view->GetWidget()->non_client_view()->SetAccessibleName( 2508 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); 2509 return view; 2510} 2511 2512void BrowserView::ShowAvatarBubble(WebContents* web_contents, 2513 const gfx::Rect& rect) { 2514 gfx::Point origin(rect.origin()); 2515 views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin); 2516 gfx::Rect bounds(origin, rect.size()); 2517 2518 AvatarMenuBubbleView* bubble = new AvatarMenuBubbleView(this, 2519 views::BubbleBorder::TOP_RIGHT, bounds, browser_.get()); 2520 views::BubbleDelegateView::CreateBubble(bubble); 2521 bubble->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); 2522 bubble->Show(); 2523} 2524 2525void BrowserView::ShowAvatarBubbleFromAvatarButton() { 2526 AvatarMenuButton* button = frame_->GetAvatarMenuButton(); 2527 if (button) 2528 button->ShowAvatarBubble(); 2529} 2530 2531void BrowserView::ShowPasswordGenerationBubble( 2532 const gfx::Rect& rect, 2533 const content::PasswordForm& form, 2534 autofill::PasswordGenerator* password_generator) { 2535 // Create a rect in the content bounds that the bubble will point to. 2536 gfx::Point origin(rect.origin()); 2537 views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin); 2538 gfx::Rect bounds(origin, rect.size()); 2539 2540 // Create the bubble. 2541 WebContents* web_contents = GetActiveWebContents(); 2542 if (!web_contents) 2543 return; 2544 2545 PasswordGenerationBubbleView* bubble = 2546 new PasswordGenerationBubbleView( 2547 form, 2548 bounds, 2549 this, 2550 web_contents->GetRenderViewHost(), 2551 PasswordManager::FromWebContents(web_contents), 2552 password_generator, 2553 browser_.get(), 2554 GetWidget()->GetThemeProvider()); 2555 2556 views::BubbleDelegateView::CreateBubble(bubble); 2557 bubble->SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR); 2558 bubble->Show(); 2559} 2560 2561bool BrowserView::DoCutCopyPaste(void (content::RenderWidgetHost::*method)()) { 2562#if defined(USE_AURA) 2563 WebContents* contents = chrome::GetActiveWebContents(browser_.get()); 2564 if (contents && contents->GetContentNativeView() && 2565 contents->GetContentNativeView()->HasFocus()) { 2566 (contents->GetRenderViewHost()->*method)(); 2567 return true; 2568 } 2569#elif defined(OS_WIN) 2570 // TODO(yusukes): Support non-Aura Windows. 2571#endif 2572 return false; 2573} 2574 2575void BrowserView::ActivateAppModalDialog() const { 2576 // If another browser is app modal, flash and activate the modal browser. 2577 AppModalDialog* active_dialog = 2578 AppModalDialogQueue::GetInstance()->active_dialog(); 2579 if (!active_dialog) 2580 return; 2581 2582 Browser* modal_browser = 2583 browser::FindBrowserWithWebContents(active_dialog->web_contents()); 2584 if (modal_browser && (browser_ != modal_browser)) { 2585 modal_browser->window()->FlashFrame(true); 2586 modal_browser->window()->Activate(); 2587 } 2588 2589 AppModalDialogQueue::GetInstance()->ActivateModalDialog(); 2590} 2591 2592void BrowserView::MaybeStackBookmarkBarAtTop() { 2593 if (bookmark_bar_view_.get()) 2594 bookmark_bar_view_->MaybeStackAtTop(); 2595} 2596